豪斯多夫距离物体检测

时间:2017-10-09 00:38:42

标签: c++ opencv object-detection template-matching

我一直在努力尝试实施herehere所描述的概述算法。

本文的总体思路是确定二值图像的Hausdorff距离,并用它来从测试图像中找到模板图像。

对于模板匹配,建议构建image pyramids以及滑动窗口,您可以使用滑动窗口滑过测试图像进​​行检测。我也能够做到这两点。

我被困在如何从这里继续前进。我是否可以将模板从不同的金字塔图层滑过测试图像?或者它是模板上的测试图像?关于滑动窗口,它们是否是测试或模板图像的ROI?

简而言之,我对这个难题有所了解,但不知道要解决这个难题的方向

int distance(vector<Point>const& image, vector<Point>const& tempImage)
{
    int maxDistance = 0;

    for(Point imagePoint: image)
    {
        int minDistance = numeric_limits<int>::max();

        for(Point tempPoint: tempImage)
        {
            Point diff = imagePoint - tempPoint;
            int length = (diff.x * diff.x) + (diff.y * diff.y);

            if(length < minDistance) minDistance = length;
            if(length == 0) break;
        }
        maxDistance += minDistance;
    }
    return maxDistance;
}

double hausdorffDistance(vector<Point>const& image, vector<Point>const& tempImage)
{
    double maxDistImage = distance(image, tempImage);
    double maxDistTemp = distance(tempImage, image);

    return sqrt(max(maxDistImage, maxDistTemp));
}

vector<Mat> buildPyramids(Mat& frame)
{
    vector<Mat> pyramids;

    int count = 6;

    Mat prevFrame = frame, nextFrame;

    while(count > 0)
    {
        resize(prevFrame, nextFrame, Size(), .85, .85);
        prevFrame = nextFrame;

        pyramids.push_back(nextFrame);

        --count;
    }

    return pyramids;
}

vector<Rect> slidingWindows(Mat& image, int stepSize, int width, int height)
{
    vector<Rect> windows;

    for(size_t row = 0; row < image.rows; row += stepSize)
    {
        if((row + height) > image.rows) break;

        for(size_t col = 0; col < image.cols; col += stepSize)
        {
            if((col + width) > image.cols) break;

            windows.push_back(Rect(col, row, width, height));
        }
    }

    return windows;
}

1 个答案:

答案 0 :(得分:0)

编辑I:可以找到有关我的解决方案的更多分析here

这是一项双向任务。

前进方向

<强> 1。翻译

对于每个轮廓,计算其moment。然后对于该轮廓中的每个点,将其转换为即contour.point[i] = contour.point[i] - contour.moment[i]的时刻。这会将所有轮廓点移动到原点。

PS:您需要跟踪每个轮廓的生成时刻,因为它将在下一节中使用

<强> 2。旋转

使用新翻译的点,计算他们的rotated rect。这将为您提供旋转角度。根据此角度,您可能希望计算要旋转此轮廓的新角度; this answer会有所帮助。

获得新角度后,计算rotation matrix。请记住,您的中心位于原点,即(0, 0)。在计算旋转矩阵时,我没有考虑到缩放(金字塔在其中发挥作用),因此我通过了1。

PS:您需要跟踪每个轮廓生成的矩阵,因为它将在下一节中使用

使用此矩阵,您可以继续旋转轮廓中的每个点,如图here * 所示。

完成所有这些操作后,您可以继续计算Hausdorff距离并找到超过设定阈值的轮廓。

后退方向

第一部分完成的所有操作都必须撤消,以便我们在相机Feed中绘制有效的轮廓。

<强> 1。旋转

回想一下,每个检测到的轮廓产生一个旋转矩阵。您想要撤消有效轮廓的旋转。只需使用inverse matrix执行相同的旋转。

For each valid contour and corresponding matrix
inverse_matrix = matrix[i].inv(cv2.DECOMP_SVD)
Use * to rotate the points but with inverse_matrix as parameter

PS:计算逆时,如果生成的矩阵不是正方形,则会失败。即使原始矩阵是非正方形,cv2.DECOMP_SVD也会生成逆矩阵。

<强> 2。翻译

使用有效的轮廓&#39;旋转回来的点,你只需要撤消以前执行的翻译。而不是减去,只需将时刻添加到每个点。

现在可以继续将这些轮廓绘制到相机输入中。

缩放

这是图像金字塔发挥作用。

您所要做的就是按照固定的尺寸/比例调整模板图像的大小,直到您想要的次数(称为图层)。教程发现here很好地解释了如何在OpenCV中执行此操作。

毫无疑问,您选择调整图像大小和图层数量的值将会对您的计划的稳健性起到重要作用。

全部放在一起

模板图片操作

Create a pyramid consisting of n layers
For each layer in n
    Find contours
    Translate the contour points
    Rotate the contour points

此操作只应执行一次,并且只存储旋转点的结果。

相机Feed操作

假设

让每个级别的模板图像的旋转轮廓存储在templ_contours中。所以如果我说templ_contours[0],这将给我金字塔等级0的旋转轮廓。

让图片翻译,旋转的轮廓和时刻分别存储在transControtContmoment中。

image_contours = Find Contours
for each contour detected in image
    moment = calculate moment

for each point in image_contours
    transCont.thisPoint = forward_translate(image_contours.thisPoint)
    rotCont.thisPoint = forward_rotate(transCont.thisPoint)

for each contour_layer in templ_contours
    for each contour in rotCont
        calculate Hausdorff Distance
        valid_contours = contours_passing_distance_threshold

for each point in valid_contours
    valid_point = backward_rotate(valid_point)

for each point in valid_contours
    valid_point = backward_translate(valid_point)

drawContours(valid_contours, image)