レンズレスカメラ
twitter見てたらこんな記事が流れてきまして。
http://www.gizmodo.jp/2013/06/post_12461.html
「ベル研究所、レンズのない1画素カメラ実現。ピンぼけもない」
ランダムなフィルタを通して一画素カメラでたくさんデータを取って、最後に合わせてやるとちゃんとした画像ができ上がるというお話らしい。
なんとなく感覚的には合点が行くけど、実際に試してみるとどんなもんなんじゃろと思ったのでやってみました。これでいいのかどうかよく分からないけど。
# ...前略... shot_image = Square.new real_image = Image.new # 10万回試行 100000.times do # ランダムフィルタ生成 filter = Filter.new # valはフィルタがオープンになっている部分の明度の平均値 # 元記事の言うところの「一画素カメラ」の値 val = filter.filter real_image filter.filtered_each do |x, y| # フィルタがオープンになっていた部分の値をvalだけ増やす # 本物はこの辺できっといろいろ工夫してる shot_image[x, y] += val end end # 各画素を8ビット長に正規化 shot_image.normalize! 0..255 # 画像生成 shot_image.to_png 'shot.png'
で、結果。
ほほう。なかなかうまくいくもんですね。ちなみに試行回数を変えるとこんな感じ。今回の単に積算するだけのやり方だとたかが10×10の画像でも10万回くらいは繰り返さないとダメみたい。
しかし、結局何度も撮るなら一画素カメラで例えば左上から右下に順に走査して行った方が楽な気がするけど、そういう話でもないんですかねー。
ソースコード全文
require 'chunky_png' class Square attr_reader :width, :height def initialize(x=10, y=10) @width = x @height = y @values = Array.new y do Array.new x, 0 end end def min @values.flatten.sort.first end def max @values.flatten.sort.last end def normalize_pixel(x, y, my_min, my_max, min_value, max_value) ((self[x, y] - my_min) / (my_max - my_min) * max_value).floor + min_value end def normalize! range my_min = min my_max = max min_value = range.begin max_value = range.end each do |x, y| self[x, y] = normalize_pixel x, y, my_min, my_max, min_value, max_value end self end def [](x, y) @values[y][x] end def []=(x, y, v) @values[y][x] = v end def each(&block) @height.times do |y| @width.times do |x| block.call x, y end end end def to_png(filename='filename.png') png = ChunkyPNG::Image.new(@width, @height, ChunkyPNG::Color::TRANSPARENT) each do |x, y| color = self[x, y] png[x, y] = ChunkyPNG::Color.rgba(color, color, color, 255) end png.save(filename, :interlace => true) end def to_s @values.to_s end end class Image < Square def initialize(x=10, y=10) super each do |x, y| self[x, y] = x < y ? 255 : 0 end end end class Filter < Square def initialize(x=10, y=10) super each do |x, y| self[x, y] = Random.rand(2) end end def filter(image) count = 0 sum = 0 filtered_each do |x, y| count += 1 sum += image[x, y] end count == 0 ? 0 : sum.to_f / count end def filtered_each(&block) each do |x, y| block.call(x, y) unless self[x, y] == 0 end end end shot_image = Square.new real_image = Image.new 100000.times do filter = Filter.new val = filter.filter real_image filter.filtered_each do |x, y| shot_image[x, y] += val end end shot_image.normalize! 0..255 shot_image.to_png 'shot.png'