Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nagadomi committed May 16, 2015
0 parents commit 1273b36
Show file tree
Hide file tree
Showing 19 changed files with 7,313 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
*~
cache/*.png
78 changes: 78 additions & 0 deletions assets/index.html
@@ -0,0 +1,78 @@
<html>
<head>
<style type="text/css" rel="http://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css"></style>
<style type="text/css">
body {
margin: 1em 2em 1em 2em;
background: LightGray;
width: 640px;
}
fieldset {
margin-top: 1em;
margin-bottom: 1em;
}
.about {
font-size: 0.8em;
margin: 1em 0 1em 0;
}
.help {
font-size: 0.8em;
margin: 1em 0 1em 0;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
function clear_file() {
var new_file = $("#file").clone();
new_file.change(clear_url);
$("#file").replaceWith(new_file);
}
function clear_url() {
$("#url").val("")
}
$(function (){
$("#url").change(clear_file);
$("#file").change(clear_url);
})
</script>
</head>
<body>
<h1>waifu2x</h1>
<div class="header">
<a href="https://github.com/you">
<img style="position: absolute; top: 0; left: 540; border: 0;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png">
</a>
<a href="index.ja.html">ja</a>/<a href="index.html">en</a>
</div>
<div class="about">
Single-Image Super-Resolution for anime/fan-arts using Deep Convolutional Neural Networks.
</div>
<form action="/api" method="POST" enctype="multipart/form-data" target="_blank">
<fieldset>
<legend>Image</legend>
<div>
URL: <input id="url" type="text" name="url" size="64"/> or
</div>
<div>
FILE: <input id="file" type="file" name="file"/>
</div>
<div class="help">
Limits: FileSize: 2MB, Noise Reduction: 2560x2560px, Upscaling: 1280x1280px
</div>
</fieldset>
<fieldset>
<legend>Noise Reduction (expect JPEG Artifact)</legend>
<label><input type="radio" name="noise" value="0"> None</label>
<label><input type="radio" name="noise" value="1" checked="checked"> Low</label>
<label><input type="radio" name="noise" value="2"> High</label>
</fieldset>
<fieldset>
<legend>Upscaling</legend>
<label><input type="radio" name="scale" value="0" checked="checked"> None</label>
<label><input type="radio" name="scale" value="1"> 1.6x</label>
<label><input type="radio" name="scale" value="2"> 2x</label>
</fieldset>
<input type="submit"/>
</form>
</body>
</html>
85 changes: 85 additions & 0 deletions assets/index.ja.html
@@ -0,0 +1,85 @@
<html lang="ja">
<head>
<meta charset="UTF-8">
<style type="text/css" rel="http://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css"></style>
<style type="text/css">
body {
margin: 1em 2em 1em 2em;
background: LightGray;
width: 640px;
}
fieldset {
margin-top: 1em;
margin-bottom: 1em;
}
.about {
font-size: 0.8em;
margin: 1em 0 1em 0;
}
.help {
font-size: 0.8em;
margin: 1em 0 1em 0;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript">
function clear_file() {
var new_file = $("#file").clone();
new_file.change(clear_url);
$("#file").replaceWith(new_file);
}
function clear_url() {
$("#url").val("")
}
$(function (){
$("#url").change(clear_file);
$("#file").change(clear_url);
})
</script>
</head>
<body>
<h1>waifu2x</h1>
<div class="header">
<a href="https://github.com/you">
<img style="position: absolute; top: 0; left: 540; border: 0;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png">
</a>
</div>
<div class="about">
深層畳み込みニューラルネットワークによる二次元画像のための超解像システム.
</div>
<form action="/api" method="POST" enctype="multipart/form-data" target="_blank">
<fieldset>
<legend>Image</legend>
<div>
URL: <input id="url" type="text" name="url" size="64"/> or
</div>
<div>
FILE: <input id="file" type="file" name="file"/>
</div>
<div class="help">
制限: サイズ: 2MB, ノイズ除去: 2560x2560px, 拡大: 1280x1280px
</div>
</fieldset>
<fieldset>
<legend>ノイズ除去 (JPEGノイズを想定)</legend>
<label><input type="radio" name="noise" value="0"> なし</label>
<label><input type="radio" name="noise" value="1" checked="checked"></label>
<label><input type="radio" name="noise" value="2"></label>
</fieldset>
<fieldset>
<legend>拡大</legend>
<label><input type="radio" name="scale" value="0" checked="checked"> なし</label>
<label><input type="radio" name="scale" value="1"> 1.6x</label>
<label><input type="radio" name="scale" value="2"> 2x</label>
</fieldset>
<input type="submit" value="実行"/>
</form>
<div class="help">
<ul>
<li>なし/なしで入力画像を変換せずに出力する。ブラウザのタブで変換結果を比較したい人用。</li>
<li>JPEG画像であれば劣化がないように見えてもノイズ除去弱を推奨。</li>
<li>マンガスキャンの拡大はスクリーントーンが謎の模様に再構成されるため非対応。</li>
</ul>
</div>
</body>
</html>
Empty file added cache/.gitkeep
Empty file.
69 changes: 69 additions & 0 deletions cleanup_model.lua
@@ -0,0 +1,69 @@
require 'cunn'
require 'cudnn'
require './lib/LeakyReLU'

torch.setdefaulttensortype("torch.FloatTensor")

-- ref: https://github.com/torch/nn/issues/112#issuecomment-64427049
local function zeroDataSize(data)
if type(data) == 'table' then
for i = 1, #data do
data[i] = zeroDataSize(data[i])
end
elseif type(data) == 'userdata' then
data = torch.Tensor():typeAs(data)
end
return data
end

-- Resize the output, gradInput, etc temporary tensors to zero (so that the
-- on disk size is smaller)
local function cleanupModel(node)
if node.output ~= nil then
node.output = zeroDataSize(node.output)
end
if node.gradInput ~= nil then
node.gradInput = zeroDataSize(node.gradInput)
end
if node.finput ~= nil then
node.finput = zeroDataSize(node.finput)
end
if tostring(node) == "nn.LeakyReLU" then
if node.negative ~= nil then
node.negative = zeroDataSize(node.negative)
end
end
if tostring(node) == "nn.Dropout" then
if node.noise ~= nil then
node.noise = zeroDataSize(node.noise)
end
end
-- Recurse on nodes with 'modules'
if (node.modules ~= nil) then
if (type(node.modules) == 'table') then
for i = 1, #node.modules do
local child = node.modules[i]
cleanupModel(child)
end
end
end

collectgarbage()
end

local cmd = torch.CmdLine()
cmd:text()
cmd:text("cleanup model")
cmd:text("Options:")
cmd:option("-model", "./model.t7", 'path of model file')
cmd:option("-iformat", "binary", 'input format')
cmd:option("-oformat", "binary", 'output format')

local opt = cmd:parse(arg)
local model = torch.load(opt.model, opt.iformat)
if model then
cleanupModel(model)
torch.save(opt.model, model, opt.oformat)
else
error("model not found")
end
30 changes: 30 additions & 0 deletions lib/LeakyReLU.lua
@@ -0,0 +1,30 @@
if nn.LeakyReLU then
return
end
local LeakyReLU, parent = torch.class('nn.LeakyReLU','nn.Module')

function LeakyReLU:__init(negative_scale)
parent.__init(self)
self.negative_scale = negative_scale or 0.333
self.negative = torch.Tensor()
end

function LeakyReLU:updateOutput(input)
self.output:resizeAs(input):copy(input):abs():add(input):div(2)
self.negative:resizeAs(input):copy(input):abs():add(-1.0, input):mul(-0.5*self.negative_scale)
self.output:add(self.negative)

return self.output
end

function LeakyReLU:updateGradInput(input, gradOutput)
self.gradInput:resizeAs(gradOutput)
-- filter positive
self.negative:sign():add(1)
torch.cmul(self.gradInput, gradOutput, self.negative)
-- filter negative
self.negative:add(-1):mul(-1 * self.negative_scale):cmul(gradOutput)
self.gradInput:add(self.negative)

return self.gradInput
end
73 changes: 73 additions & 0 deletions lib/image_loader.lua
@@ -0,0 +1,73 @@
local gm = require 'graphicsmagick'
require 'pl'

local image_loader = {}

function image_loader.decode_float(blob)
local im = image_loader.decode_byte(blob)
if im then
im = im:float():div(255)
end
return im
end
function image_loader.encode_png(tensor)
local im = gm.Image(tensor, "RGB", "DHW")
im:format("png")
return im:toBlob()
end
function image_loader.decode_byte(blob)
local load_image = function()
local im = gm.Image()
im:fromBlob(blob, #blob)
-- FIXME: How to detect that a image has an alpha channel?
if blob:sub(1, 4) == "\x89PNG" or blob:sub(1, 3) == "GIF" then
-- merge alpha channel
im = im:toTensor('float', 'RGBA', 'DHW')
local w2 = im[4]
local w1 = im[4] * -1 + 1
local new_im = torch.FloatTensor(3, im:size(2), im:size(3))
-- apply the white background
new_im[1]:copy(im[1]):cmul(w2):add(w1)
new_im[2]:copy(im[2]):cmul(w2):add(w1)
new_im[3]:copy(im[3]):cmul(w2):add(w1)
im = new_im:mul(255):byte()
else
im = im:toTensor('byte', 'RGB', 'DHW')
end
return im
end
local state, ret = pcall(load_image)
if state then
return ret
else
return nil
end
end
function image_loader.load_float(file)
local fp = io.open(file, "rb")
local buff = fp:read("*a")
fp:close()
return image_loader.decode_float(buff)
end
function image_loader.load_byte(file)
local fp = io.open(file, "rb")
local buff = fp:read("*a")
fp:close()
return image_loader.decode_byte(buff)
end
local function test()
require 'image'
local img
img = image_loader.load_float("./a.jpg")
if img then
print(img:min())
print(img:max())
image.display(img)
end
img = image_loader.load_float("./b.png")
if img then
image.display(img)
end
end
--test()
return image_loader
35 changes: 35 additions & 0 deletions lib/iproc.lua
@@ -0,0 +1,35 @@
local gm = require 'graphicsmagick'
local image = require 'image'
local iproc = {}

function iproc.sample(src, width, height)
local t = "float"
if src:type() == "torch.ByteTensor" then
t = "byte"
end
local im = gm.Image(src, "RGB", "DHW")
im:sample(math.ceil(width), math.ceil(height))
return im:toTensor(t, "RGB", "DHW")
end
function iproc.scale(src, width, height, filter)
local t = "float"
if src:type() == "torch.ByteTensor" then
t = "byte"
end
filter = filter or "Box"
local im = gm.Image(src, "RGB", "DHW")
im:size(math.ceil(width), math.ceil(height), filter)
return im:toTensor(t, "RGB", "DHW")
end
function iproc.padding(img, w1, w2, h1, h2)
local dst_height = img:size(2) + h1 + h2
local dst_width = img:size(3) + w1 + w2
local flow = torch.Tensor(2, dst_height, dst_width)
flow[1] = torch.ger(torch.linspace(0, dst_height -1, dst_height), torch.ones(dst_width))
flow[2] = torch.ger(torch.ones(dst_height), torch.linspace(0, dst_width - 1, dst_width))
flow[1]:add(-h1)
flow[2]:add(-w1)
return image.warp(img, flow, "simple", false, "clamp")
end

return iproc

0 comments on commit 1273b36

Please sign in to comment.