OpenCV_Code_LOG
孔洞填充
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 segments
if (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);