匹配小灰度图像

3
我想测试两张图片是否匹配,部分匹配也很重要。问题是这些图像受到很强的噪声干扰,并且可能会以未知角度旋转。这些图像中显示的对象大致上始终具有相同的比例大小。
这些图像从俯视角度进行区域扫描。 "线" 大多数是墙壁,其他对象大多是树木和不同种类的植物。
另一个问题是左边的图像非常模糊,而右边的线条非常细。为了弥补这种差异,我使用了膨胀处理。上传的图像就是处理后的结果。
虽然可以轻松地看出这些图像几乎完美匹配,但是我的算法并不认同这一点。我的第一个想法是基于特征的匹配,但是匹配效果很差。只有-90°、0°和90°的旋转角度才能工作。尽管大多数描述符都具有旋转不变性(在过去的项目中确实如此),但在这个例子中,旋转不变性似乎失效了。
我的第二个想法是将图像分成几个较小的片段,然后使用模板匹配。因此,我对图像进行了分割,在人眼看来它们很容易匹配。这一步的目标是将不同的墙壁和树木/植物进行分割。
上面一行是左侧图像的局部,下面是右侧图像的局部。在分割后,片段再次进行了膨胀处理。
如前所述,模板匹配失败了,轮廓匹配也失败了。我认为对图像进行膨胀处理非常重要,因为在分割之前,人眼几乎无法匹配这些片段。在分割后进行的另一次膨胀处理使得这更加容易。
2个回答

4
你的第一个任务应该是修正方向。我不确定最好的算法是什么,但这是我会使用的方法:固定其中一张图像并开始旋转另一张图像。对于每次旋转,计算每行/列颜色强度的直方图。计算结果向量之间的某些距离(例如使用叉积)。选择导致叉积最小的旋转。将此方法与爬山算法相结合可能是个好主意。
一旦您大致将图像对齐到相同的方向,我认为匹配应该更容易。由于两个图像应该在相同的比例下,因此为两个图像计算类似于几何中心的东西:计算所有像素的加权和-完全白色像素的权重为1,完全黑色像素的权重为0,总和应该是大小为2(x和y坐标)的向量。之后,将这些值除以图像的尺寸,并称其为“图像的几何中心”。以两个中心重合的方式覆盖两个图像,然后再次计算差异的叉积。我想说这应该是它们的差异。

那么您建议先不对图像进行分割就进行匹配,是吗?翻译方面怎么样?我认为我的两张样本图片几乎完美匹配,但如果只有部分匹配,我是否也可以按照您描述的方式修正方向? - VoodooCode
这取决于获取图像的方式。我相信我的方法只有在白色区域分布大致相同的情况下才能奏效。如果不是这种情况,也许您可以使用霍夫变换来修正方向? - Ivaylo Strandjev
我并不是说分段是一种不好的方法。我只是提出了另一种解决方案。 - Ivaylo Strandjev
我喜欢关于修正方向的想法,但是我不理解匹配部分。如果只有部分匹配,它会起作用吗?白色区域应该匹配,分布方式大致相同,除了一些噪音或“墙壁”的小变形,例如一个人站在旁边。我不想让它听起来像你不喜欢分割方法。请勿见怪。 - VoodooCode

1
您还可以尝试以下方法来查找旋转和相似性。
  • 使用图像矩来获取旋转,如此处所示。

  • 一旦您旋转了图像,请使用交叉相关来评估相似性。

编辑

我已经使用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旋转后,我得到了最大值为0.758。下面是在此情况下旋转的图像及其匹配区域。

enter image description here

否则max = 0.293

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接