一、前提
课程中提供了关于MATLAB识别道路的代码。代码如下
srcImage = imread('lane.jpg');%读取图像
grayImage = rgb2gray(srcImage);%灰度图?
denoisedImage = medfilt2(grayImage, [5,5]); %中值滤波
H = fspecial('sobel'); %预定义边缘增强算子为sobel算子
sobelImage= imfilter(denoisedImage, H); %采用sobel算子突出边缘
% imshow(sobelImage);
thresh = graythresh(sobelImage); %通过Otsu方法获得阈值
% imshow(thresh);
binaryImage = imbinarize(sobelImage, thresh); %图像二值化
% imshow(binaryImage);
[H, theta, rho] = hough(binaryImage); %hough变换
p=houghpeaks(H, 8, 'threshold', ceil(0.3*max(H(:)))); %获取hough空间中前5个最大点
lines = houghlines(binaryImage,theta, rho,p,'FillGap',50,'MinLength',60); %通过hough空间中找到图像中对应的直线段
line_length_thred = 100;%车道线长度阈值?
slope_thred = 0.3;%车道线斜率阈值?
imshow(srcImage);
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
line_length = sqrt((xy(1,1)-xy(2,1)) * (xy(1,1)-xy(2,1)) + (xy(1,2)-xy(2,2)) * (xy(1,2)-xy(2,2)));%线段长度
%根据线段长度筛除部分线段
if(line_length < line_length_thred)
continue;
end
slopes = (xy(1,2)-xy(2,2)) / (xy(1,1)-xy(2,1)); %斜率
%根据线段斜率筛除部分线段
if abs(slopes) < slope_thred
continue;
end
%在图像上画出车道
xx = [xy(1,1), xy(2,1)];
yy = [xy(1,2), xy(2,2)];
% plot(xx,yy,'LineWidth',2,'Color','green');
line(xx, yy,'LineWidth',2,'Color','green');
end
所处理的图像如图所示:
二、转化为C++代码
(一)展示图像
将图像展示封装成函数进行使用。
// 图片展示封装
void PictureShow(const cv::Mat pic)
{
cv::imshow("haha", pic);
cv::waitKey();
}
(二)转化为灰度图
转化为灰度图。需要包含头文件,CV_BGR2GRAY才可以使用。
具体参考opencv4中未定义标识符CV_BGR2GRAY和CV_CAP_PROP_FRAME_COUNT问题-CSDN博客
// 转化为灰度图使用
#include <opencv2/imgproc/types_c.h> // 里面包含着CV_BGR2GRAY,转换为灰度图使用
// 图片转化为灰度值图片
void myFunction2Gray(cv::Mat& pic)
{
cv::Mat grey;
cv::cvtColor(pic, grey, CV_BGR2GRAY);
pic = grey;
}
(三)中值滤波
进行中值滤波。
可参考C/C++ OpenCV中值滤波&双边滤波_opencv c++ 消除笔-CSDN博客
// 中值滤波
void myFunctionMedianBlur(cv::Mat& pic)
{
cv::Mat out;
// cv::medianBlur最后一个参数是滤波模块的大小
cv::medianBlur(pic, out, 5);
pic = out;
//PictureShow(pic);
}
(四)使用sobel算子进行边缘增强
使用sobel算子进行边缘增强。分别包含x方向、y方向以及xy两者的混合梯度。测试之后发现只使用x方向的梯度效果最好。
可以参考Opencv(C++)学习系列---Sobel索贝尔算子边缘检测_cv::sobel-CSDN博客【OpenCV3】cv::convertScaleAbs()使用详解_cv.convertscaleabs-CSDN博客
// 使用sobel算子进行边缘增强
void myFunctionSobel(cv::Mat& pic)
{
// grad_x是求x方向的梯度,grad_y是求y方向的梯度
cv::Mat grad_x, grad_y;
cv::Mat abs_grad_x, abs_grad_y, dst;
// 计算x方向的梯度
cv::Sobel(pic, grad_x, CV_16S, 1, 0, 3);
//PictureShow(grad_x); // 这个图像不能看
// 需要使用这个
cv::convertScaleAbs(grad_x, abs_grad_x);
//PictureShow(abs_grad_x);
// 计算y方向的梯度
//cv::Sobel(pic, grad_y, CV_16S, 0, 1, 3);
//PictureShow(grad_x); // 这个图像不能看
// 需要使用这个
//cv::convertScaleAbs(grad_y, abs_grad_y);
//PictureShow(abs_grad_y);
// 合并梯度(近似)
//cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
//PictureShow(dst);
//pic = dst;
pic = abs_grad_x;
//pic = abs_grad_y;
//PictureShow(pic);
}
(五)计算Otsu所需要的阈值范围
使用Otsu算法进行二值化处理。
可以参考OpenCV基础——threshold函数的使用_cv::threshold-CSDN博客
// 使用Ostu算法
void myFunctionOtsu(cv::Mat& pic)
{
cv::Mat temp;
cv::threshold(pic, temp, 0, 255, CV_THRESH_OTSU);
PictureShow(temp);
pic = temp;
}
(六)使用hough,并绘制图像
使用hough,并绘制图像。
可以参考hough transform algorithm c++-掘金
https://www.cnblogs.com/nipan/p/4162747.html
// 使用hough变换
void myFunctionHough(cv::Mat& pic, cv::Mat& src)
{
//vector<Vec2f> lines;
vector<cv::Vec2f> lines;
cv::HoughLines(pic, lines, 1, CV_PI / 180, 100, 0, 0);
//cout << lines.size() << endl;
for (size_t i = 0; i < lines.size(); i++)
{
double rho = lines[i][0], theta = lines[i][1];
cv::Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a * rho, y0 = b * rho;
pt1.x = cvRound(x0 + 1000 * (-b));
pt1.y = cvRound(y0 + 1000 * (a));
pt2.x = cvRound(x0 - 1000 * (-b));
pt2.y = cvRound(y0 - 1000 * (a));
/*pt1.x = cvRound(x0);
pt2.y = cvRound(y0);*/
cv::line(src, pt1, pt2, cv::Scalar(0, 0, 255), 3, cv::LINE_AA);
//PictureShow(src);
}
PictureShow(src);
}
(七)主函数及头文件
#include <iostream>
#include <opencv2/opencv.hpp>
// 转化为灰度图使用
#include <opencv2/imgproc/types_c.h> // 里面包含着CV_BGR2GRAY,转换为灰度图使用
// 中值滤波使用、sobel算子使用、使用Ostu
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main(int argc, char** argv)
{
// 图片路径
const char* imagePath = "D:/北京理工大学/学习/大三下学期/智能无人车/test/one/lane.jpg";
// 读取图片
cv::Mat pic = cv::imread(imagePath);
// 将原图图像保存
cv::Mat src = pic;
// 转化为灰度图像
myFunction2Gray(pic);
// 中值滤波
myFunctionMedianBlur(pic);
// 使用sobel算子
myFunctionSobel(pic);
// 使用Otsu算法
myFunctionOtsu(pic);
// hough变换
myFunctionHough(pic, src);
// 展示图片进行测试
//cv::imshow("zhanshi", pic);
//cv::waitKey();
//PictureShow(pic);
return 0;
}
(八)结果展示
三、总结
可以识别出来,但是效果不好,后续进行改进。