🐕

opencvr-0.3リリース

2023/05/12に公開

こちらの記事の続き。
https://zenn.dev/waruby/articles/4be730787f9a12

相変わらずgemになっていないので使う人はいない気がしますが、0.3をリリースしました。

対応する引数・戻り値型の追加

以下の型に対応しました。

  • char, uchar, vector_char, vector_uchar
  • `std::vector<String>
  • const char*

クラスインスタンスを返す関数の対応

関数の戻り値としてサポートするクラスは、これまではcv::Matcv::Scalarなど特別に対応したクラスのみでしたが、0.3からはその他のクラスにも対応しました。

CV_WRAP_ASの対応

C++のヘッダでCV_WRAP_ASが指定されているものはC++のメソッド名とは異なる名前でバインドされます。主にoverloadされている関数で、Pythonでは同名にできないものに対して使われます。Rubyでも別名でバインドするようにしました。

Enum型

enum型引数・戻り値を持つ関数に対応しました。なお、cv::imread()は引数flagscv::ImreadModesを取りますが、引数型はintなので以前から対応しています。

コンストラクタがないクラス

opencvrではC++のクラスのコンストラクタに対してRubyのinitialize相当のメソッドをバインドさせています。そのためコンストラクタがないクラスはインスタンス化することができません。
ただし、コンストラクタがないクラスの多くは抽象クラスで、コンストラクタではなく別の方法でインスタンスを取得します(例えばインスタンスを生成するスタティックメソッドなど)。このようなクラスについてはすでに対応していました。
コンストラクタがなく、かつ抽象クラスでもないクラスは対応できていませんでしたが、0.3で対応しました。具体例としてはcv::Stitcherがあります。

新規対応クラスの例

cv::Stitcher

0.3から対応したクラスの一つにcv::Stitcherがあります。これは複数の画像を繋げて大きな画像を作るものです。例えば以下の写真は大室山という山の上から撮ったものです。

これらの画像が./images/以下にある場合、パノラマ画像を作るには以下のようにします。

#!/usr/bin/env ruby

$:.unshift(__dir__)
require 'numo/narray'
require 'cv2'

src_paths = Dir.glob("./images/*.JPG")
imgs = []
src_paths.each{|path|
  img = CV2::imread(path)
  imgs << img
}
stitcher = CV2::Stitcher::create()
ret, pano = stitcher.stitch(imgs)
CV2::imwrite("pano.jpg", pano)

出来上がった画像はこんな感じ。

長方形を切り出すと以下のようになります。

cv::VideoWriter

cv::VideoWriterも使えるようになりました。以下は動画のサイズを縦横半分にするスクリプトです。

#!/usr/bin/env ruby

$:.unshift(__dir__)
require 'numo/narray'
require 'cv2'

in_path = "./in.mp4"
vid = CV2::VideoCapture.new(in_path)
orig_width = vid.get(CV2::CAP_PROP_FRAME_WIDTH).to_i
orig_height =  vid.get(CV2::CAP_PROP_FRAME_HEIGHT).to_i
fps =  vid.get(CV2::CAP_PROP_FPS).to_i
fcount = vid.get(CV2::CAP_PROP_FRAME_COUNT).to_i
puts "#{orig_width}x#{orig_height} #{fps} #{fcount}"
out_path = "./out.mp4"
width = (orig_width/2).to_i
height = (orig_height/2).to_i

# Pythonならcv2.VideoWriter_fourcc("m", "p", "4", "v")と書けるが
# Rubyでは今のところ文字コードを直接指定する
fourcc = CV2::VideoWriter::fourcc(0x6d, 0x70, 0x34, 0x76)
writer = CV2::VideoWriter.new(out_path, fourcc, fps, [width, height])

n = 0
loop do
  ret, frame = vid.read()
  break if !ret
  resized = CV2::resize(frame, dsize=[width, height])
  writer.write(resized)
  n += 1
  print "\r#{n}/#{fcount}"
end
puts
writer.release()
vid.release()

今後やりたいこと

gem対応

そろそろgemを作りたいところですが、opencvrのようにネイティブのバイナリを含むものはバイナリ部分をどうするかという問題があります。この問題については以下の記事が詳しいです。
https://www.clear-code.com/blog/2019/11/22.html

Pythonではpip installでバイナリまでインストールされますが、Rubyではどうするか迷ってます。

リファクタリング

gen2rb.pyは非常に汚いコードになっているので(多分自分史上最恐)、そろそろこれをリファクタリングしないと機能追加できなそうです。

Discussion