匹配小灰度图像

时间:2014-10-22 13:28:00

标签: c++ image opencv image-processing pattern-matching

我想测试两个图像是否匹配。部分比赛也让我感兴趣。 问题是图像遭受强烈的噪音。另一个问题是图像可能以未知角度旋转。图像中显示的对象大致总是具有相同的比例!

图像显示从顶部拍摄的区域扫描。 “线”主要是墙壁,其他物体主要是树木和不同种类的植物。

enter image description here enter image description here

另一个问题是,左图像非常模糊,右图像的线条非常薄。 为了弥补这种差异,我使用了扩张。生成的图像是我上传的图像。

虽然很容易看出这些图像几乎完美匹配但我无法说服我的算法这个事实。

我的第一个想法是基于功能的匹配,但匹配很糟糕。它仅适用于-90°,0°和90°的旋转角度。尽管大多数描述符都是旋转不变的(在过去的项目中它们确实存在),但这个例子的旋转不变性似乎都失败了。

我的第二个想法是将图像分成几个较小的片段并使用模板匹配。所以我对图像进行了分割,再次,对于人眼来说,它们很容易匹配。这一步的目标是分割不同的墙壁和树木/植物。

enter image description here

上排是左侧的部分,下侧是右侧图像的一部分。分割后,片段再次扩张。

如前所述:模板匹配失败,基于轮廓的模板匹配和轮廓匹配也失败了。

我认为图像的扩张是非常重要的,因为在分割之前人眼几乎不可能在没有扩张的情况下匹配片段。分割后的另一次扩张使得这一点变得更加困难。

2 个答案:

答案 0 :(得分:4)

你的第一份工作应该是确定方向。我不确定这样做的最佳算法是什么,但这是我将使用的方法:修复其中一个图像并开始旋转另一个。对于每个旋转,计算每个行/列上强烈颜色的直方图。计算得到的矢量之间的一些距离(例如,使用叉积)。选择产生最小叉积的旋转。将此方法与hill climbing结合使用可能是个好主意。

一旦你的图像在大致相同的方向上对齐,我相信匹配应该更容易。由于两个图像应该是相同的比例,计算两个图像的几何中心类似的东西:计算所有像素的加权和 - 一个完全白色的像素将具有1的权重,一个完全黑色的权重0,总和应该是大小为2的向量(x和y坐标)。之后,将这些值除以图像的尺寸,并将其称为图像的几何中心"。以两个中心重合的方式叠加两个图像,然后再次计算图像之间差异的交叉乘积。我会说这应该是他们的区别。

答案 1 :(得分:1)

您还可以尝试以下方法来查找旋转和相似度。

  • 使用图像时刻获得如here所示的旋转。

  • 旋转图像后,请使用互相关来评估相似度。

修改

我尝试使用OpenCV和C ++来处理两个样本图像。我在下面发布代码和结果,因为它似乎至少对于给定的样本效果很好。

这是使用图像矩计算方向向量的函数:

Mat orientVec(Mat& im)
{
    Moments m = moments(im);
    double cov[4] = {m.mu20/m.m00, m.mu11/m.m00, m.mu11/m.m00, m.mu02/m.m00};
    Mat covMat(2, 2, CV_64F, cov);
    Mat evals, evecs;
    eigen(covMat, evals, evecs);

    return evecs.row(0);
}

旋转并匹配样本图像:

    Mat im1 = imread(INPUT_FOLDER_PATH + string("WojUi.png"), 0);
    Mat im2 = imread(INPUT_FOLDER_PATH + string("XbrsV.png"), 0);

    // get the orientation vector
    Mat v1 = orientVec(im1);
    Mat v2 = orientVec(im2);

    double angle = acos(v1.dot(v2))*180/CV_PI;
    // rotate im2. try rotating with -angle and +angle. here using -angle
    Mat rot = getRotationMatrix2D(Point(im2.cols/2, im2.rows/2), -angle, 1.0);
    Mat im2Rot;
    warpAffine(im2, im2Rot, rot, Size(im2.rows, im2.cols));

    // add a border to rotated image
    int borderSize = im1.rows > im2.cols ? im1.rows/2 + 1 : im1.cols/2 + 1;
    Mat im2RotBorder;
    copyMakeBorder(im2Rot, im2RotBorder, borderSize, borderSize, borderSize, borderSize, 
        BORDER_CONSTANT, Scalar(0, 0, 0));

    // normalized cross-correlation
    Mat& image = im2RotBorder;
    Mat& templ = im1;
    Mat nxcor;
    matchTemplate(image, templ, nxcor, CV_TM_CCOEFF_NORMED);

    // take the max
    double max;
    Point maxPt;
    minMaxLoc(nxcor, NULL, &max, NULL, &maxPt);

    // draw the match
    Mat rgb;
    cvtColor(image, rgb, CV_GRAY2BGR);
    rectangle(rgb, maxPt, Point(maxPt.x+templ.cols-1, maxPt.y+templ.rows-1), Scalar(0, 255, 255), 2);

    cout << "max: " << max << endl;

在代码中使用-angle旋转,我得到max = 0.758。在这种情况下,下面是带有匹配区域的旋转图像。

enter image description here

否则max = 0.293