前回でJava+OpenCV3.2.0でSURFやSIFTを使うための環境構築をしました.
で,今回は,構築した環境を使って,実際に特徴点検出をしてみます.
最終的にはカメラからの入力映像での検出をしたいのですが,まずは,画像同士での検出から.
ソースは,ほぼコチラを参考に,OpenCV3系に対応させるよう少し変更してあります.
変更点は,
import org.opencv.highgui.Highgui; を削除し,
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc; の2行を追加.
3系から,highgui は,imgcodecs と imgproc に分かれたようです.
比較用の画像は,Workspaceの下にあるプロジェクトフォルダの下へ,resourcesなどの名前でフォルダを作り,その下に入れます.
コード
import java.util.Calendar; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfDMatch; import org.opencv.core.MatOfKeyPoint; import org.opencv.core.DMatch; import org.opencv.features2d.DescriptorExtractor; import org.opencv.features2d.DescriptorMatcher; import org.opencv.features2d.FeatureDetector; import org.opencv.features2d.Features2d; //import org.opencv.highgui.Highgui; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class imagematch { public static void main(String[] args) { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 比較画像01 Mat image01 = Imgcodecs.imread("./resources/test01.jpg"); // 比較画像02 Mat image02 = Imgcodecs.imread("./resources/test02.jpg"); if (image01 == null || image02 == null) { System.out.println("no image"); System.exit(0); } Mat grayImage01 = new Mat(image01.rows(), image01.cols(), image01.type()); Imgproc.cvtColor(image01, grayImage01, Imgproc.COLOR_BGRA2GRAY); Core.normalize(grayImage01, grayImage01, 0, 255, Core.NORM_MINMAX); Mat grayImage02 = new Mat(image02.rows(), image02.cols(), image02.type()); Imgproc.cvtColor(image02, grayImage02, Imgproc.COLOR_BGRA2GRAY); Core.normalize(grayImage02, grayImage02, 0, 255, Core.NORM_MINMAX); // ------ SIFTの処理 ここから ------ FeatureDetector siftDetector = FeatureDetector.create(FeatureDetector.SIFT); // SURFの場合はここをSURFに DescriptorExtractor siftExtractor = DescriptorExtractor.create(DescriptorExtractor.SIFT); // SURFの場合はここをSURFに MatOfKeyPoint keyPoint01 = new MatOfKeyPoint(); siftDetector.detect(grayImage01, keyPoint01); MatOfKeyPoint keyPoint02 = new MatOfKeyPoint(); siftDetector.detect(grayImage02, keyPoint02); Mat descripters01 = new Mat(image01.rows(), image01.cols(), image01.type()); siftExtractor.compute(grayImage01, keyPoint01, descripters01); Mat descripters02 = new Mat(image02.rows(), image02.cols(), image02.type()); siftExtractor.compute(grayImage02, keyPoint02, descripters02); MatOfDMatch matchs = new MatOfDMatch(); DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE); matcher.match(descripters01, descripters02, matchs); // 上位50点以外の点を除去する int N = 50; DMatch[] tmp01 = matchs.toArray(); DMatch[] tmp02 = new DMatch[N]; for (int i=0; i<tmp02.length; i++) { tmp02[i] = tmp01[i]; } matchs.fromArray(tmp02); int year = Calendar.getInstance().get(Calendar.YEAR); int month = Calendar.getInstance().get(Calendar.MONTH) + 1; int day = Calendar.getInstance().get(Calendar.DAY_OF_MONTH); int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); int minute = Calendar.getInstance().get(Calendar.MINUTE); int second = Calendar.getInstance().get(Calendar.SECOND); String now = year + "" + month + "" + day + "" + hour + "" + minute + "" + second; Mat matchedImage = new Mat(image01.rows(), image01.cols()*2, image01.type()); Features2d.drawMatches(image01, keyPoint01, image02, keyPoint02, matchs, matchedImage); // 出力画像 at SIFT Imgcodecs.imwrite("./resources/descriptedImageBySIFT-" + now + ".jpg", matchedImage); // ------ SIFTの処理 ここまで ------ } }
結果画像
SIFT
SURF
こうしてみると,今回選んだ画像では,SURFの方が特徴点自体の検出は多くしていますが,SIFTのほうが正しく認識しているようです.このあたり,何かしきい値を変更したり,画像によって得意不得意がありそうです.