孔洞填充
void fillHole(const Mat srcBw, Mat &dstBw)
{Size m_Size = srcBw.size();Mat Temp=Mat::zeros(m_Size.height+2,m_Size.width+2,srcBw.type());//延展图像srcBw.copyTo(Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)));cv::floodFill(Temp, Point(0, 0), Scalar(255,255,255));Mat cutImg;//裁剪延展的图像Temp(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)).copyTo(cutImg);dstBw = srcBw | (~cutImg);
}
fillHole(ThrImg, ThrImg);
https://blog.csdn.net/wangyaninglm/article/details/47701047?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-47701047-blog-128034901.235^v43^pc_blog_bottom_relevance_base5&spm=1001.2101.3001.4242.1&utm_relevant_index=3
转换
16位转8位
cvtColor(OpenImage,OpenImage,COLOR_BGR2GRAY);
字符串转换
std::to_string(i)
//生成随机颜色,用于区分不同连通域RNG rng(10086);Mat out;int number=connectedComponents(OpenImage,out,8,CV_16U);//统计图像连通域的个数vector<Vec3b>colors;for(int i=0;i<number;++i){//使用均匀分布的随机确定颜色Vec3b vec3=Vec3b(rng.uniform(0,256),rng.uniform(0,256),rng.uniform(0,256));colors.push_back(vec3);}//以不同颜色标记出不同的连通域Mat result=Mat::zeros(OpenImage.size(),SrcImage_1.type());int w=result.cols;int h=result.rows;for(int row=0;row<h;++row){for(int col=0;col<w;++col){int label=out.at<uint16_t>(row,col);if(label==0){//背景的黑色不改变continue;}result.at<Vec3b>(row,col)=colors[label];}}imshow("标记后的图像",result);
https://blog.csdn.net/qq_33287871/article/details/112691790
图像混合:
float alpha=0.5; Mat MixImage;
addWeighted(ConnectImg, alpha, SrcImage_1, 1 - alpha, 0, MixImage);
中值滤波(去二值化图像毛刺):
medianBlur(ConnectImg,ConnectImg,9);
https://ask.csdn.net/questions/375741
霍夫直线检测
//1、边缘检测
Canny(ConnectImg, CanImg, position, 255, 3);
imshow("CanImg", CanImg);vector<Vec4i> lines; // 存储检测到的直线
HoughLinesP(CloseImage, lines, 1, CV_PI / 180, 80, 30, 10); // 应用霍夫直线检测算法,输入图像必须是边缘检测后的图像 因为它需要的是边缘信息或者梯度信息来找到线段。
for (size_t i = 0; i < lines.size(); i++)
{Vec4i l = lines[i];line(SrcImage_1, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, LINE_AA); //直线必须画在三通道的RGB图像中
}
imshow("HoughSrcImage_1", SrcImage_1);
LSD直线检测
方法一:
#include <iostream>
#include <string>
#include "opencv2/core/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"//1、边缘检测
Canny(ConnectImg, CanImg, 0, 255, 3);
imshow("CanImg", CanImg);Ptr<LineSegmentDetector> LS=createLineSegmentDetector(LSD_REFINE_STD);
vector<Vec4f>lines_LSD;
LS->detect(CanImg,lines_LSD);
Mat drawLSDlines(CanImg);
LS->drawSegments(drawLSDlines,lines_LSD);
imshow("LSD",drawLSDlines);
方法二:
Ptr<LineSegmentDetector> detector = createLineSegmentDetector();vector<Vec4f> lines;
detector->detect(CanImg,lines);Mat resultLSD(CanImg.size(),CV_8UC3,Scalar(0, 0, 0));Scalar color(0,0,255);
int thickness = 1;
cout<<"lines.size : "<<lines.size();
for(int i=0; i<lines.size(); i++)
{Point start(static_cast<int>(lines[i][0]), static_cast<int>(lines[i][1]));Point end(static_cast<int>(lines[i][2]), static_cast<int>(lines[i][3]));line(resultLSD, start, end, color, thickness);
}
imshow("resultLSD", resultLSD);
点距离直线筛选(检查直线是否与圆相交)
bool isLineIntersectsCircle(const Vec4i& line, const Point& circleCenter, int circleRadius) {Point start(line[0], line[1]);Point end(line[2], line[3]);// 使用点到直线距离来判断是否相交double dist = pointToLineDistance(circleCenter, start, end);if (dist <= circleRadius) {return true;}// 补充:检查圆心是否在直线上(重要!)double dotProduct = ((end.x - start.x) * (circleCenter.x - start.x) + (end.y - start.y) * (circleCenter.y - start.y));double squaredLength = (end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y);if (squaredLength != 0) {double param = dotProduct / squaredLength;if (param >= 0 && param <= 1) {Point closestPoint;closestPoint.x = start.x + param * (end.x - start.x);closestPoint.y = start.y + param * (end.y - start.y);double distanceFromCenter = norm(circleCenter - closestPoint); //计算圆心到最近点的距离if (distanceFromCenter <= circleRadius) {return true;}}}return false;
}
函数调用:
Point circleCenter1(140, 135); // 替换为你的圆心坐标(别忘了你图像缩小了6倍)Point circleCenter2(690, 72); // 替换为你的圆心坐标int circleRadius =60;// 使用 std::vector<int> 来存储与圆相交的第一条直线std::vector<int> intersectingLineIndices;for (size_t i = 0; i < extendedLines.size(); ++i) {if (isLineIntersectsCircle(extendedLines[i], circleCenter1, circleRadius)) {intersectingLineIndices.push_back(i);break; // 找到一条后立即退出循环,避免继续查找}}// 检验是否存在相交线if (!intersectingLineIndices.empty()) {int index = intersectingLineIndices[0];line(SrcImage_1, Point(extendedLines[index][0], extendedLines[index][1]),Point(extendedLines[index][2], extendedLines[index][3]), Scalar(0, 0, 255), 2);std::cout << "Found intersecting line at index " << index << std::endl;}else {std::cout << "No intersecting line found." << std::endl;}
直线交点探测(指定坐标下延长直线探测与其相交的直线)
cv::Point findIntersection(const cv::Vec4i& line1, const cv::Vec4i& line2) {double x1 = line1[0], y1 = line1[1], x2 = line1[2], y2 = line1[3];double x3 = line2[0], y3 = line2[1], x4 = line2[2], y4 = line2[3];double den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);// Check for parallel lines (or nearly parallel)if (std::abs(den) < 1e-6) {return cv::Point(-1, -1); // No intersection or nearly parallel}double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / den;double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / den;// Check if intersection point lies within both line segmentsif (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {double x = x1 + ua * (x2 - x1);double y = y1 + ua * (y2 - y1);// qDebug()<<"x = " <<x<<"y = " <<y;return cv::Point(static_cast<int>(x + 0.5), static_cast<int>(y + 0.5)); //Adding 0.5 for proper rounding} else {return cv::Point(-1, -1); // No intersection within line segments}
}double dist(const Point& p1, const Point& p2) {return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}Vec4i findClosestIntersectingLine(const vector<Vec4i>& extendedLines, const Point& center, const Vec4i& horizontalLine, const Mat& image) {Vec4i closestLine;double minDist = numeric_limits<double>::max();for (const auto& extLine : extendedLines) {Point intersection = findIntersection(extLine, horizontalLine);if (intersection.x != -1 && intersection.y != -1) {double d = dist(intersection, center);if (d < minDist) {minDist = d;closestLine = extLine;}}}return closestLine;
}Vec4i findClosestIntersectingLine(const vector<Vec4i>& extendedLines, const Point& center, const Vec4i& verticalLine) {Vec4i closestLine;double minDist = std::numeric_limits<double>::max();for (const auto& extLine : extendedLines) {Point intersection = findIntersection(verticalLine, extLine);if (intersection.x != -1 && intersection.y != -1) {double dist = norm(intersection - center);if (dist < minDist) {minDist = dist;closestLine = extLine;}}}return closestLine;
}
vector<Vec4i> extendedLines;for (size_t i = 0; i <lines_HLP.size() ; i++){Vec4i l = lines_HLP[i];Vec4i extendedLine;//延长直线extendLine(l, 500, extendedLine); // 延长 50 像素 独立的函数extendedLines.push_back(extendedLine);line(CanImg, Point(extendedLine[0], extendedLine[1]), Point(extendedLine[2], extendedLine[3]), Scalar(0, 255, 255), 1, LINE_AA);//line(CanImg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 255), 2, LINE_AA); //直线必须画在三通道的RGB图像中}imshow("extendedLine", CanImg);Point circleCenter1(140, 135); // 替换为你的圆心坐标(别忘了你图像缩小了8倍)Point circleCenter2(561, 128); // 替换为你的圆心坐标line(SrcImage_1, Point(circleCenter1.x, 0), Point(circleCenter1.x, SrcImage_1.rows), Scalar(0, 0 ,255), 2); // 绘制红色垂直线line(SrcImage_1, Point(0, circleCenter1.y), Point(SrcImage_1.cols,circleCenter1.y), Scalar(0, 0 ,255), 2); // 绘制红色垂直线line(SrcImage_1, Point(circleCenter2.x, 0), Point(circleCenter2.x, SrcImage_1.rows), Scalar(255, 0 ,255), 2); // 绘制红色垂直线line(SrcImage_1, Point(0, circleCenter2.y), Point(SrcImage_1.cols,circleCenter2.y), Scalar(255, 0 ,255), 2); // 绘制红色垂直线Vec4i verticalLine = Vec4i(circleCenter1.x, 0, circleCenter1.x, SrcImage_1.rows);Vec4i horizonLine = Vec4i(0, circleCenter2.y, SrcImage_1.cols, circleCenter2.y);line(CanImg, Point(horizonLine[0], horizonLine[1]), Point(horizonLine[2], horizonLine[3]), Scalar(255, 255, 0), 1);Vec4i closestLineA = findClosestIntersectingLine(extendedLines, circleCenter1,verticalLine);Vec4i closestLineB = findClosestIntersectingLine(extendedLines, circleCenter2,horizonLine);line(SrcImage_1, Point(closestLineA[0], closestLineA[1]), Point(closestLineA[2], closestLineA[3]), Scalar(0, 255, 0), 2, LINE_AA);line(SrcImage_1, Point(closestLineB[0], closestLineB[1]), Point(closestLineB[2], closestLineB[3]), Scalar(0, 255, 0), 2, LINE_AA);
相似斜率直线拟合(将斜率相近的几条直线分组并拟合成一条直线)
// 定义一个结构体来存储直线信息,方便后续处理
struct LineInfo {double k; // 斜率double b; // 截距Vec4i line; // 原直线段
};vector<Vec4i> fitOverlappingLines(const vector<Vec4i>& extendedLines, double slopeThreshold) {vector<LineInfo> linesInfo;for (const auto& line : extendedLines) {double x1 = line[0];double y1 = line[1];double x2 = line[2];double y2 = line[3];if (abs(x2 - x1) < 1e-6) { // 垂直线linesInfo.push_back({1e9, x1, line});} else {double k = (y2 - y1) / (x2 - x1);double b = y1 - k * x1;linesInfo.push_back({k, b, line});}}vector<Vec4i> fittedLines;vector<bool> used(linesInfo.size(), false);for (size_t i = 0; i < linesInfo.size(); ++i) {if (used[i]) continue;vector<LineInfo> group;group.push_back(linesInfo[i]);used[i] = true;for (size_t j = i + 1; j < linesInfo.size(); ++j) {if (used[j]) continue;// 关键判断:斜率接近且重合部分足够长if (abs(linesInfo[i].k - linesInfo[j].k) < slopeThreshold &&// 这里增加重合判断(例如,两个直线段的端点是否足够接近)((abs(linesInfo[i].line[0] - linesInfo[j].line[0]) < 10) && (abs(linesInfo[i].line[1] - linesInfo[j].line[1]) < 10) || (abs(linesInfo[i].line[2] - linesInfo[j].line[2]) < 10) && (abs(linesInfo[i].line[3] - linesInfo[j].line[3]) < 10))) {group.push_back(linesInfo[j]);used[j] = true;}}if (group.size() > 0) {// 计算所有group内直线的平均斜率和截距,用于拟合double sumX = 0, sumY = 0, n = group.size();for (const auto& lineInfo : group) {sumX += (lineInfo.line[0] + lineInfo.line[2]);sumY += (lineInfo.line[1] + lineInfo.line[3]);}double avgX = sumX / (2 * n);double avgY = sumY / (2 * n);double avg_k = 0;double avg_b = 0;for(const auto& lineInfo : group){avg_k = lineInfo.k;avg_b = lineInfo.b;}int x1 = 0;int y1 = static_cast<int>(avg_k * x1 + avg_b);int x2 = 666;int y2 = static_cast<int>(avg_k * x2 + avg_b);fittedLines.push_back({x1, y1, x2, y2});}}return fittedLines;
}
vector<Vec4i> fittedLines = fitOverlappingLines(extendedLines, 0.1);for(const auto& lineFT : fittedLines){line(SrcImage_1, Point(lineFT[0], lineFT[1]), Point(lineFT[2], lineFT[3]), Scalar(0, 255, 0), 2, LINE_AA);}imshow("FitImg", SrcImage_1);