车道线检测—python_opencv 代码解读

  1 #!D:/Code/python 
  2 # -*- coding: utf-8 -*- 
  3 # @Time : 2019/8/29 16:58 
  4 # @Author : Johnye 
  5 # @Site :  
  6 # @File : detect_RoadL.py 
  7 # @Software: PyCharm
  8 
  9 import cv2 as cv
 10 import numpy as np
 11 import math
 12 
 13 # LaneLineDetection类
 14 # 通过对象封装,将其中的重要函数隔离开
 15 class LaneLineDetection:
 16     def __init__(self):
 17         print("instace it")
 18         # leftline 和rightline车道检测的两条线
 19         # 每一条线分别有两个点决定
 20         self.left_line = {'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0}
 21         self.right_line = {'x1': 0, 'y1': 0, 'x2': 0, 'y2': 0}
 22 
 23     def process(self, frame, method=0):
 24         # 将图像转化为灰度图像
 25         gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
 26         # canny边缘检测
 27         binary = cv.Canny(gray, 150, 300)
 28         h, w = gray.shape
 29         # 这一步操作没看懂
 30         binary[0:np.int(h/2+40),0:w] = 0
 31         # 轮廓查找
 32         contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
 33         # 创建输出用的空白图像
 34         out_image = np.zeros((h, w), frame.dtype)
 35         # 遍历每一个轮廓,进行轮廓分析
 36         for cnt in range(len(contours)):
 37             # 通过多种特征筛选
 38             p = cv.arcLength(contours[cnt], True)
 39             # 计算轮廓面积
 40             area = cv.contourArea(contours[cnt])
 41             # 获取轮廓的中心坐标以及长、宽
 42             x, y, rw, rh = cv.boundingRect(contours[cnt])
 43             if p < 5 or area < 10:
 44                 continue
 45             if y > (h - 50):
 46                 continue
 47             # 计算最小外接矩形角度
 48             (x, y), (a, b), angle = cv.minAreaRect(contours[cnt]);
 49             angle = abs(angle)
 50             # 筛选标准 角度不能小于20或者大于90度或者等于90度,剔除
 51             if angle < 20 or angle > 160 or angle == 90.0:
 52                 continue
 53             # contour的长度大于5
 54             if len(contours[cnt]) > 5:
 55             # 椭圆拟合
 56                 (x, y), (a, b), degree = cv.fitEllipse(contours[cnt])
 57             # 椭圆的角度小于5 或者 角度大于160 或者角度在80和160之间,剔除
 58                 if degree< 5 or degree>160 or 80<degree<100:
 59                     continue
 60             # 不被以上的条件剔除的,在创建的空白图像上绘制该轮廓
 61             cv.drawContours(out_image, contours, cnt, (255), 2, 8)
 62         result = self.fitLines(out_image)
 63         cv.imshow("contours", out_image)
 64         dst = cv.addWeighted(frame, 0.8, result, 0.5, 0)
 65         cv.imshow("lane-lines", dst)
 66     #  直线拟合
 67     def fitLines(self, image):
 68         h, w = image.shape
 69         h1 = np.int(h / 2 + 40)
 70         out = np.zeros((h, w, 3), dtype=np.uint8)
 71         cx = w // 2
 72         cy = h // 2
 73         left_pts = []
 74         right_pts = []
 75         for col in range(100, cx, 1):
 76             for row in range(cy, h, 1):
 77                 pv = image[row, col]
 78                 if pv == 255:
 79                     left_pts.append((col, row))
 80         for col in range(cx, w-20, 1):
 81             for row in range(cy, h, 1):
 82                 pv = image[row, col]
 83                 if pv == 255:
 84                     right_pts.append((col, row))
 85         # 检测出的左车道线数量大于2
 86         if len(left_pts) >= 2:
 87             [vx, vy, x, y] = cv.fitLine(np.array(left_pts), cv.DIST_L1, 0, 0.01, 0.01)
 88             y1 = int((-x * vy / vx) + y)
 89             y2 = int(((w - x) * vy / vx) + y)
 90             dy = y2 - y1
 91             dx = w - 1
 92             k = dy/dx
 93             c = y1
 94 
 95             w1 = (h1 -c)/k
 96             w2 = (h - c) / k
 97             cv.line(out, (np.int(w1), np.int(h1)), (np.int(w2), np.int(h)), (0, 0, 255), 8, 8, 0)
 98             self.left_line['x1'] = np.int(w1)
 99             self.left_line['y1'] = np.int(h1)
100             self.left_line['x2'] = np.int(w2)
101             self.left_line['y2'] = np.int(h)
102         # 检测出的左车道线数量为1
103         else:
104             x1 = self.left_line['x1']
105             y1 = self.left_line['y1']
106             x2 = self.left_line['x2']
107             y2 = self.left_line['y2']
108             cv.line(out, (x1, y1), (x2, y2), (0, 0, 255), 8, 8, 0)
109         # 检测出的右车道线数量大于2
110         if len(right_pts) >= 2:
111             x1, y1 = right_pts[0]
112             x2, y2 = right_pts[len(right_pts) - 1]
113             dy = y2 - y1
114             dx = x2 - x1
115             k = dy / dx
116             c = y1 - k * x1
117             w1 = (h1 - c) / k
118             w2 = (h - c)/k
119             cv.line(out, (np.int(w1), np.int(h1)), (np.int(w2), np.int(h)), (0, 0, 255), 8, 8, 0)
120             self.right_line['x1'] = np.int(w1)
121             self.right_line['y1'] = np.int(h1)
122             self.right_line['x2'] = np.int(w2)
123             self.right_line['y2'] = np.int(h)
124         # 检测出的右车道线数量为1
125         else:
126             x1 = self.right_line['x1']
127             y1 = self.right_line['y1']
128             x2 = self.right_line['x2']
129             y2 = self.right_line['y2']
130             cv.line(out, (x1, y1), (x2, y2), (0, 0, 255), 8, 8, 0)
131         return out
132 
133 
134 def video_run():
135     capture = cv.VideoCapture("images/road_line.mp4")
136     height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
137     width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
138     count = capture.get(cv.CAP_PROP_FRAME_COUNT)
139     fps = capture.get(cv.CAP_PROP_FPS)
140     print(height, width, count, fps)
141     detector = LaneLineDetection()
142     while (True):
143         ret, frame = capture.read()
144         if ret is True:
145             cv.imshow("video-input", frame)
146             detector.process(frame, 0)
147             c = cv.waitKey(1)
148             if c == 27:
149                 break
150         else:
151             break
152 
153 
154 if __name__ == "__main__":
155     video_run()
156     cv.waitKey(0)
157     cv.destroyAllWindows()

 

posted @ 2019-08-29 22:15  ID是菜鸟  阅读(3665)  评论(0编辑  收藏  举报