iproc.lua 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. local gm = {}
  2. gm.Image = require 'graphicsmagick.Image'
  3. require 'dok'
  4. local image = require 'image'
  5. local iproc = {}
  6. local clip_eps8 = (1.0 / 255.0) * 0.5 - (1.0e-7 * (1.0 / 255.0) * 0.5)
  7. function iproc.crop_mod4(src)
  8. local w = src:size(3) % 4
  9. local h = src:size(2) % 4
  10. return iproc.crop(src, 0, 0, src:size(3) - w, src:size(2) - h)
  11. end
  12. function iproc.crop(src, w1, h1, w2, h2)
  13. local dest
  14. if src:dim() == 3 then
  15. dest = src[{{}, { h1 + 1, h2 }, { w1 + 1, w2 }}]:clone()
  16. else -- dim == 2
  17. dest = src[{{ h1 + 1, h2 }, { w1 + 1, w2 }}]:clone()
  18. end
  19. return dest
  20. end
  21. function iproc.crop_nocopy(src, w1, h1, w2, h2)
  22. local dest
  23. if src:dim() == 3 then
  24. dest = src[{{}, { h1 + 1, h2 }, { w1 + 1, w2 }}]
  25. else -- dim == 2
  26. dest = src[{{ h1 + 1, h2 }, { w1 + 1, w2 }}]
  27. end
  28. return dest
  29. end
  30. function iproc.byte2float(src)
  31. local conversion = false
  32. local dest = src
  33. if src:type() == "torch.ByteTensor" then
  34. conversion = true
  35. dest = src:float():div(255.0)
  36. end
  37. return dest, conversion
  38. end
  39. function iproc.float2byte(src)
  40. local conversion = false
  41. local dest = src
  42. if src:type() == "torch.FloatTensor" then
  43. conversion = true
  44. dest = (src + clip_eps8):mul(255.0)
  45. dest:clamp(0, 255.0)
  46. dest = dest:byte()
  47. end
  48. return dest, conversion
  49. end
  50. function iproc.scale(src, width, height, filter, blur)
  51. local conversion, color
  52. src, conversion = iproc.byte2float(src)
  53. filter = filter or "Box"
  54. if src:size(1) == 3 then
  55. color = "RGB"
  56. else
  57. color = "I"
  58. end
  59. local im = gm.Image(src, color, "DHW")
  60. im:size(math.ceil(width), math.ceil(height), filter, blur)
  61. local dest = im:toTensor("float", color, "DHW")
  62. if conversion then
  63. dest = iproc.float2byte(dest)
  64. end
  65. return dest
  66. end
  67. function iproc.scale_with_gamma22(src, width, height, filter, blur)
  68. local conversion
  69. src, conversion = iproc.byte2float(src)
  70. filter = filter or "Box"
  71. local im = gm.Image(src, "RGB", "DHW")
  72. im:gammaCorrection(1.0 / 2.2):
  73. size(math.ceil(width), math.ceil(height), filter, blur):
  74. gammaCorrection(2.2)
  75. local dest = im:toTensor("float", "RGB", "DHW"):clamp(0.0, 1.0)
  76. if conversion then
  77. dest = iproc.float2byte(dest)
  78. end
  79. return dest
  80. end
  81. function iproc.padding(img, w1, w2, h1, h2)
  82. local conversion
  83. img, conversion = iproc.byte2float(img)
  84. image = image or require 'image'
  85. local dst_height = img:size(2) + h1 + h2
  86. local dst_width = img:size(3) + w1 + w2
  87. local flow = torch.Tensor(2, dst_height, dst_width)
  88. flow[1] = torch.ger(torch.linspace(0, dst_height -1, dst_height), torch.ones(dst_width))
  89. flow[2] = torch.ger(torch.ones(dst_height), torch.linspace(0, dst_width - 1, dst_width))
  90. flow[1]:add(-h1)
  91. flow[2]:add(-w1)
  92. local dest = image.warp(img, flow, "simple", false, "clamp")
  93. if conversion then
  94. dest = iproc.float2byte(dest)
  95. end
  96. return dest
  97. end
  98. function iproc.zero_padding(img, w1, w2, h1, h2)
  99. local conversion
  100. img, conversion = iproc.byte2float(img)
  101. image = image or require 'image'
  102. local dst_height = img:size(2) + h1 + h2
  103. local dst_width = img:size(3) + w1 + w2
  104. local flow = torch.Tensor(2, dst_height, dst_width)
  105. flow[1] = torch.ger(torch.linspace(0, dst_height -1, dst_height), torch.ones(dst_width))
  106. flow[2] = torch.ger(torch.ones(dst_height), torch.linspace(0, dst_width - 1, dst_width))
  107. flow[1]:add(-h1)
  108. flow[2]:add(-w1)
  109. local dest = image.warp(img, flow, "simple", false, "pad", 0)
  110. if conversion then
  111. dest = iproc.float2byte(dest)
  112. end
  113. return dest
  114. end
  115. function iproc.white_noise(src, std, rgb_weights, gamma)
  116. gamma = gamma or 0.454545
  117. local conversion
  118. src, conversion = iproc.byte2float(src)
  119. std = std or 0.01
  120. local noise = torch.Tensor():resizeAs(src):normal(0, std)
  121. if rgb_weights then
  122. noise[1]:mul(rgb_weights[1])
  123. noise[2]:mul(rgb_weights[2])
  124. noise[3]:mul(rgb_weights[3])
  125. end
  126. local dest
  127. if gamma ~= 0 then
  128. dest = src:clone():pow(gamma):add(noise)
  129. dest:clamp(0.0, 1.0)
  130. dest:pow(1.0 / gamma)
  131. else
  132. dest = src + noise
  133. end
  134. if conversion then
  135. dest = iproc.float2byte(dest)
  136. end
  137. return dest
  138. end
  139. function iproc.hflip(src)
  140. local t
  141. if src:type() == "torch.ByteTensor" then
  142. t = "byte"
  143. else
  144. t = "float"
  145. end
  146. if src:size(1) == 3 then
  147. color = "RGB"
  148. else
  149. color = "I"
  150. end
  151. local im = gm.Image(src, color, "DHW")
  152. return im:flop():toTensor(t, color, "DHW")
  153. end
  154. function iproc.vflip(src)
  155. local t
  156. if src:type() == "torch.ByteTensor" then
  157. t = "byte"
  158. else
  159. t = "float"
  160. end
  161. if src:size(1) == 3 then
  162. color = "RGB"
  163. else
  164. color = "I"
  165. end
  166. local im = gm.Image(src, color, "DHW")
  167. return im:flip():toTensor(t, color, "DHW")
  168. end
  169. local function rotate_with_warp(src, dst, theta, mode)
  170. local height
  171. local width
  172. if src:dim() == 2 then
  173. height = src:size(1)
  174. width = src:size(2)
  175. elseif src:dim() == 3 then
  176. height = src:size(2)
  177. width = src:size(3)
  178. else
  179. dok.error('src image must be 2D or 3D', 'image.rotate')
  180. end
  181. local flow = torch.Tensor(2, height, width)
  182. local kernel = torch.Tensor({{math.cos(-theta), -math.sin(-theta)},
  183. {math.sin(-theta), math.cos(-theta)}})
  184. flow[1] = torch.ger(torch.linspace(0, 1, height), torch.ones(width))
  185. flow[1]:mul(-(height -1)):add(math.floor(height / 2 + 0.5))
  186. flow[2] = torch.ger(torch.ones(height), torch.linspace(0, 1, width))
  187. flow[2]:mul(-(width -1)):add(math.floor(width / 2 + 0.5))
  188. flow:add(-1, torch.mm(kernel, flow:view(2, height * width)))
  189. dst:resizeAs(src)
  190. return image.warp(dst, src, flow, mode, true, 'clamp')
  191. end
  192. function iproc.rotate(src, theta)
  193. local conversion
  194. src, conversion = iproc.byte2float(src)
  195. local dest = torch.Tensor():typeAs(src):resizeAs(src)
  196. rotate_with_warp(src, dest, theta, 'bilinear')
  197. dest:clamp(0, 1)
  198. if conversion then
  199. dest = iproc.float2byte(dest)
  200. end
  201. return dest
  202. end
  203. function iproc.negate(src)
  204. if src:type() == "torch.ByteTensor" then
  205. return -src + 255
  206. else
  207. return -src + 1
  208. end
  209. end
  210. function iproc.gaussian2d(kernel_size, sigma)
  211. sigma = sigma or 1
  212. local kernel = torch.Tensor(kernel_size, kernel_size)
  213. local u = math.floor(kernel_size / 2) + 1
  214. local amp = (1 / math.sqrt(2 * math.pi * sigma^2))
  215. for x = 1, kernel_size do
  216. for y = 1, kernel_size do
  217. kernel[x][y] = amp * math.exp(-((x - u)^2 + (y - u)^2) / (2 * sigma^2))
  218. end
  219. end
  220. kernel:div(kernel:sum())
  221. return kernel
  222. end
  223. function iproc.rgb2y(src)
  224. local conversion
  225. src, conversion = iproc.byte2float(src)
  226. local dest = torch.FloatTensor(1, src:size(2), src:size(3)):zero()
  227. dest:add(0.299, src[1]):add(0.587, src[2]):add(0.114, src[3])
  228. dest:clamp(0, 1)
  229. if conversion then
  230. dest = iproc.float2byte(dest)
  231. end
  232. return dest
  233. end
  234. local function test_conversion()
  235. local a = torch.linspace(0, 255, 256):float():div(255.0)
  236. local b = iproc.float2byte(a)
  237. local c = iproc.byte2float(a)
  238. local d = torch.linspace(0, 255, 256)
  239. assert((a - c):abs():sum() == 0)
  240. assert((d:float() - b:float()):abs():sum() == 0)
  241. a = torch.FloatTensor({256.0, 255.0, 254.999}):div(255.0)
  242. b = iproc.float2byte(a)
  243. assert(b:float():sum() == 255.0 * 3)
  244. a = torch.FloatTensor({254.0, 254.499, 253.50001}):div(255.0)
  245. b = iproc.float2byte(a)
  246. print(b)
  247. assert(b:float():sum() == 254.0 * 3)
  248. end
  249. local function test_flip()
  250. require 'sys'
  251. require 'torch'
  252. torch.setdefaulttensortype("torch.FloatTensor")
  253. image = require 'image'
  254. local src = image.lena()
  255. local src_byte = src:clone():mul(255):byte()
  256. print(src:size())
  257. print((image.hflip(src) - iproc.hflip(src)):sum())
  258. print((image.hflip(src_byte) - iproc.hflip(src_byte)):sum())
  259. print((image.vflip(src) - iproc.vflip(src)):sum())
  260. print((image.vflip(src_byte) - iproc.vflip(src_byte)):sum())
  261. end
  262. local function test_gaussian2d()
  263. local t = {3, 5, 7}
  264. for i = 1, #t do
  265. local kp = iproc.gaussian2d(t[i], 0.5)
  266. print(kp)
  267. end
  268. end
  269. local function test_conv()
  270. local image = require 'image'
  271. local src = image.lena()
  272. local kernel = torch.Tensor(3, 3):fill(1)
  273. kernel:div(kernel:sum())
  274. --local blur = image.convolve(iproc.padding(src, 1, 1, 1, 1), kernel, 'valid')
  275. local blur = image.convolve(src, kernel, 'same')
  276. print(src:size(), blur:size())
  277. local diff = (blur - src):abs()
  278. image.save("diff.png", diff)
  279. image.display({image = blur, min=0, max=1})
  280. image.display({image = diff, min=0, max=1})
  281. end
  282. --test_conversion()
  283. --test_flip()
  284. --test_gaussian2d()
  285. --test_conv()
  286. return iproc