opencv-python 小白笔记(19)

(一)实现流程

今天写一个车道线检测,本来打算写两种的,但是另一种比较麻烦且效果不咋地,所以就写这个了。

下面先附上车道线的检测结果视频:
传送门

PS:下面的程序也是借鉴了一些网上现有的例子

下面来写程序的实现流程

1读取视频的某一帧
2相关预处理
3截取图像的roi区域
4对图像透射变换
5统计图像的直方图信息
5统计图像的直方图信息
6设置左右车道线像素点拟合区域
7提取左右车道线的待拟合像素点
8拟合像素点
9填充拟合之间的区域
9填充拟合之间的区域
10将填充好的取再次透射变换
11见变换的结果与原图进行叠加

这里展示了处理过程中的一些图像,程序就不一一解读了,都有注释。
在这里插入图片描述

import cv2
import numpy as np
import matplotlib.pyplot as plt


cap=cv2.VideoCapture('3.mp4')

while True:

    success,img=cap.read()
    #这几步可以理解为预处理
    #########################################################################
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    #clahe=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))#这是自适应均衡化
    #gray=clahe.apply(gray)
    blur = cv2.GaussianBlur(gray, (5,5), 1)
    #edges = cv2.Canny(blur, 50, 150)#这里没有选择边缘检测
    #########################################################################


    # 设置四个坐标点用于ROI截取,去除干扰信息(这四个点很重要)
    #########################################################################
    y, x = blur.shape
    #print(y,x)
    points = np.array([[(257, 238),(0,y), (x, y), (400, 238) ]])#这四个点需要具体修改

    mask = np.zeros_like(blur)
    cv2.fillPoly(mask, points, 255)
    roi = cv2.bitwise_and(blur,blur, mask=mask)
    cv2.imshow('roi',roi)
    #########################################################################

    ret,th1=cv2.threshold(roi,135,225,cv2.THRESH_BINARY)#图像二值化,这里的值需要视情况修改

    #这里生成投射变换的矩阵与逆矩阵
    ##############################################################################
    height,width = img.shape[:2] #这里是预设提取出的图片大小
    pts1 = np.float32([[(257, 238), (400, 238),(0,y), (x, y) ]]) #这里是提取目标的四个坐标点
    pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]]) #这里是定义上面四个点在像新窗口中的对应位置
    matrix = cv2.getPerspectiveTransform(pts1,pts2)  #这里是通过cv2.getPerspectiveTransform得到变换矩阵,等一会传入cv2.warpPerspective函数
    matrix_inv = cv2.getPerspectiveTransform(pts2,pts1)#获得上面透射变换的逆矩阵
    imgOutput = cv2.warpPerspective(th1,matrix,(width,height))
    ##############################################################################

    #cv2.imshow('th1',th1)
    #cv2.imshow('roi',roi)
    #cv2.imshow('imgOutput',imgOutput)


    hist = np.sum(imgOutput, axis=0)#统计图片信息

    #plt.plot(hist)
    #plt.show()

    # 在统计结果中找到左右最大的点的位置,作为左右车道检测的开始点
    # 将统计结果一分为二,划分为左右两个部分,分别定位峰值位置,即为两条车道的搜索位置
    middle = np.int(hist.shape[0] / 2)
    leftx_starting = np.argmax(hist[:middle])
    rightx_starting = np.argmax(hist[middle:]) + middle


    # 设置窗口检测车道线
    # 设置滑动窗口的数量,计算每一个窗口的高度

    window_height = imgOutput.shape[0]

    # 获取图像中不为0的点
    nonzero = imgOutput.nonzero()
    nonzeroy = np.array(nonzero[0])
    nonzerox = np.array(nonzero[1])

    cv2.imshow('imgOutput',imgOutput)

    # 设置x的检测范围,设置检测半径为100
    radius = 100

    # 设置窗口的y的检测范围,因为图像是(行列),shape[0]表示y方向的结果,上面是0
    win_y_low = 0
    win_y_high = imgOutput.shape[0]

    # 左车道x的范围
    left_min = leftx_starting - radius
    left_max = leftx_starting + radius


    # 右车道x的范围
    right_min = rightx_starting - radius
    right_max = rightx_starting + radius

    # 确定非零点的位置x,y是否在搜索窗口中,将在搜索窗口内的x,y的索引存入left_inds和right_inds中
    left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) &
                        (nonzerox >= left_min) & (nonzerox < left_max)).nonzero()[0]

    right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) &
                        (nonzerox >= right_min) & (nonzerox < right_max)).nonzero()[0]


    # 获取检测出的左右车道点在图像中的位置
    left_x = nonzerox[left_inds]
    left_y = nonzeroy[left_inds]
    right_x = nonzerox[right_inds]
    right_y = nonzeroy[right_inds]


    #用曲线拟合检测出的点,二次多项式拟合
    left_fit = np.polyfit(left_y, left_x, 2)
    right_fit = np.polyfit(right_y, right_x, 2)


    # 设置输出图像的大小,将imgOutput进行堆叠成三通道的图片
    out_img = np.dstack((imgOutput, imgOutput, imgOutput))
    


    # 在拟合曲线中获取左右车道线的像素位置
    y_max = imgOutput.shape[0]
    left_points = [[left_fit[0] * y ** 2 + left_fit[1] * y + left_fit[2], y] for y in range(y_max)]
    right_points = [[right_fit[0] * y ** 2 + right_fit[1] * y + right_fit[2], y] for y in range(y_max - 1, -1, -1)]


    # 将左右车道的像素点进行合并
    line_points = np.concatenate((left_points, right_points))


    # 根据左右车道线的像素位置绘制多边形
    out_img=cv2.fillPoly(out_img, np.int_([line_points]), (0, 255, 0))


    #这里绘制像素点的拟合范围
    cv2.rectangle(out_img,(left_min,0),(left_max,win_y_high),(0,0,255),3)
    cv2.rectangle(out_img, (right_min, 0), (right_max, win_y_high), (0, 0, 255), 3)

    cv2.imshow('out_img',out_img)

    #这里将处理过的透射变换图像通过上面的透射变换的逆矩阵返回成原来的样子
    transform_img_inv=cv2.warpPerspective(out_img, matrix_inv,(width,height))


    #将原图与处理后的图像进行叠加
    result = cv2.addWeighted(img, 1, transform_img_inv, 0.5, 0)


    cv2.imshow('result', result)
    if cv2.waitKey(0)& 0xFF==ord('q'):
        break

PS:跑程序时需按住键盘上的“ESC”键或空格键,回车键。因为当时为了调试程序。如果小伙伴们不想这样,只需将程序倒数第二行cv2.waitkey括号里的0改为1即可

视频传送门

(二)备注

下面是上面程序中用到的几个函数用法
np.sum的用法
np.nonzero的用法
np.concatenate的用法

(三)结语

学习opencv有很多的方法,我的建议是你可以加一些群,可以充分利用B站,CSDN,和百度。

在我的博客中,我不会讲解opencv的算法实现(当然我也不太会),我只会讲解一些函数的调用,不理解就多改一些参数,多尝试尝试,慢慢你就理解来。相信你总有一天可以说opencv不过“Ctrl+C,Crtl+V”

如果有什么错误的地方,还请大家批评指正,最后,希望小伙伴们都能有所收获。
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值