Java(Eclipse) + OpenCV3.2.0 でSURFとかSIFTを使っての特徴点検出(Mac)

Java(Eclipse) + OpenCV3.2.0 でSURFとかSIFTを使っての特徴点検出(Mac)

前回で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のほうが正しく認識しているようです.このあたり,何かしきい値を変更したり,画像によって得意不得意がありそうです.