OpenCV图像处理——查找线条的转折点

问题描述

图像中有一条线,如何判断这条线的转折点?
比如下面一张图:

目的是找到图中的三个转折点。

要在图像中检测线的转折点,可以通过分析线的几何形状来完成。这通常需要首先提取线的轮廓,然后根据曲率、角度变化等特征来判断转折点。以下是一个通用的步骤概述,以及如何使用 OpenCV 来检测线的转折点。

步骤:

  1. 图像预处理

    • 将图像转换为灰度图像,去除噪声(如使用高斯模糊)。
  2. 提取线的轮廓

    • 使用边缘检测算法(如 Canny 边缘检测)来提取图像中的边缘。
    • 使用 cv::findContours 来找到图像中连通的轮廓。
  3. 检测转折点

    • 根据线的轮廓计算角度变化或曲率。
    • 可以通过逐个点的夹角来判断是否有显著的角度变化,转折点会对应着大的角度变化。

代码实现

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

// 计算两个向量的夹角
double angleBetween(cv::Point p1, cv::Point p2, cv::Point p3) {
    
    
    cv::Point v1 = p1 - p2;
    cv::Point v2 = p3 - p2;
    double dot = v1.x * v2.x + v1.y * v2.y;
    double det = v1.x * v2.y - v1.y * v2.x;
    return std::atan2(det, dot) * 180 / CV_PI;
}

// 检测转折点
std::vector<cv::Point> findCorners(const std::vector<cv::Point>& contour, double thresholdAngle = 30.0) {
    
    
    std::vector<cv::Point> corners;
    for (size_t i = 1; i < contour.size() - 1; ++i) {
    
    
        double angle = angleBetween(contour[i-1], contour[i], contour[i+1]);
        if (std::abs(angle) > thresholdAngle) {
    
    
            corners.push_back(contour[i]);
        }
    }
    return corners;
}

int main() {
    
    
    // 加载图像
    cv::Mat image = cv::imread("line_image.png", cv::IMREAD_GRAYSCALE);
    if (image.empty()) {
    
    
        std::cout << "无法加载图像!" << std::endl;
        return -1;
    }

    // 边缘检测
    cv::Mat edges;
    cv::Canny(image, edges, 50, 150);

    // 找到轮廓
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(edges, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 处理每一个轮廓
    for (const auto& contour : contours) {
    
    
        // 找到转折点
        std::vector<cv::Point> corners = findCorners(contour);

        // 可视化转折点
        cv::Mat colorImage;
        cv::cvtColor(image, colorImage, cv::COLOR_GRAY2BGR);
        for (const auto& corner : corners) {
    
    
            cv::circle(colorImage, corner, 5, cv::Scalar(0, 0, 255), -1);
        }

        // 显示结果
        cv::imshow("Corners", colorImage);
        cv::waitKey(0);
    }

    return 0;
}

代码说明:

  1. angleBetween 函数

    • 用于计算相邻三个点之间的夹角。通过两个向量的叉乘和点乘计算夹角。
  2. findCorners 函数

    • 遍历轮廓中的每个点,计算夹角。如果夹角大于设定的阈值(如 30 度),则判断为转折点。
  3. 主流程

    • 使用 cv::Canny 提取图像的边缘,然后使用 cv::findContours 找到轮廓。
    • 对每条轮廓,调用 findCorners 来检测转折点,并在图像上标记出来。

可调参数:

  • thresholdAngle:这个值控制判断转折点的角度阈值。你可以根据具体图像情况调整此值。如果线比较平滑,可以设置较小的阈值;如果线有很多小的波动,可以设置较大的阈值以避免检测过多的噪点。

总结:

该方法通过计算轮廓上相邻点的角度变化来检测转折点。转折点通常对应着显著的角度变化或曲率变化。通过调整角度阈值,可以灵活地检测图像中的线条转折点。