<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
import cv2 gray_img = cv2.imread('img.jpg',cv2.IMREAD_GRAYSCALE) canny_img = cv2.Canny(gray_img,50,100) cv2.imwrite('canny_img.jpg',canny_img) cv2.imshow('canny',canny_img) cv2.waitKey(0)
方法:在影象中,黑色表示0,白色為1,那麼要保留矩形內的白色線,就使用邏輯與,當然前提是影象矩形外也是0,那麼就採用建立一個全0影象,然後在矩形內全1,之後與之前的canny影象進行與操作,即可得到需要的車道線邊緣。
import cv2 import numpy as np canny_img = cv2.imread('canny_img.jpg',cv2.IMREAD_GRAYSCALE) roi = np.zeros_like(canny_img) roi = cv2.fillPoly(roi,np.array([[[0, 368],[300, 210], [340, 210], [640, 368]]]),color=255) roi_img = cv2.bitwise_and(canny_img, roi) cv2.imwrite('roi_img.jpg',roi_img) cv2.imshow('roi_img',roi_img) cv2.waitKey(0)
TIPs:使用霍夫變換需要將影象先二值化
概率霍夫變換函數:
- lines=cv2.HoughLinesP(image, rho,theta,threshold,minLineLength, maxLineGap)
- image:影象,必須是8位元單通道二值影象
- rho:以畫素為單位的距離r的精度,一般情況下是使用1
- theta:表示搜尋可能的角度,使用的精度是np.pi/180
- threshold:閾值,該值越小,判定的直線越多,相反則直線越少
- minLineLength:預設為0,控制接受直線的最小長度
- maxLineGap:控制接受共線線段的最小間隔,如果兩點間隔超過了引數,就認為兩點不在同一直線上,預設為0
- lines:返回值由numpy.ndarray構成,每一對都是一對浮點數,表示線段的兩個端點
import cv2 import numpy as np #計算斜率 def calculate_slope(line): x_1, y_1, x_2, y_2 = line[0] return (y_2 - y_1) / (x_2 - x_1) edge_img = cv2.imread('masked_edge_img.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]
流程:
- 獲取所有的線段的斜率,然後計算斜率的平均值
- 遍歷所有斜率,計算和平均斜率的差值,尋找最大的那個斜率對應的直線,如果差值大於閾值,那麼就從列表中剔除對應的線段和斜率
- 迴圈執行操作,直到剩下的全部都是小於閾值的線段
def reject_abnormal_lines(lines, threshold): 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 reject_abnormal_lines(left_lines, threshold=0.2) reject_abnormal_lines(right_lines, threshold=0.2)
流程:
- 取出所有的直線的x和y座標,組成列表,利用np.ravel進行將高維轉一維陣列
- 利用np.polyfit進行直線的擬合,最終得到擬合後的直線的斜率和截距,類似y=kx+b的(k,b)
- 最終要返回(x_min,y_min,x_max,y_max)的一個np.array的資料,那麼就是用np.polyval求多項式的值,舉個example,np.polyval([3,0,1], 5) # 3 * 5**2 + 0 * 5**1 + 1,即可以獲得對應x座標的y座標。
def least_squares_fit(lines): # 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) print(poly) # 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))
cv2.line(img, tuple(left_line[0]), tuple(left_line[1]), color=(0, 255, 255), thickness=5) cv2.line(img, tuple(right_line[0]), tuple(right_line[1]), color=(0, 255, 255), thickness=5)
import cv2 import numpy as np def get_edge_img(color_img, gaussian_ksize=5, gaussian_sigmax=1, canny_threshold1=50, canny_threshold2=100): """ 灰度化,模糊,canny變換,提取邊緣 :param color_img: 彩色圖,channels=3 """ gaussian = cv2.GaussianBlur(color_img, (gaussian_ksize, gaussian_ksize), gaussian_sigmax) gray_img = cv2.cvtColor(gaussian, cv2.COLOR_BGR2GRAY) edges_img = cv2.Canny(gray_img, canny_threshold1, canny_threshold2) return edges_img def roi_mask(gray_img): """ 對gray_img進行掩膜 :param gray_img: 灰度圖,channels=1 """ poly_pts = np.array([[[0, 368], [300, 210], [340, 210], [640, 368]]]) mask = np.zeros_like(gray_img) mask = cv2.fillPoly(mask, pts=poly_pts, color=255) img_mask = cv2.bitwise_and(gray_img, mask) return img_mask def get_lines(edge_img): """ 獲取edge_img中的所有線段 :param edge_img: 標記邊緣的灰度圖 """ def calculate_slope(line): """ 計算線段line的斜率 :param line: np.array([[x_1, y_1, x_2, y_2]]) :return: """ x_1, y_1, x_2, y_2 = line[0] return (y_2 - y_1) / (x_2 - x_1) def reject_abnormal_lines(lines, threshold=0.2): """ 剔除斜率不一致的線段 :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]])] """ 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 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]]) """ 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]) poly = np.polyfit(x_coords, y_coords, deg=1) 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) # 獲取所有線段 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] # 剔除離群線段 left_lines = reject_abnormal_lines(left_lines) right_lines = reject_abnormal_lines(right_lines) return least_squares_fit(left_lines), least_squares_fit(right_lines) def draw_lines(img, lines): left_line, right_line = lines cv2.line(img, tuple(left_line[0]), tuple(left_line[1]), color=(0, 255, 255), thickness=5) cv2.line(img, tuple(right_line[0]), tuple(right_line[1]), color=(0, 255, 255), thickness=5) def show_lane(color_img): edge_img = get_edge_img(color_img) mask_gray_img = roi_mask(edge_img) lines = get_lines(mask_gray_img) draw_lines(color_img, lines) return color_img capture = cv2.VideoCapture('video.mp4') while True: ret, frame = capture.read() if not ret: break frame = show_lane(frame) cv2.imshow('frame', frame) cv2.waitKey(10)
到此這篇關於OpenCV實戰案例之車道線識別詳解的文章就介紹到這了,更多相關OpenCV車道線識別內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45