计算机视觉基础

1.车道线检测小程序

  1. 利用颜色进行检测
  2. 创建分割区域
  3. 边缘检测
  4. 直线提取

综合以上技术,尤其是2,3,4,我们可以对一些比较规则的图片进行检测,得到一个比较不错的车道线检测效果

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
fig_size = 25
COL = 2
#绘图
def draw_imgs(imgs):
    fig = plt.figure(figsize=(fig_size,fig_size),dpi=80)
    for index,img in enumerate(imgs):
        plt.subplot(len(imgs)/COL+1, COL, index+1)
        #plt.imshow(img)
        plt.title(list(img.keys())[0])
        plt.imshow(list(img.values())[0])
        fig.tight_layout() #子图紧凑排版
        
#在每张图上绘制多边形
def draw_poly(vertices):
    x = []
    y = []
    for v in vertices:
        for xx,yy in v:
            x.append(xx)
            y.append(yy)
    x.append(x[0])
    y.append(y[0])
    plt.plot(x, y, 'b--', lw=4)
imgs = []
# Read in and grayscale the image
image = mpimg.imread('exit.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)

# Define a kernel size and apply Gaussian smoothing
###### 高斯模糊 #######
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)

# Define our parameters for Canny and apply
###### canny 边缘检测 #######
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)

# Next we'll create a masked edges image using cv2.fillPoly()
# 使用zeros_like构造一个和edges一样规模的零矩阵
mask = np.zeros_like(edges)   
ignore_mask_color = 255   

# This time we are defining a four sided polygon to mask
###### 构建多边形区域 #######
imshape = image.shape
vertices = np.array([[(0,imshape[0]),(450, 290), (490, 290), (imshape[1],imshape[0])]], dtype=np.int32)
cv2.fillPoly(mask, vertices, ignore_mask_color)
masked_edges = cv2.bitwise_and(edges, mask)


###### 霍夫变换检测直线段 #######
# Define the Hough transform parameters
# Make a blank the same size as our image to draw on
rho = 1 # distance resolution in pixels of the Hough grid
theta = np.pi/180 # angular resolution in radians of the Hough grid
threshold = 1     # minimum number of votes (intersections in Hough grid cell)
min_line_length = 5 #minimum number of pixels making up a line
max_line_gap = 1    # maximum gap in pixels between connectable line segments
line_image = np.copy(image)*0 # creating a blank to draw lines on

# Run Hough on edge detected image
# Output "lines" is an array containing endpoints of detected line segments
# 返回值是得到的霍夫变换检测到的符合条件的线段
lines = cv2.HoughLinesP(masked_edges, rho, theta, threshold, np.array([]),
                            min_line_length, max_line_gap)



# Iterate over the output "lines" and draw lines on a blank image
###### 给检测到到线段着色并绘制在图像上 #######
for line in lines:
    for x1,y1,x2,y2 in line:
        cv2.line(line_image,(x1,y1),(x2,y2),(0,200,0),20)

# Create a "color" binary image to combine with line image
color_edges = np.dstack((edges, edges, edges)) 

# Draw the lines on the edge image
lines_edges = cv2.addWeighted(color_edges, 0.8, line_image, 1, 0) 

imgs.append({"origin":image})
imgs.append({"blur_gray":blur_gray})
imgs.append({"edges":edges})
imgs.append({"mask":mask})
imgs.append({"masked_edges":masked_edges})
imgs.append({"line_image":line_image}

draw_imgs(imgs,vertices)

2.相关库函数

1. numpy相关函数

功能函数使用
多边形拟合numpy.polyfit
深度方向叠加矩阵numpy.dstack

2. matplotlib相关函数

功能函数使用
绘制子图matplotlib.pyplot..subplotsubplot(nrows, ncols, index, **kwargs)
plt.figure(figsize=(fig_size,fig_size),dpi=80)
plt.subplot(1, 2, 1) # 一共绘制1行2列子图,这个是第1个
plt.imshow(image)
plt.subplot(1, 2, 2)# 一共绘制1行2列子图,这个是第2个
plt.imshow(gray)

https://blog.csdn.net/yuejisuo1948/article/details/81023125

3. opencv相关函数

功能函数用法
绘制线条cv2.linecv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) → img
绘制多边形cv2.fillPolycv2.fillPoly(img, pts, color[, lineType[, shift[, offset]]]) → img
按位与,即应用一个mask到目标图像cv2.bitwise_and
霍夫直线检测cv2.HoughLinesP

cv2.inRange() for color selection cv2.fillPoly() for regions selection cv2.line() to draw lines on an image given endpoints cv2.addWeighted() to coadd / overlay two images cv2.cvtColor() to grayscale or change color cv2.imwrite() to output images to file cv2.bitwise_and() to apply a mask to an image

图片缩放

def save_image(filename,img):
    size = img.shape
    print(size)
    img2save = cv2.resize(img,(size[1]//2,size[0]//2),cv2.INTER_LINEAR)
    print(img2save.shape)
    plt.imsave("./examples/{0}.jpg".format(filename),img2save)

plot转换为图片

子图


def draw_poly(filename,img,vertices):
    fig = plt.figure()
    x = []
    y = []
    for v in vertices:
        for xx,yy in v:
            x.append(xx)
            y.append(yy)
            plt.plot(xx,yy,'.', color='red',markersize=20)
            note_point = "({0},{1})".format(xx,yy)
            plt.annotate(note_point,xy=(xx,yy),color='red')
            
    x.append(x[0])
    y.append(y[0])
    plt.plot(x, y, 'b--', lw=4)
    plt.imshow(img)
    #print(help(poly_img))
    fig.savefig("./examples/{0}.jpg".format(filename))
    #ax = plt.gca()
    #ax.invert_yaxis() 
f, ((ax1, ax2) ,(ax3,ax4)) = plt.subplots(2, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(image)
ax1.set_title('Original Image', fontsize=50)
ax3.imshow(grad_binary_x, cmap='gray')
ax3.set_title('Thresholded Gradient', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=1.5, bottom=0.)
ax4.imshow(grad_binary_y, cmap='gray')
ax4.set_title('Thresholded Gradient', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=1.5, bottom=0.)

dpi

3.图像矩阵及mask

4. 霍夫变换

1.霍夫变换

阅读材料2是一个非常好的了解霍夫变换的资料。在此做一些总结。

1. 斜率-截距空间

首先,我们在图像空间中,找到两个端点 (𝑥1,𝑦1) 和 (𝑥2,𝑦2),它们是可以构成一条直线的,但是我们先不去管通过它们的直线,但看每一个点,都有无限个直线,以不同的斜率m和截距b,通过这个点。

我们把y=mx+b变换成b=y-mx之后,实际上可以将这某个直线变换到一个以b和m做参数的空间中,此时,图像空间中的一条固定直线,因其b和m是定值,所以在m-b空间中是一个点(m,b)。 类似的,图像空间中的某个点(𝑥1,𝑦1) ,因其b和m符合b=y-mx方程,因此在m-b空间中是一条直线。

这时我们再看之前穿过 (𝑥1,𝑦1) 和 (𝑥2,𝑦2)的直线,这条直线上的所有的点,其斜率和截距都是m和b,因此这个直线上的所有的点,在m-b空间中都经过点(m,b)。

每当我们找到端点为 (𝑥1,𝑦1) 和 (𝑥2,𝑦2)的一条直线上的点,mb空间中的点(m,b)就会被一条直线经过,这个过程称为vote,因此,vote越多,说明我们在 (𝑥1,𝑦1) 和 (𝑥2,𝑦2)上找到的线段越多,越可能是直线。

2. 极坐标空间

上述m-b空间最大的问题是,截距可能会是无穷,这样在m-b空间上就找不到点(m,b)了。 因此引入极坐标空间。

ρ = x cos θ + y sin θ

where:
ρ (rho) = distance from origin to the line. [-max_dist to max_dist].
          max_dist is the diagonal length of the image.  
θ = angle from origin to the line. [-90° to 90°]

变换到霍夫空间中的时候,原图像中的点,变换为曲线,原图像中的直线,变换为点。因此两条曲线的焦点就表示找到了过这两个点的一条直线。

同样,越多的直线经过这两点,霍夫空间中的曲线焦点被相交的次数越多,vote次数也越多。

我们在实际的运用中,可以设定一个阈值,相交点被vote的次数为5,也就是说,在图像空间两个端点 (𝑥1,𝑦1) 和 (𝑥2,𝑦2),连成的直线上,我们至少还能找到其他5个点组成的线段。

rho = 1 # distance resolution in pixels of the Hough grid
theta = np.pi/180 # angular resolution in radians of the Hough grid
threshold = 100   #这个值越大,被检测到的直线段越少,有可能检测不到 
min_line_len = 50 #minimum number of pixels making up a line
max_line_gap = 100    # maximum gap in pixels between connectable line segments
line_img,lines = hough_lines(masked_edges, rho, theta, threshold, min_line_len, max_line_gap)

TODO

绘图描述

5. 边缘检测之Canny

https://blog.csdn.net/wishchin/article/details/50969322