Java/Scala で風景から歩行者を消してみる
一昨日くらいにホッテントリ入りしてた記事↓を見て、
- 風景から歩行者を消す手軽な方法(配電盤)
Export["result.jpg", Image[Mean[Map[ImageData, Import["movie.mov", "ImageList"]]]]]
このくらいのコードで済むなら Java/Scala でもすぐに書けるかも? と思ってやってみた。
理想
ヤッター、こんなに簡単にできたよー^^
import opencv._ // ← ん? System.loadLibrary(Core.NATIVE_LIBRARY_NAME) // ← んんん??? saveImage("result.jpg", loadVideo("movie.mov")(mean))
現実
Isolator requires Java bindings for OpenCV. $ curl -OL https://github.com/Itseez/opencv/archive/2.4.9.zip -o opencv-2.4.9.zip $ unzip opencv-2.4.9.zip $ cd opencv-2.4.9 $ mkdir build $ cd build/ $ cmake -DBUILD_SHARED_LIBS=OFF .. $ make -j8
import org.opencv.core.{Core, CvType, Mat, Scalar, Size} import org.opencv.highgui.{Highgui, VideoCapture} package object opencv { ... def mean(frames: Iterator[Mat]): Mat = if (frames.hasNext) { val head = convertTo(CvType.CV_64FC3)(frames.next) val (count, out) = frames. map(convertTo(CvType.CV_64FC3)). foldLeft((1, head)) { case ((cnt, sum), f) => (cnt + 1, add(sum, f)) } divide(out, new Scalar(count, count, count)) } else { new Mat } def loadVideo[A](filename: String)(f: Iterator[Mat] => A): A = { val cap = new VideoCapture(filename) try { f(Iterator.continually(nextFrame(cap)).takeWhile(_ != None).map(_.get)) } finally { cap.release() } } ... def saveImage(filename: String, m: Mat) = Highgui.imwrite(filename, m) }
^^;;;
考察
Mathematica、画像や動画の読み書きをネイティブサポートしているのはホントにいいなぁ、という感想。
なんか、動画を扱える Pure Java の成熟したソリューションって未だにあんまりないらしくて、したがって OpenCV を Java から叩くのが一番堅実な選択肢ということになり、その道の先には jar をソースからビルドする楽しい作業が待ってたり、コーディング時もリソースの明示的な解放をサボると一瞬でメモリが爆裂したりと、色々めんどくさい…。
コード
今回書いたコードは GitHub に置いておきますので、世紀末ごっこして遊ぶなり改造するなりどうぞ。
あと、mean のアルゴリズムはもう少しマシな方法があるように思うので、OpenCV に詳しい方、どなたかご教示くださいませ…。
追記
- Webカメラ映像から人を消す(colspan's blog)