第5章 Python的图像处理 Python有很强的图像处理能力,本章分别介绍应用Pillow模块和Open CV处理图像的方法。 5.1 图像像素的存储形式 为了方便介绍数据图像处理知识,首先要了解图像在计算机中的存储形式。 1. 灰度图 把黑白图像中的白色与黑色之间按对数关系分为若干等级,称为灰度。灰度图为单通道,一个像素块对应矩阵中的一个数字,数值为0~255, 其中0表示最暗(黑色),255表示最亮(白色)。灰度图用矩阵表示如图5.1所示(为了方便起见,每列像素值都写一样了)。 图5.1 灰度图用矩阵表示 2. RGB模式彩色图 RGB模式彩色图用三维矩阵表示如图5.2所示。 图5.2 RGB模式彩色图用三维矩阵表示 5.2 Pillow模块处理图像 5.2.1 PIL概述 PIL(Python Imaging Library,Python图像处理库)提供了通用的图像处理功能,以及大量有用的基本图像操作,如图像缩放、裁剪、旋转、颜色转换等。 1. 安装Pillow模块 PIL仅支持到Python 2.7版本,Python 3.x的PIL兼容版本称为Pillow(Python 3.x在使用引用模块语句时,仍称为PIL,即import PIL)。在命令行窗口中使用pip安装Pillow模块,其命令为: pip install pillow 安装过程如图5.3所示。 图5.3 安装Pillow模块 2. Pillow模块的方法 Pillow模块提供了大量用于图像处理的方法,通过创建的图像对象可以调用这些图像处理方法。Pillow模块图像处理的常用方法如表5.1所示。 表5.1 Pillow模块图像处理的常用方法 方法 说明 Image.open("图像文件名") 打开图像文件,返回图像对象 show() 显示图像 Save("文件名") 保存图像文件 resize(宽高元组) 图像缩放 thumbnail() 创建图像的缩略图 rotate() 旋转图像 transpose(Image.FLIP_LEFT_RIGHT) 图像水平翻转 transpose(Image.FLIP_TOP_BOTTOM) 图像垂直翻转 crop(矩形区域元组) 裁剪图像续表 方法 说明 paste(裁剪图像对象,矩形区域) 粘贴图像 ImageGrab.grab(矩形区域元组) 屏幕截图,若区域为空,则表示全屏幕截图 filter(ImageFilter.EDGE_ENHANCE) 图像增强 filter(ImageFilter.BLUR) 图像模糊 filter(ImageFilter.FIND_EDGES) 图像边缘提取 point(lambda i:i*r) 图像点运算。r>1,图像变亮;r<1,图像变暗 format 查看图像格式的属性值 size 查看图像大小的属性值,格式为(宽度,高度) getpixel(坐标元组) 读取指定坐标点的像素的颜色值,参数为(x,y)坐标元组,返回值为红、绿、蓝三色分量的值 putpixel((元组1), (元组2))? 元组2的值改变目标像素元组1的颜色值 split() 将彩色图像分离为红、绿、蓝三个分量通道。例如:r, g, b = im.split() Image.merge(im.mode, (r,g,b)) 将红、绿、蓝三个分量通道合并成一个彩色图像 enhance(n) 对比度增强为原来的n倍(n为实数)。例如: img = ImageEnhance.Contrast(img) img = im.enhance(1.5) # 对比度增强为原图的1.5倍 5.2.2 PIL的图像处理方法 利用 PIL 中的函数,可以从大多数图像格式的文件中读取数据,然后写入最常见的图像格式文件中。PIL中常用的模块为 Image和ImageTk。Image用于加载图像文件,得到PIL图像对象,而ImageTk模块负责对PIL对象进行各种图像处理。例如,要读取一幅图像,可以使用: from PIL import Image img = Image.open("img1.gif") 上述代码的返回值img是一个PIL图像对象。可以对这个PIL图像对象进行各种处理。下面介绍几个典型的图像处理的应用示例。 1. 图像的打开和显示 【例5.1】 打开和显示图像示例。 程序代码如下: import tkinter from PIL import Image, ImageTk win = tkinter.Tk() win.title('图像显示') win.geometry('300x300') # 定义窗体的大小300像素×300像素 can = tkinter.Canvas(win, # 创建画布组件 bg='white', # 指定画布组件的背景色 width=300, # 指定画布组件的宽度 height=300) # 指定画布组件的高度 image = Image.open("dukou.jpg") # 打开图像文件 img = ImageTk.PhotoImage(image) # 获取图像像素 can.create_image(160,120,image=img) # 将图像添加到画布组件中 can.pack() # 将画布组件添加到主窗口 win.mainloop() 程序运行结果如图5.4所示。 图5.4 打开和显示图像 2. 建立图像的缩略图 使用 PIL 可以很方便地创建图像的缩略图。PIL 图像对象的thumbnail(size)方法将图像转换为由元组参数设定大小的缩略图。 【例5.2】 建立图像缩略图示例。 程序代码如下: import tkinter from tkinter import Label from PIL import Image, ImageTk import os win = tkinter.Tk() win.title('建立图像缩略图') win.geometry('200x200') # 定义窗体大小为400像素×200像素 def imgshow(): size = (64, 64) # 设置缩略图尺寸的元组参数 img = Image.open("dukou.jpg") img.thumbnail(size) img.save("dukou(1).jpg", "JPEG") # 保存缩略图为dukou(1).jpg photo = ImageTk.PhotoImage(file='dukou(1).jpg') label = Label(win, image=photo) label.pack() label.image = photo tkinter.Button(win, text='建立图像缩略图 ',command=imgshow).pack() win.mainloop() 运行程序,单击“建立图像缩略图”按钮后,则将当前文件夹中名为dukou.jpg的图像文件生成64×64像素的缩略图,如图5.5所示。 图5.5 生成图像缩略图 3. 增强图像处理 使用 PIL可以很方便地对图像进行各种数字图像处理。例如,应用filter()方法的ImageFilter.EDGE_ENHANCE属性可以将图像的对比度增强。 【例5.3】 增加图像的对比度示例。 程序代码如下: import tkinter from tkinter import Label from PIL import Image, ImageTk, ImageEnhance, ImageFilter win = tkinter.Tk() win.title('增强图像') win.geometry('400x200') # 定义窗体大小为400像素×200像素 photo = Image.open('dukou.jpg') img1 = ImageTk.PhotoImage(photo) # 获取图像像素 label_1 = Label(win, image=img1) # 显示原图 def imgshow(): img = photo.filter(ImageFilter.EDGE_ENHANCE) img2 = ImageTk.PhotoImage(img) # 获取图像像素 label_2 = Label(win, image=img2).grid(row=1, column=1) # 显示增强后的图 label_2.image = img2 button = tkinter.Button(win, text='增强图像处理 ',command=imgshow) button.grid(row=0, column=0, columnspan=2) label_1.grid(row=1, column=0) win.mainloop() 程序运行结果如图5.6所示。 图5.6 图像增强 5.3 Open CV数字图像处理 Open CV 是Open Source Computer Vision Library 的简称,是一个计算机视觉库。Open CV可用于开发实时的图像处理、计算机视觉以及模式识别程序,目前使用十分广泛。 5.3.1 Open CV模块的安装和导入 1. 安装Open CV模块 Python的Open CV模块名为opencv-python,在命令行窗口中使用pip安装Open CV模块,其命令为: pip install opencv-python 安装过程如图5.7所示。 图5.7 用pip安装Open CV模块的过程 2. Open CV模块的导入 导入Open CV模块,其名称为cv2,其导入语句如下: import cv2 5.3.2 图像的读取、显示和保存 调用Open CV模块的相关函数,就可以很方便地对图像进行操作。下面介绍图像的加载、显示和保存函数及其使用方法。 1. 读取图像函数imread() Open CV 的imread()函数可以读取图像文件,返回图像对象。其基本格式为 cv2.imread(img_path, flag) 该函数的参数含义如下: ● img_path:图像的路径,即使路径错误也不会报错,但打印返回的图像对象为None。 ● flag: —cv2.IMREAD_COLOR,读取彩色图像,为默认参数,也可以传入1。 —cv2.IMREAD_GRAYSCALE,按灰度模式读取图像,也可以传入0。 —cv2.IMREAD_UNCHANGED,读取图像,包括其alpha通道,也可以传入?1。 2. 显示图像函数imshow() Open CV 的imshow()函数在自适应图像大小的窗口中显示图像。其基本格式为 cv2.imshow(window_name,img) 该函数的参数含义如下: ● window_name: 指定窗口的名字。 ● img:显示的图像对象。 该函数可以指定多个窗口名称,显示多个图像。 3. 保持窗体显示的函数 由于imread()函数显示图像的窗口会发生闪退,图像无法显示出来。因此,需要使用waitKey()使窗口保持显示状态。waitKey()的格式为: cv2.waitKey(millseconds) 其中,参数millseconds为设定时间数(毫秒),在该时间内等待键盘事件;当参数为0时,会无限等待。 通常与waitKey()配合使用的还有销毁窗口函数destroyAllWindows(),其格式为: cv2.destroyAllWindows(window_name) 其中,参数window_name为需要关闭的窗口。 4. 保存图像函数imwrite() 保存图像函数的格式为: cv2.imwrite((img_path_name, img) 其中,参数img_path_name为保存的文件名,img为需要保存的图像对象。 【例5.4】 使用Open CV模块打开和显示图像示例。 程序代码如下: import cv2 img = cv2.imread('test.jpg', 0) # 读取图像,参数0表示灰度 cv2.imshow('title', img) # 显示图像,第1个参数为图像窗体的标题 cv2.imwrite('Grey_img.jpg', img) # 保存灰度图像 cv2.waitKey(0) # 等待图像的关闭 cv2.destroyAllWindows() # 关闭和销毁图像窗口 程序运行结果如图5.8所示。 图5.8 使用Open CV打开和显示图像 5.3.3 绘制基本几何图形 1. 在图像上绘制点和直线 1)绘制点 在OPen CV中,当绘制一个半径很小的圆时,就是一个点了。其函数为: cv2.circle(img, center, radius, color[, thickness[, lineType[,shift]]]) 函数的参数含义如下: ● img:要画的圆所在的矩形或图像。 ● center:圆心坐标,如 (100, 100)。 ● radius:半径,如10。 ● color:圆边框颜色,如 (0, 0, 255)表示红色,为BGR。 ● thickness:取正值时表示圆的边框宽度,取负值时表示画一个填充圆形。 ● lineType:圆边框线型,可为 0,4,8。 ● shift:圆心坐标和半径的小数点位数。 2)绘制直线 绘制直线函数为: cv2.line(img, pt1, pt2, color[, thickness[, lineType[, shift]]]) 函数的参数含义如下: ● img:要画的圆所在的矩形或图像。 ● pt1:直线的起点。 ● pt2:直线的终点。 ● color:线条的颜色,如(0, 0, 255)表示红色,为BGR。 ● thickness:线条的宽度 ● lineType:取值4或8(-- 8:8连通线段,-- 4:4连通线段)。 【例5.5】 在图像上绘制点和直线示例。 程序代码如下: import cv2 as cv point_size = 5 point_color = (0, 0, 255) # BGR thickness = 4 # 可以为 0,4,8 img = cv.imread('xiamen.jpg',1) # 要画的点的坐标 points_list = [(80, 12), (320, 200)] for point in points_list: cv.circle(img, point, point_size, point_color, thickness) # 直线的起点和终点坐标 ptStart = (80, 14) ptEnd = (318, 200) lineType = 4 cv.line(img, ptStart, ptEnd, point_color, thickness, lineType) cv.imshow('a_window', img) cv.waitKey(0) cv.destroyAllWindows() 程序运行结果如图5.9 所示。 图5.9 在图像上绘制点和直线 2. 在图像上绘制矩形和注释文字 1)绘制矩形 绘制矩形函数为: cv2.rectangle(img,pt1,pt2,color,thickness) 函数的参数意义如下: ● img:指定的图片。 ● pt1:矩形左上角点的坐标。 ● pt2:矩形右下角点的坐标。 ● color:线条的颜色 (RGB) 或亮度(灰度图像 )(grayscale image)。 ● thickness:组成矩形的线条的粗细程度。取负值(如 CV_FILLED)时函数绘制填充了色彩的矩形。 2)注释文字 显示文字函数为: cv2.putText(img, str, origin, font, size, color, thickness) 其中,各参数依次是:图片、添加的文字、左上角坐标、字体、字体大小、颜色和字体粗细。 【例5.6】 在图片上显示矩形框及文字。 程序代码如下: import cv2 as cv color1 = (0, 0, 255) color2 = (255, 0, 0) x = 140 y = 170 row = 150 col = 180 img = cv.imread('face.jpg', 1) cv.rectangle(img, (x, y), (x+row, y+col), color1, 3) cv.putText(img, 'face', (30, 150), cv.FONT_HERSHEY_COMPLEX, 3, color2, 11) cv.imshow('a_window', img) cv.waitKey(0) cv.destroyAllWindows() 程序运行结果如图5.10 所示。 图5.10 在图像上绘制矩形框和文字 5.4 案 例 精 选 5.4.1 用画布绘制图形 画布Canvas是图形用户界面tkinter的组件,它是一个矩形区域,用于绘制图形或作为容器放置其他组件。 Canvas对象包含了大量的绘图方法,表5.2列出了常用的绘图方法。 表5.2 Canvas对象常用的绘图方法 方法 说明 create_line(x1, y1, x2, y2) 绘制一条从(x1,y1)到(x2,y2)的直线 create_rectangle(x1, y1, x2, y2) 绘制一个左上角为(x1,y1)、右下角为(x2,y2)的矩形 create_polygon(x1, y1, x2, y2,x3, y3, x4, y4,x5, y5, x6, y6) 绘制一个顶点为(x1,y1)、(x2,y2)、(x3,y3)、(x4,y4)、(x5,y5)、(x6,y6)的多边形 create_oval(x1, y1, x2, y2, fill='color') 绘制一个左上角为(x1,y1)、右下角为(x2,y2)的外接矩形所包围的圆,fill为填充颜色 create_arc(x1, y1, x2, y2, start=s0,extent=s) 绘制在左上角为(x1,y1),右下角为(x2,y2)的外接矩形所包围的一段圆弧,圆弧角度为s,从s0开始 create_image(w, h, anchor=NE, image=filename) 在w宽、 h高的矩形区域内显示文件名为filename的图像 move(obj, x, y) 移动组件obj。x为水平方向变化量,y为垂直方向变化量 【例5.7】 绘制笑脸。 程序代码如下: import tkinter import tkinter.messagebox win = tkinter.Tk() win.title('画布示例') win.geometry('250x250') can = tkinter.Canvas(win, height=250, width=250) # 定义画布 io1 = can.create_oval(35,30,210,210, fill='yellow') # 画一个黄色的圆 io2 = can.create_oval(70,70,180,180, fill='black') io3 = can.create_oval(65,70,185,170, outline='yellow', fill='yellow') io4 = can.create_oval(80,100,110,130, fill='black') io5 = can.create_oval(150,100,180,130, fill='black') can.pack() win.mainloop() 程序运行结果如图5.11所示。 【例5.8】 用方向键移动矩形块。 tkinter的画布Canvas类可以用于设计简单动画,使用move(tags、dx、dy)方法实现移动图片或文字等组件。Canvas的update()方法为刷新界面,重新显示画布。 程序代码如下: import time from tkinter import * x = 50 y = 50 #(1)定义窗口 win = Tk() win.title("移动小矩形块") #(2)定义画布 canvas = Canvas(win,width=400,height=400) canvas.pack() # 显示画布 #(3)定义矩形块 rect = canvas.create_rectangle(x, y, x+30, y+30, fill='red') print(rect) #(4)定义移动小矩形的函数 def moveRect(event): if event.keysym == 'Up': canvas.move(rect, 0, -3) elif event.keysym == 'Down': canvas.move(rect, 0, 3) elif event.keysym == 'Left': canvas.move(rect, -3, 0) elif event.keysym == 'Right': canvas.move(rect, 3, 0) win.update() # 界面刷新 time.sleep(0.05) # 休眠 #(5)绑定方向键 canvas.bind_all('<KeyPress-Up>', moveRect) canvas.bind_all('<KeyPress-Down>', moveRect) canvas.bind_all('<KeyPress-Left>', moveRect) canvas.bind_all('<KeyPress-Right>', moveRect) win.mainloop() 程序运行结果如图5.12所示。 图5.12 用方向键移动小矩形块 5.4.2 识别二维码及条形码 pyzbar是Python的一个开源库,用于扫描、识别二维码和条形码信息。用pip安装pyzbar库,其命令为: pip install pyzbar 【例5.9】 设有条形码图片bar_code.jpg和二维码图片two_bar_code.jpg,编写一个识别二维码及条形码的程序。 程序代码如下: from pyzbar import pyzbar import matplotlib.pyplot as plt import cv2 # 条码定位及识别 def decode(image, barcodes): # 循环检测到的条形码 for barcode in barcodes: # 提取条形码的边界框的位置 # 画出图像中条形码的边界框 (x, y, w, h) = barcode.rect cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 5) # 条形码数据为字节对象,所以如果想在输出图像上 # 画出来,就需要先将它转换为字符串 barcodeData = barcode.data.decode("utf-8") barcodeType = barcode.type # 绘出图像上条形码的数据和条形码类型 text = "{} ({})".format(barcodeData, barcodeType) cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, .8, (255, 0, 0), 2) # 向终端打印条形码数据和条形码类型 print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData)) plt.figure(figsize=(10,10)) plt.imshow(image) plt.show() # (1)读取条形码图片 image = cv2.imread('tiaoma.jpg') # 找到图像中的条形码并进行解码 barcodes = pyzbar.decode(image) # 识别条形码 decode(image, barcodes) # (2)读取二维码图片 image = cv2.imread('zsmma.jpg') # 找到图像中的二维码并进行解码 barcodes = pyzbar.decode(image) # 识别二维码 decode(image, barcodes) 程序运行结果: [INFO] 识别 EAN13 barcode: 6902265501114 [INFO] 识别 QRCODE barcode: http://qr61.cn/odmOqs/qAI1Bft 显示结果如图5.13所示。 图5.13 识别条形码及二维码 5.4.3 无人驾驶汽车车道线检测 车道线检测是无人驾驶汽车的一项重要技术。有效地获取车道线信息,对无人驾驶汽车的决策有至关重要的作用。 车道线检测主要步骤及主要算法说明如下。 1.将视频流转换为一帧帧的图像 在本案例中,为了简化程序,将其省略为加载图像。 src = cv2.imread('gaosu_lane.jpg') 2.对图像进行去噪处理 使用高斯滤波对图像进行去噪处理。 src1 = cv2.GaussianBlur(src, (5,5), 0, 0) 3.把图像转换为灰度图 src2 = cv2.cvtColor(src1,cv2.COLOR_BGR2GRAY) cv2.imshow('huidu',src2) 其效果如图5.14所示。 图5.14 灰度图 4.边缘处理,提取图像的轮廓 src3 = cv2.Canny(src2,lthrehlod,hthrehlod) cv2.imshow('bianyuan',src3) 其效果如图5.15所示。 图5.15 图像的轮廓 5.保留感兴趣的区域并提取轮廓图中的直线 因为在实际应用中摄像头固定在车上,所拍摄的图像中特定的部分包含车道线,它一般都位于图片的中下部,所以只需要对这个区域进行处理即可;然后使用霍夫变换原理,提取轮廓图中的直线。 regin = np.array([[(0,src.shape[0]),(460,325), (520,325),(src.shape[1],src.shape[0])]]) mask = np.zeros_like(src3) mask_color = 255 # src3图像的通道数是1,且是灰度图像,所以颜色值为0~255 cv2.fillPoly(mask,regin,mask_color) src4 = cv2.bitwise_and(src3,mask) cv2.imshow('bianyuan',src4) 其效果如图5.16所示。 图5.16 在感兴趣区域提取轮廓图中的直线 6.优化处理并画出车道线 在第5步中提取到的图像中包含了很多直线,其中有很多直线是不需要的,这就需要去掉冗余的直线。具体的办法如下:首先对直线点集根据斜率的正负分成左右两类直线集;然后再分别对左右直线集进行处理。计算直线集的平均斜率和每条直线的斜率与平均斜率的差值,求出其中差值最大的直线,判断该直线的斜率是否大于阈值,如果大于阈值,就将其去除,然后对剩下的直线继续进行相同的操作,直到满足条件为止。 经过优化处理,得到的直线集依然很多,但是范围已经很小了,进一步采用最小二乘拟合的方式,将这些都用直线拟合,得到最后的左右车道线。 good_leftlines = choose_lines(lefts, 0.1) # 左边优化处理后的点 good_rightlines = choose_lines(rights, 0.1) # 右边优化处理后的点 leftpoints = [(x1,y1) for left in good_leftlines for x1,y1,x2,y2 in left] leftpoints = leftpoints+[(x2,y2) for left in good_leftlines for x1,y1,x2,y2 in left] rightpoints = [(x1,y1) for right in good_rightlines for x1,y1,x2,y2 in right] rightpoints = rightpoints+[(x2,y2) for right in good_rightlines for x1,y1,x2,y2 in right] lefttop = clac_edgepoints(leftpoints,325,src.shape[0]) # 左右车道线的端点 righttop = clac_edgepoints(rightpoints,325,src.shape[0]) src6 = np.zeros_like(src5) cv2.line(src6,lefttop[0],lefttop[1],linecolor,linewidth) cv2.line(src6,righttop[0],righttop[1],linecolor,linewidth) cv2.imshow('onlylane',src6) 其效果如图5.17所示。 图5.17 画出车道线 7.图像合成 将所画的车道线与原图像进行叠加,得到合成的图像。 src7 = cv2.addWeighted(src1,0.8,src6,1,0) cv2.imshow('Finally Image',src7) 其效果如图5.18所示。 图5.18 合成后的图像 8.完整的无人驾驶汽车车道线检测程序代码 【例5.10】 无人驾驶汽车车道线检测程序。 程序代码如下: import cv2 import numpy as np # 读取图片 src = cv2.imread('line.jpg') # 高斯降噪 src1 = cv2.GaussianBlur(src, (5,5), 0, 0) # cv2.imshow('gaosi', src1) # 灰度处理 src2 = cv2.cvtColor(src1, cv2.COLOR_BGR2GRAY) # cv2.imshow('huidu', src2) # 边缘检测 lthrehlod = 50 hthrehlod =150 src3 = cv2.Canny(src2, lthrehlod, hthrehlod) # cv2.imshow('bianyuan', src3) # ROI划定区间,并将非此区间变成黑色 regin = np.array([[(0,src.shape[0]), (460,325), (520,325),(src.shape[1], src.shape[0])]]) mask = np.zeros_like(src3) mask_color = 255 # src3图像的通道数是1,且是灰度图像,所以颜色值为0~255 cv2.fillPoly(mask,regin, mask_color) src4 = cv2.bitwise_and(src3, mask) # cv2.imshow('bianyuan', src4) # 利用霍夫变换原理找出图中的像素点组成的直线,然后画出来 rho = 1 theta = np.pi/180 threhold =15 minlength = 40 maxlengthgap = 20 lines = cv2.HoughLinesP(src4, rho, theta, threhold, np.array([]), minlength, maxlengthgap) # 画线 linecolor =[0, 255, 255] linewidth = 4 src5 = cv2.cvtColor(src4, cv2.COLOR_GRAY2BGR) # 转换为三通道的图像 lefts =[] rights =[] for line in lines: for x1,y1,x2,y2 in line: # cv2.line(src5,(x1,y1),(x2,y2),linecolor,linewidth) # 分左右车道 k = (y2-y1)/(x2-x1) if k<0: lefts.append(line) else: rights.append(line) # 优化处理 def choose_lines(lines,threhold): # 过滤斜率差别较大的点 slope =[(y2-y1)/(x2-x1) for line in lines for x1,x2,y1,y2 in line] while len(lines) >0: mean = np.mean(slope) # 平均斜率 diff = [abs(s- mean) for s in slope] idx = np.argmax(diff) if diff[idx] > threhold: slope.pop(idx) lines.pop(idx) else: break return lines def clac_edgepoints(points,ymin,ymax): # 寻找直线的端点 x = [p[0] for p in points ] y = [p[1] for p in points ] k = np.polyfit(y, x, 1) func = np.poly1d(k) xmin = int(func(ymin)) xmax = int(func(ymax)) return [(xmin,ymin),(xmax,ymax)] good_leftlines = choose_lines(lefts, 0.1) # 处理后的点 good_rightlines = choose_lines(rights, 0.1) leftpoints = [(x1,y1) for left in good_leftlines for x1,y1,x2,y2 in left] leftpoints = leftpoints+[(x2,y2) for left in good_leftlines for x1,y1,x2,y2 in left] rightpoints = [(x1,y1) for right in good_rightlines for x1,y1,x2,y2 in right] rightpoints = rightpoints+[(x2,y2) for right in good_rightlines for x1,y1,x2,y2 in right] lefttop = clac_edgepoints(leftpoints,325,src.shape[0]) # 左车道线的端点 righttop = clac_edgepoints(rightpoints,325,src.shape[0]) # 右车道线的端点 src6 = np.zeros_like(src5) cv2.line(src6, lefttop[0], lefttop[1], linecolor, linewidth) cv2.line(src6, righttop[0], righttop[1], linecolor, linewidth) #cv2.imshow('onlylane',src6) # 图像叠加 src7 = cv2.addWeighted(src1, 0.8, src6, 1, 0) cv2.imshow('Finally Image', src7) cv2.waitKey(16000) # 等待图片的关闭 cv2.destroyAllWindows() # 关闭和销毁图片窗口 习 题 5 1. 绘制一个带阴影的小矩形块。 2. 设计一个图片浏览器,单击“上一张”按钮,则显示前一张图片;单击“下一张”按钮,则显示后一张图片。 3. 编写一个程序,显示图像的轮廓,如图5.19所示。 (a) 原图 (b) 轮廓图 图5.19 显示图像的轮廓