Qt+Opencv:基于Hough变换的直线检测

一、开场引言

在工业机器视觉领域,有很多直线检测和计算角度的应用场景。如下图,需要进行晶圆的粗对位校正:

此时需要计算出图像中的近似水平切割道的线条与实际水平线的夹角,从而进行晶圆的位置校正。在这个场景下,Hough变换就派上用场了。

二、认识Hough变换

2.1 Hough变换

Hough变换是一种图像处理技术,用于检测图像中的直线、圆或其他形状。它的基本原理是将图像空间中的特定形状映射到参数空间中,并在参数空间中进行累加,以找到图像中的特定形状。

优点:

  • 对噪声具有一定的鲁棒性,能够在一定程度上抵抗图像中的噪声。
  • 可以检测多种形状,包括直线、圆等。
    缺点:
  • 计算复杂度高,特别是对于大型图像和复杂形状的检测。
  • 对参数空间的离散化和累加需要大量的内存和计算资源。

2.2 概率Hough变换

概率Hough变换是对标准Hough变换的改进,通过随机地选择图像中的像素点来进行累加,从而减少计算量。

优点:

  • 计算量相对较小,适用于大型图像和复杂形状的检测。
  • 对于一些特定的应用场景,如检测长直线,概率Hough变换通常比标准Hough变换更有效。
    缺点:
  • 对于某些形状的检测可能不够精确,特别是在图像中存在大量噪声或形状重叠的情况下。
    比较
  • Hough变换适用于对图像中各种形状的检测,但计算复杂度高。
  • 概率Hough变换通过随机采样来减少计算量,适用于大型图像和复杂形状的检测,但可能牺牲一定的精度。

总的来说,选择使用Hough变换还是概率Hough变换取决于具体的应用场景和对计算效率和检测精度的要求。

三、示例

仍以引言中的图像作为示例,我们在这里作为晶圆级的粗对位,采用概率hough变换即可。代码示例如下:

cpp 复制代码
#ifndef HOUGHLINESDEMO_H
#define HOUGHLINESDEMO_H
class HoughLinesDemo
{
public:
    HoughLinesDemo();

    static int run();
};

#endif // HOUGHLINESDEMO_H
cpp 复制代码
#include "houghlinesdemo.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <QDateTime>
#include <vector>
#include <algorithm>

HoughLinesDemo::HoughLinesDemo()
{

}

int HoughLinesDemo::run()
{

    // 读取图像
    cv::Mat image = cv::imread("image/large_field_1.png");
    // cv::Mat image = cv::imread("image/large_field.bmp");

    /// 将图像转为灰度图
    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

    // 使用Canny边缘检测
    cv::Mat edges;
    cv::Canny(gray, edges, 50, 150, 3);

    // 进行Probabilistic Hough Transform直线检测
    std::vector<cv::Vec4i> lines;
    cv::HoughLinesP(edges, lines, 1, CV_PI/180, 50, 50, 5);


    std::vector<double> angles;
    // 计算每条直线的斜率和与水平线的夹角
    for (size_t i = 0; i < lines.size(); i++) {
        cv::Vec4i l = lines[i];
        cv::line(image, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0, 0, 255), 2);
        double angle = atan2(l[3] - l[1], l[2] - l[0]) * 180.0 / CV_PI;
        if(angle <= 0){
            angles.push_back(angle);
        }
        std::cout << "Angle with horizontal: " << angle << std::endl;
    }

    // 显示结果
    cv::imshow("Probabilistic Hough Transform", image);
    const QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh-mm-ss");
    QString sImge = QString("result/%1.png").arg(time);
    cv::imwrite(sImge.toStdString(),image);

    // 对角度数据进行排序
    std::sort(angles.begin(), angles.end());

    // 计算中值
    double median;
    if (angles.size() % 2 == 0) {
        median = (angles[angles.size() / 2 - 1] + angles[angles.size() / 2]) / 2.0;
    } else {
        median = angles[angles.size() / 2];
    }
    std::cout << "Median angle: " << median << " degrees" << std::endl;


    // cv 旋转原图
    cv::Point2f center(image.cols / 2.0, image.rows / 2.0); // 旋转中心
    cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, median, 1.0); // 旋转矩阵
    cv::Mat rotatedImage;
    cv::warpAffine(image, rotatedImage, rotationMatrix, image.size());

    // 显示原始图像和旋转后的图像
    cv::imshow("Rotated Image", rotatedImage);

    do { }  while (cvWaitKey(30) < 0);
    cv::destroyAllWindows();

    return 0;
}

四、结果展示

我们在角度数据处理时,采用的中值计算的方式,误差也会比较大。
Median angle: -0.79298 degrees

可以看到原图及计算角度旋转校正之后的图像,图像有明显的校正,但是水平切割道依然不是完美的水平。将种植计算改为计算直方,将概率hough变换换为hough变换,精度定然会有明显提高。不过作为粗对位而言,实际现场基本够用~

相关推荐
陌小呆^O^7 分钟前
Cmakelist.txt之win-c-udp-server
c语言·开发语言·udp
lindsayshuo8 分钟前
jetson orin系列开发版安装cuda的gpu版本的opencv
人工智能·opencv
Gu Gu Study14 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Mr.Q17 分钟前
OpenCV和Qt坐标系不一致问题
qt·opencv
时光の尘28 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
以后不吃煲仔饭42 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师43 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者1 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
程序猿阿伟1 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
傻啦嘿哟1 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel