一种比findContour时间复杂度更小的图像目标轮廓查找算法是Suzuki和Abe提出的连通域标记算法。该算法的原理是对二值化图像中的每个像素进行扫描,找到连通区域并进行标记,最终得到目标轮廓。

该算法的时间复杂度为O(N),其中N为像素数目。相比之下,findContour算法的时间复杂度为O(NlogN)。

以下是C++代码实现:

void findContours(const Mat& binaryImg, vector<vector<Point>>& contours, vector<Vec4i>& hierarchy)
{
    contours.clear();
    hierarchy.clear();

    int rows = binaryImg.rows;
    int cols = binaryImg.cols;

    Mat label(rows, cols, CV_32SC1, Scalar(0)); // 用于标记每个像素是否已经被扫描过
    int labelNum = 1; // 连通区域的标记数

    // 第一遍扫描,标记连通区域
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (binaryImg.at<uchar>(i, j) == 0) { // 如果当前像素为背景
                label.at<int>(i, j) = -1; // 标记为已扫描过
                continue;
            }
            if (label.at<int>(i, j) != 0) { // 如果当前像素已经被扫描过
                continue;
            }
            queue<Point> q;
            q.push(Point(j, i));
            label.at<int>(i, j) = labelNum;
            while (!q.empty()) {
                Point p = q.front();
                q.pop();
                int x = p.x;
                int y = p.y;
                if (x > 0 && binaryImg.at<uchar>(y, x - 1) != 0 && label.at<int>(y, x - 1) == 0) { // 左边像素
                    q.push(Point(x - 1, y));
                    label.at<int>(y, x - 1) = labelNum;
                }
                if (x < cols - 1 && binaryImg.at<uchar>(y, x + 1) != 0 && label.at<int>(y, x + 1) == 0) { // 右边像素
                    q.push(Point(x + 1, y));
                    label.at<int>(y, x + 1) = labelNum;
                }
                if (y > 0 && binaryImg.at<uchar>(y - 1, x) != 0 && label.at<int>(y - 1, x) == 0) { // 上边像素
                    q.push(Point(x, y - 1));
                    label.at<int>(y - 1, x) = labelNum;
                }
                if (y < rows - 1 && binaryImg.at<uchar>(y + 1, x) != 0 && label.at<int>(y + 1, x) == 0) { // 下边像素
                    q.push(Point(x, y + 1));
                    label.at<int>(y + 1, x) = labelNum;
                }
            }
            labelNum++;
        }
    }

    // 第二遍扫描,得到轮廓
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            int l = label.at<int>(i, j);
            if (l <= 0) {
                continue;
            }
            if (i > 0 && label.at<int>(i - 1, j) != l) { // 上边像素
                contours[l - 1].push_back(Point(j, i));
            }
            else if (i == 0) {
                contours[l - 1].push_back(Point(j, i));
            }
            if (i < rows - 1 && label.at<int>(i + 1, j) != l) { // 下边像素
                contours[l - 1].push_back(Point(j, i + 1));
            }
            else if (i == rows - 1) {
                contours[l - 1].push_back(Point(j, i + 1));
            }
            if (j > 0 && label.at<int>(i, j - 1) != l) { // 左边像素
                contours[l - 1].push_back(Point(j - 1, i));
            }
            else if (j == 0) {
                contours[l - 1].push_back(Point(j - 1, i));
            }
            if (j < cols - 1 && label.at<int>(i, j + 1) != l) { // 右边像素
                contours[l - 1].push_back(Point(j + 1, i));
            }
            else if (j == cols - 1) {
                contours[l - 1].push_back(Point(j + 1, i));
            }
        }
    }

    // 得到轮廓的层级关系
    hierarchy.resize(labelNum - 1);
    for (int i = 0; i < contours.size(); i++) {
        int parent = -1;
        for (int j = 0; j < contours[i].size(); j++) {
            Point p = contours[i][j];
            int l = label.at<int>(p.y, p.x);
            if (l != i + 1) {
                if (parent == -1 || label.at<int>(p.y, p.x) == parent + 1) {
                    parent = l - 1;
                }
            }
        }
        hierarchy[i][3] = parent;
    }
}
``
C++实现查找图像目标轮廓时间复杂度比findContour小的一种算法以及原理和代码

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

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