算法原理:

本文介绍的算法是基于边缘跟踪的轮廓查找算法,也叫做“Moore-Neighbor Tracing”算法。该算法的基本思想是从某个起始点开始,按照固定的顺序依次查找相邻的像素点,直到回到起始点为止,形成一个封闭的轮廓。

具体实现步骤如下:

  1. 找到二值图像中的第一个前景像素点,作为起始点。

  2. 按照固定的顺序查找起始点周围的8个像素点,找到第一个前景像素点作为下一个点,并标记为已访问。

  3. 以下一个点为起始点,重复步骤2,直到回到起始点为止。

  4. 将轮廓上的所有像素点标记为已访问。

  5. 重复步骤1~4,直到所有的前景像素点都被访问过。

  6. 将标记为已访问的像素点在原图中用红色标出。

C++代码实现:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

void findContoursByTracing(Mat& src, Mat& dst);

int main()
{
    Mat src = imread("lena.jpg", IMREAD_GRAYSCALE);
    if (src.empty())
    {
        cout << "Failed to read image!" << endl;
        return -1;
    }

    Mat bw;
    threshold(src, bw, 128, 255, THRESH_BINARY);

    Mat dst = src.clone();
    findContoursByTracing(bw, dst);

    namedWindow("src", WINDOW_AUTOSIZE);
    imshow("src", src);

    namedWindow("dst", WINDOW_AUTOSIZE);
    imshow("dst", dst);

    waitKey();

    return 0;
}

void findContoursByTracing(Mat& src, Mat& dst)
{
    dst.setTo(Scalar(0));

    int rows = src.rows;
    int cols = src.cols;

    vector<Point> contour;
    vector<Point> neighbors = {
        Point(-1, -1), Point(-1, 0), Point(-1, 1),
        Point(0, -1), Point(0, 1),
        Point(1, -1), Point(1, 0), Point(1, 1)
    };

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            if (src.at<uchar>(i, j) == 255 && dst.at<uchar>(i, j) == 0)
            {
                int x = i;
                int y = j;
                int dir = 0;

                do
                {
                    contour.push_back(Point(y, x));
                    dst.at<uchar>(x, y) = 255;

                    bool found = false;
                    for (int k = 0; k < 8; k++)
                    {
                        int new_x = x + neighbors[dir].y;
                        int new_y = y + neighbors[dir].x;

                        if (new_x >= 0 && new_x < rows && new_y >= 0 && new_y < cols &&
                            src.at<uchar>(new_x, new_y) == 255 && dst.at<uchar>(new_x, new_y) == 0)
                        {
                            x = new_x;
                            y = new_y;
                            dir = (dir + 6 + k) % 8;
                            found = true;
                            break;
                        }

                        dir = (dir + 1) % 8;
                    }

                    if (!found)
                        break;
                } while (x != i || y != j);

                for (auto& p : contour)
                    dst.at<uchar>(p.y, p.x) = 255;

                contour.clear();
            }
        }
    }
}

参考文献:

[1] https://en.wikipedia.org/wiki/Moore_neighborhood

[2] https://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.htm

opencv中的findContours找二值图图像轮廓耗费的时间太多了如何用C++实现一个耗时最少的轮廓查找算法并再原图中给原图用红色标出轮廓区域。给出C++完整代码和算法原理

原文地址: https://www.cveoy.top/t/topic/dbe8 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录