目前我基于opencv用c++写了一个代码,但是总感觉笨笨的,因为刚接触图像处理,自己一个人实在是有太多不懂的,所以来请教各位大佬,看看有没有更好更简洁的办法。
线结构光扫描的焊缝图像
我需要将图中焊缝的顶点,也就是那个尖尖给检测到,还要尽可能的准确,由于这个图像在实际应用中不一定是朝上的,所以不能直接遍历所有点直接检测最高点。最好是通过拟合直线求交点的方式,把那个顶点计算出来。所以算法的关键是通过直线的拟合来找交点。我自己写的代码直线拟合的不是很好,经常丢直线,或者有重复直线,导致求交点经常出现一些奇怪的点。
我的检测结果如下图,最左边的直线检测不到拟合不上不知道为啥,改阈值也不行,不是最左边拟合不上就是最右边拟合不上,挺头疼的。而且求交点我写的也不好,我是让相邻两直线求交点,然后对交点进行筛选,保留最高点,这样在实际应用中是不行的,因为如果焊缝是歪的那这个检测的就不对了,我不清楚该怎么改筛选条件能确保把这个尖尖处的点给保留下来。
结果
代码如下:- Mat image, grayImg, binaryImg;
- image = imread("C:\\Users\\86150\\Desktop\\tiliang.jpg");
- //灰度二值化
- cvtColor(image, grayImg, COLOR_BGR2GRAY);
- threshold(grayImg, binaryImg, 50, 255, THRESH_BINARY);//阈值调节
- // 霍夫直线检测
- vector<Vec4i> lines; // 注意这里使用了 Vec4i,它包含了两个点的坐标 (x1, y1) 和 (x2, y2),表示直线的两个端点
- HoughLinesP(binaryImg, lines, 1, CV_PI / 180, 10, 30, 30); // 参数可根据具体情况调整(后三个,阈值、最小直线长度、最大线段间隙)
- // 创建彩色直线图像
- Mat colorLinesImage = Mat::zeros(binaryImg.size(), CV_8UC3);
- // 存储代表性直线和对应的斜率
- vector<pair<Vec4i, double>> uniqueLinesWithSlope;
- // 绘制直线并记录斜率
- for (size_t i = 0; i < lines.size(); i++) {
- Vec4i l = lines[/color][i][color=#2e8b57]; //l的存储大概是x,y。l[0]是第一个点的横坐标,l[1]是纵坐标
- bool unique = true;
- // 检查直线是否有效,避免起点和终点重合导致的问题
- if (l[0] == l[2] && l[1] == l[3]) {
- continue; // 起点和终点重合,跳过这条直线
- }
- // 计算当前直线的斜率
- double dx = static_cast<double>(double(l[2]) - double(l[0]));
- if (dx == 0.0) {
- continue; // 避免除数为零的情况
- }
- double slope_current = static_cast<double>(double(l[3]) - double(l[1]) )/ dx;
- // 遍历已有的代表性直线,判断是否与当前直线相似
- for (size_t j = 0; j < uniqueLinesWithSlope.size(); j++) {
- Vec4i ul = uniqueLinesWithSlope[j].first;
- double slope_unique = uniqueLinesWithSlope[j].second;
- // 判断当前直线与已有直线是否相似,小于的是阈值
- if (abs(slope_current - slope_unique) < 0.07) {
- unique = false;
- break;
- }
- }
- // 如果当前直线是独特的,则加入到代表性直线集合中
- if (unique) {
- uniqueLinesWithSlope.push_back(make_pair(l, slope_current));
- // line(colorLinesImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, LINE_AA);//在colorLinesImage中显示图像
- line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, LINE_AA);//在image中显示图像
- }
- }
- // 对检测到的直线按照左端点的横坐标排序
- sort(uniqueLinesWithSlope.begin(), uniqueLinesWithSlope.end(), [](const pair<Vec4i, double>& a, const pair<Vec4i, double>& b) {
- return a.first[0] < b.first[0];
- });
- // 存储直线交点及其对应的直线索引
- vector<pair<Point2f, pair<int, int>>> intersections;
- // 对相邻直线进行遍历,找到斜率突变的直线并求交点
- for (size_t i = 0; i < uniqueLinesWithSlope.size() - 1; i++) {
- Vec4i line1 = uniqueLinesWithSlope[/color][i][color=#2e8b57].first;
- double slope1 = uniqueLinesWithSlope[/color][i][color=#2e8b57].second;
- Vec4i line2 = uniqueLinesWithSlope[i + 1].first;
- double slope2 = uniqueLinesWithSlope[i + 1].second;
- // 计算直线1的参数
- double x1 = line1[0], y1 = line1[1], x2 = line1[2], y2 = line1[3];
- double A1 = y2 - y1;
- double B1 = x1 - x2;
- double C1 = A1 * x1 + B1 * y1;
- // 计算直线2的参数
- double x3 = line2[0], y3 = line2[1], x4 = line2[2], y4 = line2[3];
- double A2 = y4 - y3;
- double B2 = x3 - x4;
- double C2 = A2 * x3 + B2 * y3;
- // 计算交点坐标
- double det = A1 * B2 - A2 * B1;
- if (det != 0) { // 确保直线不平行
- double intersection_x = (B2 * C1 - B1 * C2) / det;
- double intersection_y = (A1 * C2 - A2 * C1) / det;
- // 将交点坐标及对应的直线索引添加到交点向量中
- intersections.push_back(make_pair(Point2f(intersection_x, intersection_y), make_pair(i, i + 1)));
- }
- }
- // 在彩色直线图像上绘制交点及其来源直线
- for (const auto& intersection : intersections) {
- Point2f point = intersection.first;
- int line1_index = intersection.second.first;
- int line2_index = intersection.second.second;
- // 标注交点
- circle(image, point, 5, Scalar(255, 0, 0), -1); // 以蓝色绘制交点
- // 在交点附近标注直线索引
- putText(image, "Line " + to_string(line1_index) + " & Line " + to_string(line2_index),
- point + Point2f(10, -10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
- }
- // 找到位置最高的交点,,要修改,最高点不准确
- Point2f highestPoint;
- bool foundHighestPoint = false;
- for (const auto& intersection : intersections) {
- Point2f point = intersection.first;
- if (!foundHighestPoint || point.y < highestPoint.y) {
- highestPoint = point;
- foundHighestPoint = true;
- }
- }
- // 在图像上绘制位置最高的交点及其坐标
- if (foundHighestPoint) {
- // 标注交点
- circle(image, highestPoint, 5, Scalar(0, 255, 0), -1); // 以绿色绘制最高点
- // 在交点附近标注坐标
- putText(image, "(" + to_string(static_cast<int>(highestPoint.x)) + ", " + to_string(static_cast<int>(highestPoint.y)) + ")",
- highestPoint + Point2f(10, -10), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1);
- }
- //// 显示彩色直线图像
- imshow("Detected Lines", image);
复制代码
|