从车道线检测入门OpenCV
Posted *大祺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从车道线检测入门OpenCV相关的知识,希望对你有一定的参考价值。
本文为纯小白之作(So大佬读者们可以移步了),读者可结合视频,
相信大家“一定”(当否定的概率小到渺茫时我认为其为绝对事件bushi)看不到文末,
所以看到开头的小伙伴可以点个赞不?
——快裂开的小白
目录
#01图片的读取、展示和保存
彩色图像
图像中的每个像素值都分成B(蓝)、G(绿)、R(红)三个基色分量,每个基色分量直接决定其基色的强度,这样产生的色彩称为真彩色。例如图像深度为24,用B:G:R=8:8:8来表示色彩,则R、G、B各占用8位来表示各自基色分量的强度,每个基色分量的强度等级为2^8=256种。图像可容纳2^24=16M种色彩(24位色)。24位色被称为真彩色,它可以达到人眼分辨的极限,发色数是1677万多色,也就是2的24次方。
灰度图像
每个像素只有一个采样颜色的图像。这类图像通常显示为从最暗黑色到最亮的白色的灰度 ,像素0~255,越大越亮。
####waitkey()函数
cv2.waitkey(delay),delay 的单位为ms毫秒,当 delay 取大于0的值时,程序在给定的 delay 时间内等待用户按键触发,如果用户没有按下键,则继续等待下一个delay时间(循环),直到用户按键触发,退出程序。若设置delay为0,则表示必须点击窗口界面的×才能关闭程序。 若设置delay的值小于0,等待键盘按键,任何一个按键都会关闭程序,默认参数为小于0(我电脑上打印出来是-1)。 ———————————————— 版权声明:本文为CSDN博主「楊建业」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:opencv中cv2.waitkey()参数详解_csdn_bajie-CSDN博客_cv2.waitkey(0)
代码
'''_read_and_display.py
import cv2
img=cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE)
print(type(img))
print(img.shape)
'''
cv2.imshow('image',img)
k = cv2.waitKey(0)print(k)
'''
cv2.imwrite('img_gray.jpg',img)
print('yes')
常数用大写表示:cv2.IMREAD_GRAYSCALE == 0
(一开始imwrite函数不报错但却不能生成图片,然后康康学长说我的.py文件是在venv虚拟环境里的,所以跟视频里不一样,然后我点“项目”就突然好了。。。我不知道发生了啥。)
#02Canny边缘检测
边缘认定标准
cv2.Canny()函数,第一个参数是输入图像,第二、三个参数是minVal和maxVal
处在上、下阈值之间的为弱边缘,大于上阈值的为强边缘(我们认为它肯定是边缘),弱边缘中与强边缘相连的才视为真正的边缘:
如上图将c看作边缘,b为噪声。
选取四个梯度方向(实际上相当于八个方向,因为有正负)
代码
'''_edge_detect.py
import cv2
img = cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE)
edge_img=cv2.Canny(img,70,120)
cv2.imshow('edges',edge_img)
cv2.waitKey(0)
#03.roi_mask
·ROI ( region of interest , 感兴趣的区域 )
·数组切片
·布尔运算(与运算)
np.zeros_like(a) : 构建一个与a同维度的数组,并初始化为0.
fillPolly函数
fillPolly(img,ppt,npt,1,Scalar(255,255,255),lineType)
函数参数:
1.多边形将被画到img上
2.多边形的顶点集为ppt(注意点的顺序)
3.绘制的多边形顶点数目为npt
4.要绘制的多边形数量为1
5.多边形的颜色定义为Scarlar(255,255,255),即RGB的值为白色
注意:点构成的边界,要加中括号
颜色原理:
按位与:因为掩膜图片中ROI区域的白色部分,即255(二进制是11111111,故与此部分相与仍是原数,
但非ROI区域是黑色,即00000000,与全0相与那么就会变成0,即不感兴趣的部分就会变成黑色
numpy.array函数:
一个常见的错误包括用多个数值参数调用array而不是提供一个由数值组成的列表作为一个参数。
>>> a = array(1,2,3,4) # WRONG
>>> a = array([1,2,3,4]) # RIGHT
数组将序列包含序列转化成二维的数组,序列包含序列包含序列转化成三维数组等等。
>>> b = array( [ (1.5,2,3), (4,5,6) ] )
>>> b
array([[ 1.5, 2. , 3. ],
[ 4. , 5. , 6. ]])
数组类型可以在创建时显示指定
>>> c = array( [ [1,2], [3,4] ], dtype=complex )
>>> c
array([[ 1.+0.j, 2.+0.j],
[ 3.+0.j, 4.+0.j]])
还有一篇讲得很详细:
numpy.array函数详解Android 小萌新的博客-CSDN博客np.array函数
bitwise_and函数
函数原型: bitwise_and(src1, src2, dst=None, mask=None)
参数说明: ·src1、src2:为输入图像或标量,标量可以为单个数值或一个四元组 · dst:可选输出变量,如果需要使用非None则要先定义,且其大小与输 入变量相同 ·mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0
代码
'''roi_mask.py
import cv2
import numpy as np
edge_img =cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE)
mask = np.zeros_like(edge_img)
mask2 = cv2.fillPoly(mask,np.array([[[0,368],[280,210],[360,210],[640,368]]]),color=255)
masked_edge_img = cv2.bitwise_and(edge_img, mask2)
cv2.imshow('newmask',masked_edge_img)
cv2.waitKey(0)
#04霍夫变换
霍夫变换(其一:直角坐标-->极坐标 找曲线交点
二值图像
二值图像(也可表示为 黑白、B&W、单色图像 )是每个像素只有两个可能值(0或225)的数字图像。但是也可以用来表示每个像素只有一个采样值的任何图像,例如灰度图像等。二值图像只能展示边缘信息。
cv2.line()
用于“画直线”
cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) → img
·img,背景图 ·pt1,直线起点坐标 ·pt2,直线终点坐标 ·color,当前绘画的颜色。如在BGR模式下,传递(255,0,0)表示蓝色画笔。灰度图下,只需要传递亮度值即可。 ·thickness,画笔的粗细,线宽。若是-1表示画封闭图像,如填充的圆。默认值是1. ·lineType,线条的类型, 如8-connected类型、anti-aliased线条(反锯齿),默认情况下是8-connected样式ide,cv2.LINE_AA表示反锯齿线条,在曲线的时候视觉效果更佳。
注:pt1, pt2 必须要为元组(tuple)形式,不能为列表
cv2.HoughLinesP()
lines = cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap)
● image 是输入图像,即源图像,必须为 8 位的单通道二值图像。对于其他类型的图像,在进行霍夫变换之前,需要将其修改为这个指定的格式。
● rho 为以像素为单位的距离 r 的精度。一般情况下,使用的精度是 1。(值越大,考虑越多的线.)
● theta 是角度 θ 的精度。一般情况下,使用的精度是 np.pi/180,表示搜索所有可能的角度。
● threshold 是阈值。该值越小,判定出的直线越多;值越大,判定出的直线就越少。
【 识别直线时,要判定有多少个点位于该直线上。在判定直线是否存在时,对直线所穿过的点的 数量进行评估,如果直线所穿过的点的数量小于阈值,则认为这些点恰好(偶然)在算法上构 成直线,但是在源图像中该直线并不存在;如果大于阈值,则认为直线存在】
● minLineLength 用来控制「接受直线的最小长度」的值,默认值为 0。
● maxLineGap 用来控制接受共线线段之间的最小间隔,即在一条线中两点的最大间隔。
如果两点间的间隔超过了参数 maxLineGap 的值,就认为这两点不在一条线上。默认值为 0。
● 返回值:x1,y1,x2,y2.
[ np.array ( [ [x1, y1, x2, y2] ]),
np.array ( [ [x1, y1, x2, y2] ]),
...,
np.array ( [ [x1, y1, x2, y2] ]) ]
———————————————— 版权声明:本文为CSDN博主「江南蜡笔小新」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:[OpenCV] HoughLines和HoughLinesP的区别与不同效果展示_江南蜡笔小新-CSDN博客_cv2.houghlines
代码
’‘’
import cv2
import numpy as np
def calculate_slope(line):
''' 功能:计算线段line的斜率
:param line: np.arry([[x1,y1,x2,y2]])
:return:
'''
x1,y1,x2,y2=line[0]
return (y1-y2)/(x1-x2)
def reject_abnormal_lines(lines,threshold):
''' 剔除斜率离群的线段
:param lines: 线段集合,[np.array([[x1, y1, x2, y2]]),...]
:param threshold: 允许最小误差
:return:斜率在误差内一致的线段
'''
slopes = [calculate_slope(line)for line in lines]
while len(lines) > 0:
mean = np.mean(slopes)
diff = [abs(s - mean)for s in slopes]
idx = np.argmax(diff)
if diff[idx] > threshold:
slopes.pop(idx)
lines.pop(idx)
else:
break
return lines
edge_img=cv2.imread('masked_edge.jpg',cv2.IMREAD_GRAYSCALE)
lines = cv2.HoughLinesP(edge_img,1,np.pi/180,15, minLineLength=40,maxLineGap=20)
left_lines = [line for line in lines if calculate_slope(line)>0]
right_lines = [line for line in lines if calculate_slope(line)<0]
print(len(lines))
print(len(left_lines))
print(len(right_lines))
reject_abnormal_lines(left_lines,0.07)
reject_abnormal_lines(right_lines,0.07)
print(len(left_lines))
print(len(right_lines))
#05离群值过滤
show me the code!
'''
import cv2
import numpy as np
def calculate_slope(line):
''' 功能:计算线段line的斜率
:param line: np.arry([[x1,y1,x2,y2]])
:return:
'''
x1,y1,x2,y2=line[0]
return (y1-y2)/(x1-x2)
def reject_abnormal_lines(lines,threshold):
''' 剔除斜率离群的线段
:param lines: 线段集合,[np.array([[x1, y1, x2, y2]]),...]
:param threshold: 允许最小误差
:return:斜率在误差内一致的线段
'''
slopes = [calculate_slope(line)for line in lines]
while len(lines) > 0:
mean = np.mean(slopes) #求平均斜率
diff = [abs(s - mean)for s in slopes]
idx = np.argmax(diff) #最大差的斜率元素下标
if diff[idx] > threshold:
slopes.pop(idx)
lines.pop(idx)
else:
break
return lines
edge_img=cv2.imread('masked_edge.jpg',cv2.IMREAD_GRAYSCALE)
lines = cv2.HoughLinesP(edge_img,1,np.pi/180,15, minLineLength=40,maxLineGap=20)
#注意此处斜率跟我们平时的相反
left_lines = [line for line in lines if calculate_slope(line)<0]
right_lines = [line for line in lines if calculate_slope(line)>0]
print(len(lines))
print(len(left_lines))
print(len(right_lines))
reject_abnormal_lines(left_lines,0.07)
reject_abnormal_lines(right_lines,0.07)
print(len(left_lines))
print(len(right_lines))
#06最小二乘拟合
polyfit()和polyval()
polyval是求值函数
polyfit是曲线拟合函数,主要用于多项式曲线拟合
p = polyfit(x, y, m)
其中 x, y 为已知数据点向量的横纵坐标,m为拟合多项式的次数,结果返回m次拟合多项式系数,从高到低次存放在向量p中。
y_0 = polyval(p, x_0)
可求得多项式在x_0处的值为y_0
如:输入
p = [4 2 1]
x = [5 6 7]
polyval(p, x)
可以得到多项式p(x)= 4 * x^2+2*x+1在x=[5 6 7]的值
np.ravel()
将多维数组降为一维。
代码片段
‘’‘
def least_squares_fit(lines):
"""
将lines中的线段拟合成一条线段
:param lines: 线段集合, [np.array([[x_1, y_1, x_2, y_2]]),np.array([[x_1, y_1, x_2, y_2]]),...,np.array([[x_1, y_1, x_2, y_2]])]
:return: 线段上的两点,np.array([[xmin, ymin], [xmax, ymax]])
"""
# 1. 取出所有坐标点
x_coords = np.ravel([[line[0][0], line[0][2]] for line in lines])
y_coords = np.ravel([[line[0][1], line[0][3]] for line in lines])
# 2. 进行直线拟合.得到多项式系数
poly = np.polyfit(x_coords, y_coords, deg=1)
# 3. 根据多项式系数,计算两个直线上的点,用于唯一确定这条直线
point_min = (np.min(x_coords), np.polyval(poly, np.min(x_coords)))
point_max = (np.max(x_coords), np.polyval(poly, np.max(x_coords)))
return np.array([point_min, point_max], dtype=np.int)
print("left lane")
print(least_squares_fit(left_lines))
print("right lane")
print(least_squares_fit(right_lines))
#07画直线
plus:(画直线问题之种种)函数见cv2.line()
1.因为左上角是原点,所以k>0是从左上往右下走的,这个k和我们平时的是反的。
2.关于直线颜色,cv2.imread()读进来的是BGR格式的,不是我们最常见的RGB格式,即(255,0,0)是蓝色不是红色。
#08视频流读写
通过不断循环读取视频的每一帧
一、基础函数
#1.cap = cv2.VideoCapture()
VideoCapture()中参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频,
#2.ret,frame = cap.read()
cap.read()按帧读取视频,ret,frame是获cap.read()方法的两个返回值。其中ret是布尔值,如果读取帧是正确的则返回True,如果文件读取到结尾,它的返回值就为False。frame就是每一帧的图像,是个三维矩阵。
#3.cv2.resize()
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) -> dst
参数说明:
src :需要改变尺寸的图像 dsize:目标图像大小 dst:目标图像 fx:w方向上的缩放比例 fy:h方向上的缩放比例 interpolation - 插值方法。共有5种(此处略)。
有三点需要注意:
1.dsize的形状是(w,h),而opencv读取出来的图像的形状是(h,w) 2.当参数dsize不为0时,dst的大小为dsize;否则,由src的大小以及缩放比例fx和fy来决定;可以看出dsize和(fx,fy)两者不能同时为0 3.因为dsize是没有默认值的,所以必须指定,也即我们使用fx和fy来控制大小的时候必须设置dsize=(0,0)
#4.cv2.cvtcolor()
hsv = cv2.cvtColor(rgb_image, cv2.COLOR_BGR2HSV)
#5.cv2.inRange()
mask = cv2.inRange(hsv, lower_red, upper_red)
参数说明:
hsv:原图
lower_red:图像中低于 lower_red的值,图像值变为0
upper_red:图像中高于upper_red的值,图像值变为0
二、滑动条
cv2.createTrackbar()
功能:绑定滑动条和窗口,定义滚动条的数值。
cv2.createTrackbar(“scale”, “display”, 0, 100, self.opencv_calibration_node.on_scale)
*参数意义:*
-
第一个参数:滑动条的名字,
-
第二个参数:滑动条被放置的窗口的名字,
-
第三个参数:滑动条默认值,
-
第四个参数:滑动条的最大值,
-
第五个参数:回调函数,每次滑动都会调用回调函数。
cv2.getTrackbarPos()
功能:得到滑动条的数值。
cv2.getTrackbarPos("hue min", "TrackBars")
参数:
·第一个参数是滑动条名字,
·第二个是所在窗口,
·返回值是滑动条的数值
cv2.setTrackbarPos()
功能:设置滑动条的默认值。
cv2.setTrackbarPos(‘Alpha’, ‘image’, 100)
参数:
-
第一个参数是滑动条名字,
-
第二个是s所在窗口,
-
第三个参数是滑动条默认值,
附:
以上是关于从车道线检测入门OpenCV的主要内容,如果未能解决你的问题,请参考以下文章