5

假设我有一个非常简单的图像或形状,例如这个火柴人绘图:

在此处输入图像描述

我还有一个其他简单图像的库,我想将第一张图像与之进行比较并确定最接近的匹配:

在此处输入图像描述

请注意,这两个火柴人并不完全相同,但相当相似。

我希望能够将第一张图像与我的库中的每个图像进行比较,直到找到相当接近的匹配。如有必要,我的图像库可以包含同一图像的许多变体,以帮助确定我拥有哪种类型的图像。例如:

在此处输入图像描述

我的问题是这是否是 OpenCV 能够做到的?以前有没有做过,如果有,你能指出一些例子的方向吗?非常感谢您的帮助。

编辑:通过我的搜索,我发现了许多比较图像的人的例子,甚至是比较被拉伸或倾斜的图像的人,例如:Checking images forsimilarity with OpenCV。不幸的是,正如您所看到的,我的图像不仅仅是彼此的翻译(旋转/倾斜/拉伸)版本 - 它们实际上是不同的图像,尽管它们非常相似。

4

6 回答 6

2

您应该可以使用 OpenCV 的特征模板匹配功能来做到这一点。您可以使用matchTemplate函数来查找特征,然后minMaxLoc找到它的位置。查看 OpenCV 网站上的教程以获取matchTemplate.

于 2015-02-02T14:04:40.567 回答
1

似乎您需要特征点检测和匹配。从 OpenCV 检查这些文档:

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

于 2015-02-02T14:03:13.063 回答
1

由于涉及轮换,我认为模板匹配不会很好。您可能需要使用特征点检测,例如 SIFT 或 SURF。

于 2015-02-02T14:19:21.730 回答
1

编辑:这不适用于旋转。对matchTemplate. 我还没有尝试bjoernz 答案中的findContours+ ,这听起来很有希望。moments

失败的解决方案: 我尝试使用OpenCV 3.0 中可用的ShapeContextDistanceExtractor( 1findContours ) 以及您的示例图像来获得良好的结果。样本图像被裁剪为与原始图像相同的大小(128 * 200)。您也可以resize在 OpenCV 中使用。


下面的代码将images文件夹1.png中的图像与基本图像进行比较。

#include "opencv2/shape.hpp"
#include "opencv2/opencv.hpp"
#include <iostream>
#include <string>

using namespace std;
using namespace cv;

const int MAX_SHAPES = 7;

vector<Point> findContours( const Mat& compareToImg )
{
    vector<vector<Point> > contour2D;
    findContours(compareToImg, contour2D, RETR_LIST, CHAIN_APPROX_NONE);

    //converting 2d vector contours to 1D vector for comparison
    vector <Point> contour1D;
    for (size_t border=0; border < contour2D.size(); border++) {
        for (size_t p=0; p < contour2D[border].size(); p++) {
            contour1D.push_back( contour2D[border][p] );
        }
    }

    //limiting contours size to reduce distance comparison time
    contour1D.resize( 300 );
    return contour1D;
}

int main()
{
    string path = "./images/";
    cv::Ptr <cv::ShapeContextDistanceExtractor> distanceExtractor = cv::createShapeContextDistanceExtractor();

    //base image
    Mat baseImage= imread( path + "1.png", IMREAD_GRAYSCALE);

    vector<Point> baseImageContours= findContours( baseImage );

    for ( int idx = 2; idx <= MAX_SHAPES; ++idx ) {

        stringstream imgName;
        imgName << path << idx << ".png";
        Mat compareToImg=imread( imgName.str(), IMREAD_GRAYSCALE ) ;

        vector<Point> contii = findContours( compareToImg );
        float distance = distanceExtractor->computeDistance( baseImageContours, contii );

        std::cout<<" distance to " << idx << " : " << distance << std::endl;
    }

    return 0;
}

结果

到 2 的
距离:89.7951 到 3 的
距离:14.6793 到 4 的
距离:6.0063 到 5 的
距离:4.79834 到 6 的
距离:0.0963184 到 7 的距离:0.00212693

于 2015-02-02T16:45:26.593 回答
1

对于您的特定类型的图像,您可能会通过使用连接组件的时刻/ HuMoments获得良好的结果(您可以使用findContours找到)。

于 2015-02-02T14:15:09.140 回答
0

做三件事: 1. 忘记图像比较,因为你真的比较笔画符号。2.从谷歌商店下载并使用手势搜索应用程序;3. 意识到要获得良好的性能,如果不使用有关笔画的时间戳信息,您将无法识别您的笔画。否则我们将有一个成功的手写识别。然后,您可以研究 Android stroke reco 库以正确编写代码。

于 2015-02-06T03:48:57.373 回答