Hej, próbuję napisać kod w Javie, który rozpozna, czy obraz A zawiera się w obrazie B - template matching. Chcę tylko dostać true/false bez zaznaczania na większym obrazie znalezionego wzorca. Mam w tym 0 doświadczenia i wygooglowałem sobie bibliotekę JavaCV - wrapper dla Javy do OpenCV. Bibliotekę importuję poprzez Gradle:
compile group: 'org.bytedeco', name: 'javacv-platform', version: '1.3.3'
Jeden przykład, jaki znalazłem, jest tutaj: https://docs.opencv.org/3.2.0/d5/d6f/tutorial_feature_flann_matcher.html. Jeśli dobrze rozumiem, oblicza on deskryptory dla obu obrazów, a następnie wyszukuje się te, dla których dystans jest odpowiednio mały. Myślałem, że mały dystans deskryptora oznacza, że zostały znalezione cechy wspólne obu obrazów i obecność "dobrych" deskryptorów, oznacza, że jeden obraz jest podobrazem drugiego. Niestety, "dobre" deskryptory występują zarówno w przypadkach, gdy jeden obraz zawiera się w drugim, jak i w sytuacjach, gdy obrazy są zupełnie różne, a liczba "dobrych" deskryptorów to zazwyczaj kilkaset. Mój kod zaadaptowany (głównie copy-paste) na podstawie przykładu:
public void m1(String image, String template) {
final opencv_core.Mat image1 = imread(image, IMREAD_GRAYSCALE);
final opencv_core.Mat image2 = imread(template, IMREAD_GRAYSCALE);
final opencv_core.KeyPointVector keyPoints1 = new opencv_core.KeyPointVector();
final opencv_core.KeyPointVector keyPoints2 = new opencv_core.KeyPointVector();
final opencv_xfeatures2d.SURF surf = opencv_xfeatures2d.SURF.create();
surf.setHessianThreshold(400);
opencv_core.Mat descriptors_1 = new opencv_core.Mat();
opencv_core.Mat descriptors_2 = new opencv_core.Mat();
surf.detectAndCompute(image1, new opencv_core.Mat(), keyPoints1, descriptors_1);
surf.detectAndCompute(image2, new opencv_core.Mat(), keyPoints2, descriptors_2);
opencv_features2d.FlannBasedMatcher matcher = opencv_features2d.FlannBasedMatcher.create();
opencv_core.DMatchVector matches = new opencv_core.DMatchVector();
matcher.match(descriptors_1, descriptors_2, matches);
double max_dist = 0; double min_dist = 100;
for( int i = 0; i < descriptors_1.rows(); i++ )
{
double dist = matches.get(i).distance();
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
opencv_core.DMatchVector good_matches = new opencv_core.DMatchVector();
ArrayList<opencv_core.DMatch> tmp = new ArrayList<>();
for( int i = 0; i < descriptors_1.rows(); i++ )
{
if( matches.get(i).distance() <= max(2*min_dist, 0.02) )
{
good_matches.put( matches.get(i));
tmp.add(matches.get(i));
}
}
}
Znalazłem jeszcze jeden przykład: https://github.com/bytedeco/javacv/blob/master/samples/TemplateMatching.java, ale po przerobieniu:
public void m2(String image, String template) {
opencv_core.Mat image1 = imread(image, IMREAD_GRAYSCALE);
opencv_core.Mat image2 = imread(template,CV_LOAD_IMAGE_GRAYSCALE);//int = 0
opencv_core.Size size = new opencv_core.Size(image1.cols()-image2.cols()+1, image1.rows()-image2.rows()+1);
opencv_core.Mat result = new opencv_core.Mat(size, CV_32FC1);
matchTemplate(image1, image2, result, TM_CCORR_NORMED);
DoublePointer minVal= new DoublePointer();
DoublePointer maxVal= new DoublePointer();
opencv_core.Point min = new opencv_core.Point();
opencv_core.Point max = new opencv_core.Point();
minMaxLoc(result, minVal, maxVal, min, max, null);
}
nie wiem, co dalej. Nie widzę w result
żadnych pół ani metod, które, by mi pomogły.
Wszelka pomoc mile widziana. :) Może ktoś ma doświadczenie z JavaCV?