ハフ変換

ruby-opencvでハフ変換をして、画像の線分抽出をする。

require "opencv"
include OpenCV

original_window = GUI::Window.new "original"
hough_windowS = GUI::Window.new "hough(standard)"
hough_windowP = GUI::Window.new "hough(probabilistic)"

img = IplImage::load(ARGV.shift)
gry = img.BGR2GRAY
resultS = gry.GRAY2BGR
resultP = resultS.clone

linesS = gry.canny(50,200,3).hough_lines(CV_HOUGH_STANDARD, 1, Math::PI/180, 50, 0, 0)
linesP = gry.canny(50,200,3).hough_lines(CV_HOUGH_PROBABILISTIC, 1, Math::PI/180, 50, 50, 10)

cnt = 250
linesS.each do |l|
  cos,sin = Math::cos(l.theta), Math::sin(l.theta)
  x0,y0 = l.rho*cos,l.rho*sin
#  puts "#{l.rho},#{l.theta}, #{cos},#{sin}"
  resultS.line!(CvPoint.new(x0-1000*sin,y0+1000*cos), CvPoint.new(x0+1000*sin,y0-1000*cos),
          {:color=>CvColor::Red,:thickness=>1})
  cnt-=1;break if cnt<0
end
puts linesS.size

linesP.each do |l|
#  puts "#{l.point1},#{l.point2}"
  resultP.line!(l.point1, l.point2,
          {:color=>CvColor::Red,:thickness=>1})
end
puts linesP.size

original_window.show img
hough_windowS.show resultS
hough_windowP.show resultP
GUI::wait_key

シングルプレーンの取り出しとマージ

OpenCV 2.4.11(VS10), ActiveScriptRuby 2.2(32bit), ruby-opencv-0.0.14

RGB画像から、Gプレーンのみ取り出し、RとBをゼロで埋めた画像を作成したいのだけど、感覚的に書いたコードだとエラーが出る。

b,g,r = img.split
b2 = IplImage.merge(b)
g2 = IplImage.merge(nil, g)
r2 = IplImage.merge(nil, nil, r)
で動いて欲しいのだけど、うまく動かない。

まず、merge(b)だと「array.cpp:1238: error: (-5) Array should be CvMat or IplImage in function cvGetSize」となる。
merge(b.to_CvMat)だとエラーが出ないが、RGB全てのプレーンが、B画像で埋まってしまう。
merge(b.to_CvMat, nil, nil)とすると、意図した通りに動く。(Bプレーンのみ取り出され、R/Gプレーンはゼロで埋まった画像)

同様に merge(nil, g.to_CvMat, nil)としたら Gプレーン だけ取り出されて R/Bがゼロで埋まった画像ができそうな気がするのだけど、うまく行かない。
あらかじめ全てがゼロで埋まったB画像を作成して、 merge(b0.to_CvMat, g.to_CvMat, nil) とすると意図通りに動く。

結局、以下の様にすると、RGB画像からRプレーンのみ画像/Gプレーンのみ画像/Bプレーンのみ画像を作成できる。

require 'opencv'
include OpenCV
W,H = 340,200
win = GUI::Window.new("win")
rwin = GUI::Window.new("rwin")
gwin = GUI::Window.new("gwin")
bwin = GUI::Window.new("bwin")

img = IplImage.new(W, H, CV_8U, 3).fill(CvColor::White) # 真白なキャンバスを作成 #
blk = IplImage.new(W, H, CV_8U, 3).fill(CvColor::Black)

# 赤線を引いたり、四角形を描画したり、文字を描画したりする #
img.line!(CvPoint.new(10,140),CvPoint.new(330,190),
          {:color=>CvColor::Red,:thickness=>6})
img.rectangle!(CvPoint.new(200,40),CvPoint.new(280,180),
               {:color=>CvColor::Green,:thickness=>9})
9.times do |i| # 塗り潰し(-1)を指定して、青色の円を描く #
  img.circle!(CvPoint.new(i*40,i*20), 2+i*2, {:color=>CvColor::Blue,:thickness=>-1})
end
font = CvFont.new(:plain, :hscale => 5.0, :vscale => 4.5,
                  :shear => 1.0, :thickness => 3, :line_type => 5, :italic => true)
img.put_text!('Ruby', CvPoint.new(2, 60), font, CvColor::Black)
img.put_text!('OpenCV', CvPoint.new(2, 120), font, CvColor::Black)
win.show img

b,g,r = img.split
b0,g0,r0 = blk.split # 全てがゼロで埋まった R画像/G画像/B画像を作成する #
b2 = IplImage.merge(b.to_CvMat, nil, nil)
g2 = IplImage.merge(b0.to_CvMat, g.to_CvMat, nil)
r2 = IplImage.merge(b0.to_CvMat, g0.to_CvMat, r.to_CvMat)
rwin.show r2
gwin.show g2
bwin.show b2
GUI::wait_key(0)

多分、俺の理解が浅い為だと思うのだけど、時間のある時にマジメに調査することにしよう。

GalaxyNote3 をPCからUSBカメラとして使う

今手元にあるPCにはカメラが付いていない。
なので、Androidスマホである GalaxyNote3 をUSBカメラとして使えるか試してみる。

Androidスマホ内蔵カメラをパソコン用の「Webカメラ」として使おう:「DroidCam」(開発者:Dev47Apps)』
http://pc.nikkeibp.co.jp/article/special/20130625/1095722/?P=2

↑ここで紹介されている、 DroidCam を試してみたが、フツーにUSBカメラとして使えて、 USB接続の GalaxyNote3 のカメラで取り込んだ映像を ruby-opencv で処理できた。

【手順】
1. GlaxyNote3 で Googleプレイを検索、「DroidCam」をインストール。
2. DroidCam Client v5.0.1 を PC にインストール。
http://www.dev47apps.com/droidcam/windows/
3. SAMSUNGのサイトから、USBドライバーをインストール。(下記ページの「Download for Others」から「KIESとテザリング機能のUSB DRIVER」をクリックしてDL、インストール)
http://www.samsung.com/jp/support/usefulsoftware/KIES/
4. GalaxyNote3 の設定画面で「開発者オプション」を開き、「USBデバッグ」にチェック。
(必にならば「ビルド番号」7回タップで開発者オプションが表示される様にしておいて)
5. GalaxyNote3 をPCにUSB接続して、 DroidCam を起動。
6. PC側で DroidCam Client を起動、接続モードをUSBにして「Start」を押す。

下記コードを引数無しで起動して、例外も起きずにカメラ映像が表示されるのを確認。

require 'opencv'
include OpenCV
captureDevice = 0
if ARGV.size > 1
  captureDevice = ARGV.shift
  captureDevice = captureDevice.to_i if /^\d$/ =~ captureDevice
end
win = GUI::Window.new("win")
cap = CvCapture.open(captureDevice)
puts cap.fps
if cap.fps > 67 or cap.fps < 5 # 変なfpsの時は10fps(100msec間隔)にする
  frame_msec = 100
else
  frame_msec = 1000/cap.fps
end
loop do
  img = cap.query
  break unless img
  win.show img
  c = GUI::wait_key(frame_msec)
  break if c == 27 # [ESC]で終了 #
end

ruby-opencvでマウスイベント処理

require 'opencv'
include OpenCV
w = GUI::Window.new("w")
img = IplImage.new(340, 200, CV_8U, 3)
img.fill!(CvColor::White) # 真白に塗り潰す #
p = nil
opt = {:color=>CvColor::Green, :thickness=>1}
w.on_mouse do |m|
  # 左クリックで線を太くする
  opt[:thickness]+=1 if m.event == :left_button_down
  img.line!(p, m, opt) if p # 線を描画する #
  p = m
  w.show img
end
GUI::wait_key(0)

ruby-opencvで図形描画

require 'opencv'
include OpenCV
w = GUI::Window.new("w")
img = IplImage.new(340, 200, CV_8U, 3)
img.fill!(CvColor::White) # 真白に塗り潰す #
img.line!(CvPoint.new(10,140),CvPoint.new(330,190),
          {:color=>CvColor::Red,:thickness=>4})
img.rectangle!(CvPoint.new(200,40),CvPoint.new(280,180),
               {:color=>CvColor::Green,:thickness=>9})
8.times do |i|
  img.circle!(CvPoint.new(i*30,i*30), 15, {:color=>CvColor::Blue,:thickness=>6})
end
font = CvFont.new(:plain, :hscale => 5.0, :vscale => 4.5,
                  :shear => 1.0, :thickness => 3, :line_type => 5, :italic => true)
img.put_text!('Ruby', CvPoint.new(2, 60), font, CvColor::Black)
img.put_text!('OpenCV', CvPoint.new(2, 120), font, CvColor::Black)
w.show img
GUI::wait_key(0)

ruby-opencvでカラーチャネルを分離したり

splitでblue,green,redを分離できるのだけど、シングルプレーンからIplImage.merge(blue,green,red,nil)とかしても、BGR画像を復元できない。
何故??

require 'opencv'
include OpenCV
captureDevice,mode = 0,nil
if ARGV.size > 0
  captureDevice = ARGV.shift
  captureDevice = captureDevice.to_i if /^\d$/ =~ captureDevice
end
win = GUI::Window.new("inp")
red = GUI::Window.new("red")
gre = GUI::Window.new("green")
blu = GUI::Window.new("blue")
cap = CvCapture.open(captureDevice)
begin
  fps = cap.fps
  if fps > 67 or fps < 5 # 変なfpsの時は10fps(100msec間隔)にする
    fps = 10
  end
rescue
  fps = 10
end
frame_msec = 1000/fps
loop do
  inp = cap.query
  break unless inp
  win.show inp
  b,g,r = inp.split
  red.show r
  gre.show g
  blu.show b
  bgr = inp.avg # 各カラープレーン毎に平均をとる #
  ravg,gavg,bavg = bgr[2],bgr[1],bgr[0]
  if ravg > gavg
    if ravg > bavg
      puts("赤っぽい")
    else
      puts("青っぽい")
    end
  else
    if gavg > bavg
      puts("緑っぽい")
    else
      puts("青っぽい")
    end
  end
  key = GUI::wait_key(frame_msec)
  mode = key.chr if key
  break if mode == 'q'
end

ruby-opencvで色々なフィルタを試す

カメラで絵を取り込みながら、或いは動画を再生させながら、キーを押して、色々なフィルタを試す。

require 'opencv'
include OpenCV
captureDevice,mode = 0,nil
if ARGV.size > 0
  captureDevice = ARGV.shift
  captureDevice = captureDevice.to_i if /^\d$/ =~ captureDevice
end
win = GUI::Window.new("win")
cap = CvCapture.open(captureDevice)
begin
  fps = cap.fps
  if fps > 67 or fps < 5 # 変なfpsの時は10fps(100msec間隔)にする
    fps = 10
  end
rescue
  fps = 10
end
frame_msec = 1000/fps
loop do
  out = inp = cap.query
  break unless inp
  case mode
  when 'a'; out = inp.BGR2GRAY.add(100)			#グレースケールにして白っぽくする
  when 'b'; out = inp.smooth(CV_BLUR)			#単純平滑化
  when 'c'; out = inp.BGR2GRAY.canny(120,200)		#canny法でエッジ抽出
  when 'd'; out = inp.BGR2GRAY.dilate			#ディレーション
  when 'e'; out = inp.BGR2GRAY.erode			#エロージョン
  when 'f'; out = inp.flip				#左右反転
  when 'g'; out = inp.smooth(CV_GAUSSIAN)		#ガウシアン平滑化
  when 'q'; break
  end
  win.show out
  key = GUI::wait_key(frame_msec)
  mode = key.chr if key
end