5. 无人驾驶汽车两侧道路线图片识别

环境:python3.6
数据集: 数据集
注: 博客中不知原因不能导入文件

一:tools.py

import math
import cv2
import numpy as np

# 返回图片的灰度单一通道图片
def grayscale(img):
 """Applies the Grayscale transform
 This will return an image with only one color channel
 but NOTE: to see the returned image as grayscale
 (assuming your grayscaled image is called 'gray')
 you should call plt.imshow(gray, cmap='gray')"""
 return cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
 # Or use BGR2GRAY if you read an image with cv2.imread()
 # return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


# 边缘检测
def canny(img, low_threshold, high_threshold):
 """Applies the Canny transform"""
 # 高于high_threshold被认为是边缘,低于low_threshold的被认为不是边缘
 # 在这两个中间的像素点,若与高于high_threshold的像素点相连,则被认为是边缘,否则被认为不是边缘
 return cv2.Canny(img, low_threshold, high_threshold)


# 使用高斯滤波器对图像进行平滑处理
def gaussian_blur(img, kernel_size):
 """Applies a Gaussian Noise kernel"""
 # 高斯矩阵为(kernel_size,kernel_size),标准差取0
 return cv2.GaussianBlur(img, (kernel_size, kernel_size), 0)


# 保留由顶点连接成的多边形定义的图像区域,图像的其余部分设置为黑色
def region_of_interest(img, vertices):
 """
 Applies an image mask.

 Only keeps the region of the image defined by the polygon
 formed from `vertices`. The rest of the image is set to black.
 """
 # defining a blank mask to start with - Make a black image of the same size
 mask = np.zeros_like(img)

 # defining a 3 channel or 1 channel color to fill the mask with depending on the input image

 if len(img.shape) > 2:
 # img.shape[1]和img.shape[2]表示图像的长与宽,img.shape[3]表示通道数,该处为3
 channel_count = img.shape[2] # i.e. 3 or 4 depending on your image
 # (255,255,255)
 ignore_mask_color = (255,) * channel_count
 else:
 ignore_mask_color = 255 # white

 # filling pixels inside the polygon defined by "vertices" with the fill color
 # 将由顶点包围的区域颜色设置为白色,其它的区域为黑色
 cv2.fillPoly(mask, vertices, ignore_mask_color)

 # returning the image only where mask pixels are nonzero
 # Will return only the region of interest
 # 按位与操作(bitwise是按位的意思),会将较小的那个当做0处理,把较大的那个当做1处理,则保留顶点包围的区域
 masked_image = cv2.bitwise_and(img, mask)
 return masked_image


# [255, 0, 0]表示红色,lines形式为(x1,y1,x2,y2)表示线段的两个端点
# 注:该方法中left lane、right lane和实际车辆行驶过程中的左、右边界线正好相反
# 应该是因为坐标系的原点是在左上角,而不是左下角。x轴为宽方向,y轴为高方向
def draw_lines(img, lines, color=[255, 0, 0], thickness=3):
 # Function has been written to work with Challenge video as well
 # b -0, g-1, r-2
 """
 由一段段的线段连接成一条线
 NOTE: this is the function you might want to use as a starting point once you want to
 average/extrapolate the line segments you detect to map out the full
 extent of the lane (going from the result shown in raw-lines-example.mp4
 to that shown in P1_example.mp4).
 考虑用线段的斜率判断线段属于左部分还是右部分,这时,你可以平均每条线的位置,并且外推到线的两端
 Think about things like separating line segments by their
 slope ((y2-y1)/(x2-x1)) to decide which segments are part of the left
 line vs. the right line. Then, you can average the position of each of
 the lines and extrapolate to the top and bottom of the lane.
 这个函数画的线具有颜色和粗度,线段画在原来图片中(通过转换图片)
 如果想让线条变成半透明状,考虑使用函数weighted_img()
 This function draws `lines` with `color` and `thickness`.
 Lines are drawn on the image inplace (mutates the image).
 If you want to make the lines semi-transparent, think about combining
 this function with the weighted_img() function below
 """
 # At the bottom of the image, imshape[0] and top has been defined as 330
 # imshape[0]表示高度,imshpae[1]表示宽度
 imshape = img.shape
 slope_left = 0
 slope_right = 0
 leftx = 0
 lefty = 0
 rightx = 0
 righty = 0
 i = 0
 j = 0
 for line in lines:
 # 线段的起止点坐标slope
 for x1, y1, x2, y2 in line:
 # 斜率(坡度)
 slope = (y2 - y1) / (x2 - x1)
 # 表明这是left lane而且不是一条直线
 if slope > 0.1: # Left lane and not a straight line
 # Add all values of slope and average position of a line
 slope_left += slope
 leftx += (x1 + x2) / 2
 lefty += (y1 + y2) / 2
 i += 1
 # 表明这是right lane而且不是一条直线
 elif slope < -0.2: # Right lane and not a straight line
 # Add all values of slope and average position of a line
 slope_right += slope
 rightx += (x1 + x2) / 2
 righty += (y1 + y2) / 2
 j += 1
 # 左车道:斜率和截距的平均值 Left lane - Average across all slope and intercepts
 if i > 0: # 表示有左车道If left lane is detected
 # 左车道斜率的平均值
 avg_slope_left = slope_left / i
 # 左侧线线段中点x坐标的平均值
 avg_leftx = leftx / i
 # 左侧线线段中点y坐标的平均值
 avg_lefty = lefty / i
 # 假定y固定位置,计算底部x以及顶部x。Calculate bottom x and top x assuming fixed positions for corresponding y
 # 下面公式并不知道为什么这么写。。。应该是经验值吧
 xb_l = int(((int(0.97 * imshape[0]) - avg_lefty) / avg_slope_left) + avg_leftx)
 xt_l = int(((int(0.61 * imshape[0]) - avg_lefty) / avg_slope_left) + avg_leftx)

 else:
 # 左边界线没有检测出时(直行):估计底部x以及顶部x.
 # If Left lane is not detected - best guess positions of bottom x and top x
 # # 0.21,0.43参数设置和车辆上摄像头的安装位置有关
 xb_l = int(0.21 * imshape[1])
 xt_l = int(0.43 * imshape[1])

 # Draw a line
 # 由于看远处越来越窄,所以说left lane和right lane四点围成的图像是梯形
 cv2.line(img, (xt_l, int(0.61 * imshape[0])), (xb_l, int(0.97 * imshape[0])), color, thickness)

 # Right lane - Average across all slope and intercepts
 if j > 0: # If right lane is detected
 # 平均right lane斜率
 avg_slope_right = slope_right / j
 # 平均right lane中点位置
 avg_rightx = rightx / j
 avg_righty = righty / j
 # Calculate bottom x and top x assuming fixed positions for corresponding y
 xb_r = int(((int(0.97 * imshape[0]) - avg_righty) / avg_slope_right) + avg_rightx)
 xt_r = int(((int(0.61 * imshape[0]) - avg_righty) / avg_slope_right) + avg_rightx)

 else:
 # right lane没有检测出时(直行):估计底部x以及顶部x.
 # If right lane is not detected - best guess positions of bottom x and top x
 # 0.89,0.53参数设置和车辆上摄像头的安装位置有关
 xb_r = int(0.89 * imshape[1])
 xt_r = int(0.53 * imshape[1])

 # Draw a line
 # 由于看远处越来越窄,所以说left、right lane四点围成的图像是梯形
 cv2.line(img, (xt_r, int(0.61 * imshape[0])), (xb_r, int(0.97 * imshape[0])), color, thickness)


# 霍夫线变换。img输入时经过边缘检测处理的图像,rho为参数空间中的p,theta为参数空间中的角
# threshold为识别某部分为图中一条直线时,它在累加平面必须达到的值
# 长度低于min_line_len的线段不被显示,max_line_gap:允许同一行点和点之间连接起来的最大距离
def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap):
 """
 `img` should be the output of a Canny transform.

 Returns an image with hough lines drawn.
 """
 # 输出值lines形式为(x1,y1,x2,y2),表示线段的两个端点
 lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength=min_line_len,
 maxLineGap=max_line_gap)
 line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
 # 在全0的图片(黑色)上画线
 draw_lines(line_img, lines)
 return line_img


# Python 3 has support for cool math symbols.
# img图像是霍夫线变换的输出值,输出值是全黑图片上几条线画在上面
def weighted_img(img, initial_img, α=0.8, β=1., λ=0.):
 """
 `img` is the output of the hough_lines(), An image with lines drawn on it.
 Should be a blank image (all black) with lines drawn on it.

 `initial_img` should be the image before any processing.

 The result image is computed as follows:

 initial_img * α + img * β + λ
 NOTE: initial_img and img must be the same shape!
 """
 return cv2.addWeighted(initial_img, α, img, β, λ)

二:P1_image.py


import matplotlib
import matplotlib.pyplot as plt
import matplotlib.image as mping
import numpy as np
import os
from tools import *
import glob
# 对数据的操作,比如图片
import scipy.misc
# 当输入plt.plot(x,y_1)后,不必再输入 plt.show(),图像将自动显示出来
# %matplotlib inline,只在jupyter notebook上使用,其它地方使用报错
# 读取图片
# image = mping.imread('laneLines_thirdPass.jpg')
# print('This image is:', type(image), 'with dimensions:', image.shape)
# plt.imshow(image)
# 加上这句才能显示图片
# plt.show()
# 显示文件夹下文件
# dirs = os.listdir("test_images/")
# for file in dirs:
#     print(file)
#     image = mping.imread('test_images/'+file)
#     print(image.shape)


def lane_detector(image):
    gray = grayscale(image)
    # print(image.shape)
    # 定义kernel size 并且应用高斯平滑曲线
    kernel_size = 5
    blur_gray = gaussian_blur(gray, kernel_size)
    # 边缘检测Canny
    low_threshold = 10
    high_threshold = 150
    # 高于high_threshold值的肯定是边缘,低于low_threshold值的不是边缘,中间的像素点看与是边缘的点连不连接
    # 返回值edges为描述出边缘的图像,大小和原图像一样
    edges = canny(blur_gray, low_threshold, high_threshold)
    # create masked edges image
    # (高,宽,3)
    imshape = image.shape
    # 顶点。
    vertices = np.array([[(int(0.21*imshape[1]), imshape[0]), (int(0.44*imshape[1]), int(0.59*imshape[0])), (int(0.50*imshape[1]), int(0.59*imshape[0])), (imshape[1], imshape[0])]], dtype=np.int32)
    # 保留顶点包围区域,其它区域设置为黑色
    # 图片顶点坐标是以左上角为(0,0),横坐标表示x轴(宽方向)坐标。
    masked_edges = region_of_interest(edges, vertices)
    # 定义霍夫线变换参数,并且使用她检测线条
    rho = 1  # distance resolution in pixels of the Hough grid
    theta = (np.pi/180)   # angular resolution in radians of the Hough grid
    threshold = 15  # minimum number of votes (intersections in Hough grid cell)
    min_line_len = 60  # 构成一条直线的最小像素量
    max_line_gap = 30  # 可连接线段间的最大像素间距
    line_img = hough_lines(masked_edges, rho, theta, threshold, min_line_len, max_line_gap)
    final_img = weighted_img(line_img, image, α=0.6, β=1., λ=0.)
    return edges, masked_edges, final_img


new_path = os.path.join("test_images/", "*.jpg")
# glob函数为找到test_images文件夹下的jpg文件
for infile in glob.glob(new_path):
    img = infile
    image = mping.imread(img)
    edges, masked_edges, final_img = lane_detector(image)
    # final_img为一个numpy数组,输出一个PIL图像
    soln = scipy.misc.toimage(final_img)
    # 分离文件名和扩展名,0表示文件名,1表示扩展名
    outfile = os.path.splitext(infile)[0] + "_final.jpg"
    # 保存soln图片文件名为outfile,格式为JPEG
    soln.save(outfile, 'JPEG')
    # 画图
    fig = plt.figure(figsize=(20, 20))
    a = fig.add_subplot(2, 2, 1)
    plt.imshow(image)
    a.set_title('Original')

    a = fig.add_subplot(2, 2, 2)
    # cmap为颜色映射,即显示相应的颜色
    plt.imshow(edges, cmap='Greys_r')
    a.set_title('Canny')

    a = fig.add_subplot(2, 2, 3)
    plt.imshow(masked_edges, cmap='Greys_r')
    a.set_title('Masked Edges')

    a = fig.add_subplot(2, 2, 4)
    plt.imshow(final_img)
    a.set_title('Final')
plt.show()

你可能感兴趣的:(深度学习项目实战)