使用opencv匹配一组图像中的图像,以便在C中进行识别

编辑:我通过这篇文章获得了足够的声誉,以便能够用更多的链接进行编辑,这将有助于我更好地了解自己的观点

玩耍的人们经常遇到小基座上的重要物品。

目标是让用户感到有些项目能够按下一个按钮,然后指示他“盒子”该项目(思考Windows桌面拳击)。该框给我们感兴趣的区域(实际项目加上一些背景环境)来比较整个项目网格。

理论用户盒装物品

项目的理论网格(没有更多的,我只是把这个从isaac wiki的绑定中剥离出来)

标识为用户盒装的物品的网格中的位置将表示图像上的某个区域,该区域与正确链接到isaac wiki的绑定以及关于该物品的信息相关联。

在网格中,该项目是从第一列第1列第3列。我在下面尝试的所有东西中使用这两个图像

我的目标是创建一个程序,可以从游戏“Isaac的绑定”中手动裁剪一个项目,通过将图像与游戏中的某个项目的图像进行比较来识别裁剪的项目,然后显示正确的维基页面。

这将是我第一个“真正的项目”,因为它需要大量的图书馆学习才能得到我想做的事情。这是有点压倒性的。

我已经搞砸了几个选项,只是从谷歌搜索。 (您可以通过搜索方法和opencv的名称快速找到我使用的教程。由于某些原因,我的帐户严重受到链接发布的限制)

使用bruteforcematcher:

http://docs.opencv.org/doc/tutorials/features2d/feature_description/feature_description.html

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

void readme();

/** @function main */
int main( int argc, char** argv )
{
  if( argc != 3 )
   { return -1; }

  Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
  Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );

  if( !img_1.data || !img_2.data )
   { return -1; }

  //-- Step 1: Detect the keypoints using SURF Detector
  int minHessian = 400;

  SurfFeatureDetector detector( minHessian );

  std::vector<KeyPoint> keypoints_1, keypoints_2;

  detector.detect( img_1, keypoints_1 );
  detector.detect( img_2, keypoints_2 );

  //-- Step 2: Calculate descriptors (feature vectors)
  SurfDescriptorExtractor extractor;

  Mat descriptors_1, descriptors_2;

  extractor.compute( img_1, keypoints_1, descriptors_1 );
  extractor.compute( img_2, keypoints_2, descriptors_2 );

  //-- Step 3: Matching descriptor vectors with a brute force matcher
  BruteForceMatcher< L2<float> > matcher;
  std::vector< DMatch > matches;
  matcher.match( descriptors_1, descriptors_2, matches );

  //-- Draw matches
  Mat img_matches;
  drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches );

  //-- Show detected matches
  imshow("Matches", img_matches );

  waitKey(0);

  return 0;
  }

 /** @function readme */
 void readme()
 { std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }

结果没有那么有用的东西。清洁,但同样不可靠的结果使用flann。

http://docs.opencv.org/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html

#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include <opencv2/legacy/legacy.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include "opencv2/highgui/highgui.hpp"

using namespace cv;

void readme();

/** @function main */
int main( int argc, char** argv )
{
  if( argc != 3 )
  { readme(); return -1; }

  Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
  Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );

  if( !img_1.data || !img_2.data )
  { std::cout<< " --(!) Error reading images " << std::endl; return -1; }

  //-- Step 1: Detect the keypoints using SURF Detector
  int minHessian = 400;

  SurfFeatureDetector detector( minHessian );

  std::vector<KeyPoint> keypoints_1, keypoints_2;

  detector.detect( img_1, keypoints_1 );
  detector.detect( img_2, keypoints_2 );

  //-- Step 2: Calculate descriptors (feature vectors)
  SurfDescriptorExtractor extractor;

  Mat descriptors_1, descriptors_2;

  extractor.compute( img_1, keypoints_1, descriptors_1 );
  extractor.compute( img_2, keypoints_2, descriptors_2 );

  //-- Step 3: Matching descriptor vectors using FLANN matcher
  FlannBasedMatcher matcher;
  std::vector< DMatch > matches;
  matcher.match( descriptors_1, descriptors_2, matches );

  double max_dist = 0; double min_dist = 100;

  //-- Quick calculation of max and min distances between keypoints
  for( int i = 0; i < descriptors_1.rows; i++ )
  { double dist = matches[i].distance;
    if( dist < min_dist ) min_dist = dist;
    if( dist > max_dist ) max_dist = dist;
  }

  printf("-- Max dist : %f \n", max_dist );
  printf("-- Min dist : %f \n", min_dist );

  //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )
  //-- PS.- radiusMatch can also be used here.
  std::vector< DMatch > good_matches;

  for( int i = 0; i < descriptors_1.rows; i++ )
  { if( matches[i].distance < 2*min_dist )
    { good_matches.push_back( matches[i]); }
  }

  //-- Draw only "good" matches
  Mat img_matches;
  drawMatches( img_1, keypoints_1, img_2, keypoints_2,
               good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
               vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

  //-- Show detected matches
  imshow( "Good Matches", img_matches );

  for( int i = 0; i < good_matches.size(); i++ )
  { printf( "-- Good Match [%d] Keypoint 1: %d  -- Keypoint 2: %d  \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }

  waitKey(0);

  return 0;
 }

 /** @function readme */
 void readme()
 { std::cout << " Usage: ./SURF_FlannMatcher <img1> <img2>" << std::endl; }

到目前为止,模板匹配是我最好的方法。的6种方法,其范围从只有0-4正确的身份识别。

http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

/// Global Variables
Mat img; Mat templ; Mat result;
char* image_window = "Source Image";
char* result_window = "Result window";

int match_method;
int max_Trackbar = 5;

/// Function Headers
void MatchingMethod( int, void* );

/** @function main */
int main( int argc, char** argv )
{
  /// Load image and template
  img = imread( argv[1], 1 );
  templ = imread( argv[2], 1 );

  /// Create windows
  namedWindow( image_window, CV_WINDOW_AUTOSIZE );
  namedWindow( result_window, CV_WINDOW_AUTOSIZE );

  /// Create Trackbar
  char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
  createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );

  MatchingMethod( 0, 0 );

  waitKey(0);
  return 0;
}

/**
 * @function MatchingMethod
 * @brief Trackbar callback
 */
void MatchingMethod( int, void* )
{
  /// Source image to display
  Mat img_display;
  img.copyTo( img_display );

  /// Create the result matrix
  int result_cols =  img.cols - templ.cols + 1;
  int result_rows = img.rows - templ.rows + 1;

  result.create( result_cols, result_rows, CV_32FC1 );

  /// Do the Matching and Normalize
  matchTemplate( img, templ, result, match_method );
  normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );

  /// Localizing the best match with minMaxLoc
  double minVal; double maxVal; Point minLoc; Point maxLoc;
  Point matchLoc;

  minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );

  /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
  if( match_method  == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    { matchLoc = minLoc; }
  else
    { matchLoc = maxLoc; }

  /// Show me what you got
  rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
  rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );

  imshow( image_window, img_display );
  imshow( result_window, result );

  return;
}

http://imgur.com/pIRBPQM,h0wkqer,1JG0QY0,haLJzRF,CmrlTeL,DZuW73V#3

的6
不合格,合格,不合格,合格,合格,合格

这是一个最好的案例结果。我尝试的下一个项目是

 导致失败,失败,失败,失败,失败,失败

从项目到项目,所有这些方法都有一些工作很好,有些做得很糟糕

所以我会问:模板匹配我最好的赌注还是有一种方法我不认为这将是我的圣杯?

如何让用户手动创建裁剪? Opencv的这个文档真的很糟糕,我在网上找到的例子是非常老的cpp或直线C.

感谢任何帮助。到目前为止,这个冒险是一个有趣的经历。我不得不剥离所有的链接,更好地描述了一切如何工作,但网站说我发布超过10个链接,即使我不是。

整个游戏中更多的项目示例:

岩石是一个罕见的项目,少数几个可以在屏幕上“任何地方”。像岩石这样的物品是用户裁剪物品的最佳方式是隔离物品的原因,否则他们的位置只在几个特定的​​地方。

一个老板打了一个项目,很多东西无处不在,中间的透明度。我会想象这是正确工作的难点之一

罕见的房间。简单的背景。没有项目透明度。

这里是游戏中所有项目的两个表格。我将最终使他们成为一个图像,但现在他们直接从isaac维基中获取。

这里有一个重要的细节是你的表格中的每个项目都有纯粹的形象。你知道背景颜色,可以从图片的其余部分分离项目。例如,除了表示图像本身的矩阵之外,您可以存储相同大小的1-s和0-s的矩阵,其中对应于图像区域和零到背景。让我们把这个矩阵“mask”和这个项目的纯粹图像称为“pattern”。

有两种比较图像的方法:将图像与图案匹配,并匹配图案。您所描述的是将图像与图案进行匹配 – 您有一些裁剪的图像,并希望找到类似的图案。相反,请考虑在图像上搜索模式。

我们首先定义使用相同大小的图案,掩码和图像的函数match(),并检查掩码下的图案上的区域是否与图像(伪代码)完全相同:

def match(pattern, mask, image):
    for x = 0 to pattern.width:
        for y = 0 to pattern.height: 
           if mask[x, y] == 1 and              # if in pattern this pixel is not part of background
              pattern[x, y] != image[x, y]:    # and pixels on pattern and image differ
               return False  
    return True

但是图案和裁剪图像的尺寸可能会有所不同。用于此的标准解决方案(例如在级联分类器中使用)是使用滑动窗口 – 仅在图像之间移动模式“窗口”,并检查模式是否匹配所选区域。这在OpenCV中几乎是图像检测的工作原理。

当然,这个解决方案并不是非常强大 – 裁剪,调整大小或任何其他图像变换可能会改变一些像素,在这种情况下,match()方法总是返回false。要克服这个,而不是布尔答案,你可以使用图像和图案之间的距离。在这种情况下,函数match()应该返回一些相似度值,例如在0和1之间,其中1表示“完全相同”,而0表示“完全不同”。然后,您可以设置相似度阈值(例如,图像应该与图案相似至少85%),或者只是选择具有最高相似度值的图案。

由于游戏中的项目是人造图像,它们的变化非常小,所以这种方法应该是足够的。然而,对于更复杂的情况,您将需要其他功能,而不仅仅是掩码下的像素。正如我在我的评论中已经提出的,像Eigenfaces这样的方法,使用类似Haar的功能,甚至是Active Appearance Models的级联分类器可能对这些任务更有效。至于SURF,据我所知,它更适合于具有不同角度和大小的对象的任务,但不适用于不同的背景和所有这些事情。

http://stackoverflow.com/questions/14743389/using-opencv-to-match-an-image-from-a-group-of-images-for-purpose-of-identificat

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:使用opencv匹配一组图像中的图像,以便在C中进行识别