前回からいくつか改良を加えました。
JavaとOpenCVで似ている動画を検出するrev.1 - Qiita
画像比較の変更
特徴量による比較
ヒストグラムに加え、特徴量を比較するようにしました。
特徴量のアルゴリズムにはいろいろありますが、ここでは「AKAZE」というものを使用します。
詳しくはわかりませんが、OpenCV3から追加されたものらしく、良さそうだったためです(雑)。
グレースケールに変換してから処理します。
FeatureDetector detector = FeatureDetector.create(FeatureDetector.AKAZE);
DescriptorExtractor executor = DescriptorExtractor.create(DescriptorExtractor.AKAZE);
Mat gray = new Mat();
Imgproc.cvtColor(resizedFrame, gray, Imgproc.COLOR_RGB2GRAY);
MatOfKeyPoint point = new MatOfKeyPoint();
detector.detect(gray, point);
Mat desc = new Mat();
executor.compute(gray, point, desc);
続いて、取得した特長量のMatを比較するにはDescriptorMatcherを使います。
これもいくつか方法を選べますが、これもよくわからないので、BRUTEFORCEを選択しておきました。
DescriptorMatcher macher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
MatOfDMatch feature = new MatOfDMatch();
macher.match(video1.getFeatureImg().get(i - 1), video2.getFeatureImg().get(i - 1), feature);
List<Double> distanceList = new ArrayList<>();
for (DMatch dMatch : feature.toList()) {
distanceList.add(Double.valueOf(dMatch.distance));
}
今回は動画比較の結果を平均で扱うことにしました。
"距離"なので小さい値の方が"似ている"と判断することができます。
再生時間による比較
処理時間を減らす目的もあって、再生時間の差が10%を超えるものについては比較しないようにしました。
long playtime1 = video1.getPlayTime();
long playtime2 = video2.getPlayTime();
long playtimeDiff = Math.abs(playtime1 - playtime2);
if ((playtimeDiff / playtime1) > 0.1) {
return null;
}
今の仕組み上、動画が"含まれる"ような関係のものは比較できないので、仕方なしです。
その他変更
結果からエクスプローラを開く
結果を確認した後にファイルを確認できるようにコンテキストメニューを追加しました。
TableViewにコンテキストメニューを追加する方法は以下の通りです。
ContextMenu menu = new ContextMenu();
MenuItem mi = new MenuItem("エクスプローラで開く");
mi.setOnAction(event -> {
TableItem item = table.getSelectionModel().getSelectedItem();
String command1 = "explorer /select," + item.getOrg().getVideo1().getFilename();
String command2 = "explorer /select," + item.getOrg().getVideo2().getFilename();
try {
Runtime.getRuntime().exec(command1);
Runtime.getRuntime().exec(command2);
} catch (IOException e) {
e.printStackTrace();
}
});
menu.getItems().add(mi);
table.setContextMenu(menu);
例外処理が適当・・・。
おわりに
思った以上にヒストグラムの比較だけで"似ている動画"は検出できました。
フレームレート、解像度など、元のデータを圧縮したような関係のデータを検出するには十分な精度だと思います。
これ以上となるとディープラーニングになるんでしょうかね。
次の課題は非機能的な面になっています。
実行時間についてはCore i5-4690, メモリ4GB割り当ての環境で、70ファイルで90秒程度でした。
jconsoleで見ながら動作させていますが、メモリはファイルが増えると厳しそうなので、改善の余地がありそうです。
現在取り組んでいるのが、結果をキャッシュすることと、ヒストグラムや特徴量をファイルに書き出して、メモリに持つことをやめる、といったあたりですが、中々うまくいきません。
おいおい改善していきたいです。
おわりです。