RMagickで画像を魚眼風に変換してみた。
普通の画像を魚眼レンズで撮った画像みたいに変換してみた。
画像の中心点を基準にして
点xの変換前の距離をd
変換後の距離をd'
焦点距離をf
魚眼レンズの半径をrとすると、座標の変換式は以下。
d' = (r*d) / (f^2 + d^2)^(1/2)
この変換式を使って処理する。
require 'rubygems' require "RMagick" include Magick def fisheyeconvert(image, filename, f, r) black = Magick::Pixel.new(0, 0, 0) img = ImageList.new(image) generate_img = Image.new(img.columns, img.rows) center_x = img.columns/2 center_y = img.rows/2 for y in 0...img.rows for x in 0...img.columns dx = x - center_x dy = y - center_y d = Math.sqrt(dx*dx + dy*dy) cx = (r*dx / (Math.sqrt(f*f + d*d)) + center_x).round cy = (r*dy / (Math.sqrt(f*f + d*d)) + center_y).round src = img.pixel_color(x, y) color = Magick::Pixel.new(src.red, src.green, src.blue) generate_img.pixel_color(cx, cy, color) end end generate_img.write filename end image = ARGV[0] filename = ARGV[1] f = ARGV[2] r = ARGV[3] fisheyeconvert(image, filename, f.to_i, r.to_i)
さて、今回の実験画像はこちら。
菊丸印のステップが踏めます。デスメタルおじさんです。
ruby ./fisheyeconvert.rb deathmetal_fisheye.jpg 230 400
なんか白い!変換した際に、対応しなかった点には何も割り振られてない様子。
なので超適当に補間処理を追加。
対応しなかった点には周りの平均値を割り当てる。
require 'rubygems' require "RMagick" include Magick def fisheyeconvert(image, filename, f, r) black = Magick::Pixel.new(0, 0, 0) img = ImageList.new(image) generate_img = Image.new(img.columns, img.rows) interpolation_img = Image.new(img.columns, img.rows) center_x = img.columns/2 center_y = img.rows/2 for y in 0...img.rows for x in 0...img.columns dx = x - center_x dy = y - center_y d = Math.sqrt(dx*dx + dy*dy) cx = (r*dx / (Math.sqrt(f*f + d*d)) + center_x).round cy = (r*dy / (Math.sqrt(f*f + d*d)) + center_y).round src = img.pixel_color(x, y) color = Magick::Pixel.new(src.red, src.green, src.blue) generate_img.pixel_color(cx, cy, color) interpolation_img.pixel_color(cx, cy, black) end end for y in 0...generate_img.rows for x in 0...generate_img.columns src = interpolation_img.pixel_color(x, y) if src.red == 255 r_array = Array.new g_array = Array.new b_array = Array.new for py in y-2...y+2 for px in x-2...x+2 check_img = interpolation_img.pixel_color(px, py) if check_img.red == 0 pixel = generate_img.pixel_color(px, py) r_array << pixel.red g_array << pixel.green b_array << pixel.blue end end end if r_array.size != 0 mr = r_array.inject(0){|r,i| r+=i }/r_array.size mg = g_array.inject(0){|r,i| r+=i }/g_array.size mb = b_array.inject(0){|r,i| r+=i }/b_array.size interpolation_color = Magick::Pixel.new(mr, mg, mb) generate_img.pixel_color(x, y, interpolation_color) end end end end generate_img.write filename interpolation_img.write "test2.jpg" end image = ARGV[0] filename = ARGV[1] f = ARGV[2] r = ARGV[3] fisheyeconvert(image, filename, f.to_i, r.to_i)
ruby ./fisheyeconvert.rb deathmetal_fisheye2.jpg 230 400