首页
图像中物体的形状信息是较为明显和重要的信息,可以通过对形状的识别实现对物体的检测,因此,检测图像中某些规则的形状是图像处理的重要方法.通过检测形状确定目标的位置,并通过对目标的大小,位置等信息的处理进一步理解图像中的重要信息.
直线检测
霍夫变换 (Hough Transform)是图像处理中检测是否存在直线的重要方法,该算法是由Paul Hough在1962年首次提出的,最开始只能检测图像中的直线,但是霍夫变换经过不断扩展和完善,已经可以检测多种规则形状,例如圆形,椭圆等.霍夫变换通过把图像中的像素在一个空间坐标系中变换到另一个空间坐标系中,使得在原空间中具有相同特性的曲线或者直线映射到另一个空间中形成峰值,从而把检测任意形状的问题转化为统计峰值的问题.
/**
* @author IYATT-yx
* @date 2021-2-10
* @brief 直线检测
*/
#include "opencv2/opencv.hpp"
#include
#include
#include
/**
* @brief 直线绘制
* @param img 要标记直线的图像
* @param lines 检测到的直线数据
* @param rows 图像的高度
* @param cols 图像的宽度
* @param scalar 直线的颜色
* @param n 绘制直线的线宽
*/
void drawLine(cv::Mat &img, std::vector<cv::Vec2f> lines, double rows, double cols, cv::Scalar scalar, int n)
{
cv::Point pt1, pt2;
for (size_t i = 0; i < lines.size(); ++i)
{
// 直线距离坐标原点的距离
float rho = lines[i][0];
// 直线与坐标原点的垂线与x轴的夹角
float theta = lines[i][1];
// 夹角的余弦
double cosValue = cos(theta);
// 夹角的正弦
double sinValue = sin(theta);
// 直线与过坐标原点的垂线的交点
double x0 = rho * cosValue, y0 = rho * sinValue;
// 图像高宽的最大值
double length = cv::max(rows, cols);
// 计算直线上的一点
pt1.x = cvRound(x0 + length * (-sinValue));
pt1.y = cvRound(y0 + length * cosValue);
// 计算直线上另一点
pt2.x = cvRound(x0 - length * (-sinValue));
pt2.y = cvRound(y0 - length * cosValue);
// 两点绘制一条直线
cv::line(img, pt1, pt2, scalar, n);
}
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cout << "参数错误: 请指定图片路径" << std::endl;
exit(EXIT_FAILURE);
}
cv::Mat gray = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
if (gray.empty())
{
std::cout << "图片读取错误,请检测是否存在" << std::endl;
exit(EXIT_FAILURE);
}
// 检测边缘图像并二值化
cv::Mat edge;
cv::Canny(gray, edge, 80, 180, 3);
cv::threshold(edge, edge, 170, 255, cv::THRESH_BINARY);
// 用不同的累加器检测直线
std::vector<cv::Vec2f> lines1, lines2;
cv::HoughLines(edge, lines1, 1, CV_PI / 180, 50);
cv::HoughLines(edge, lines2, 1, CV_PI / 180, 150);
// 在图像中绘制直线
cv::Mat img1, img2;
gray.copyTo(img1);
gray.copyTo(img2);
drawLine(img1, lines1, edge.rows, edge.cols, cv::Scalar(255), 2);
drawLine(img2, lines2, edge.rows, edge.cols, cv::Scalar(255), 2);
// 显示结果
cv::imshow("原图", gray);
cv::imshow("边缘和二值化", edge);
cv::imshow("第一种累加器检测直线", img1);
cv::imshow("第二种累加器检测直线", img2);
cv::waitKey(0);
}