opencv +python实现倒车车道的检测及拟合

 特别声明:鉴于本人之前的文章在CSDN及博客园上被多次未署名抄袭及转载且附加广告,特此声明,本文禁止抄袭或未经作者许可下转载,请各位作者自重!!!!!!!!!!!

 大致要求为从倒车时摄像头所拍摄的照片中寻找到车道并将其连接为完整的车道,以平面图形式呈现。
 方案概述:先将原图片进行投影变化,再运用SURF算法匹配图片间的特征点,使用FLANN快速匹配图片间特征,计算一张图片可以变换到另一张图片的变换矩阵 (homography 单应性矩阵),用这个矩阵把那张图片变换后放到另一张图片相应的位置 ( 就是相当于把两张图片中定好的四个相似的点給重合在一起)。如此,就可以实现简单的全景拼接。这里我们主要利用opencv集成好的的stitching模块进行车道的拼接。
 以下我会从原理及利用库两方面讲解此项目的实现方案

1.桶形变化

 倒车摄像头与地面呈一定角度,所拍摄的图片如果直接进行全景拼接,会使图片产生较大畸变,及范围较大的黑边。这里考虑到倒车摄像头大都斜向下俯拍,且车道大都呈矩形,我们使用投影变化做图片的桶形变化。

    #读取图片
    img1 = cv2.imread('/home/yc/Pictures/zuo.jpg')
    img2 = cv2.imread('/home/yc/Pictures/you.jpg')
    img3 = cv2.imread('/home/yc/Pictures/zuo2.jpg')
   #取图片的形态学坐标信息
    h, w = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    h3, w3 = img3.shape[:2]
    #取出所选变化前图片的矩形角点
    src=np.array([[380,7],[1432,320],[380,1904],[1432,1607]],np.float32)
    #取出期望变化后图片的矩形角点
    dst=np.array([[230,0],[1424,1],[230,1912],[1424,1912]],np.float32)
    #计算投影矩阵
    P=cv2.getPerspectiveTransform(src,dst)
   #对图片做投影变化
    img12=cv2.warpPerspective(img1,P,(w,h),borderValue=400)
    src2=np.array([[0,0],[1432,320],[0,1904],[1432,1904]],np.float32)
    dst2=np.array([[0,0],[1424,1],[0,1904],[1424,1912]],np.float32)
    #计算投影矩阵
    P2=cv2.getPerspectiveTransform(src2,dst2)                                         
    img22=cv2.warpPerspective(img2,P,(w2,h2),borderValue=400)
    src3=np.array([[0,0],[1432,320],[0,1904],[1432,1904]],np.float32)
    dst3=np.array([[0,0],[1424,1],[0,1904],[1424,1912]],np.float32)
    P3=cv2.getPerspectiveTransform(src3,dst3)#计算投影矩阵

 桶形变化的作用主要就是缩减了边缘图像匹配的发散,尽量让匹配点的纵坐标的差值减小,缩减透视变换后的变形

2.特征检测及特征匹配

 这里我们主要采用hessian角点检测及surf特征点检测算法,检测到关键点使用FLANN快速匹配器进行特征匹配,要注意,surf算法有版权限制,请下载旧版opencv依赖库。

hessian=10
surf=cv2.cv2.xfeatures2d.SURF_create(hessian) 
#将Hessian Threshold设置为400,阈值越大能检测的特征就越少
kp1,des1=surf.detectAndCompute(leftgray,None) #查找关键点和描述符
kp2,des2=surf.detectAndCompute(rightgray,None)  
FLANN_INDEX_KDTREE=0#建立FLANN匹配器的参数
indexParams=dict(algorithm=FLANN_INDEX_KDTREE,trees=5) #配置索引,密度树的数量为5
searchParams=dict(checks=50)#指定递归次数
#FlannBasedMatcher:是目前最快的特征匹配算法(最近邻搜索)
flann=cv2.FlannBasedMatcher(indexParams,searchParams)  #建立匹配器
matches=flann.knnMatch(des1,des2,k=2)  #得出匹配的关键点 

good=[]#提取优秀的特征点
for m,n in matches:    
    if m.distance < 0.7*n.distance: #如果第一个邻近距离比第二个邻近距离的0.7倍小,则保留        
        good.append(m)

 有关特征匹配算法有未曾了解的,可以参考我之前的文章https://www.jianshu.com/p/bad83a08b1a8

3.利用匹配得到的变换矩阵,合并两幅图

H=cv2.findHomography(src_pts,dst_pts)#生成变换矩阵
h,w=leftgray.shape[:2]
h1,w1=rightgray.shape[:2]
shft=np.array([[1.0,0,w],[0,1.0,0],[0,0,1.0]])
M=np.dot(shft,H[0])            #获取左边图像到右边图像的投影映射关系
dst_corners=cv2.warpPerspective(leftgray,M,(w*2,h))#透视变换,新图像可容纳完整的两幅图
cv2.namedWindow("tiledImg1", cv2.WINDOW_NORMAL)
cv2.imshow('tiledImg1',dst_corners)   #显示,第一幅图已在标准位置
dst_corners[0:h,w:w*2]=rightgray  #将第二幅图放在右侧

4.stitching模块的应用

Image Stitching 模块下共包含七个子模块,分别为:

.Features Finding and Images Matching 功能查找和图像匹配
.Rotation Estimation 轮换估计
.Autocalibration 自动校准
.Images Warping 图像变形
.Seam Estimation 接缝估计
.Exposure Compensation 曝光补偿
.Image Blenders 图像搅拌机

借用一下stitching的官方引导图。
stitching引导图

 基本上是之前三个步骤的完善版代码,也很好的克服了合成图片产生黑边的问题,但合成速度较慢,运用在普通全景图像拼接时略有小题大做。
 这里讲解一下使用python调用opencv中的stitching模块的具体应用方法。
 因为项目所用图片的特殊性,我们依然需要进行第一步的投影变化,纠正拍摄图形的视角。此步骤参考第一步。
 接着我们调用两个stitching库中的函数cv2.createStitcher以及.stitch,第一个函数仅一个参数决定调用打开stitching库的方式有try_gpu以及False,鉴于opencv对GPU的支持很有限,这里我们建议采用False,第二个函数即直接调用stitching拼接图片,有以下四个参数:
 OK = 0:图像拼接成功。
 ERR_NEED_MORE_IMGS = 1:如果您收到此状态代码,则需要更多输入图像来构建全景图。通常,如果输入图像中检测不到足够的关键点,则会发生此错误。
 ERR_HOMOGRAPHY_EST_FAIL = 2:当RANSAC单应性估计失败时,会发生此错误。同样,您可能需要更多图像,或者您的图像没有足够的区别,独特的纹理/对象,以便准确匹配关键点。
 ERR_CAMERA_PARAMS_ADJUST_FAIL = 3:我之前从未遇到过这个错误,所以我对它没有多少了解,但要点是它与未能从输入图像中正确估计相机内参/外参有关。如果遇到此错误,您可能需要参考OpenCV文档,甚至可以深入了解OpenCV C ++代码。

#-*- coding:utf-8 -*-
import numpy as np
import cv2
from cv2 import Stitcher
import matplotlib.pyplot as plt 
if __name__ == "__main__":
    img1 = cv2.imread('/home/yc/Pictures/zuo.jpg')
    img2 = cv2.imread('/home/yc/Pictures/you.jpg')
    img3 = cv2.imread('/home/yc/Pictures/zuo2.jpg')
    h, w = img1.shape[:2]
    h2, w2 = img2.shape[:2]
    h3, w3 = img3.shape[:2]
    src=np.array([[380,7],[1432,320],[380,1904],[1432,1607]],np.float32)
    dst=np.array([[230,0],[1424,1],[230,1912],[1424,1912]],np.float32)
    P=cv2.getPerspectiveTransform(src,dst)#计算投影矩阵
    img12=cv2.warpPerspective(img1,P,(w,h),borderValue=400)
    src2=np.array([[0,0],[1432,320],[0,1904],[1432,1904]],np.float32)
    dst2=np.array([[0,0],[1424,1],[0,1904],[1424,1912]],np.float32)
    P2=cv2.getPerspectiveTransform(src2,dst2)#计算投影矩阵
    img22=cv2.warpPerspective(img2,P,(w2,h2),borderValue=400)
    src3=np.array([[0,0],[1432,320],[0,1904],[1432,1904]],np.float32)
    dst3=np.array([[0,0],[1424,1],[0,1904],[1424,1912]],np.float32)
    P3=cv2.getPerspectiveTransform(src3,dst3)#计算投影矩阵
    img23=cv2.warpPerspective(img3,P,(w3,h3),borderValue=400)
    stitcher = cv2.createStitcher(False)
    #stitcher = cv2.Stitcher.create(cv2.Stitcher_PANORAMA)根据不同的OpenCV版本来调用
    (_result, out) = stitcher.stitch((img12, img22, img23))
    rows3, cols3 = out.shape[:2]
    #旋转图片
    M1 = cv2.getRotationMatrix2D((w / 2, h / 2), 90, 1)
    M2 = cv2.getRotationMatrix2D((w2 / 2, h2 / 2), 90, 1)
    M3 = cv2.getRotationMatrix2D((w3 / 2, h3 / 2), 90, 1)
    #M4 = cv2.getRotationMatrix2D((cols3 / 2, rows3 / 2), 90, 1)
    img31 = cv2.warpAffine(img1, M1, (w, h))
    img32 = cv2.warpAffine(img2, M2, (w2, h2))
    img33 = cv2.warpAffine(img3, M3, (w3, h3))
    #imgout = cv2.warpAffine(out, M4, (cols3, rows3))
   #拼接三张原图
    img4=np.vstack([img33,img32,img31])

    titles = ['orgin', 'result']
    imgs = [img4,out]
    #画出图形
    for i in range(2):
        plt.subplot(1,2,i+1)
        #plt.plot([0,10],[0,5])
        #plt.subplots_adjust(left=0.09,right=1,wspace=0.25,hspace=0.25,bottom=0.13,top=0.91)
        plt.imshow(imgs[i])
        plt.title(titles[i])
    plt.show()
以下是样图所呈现的效果,左边为拍摄的原图,右边为所拼接的车道图片
样图效果

希望我的教程可以给一起学习opencv的同学一点帮助

还请各网站水积分的网友不要随意抄袭转载,请事先经过我的同意谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容