在工业机器视觉领域,有很多直线检测和计算角度的应用场景。如下图,需要进行晶圆的粗对位校正:
此时需要计算出图像中的近似水平切割道的线条与实际水平线的夹角,从而进行晶圆的位置校正。在这个场景下,Hough变换就派上用场了。
Hough变换
Hough变换
是一种图像处理技术,用于检测图像中的直线、圆或其他形状。它的基本原理是将图像空间中的特定形状映射到参数空间中,并在参数空间中进行累加,以找到图像中的特定形状。
优点:
概率Hough变换
概率Hough变换
是对标准Hough变换的改进,通过随机地选择图像中的像素点来进行累加,从而减少计算量。
优点:
总的来说,选择使用Hough变换还是概率Hough变换取决于具体的应用场景和对计算效率和检测精度的要求。
仍以引言中的图像作为示例,我们在这里作为晶圆级的粗对位,采用概率hough变换即可。代码示例如下:
#ifndef HOUGHLINESDEMO_H
#define HOUGHLINESDEMO_H
class HoughLinesDemo
{
public:
HoughLinesDemo();
static int run();
};
#endif // HOUGHLINESDEMO_H
#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变换,精度定然会有明显提高。不过作为粗对位而言,实际现场基本够用~