// 5. 用直线拟合一组点------------------------------------------------------
cv::Mat image = cv::imread("../../aTestImage/road2.jpg", 0);//Building
cv::Mat contours;
//阈值1:确定应该包含所有认为是属于明显图像轮廓的边缘像素
//阈值2:定义属于所有重要边缘,剔除异常值(不连续边缘点)
//磁滞阈值化
cv::Canny(image, contours, 125, 350);//主体为白色
cv::namedWindow("contours", 1);
cv::imshow("contours", contours);
LinesFinder finder;
finder.setLineLengthAndGap(100, 20);
finder.setMinVote(80);
//cv::Vec4i : (x0,y0, x1,y1)
std::vector<cv::Vec4i> lines = finder.findLines(contours);
int n = 1;//选择contours中的一条线: 如第2条
cv::Mat oneline(contours.size(), CV_8U, cv::Scalar(0));
cv::line(oneline, cv::Point(lines[n][0], lines[n][1]),
cv::Point(lines[n][2], lines[n][3]), cv::Scalar(255), 10);
cv::bitwise_and(contours, oneline, oneline);// 跟轮廓contours作 与 运算
cv::namedWindow("oneline", 1);
cv::imshow("oneline", oneline);
//将oneline中的点放入到cv::points集合中
std::vector<cv::Point> points;
for (int y = 0; y < oneline.rows; y++)
{
uchar *rowPtr = oneline.ptr<uchar>(y);
for (int x = 0; x < oneline.cols; x++)
{
if (rowPtr[x])
{
points.push_back(cv::Point(x, y));
}
}
}
//使用cv::fitline函数 将点数组 拟合成直线
cv::Vec4f line; //(cos, sin, x0,y0)
cv::fitLine(cv::Mat(points), line, CV_DIST_L2, 0, 0.01, 0.01);
std::cout << "line: (" << line[0] << "," << line[1] << ")(" << line[2] << "," << line[3] << ")\n";
int x0 = line[2];
int y0 = line[3];
int x1 = x0 - 200 * line[0];
int y1 = y0 - 200 * line[1];
//在图像image上标记出该直线 设定长度100,颜色黑,宽度3
cv::line(image, cv::Point(x0, y0), cv::Point(x1, y1), cv::Scalar(0), 3);
cv::namedWindow("imageL", 1);
cv::imshow("imageL", image);
cv::waitKey(0);
return 0;
linesFinder类 .h:
#pragma once
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
#define PI 3.1415926
class LinesFinder
{
public:
LinesFinder() :
deltaRho(1), deltaTheta(PI / 180),minVote(10),minLength(0.),maxGap(0.) {} //初始化
~LinesFinder();
//设置累加器的分辨率
void setAccResolution(double dRho, double dTheta)
{
deltaRho = dRho;
deltaTheta = dTheta;
}
//设置最小投票数
void setMinVote(int minv)
{
minVote = minv;
}
//设置缺口及长度
void setLineLengthAndGap(double length, double gap)
{
minLength = length;
maxGap = gap;
}
//使用概率霍夫变换
std::vector<cv::Vec4i> findLines(cv::Mat &binary);
//绘制线段
void drawDetectLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255, 255, 255));
private:
cv::Mat img;
std::vector<cv::Vec4i> lines; //向量中包含检查到直线的端点
double deltaRho; //半径
double deltaTheta;// 与垂直线之间的角度
int minVote; //最小投票数
double minLength; // 线段最小长度
double maxGap; //沿直线方向最大缺口
};
linesFinder类 .cpp:
#include "stdafx.h"
#include "LinesFinder.h"
//LinesFinder::LinesFinder()
//{
//}
LinesFinder::~LinesFinder()
{
}
std::vector<cv::Vec4i> LinesFinder::findLines(cv::Mat & binary)
{
lines.clear();
cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap);
return lines;
}
void LinesFinder::drawDetectLines(cv::Mat & image, cv::Scalar color)
{
std::vector<cv::Vec4i>::const_iterator it2 = lines.begin();
while (it2 != lines.end())
{
cv::Point pt1((*it2)[0], (*it2)[1]);
cv::Point pt2((*it2)[2], (*it2)[3]);
cv::line(image, pt1, pt2, color);
++it2;
}
}