交通标志检测(OpenCV&Python)

来源:互联网 发布:win7仿mac主题 编辑:程序博客网 时间:2024/06/10 06:33

简述

在交通实景图中检测出交通标志,并将区域裁剪,为后续的识别做准备。

颜色过滤

加载图像

import cv2import numpy as np#加载原图img=cv2.imread('walks.jpg')print('img:',type(img),img.shape,img.dtype)cv2.imshow('img',img)

这里写图片描述

转换为HSV通道

hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)cv2.imshow('hsv',hsv)

这里写图片描述

颜色过滤

确定提取的蓝色范围(HSV颜色),然后通过inRange函数(参数图片为HSV格式)提取蓝色区域

#提取蓝色区域blue_lower=np.array([100,50,50])blue_upper=np.array([124,255,255])mask=cv2.inRange(hsv,blue_lower,blue_upper)print('mask',type(mask),mask.shape)cv2.imshow('mask',mask)

这里写图片描述
如图所示,颜色区域在mask中白色表示,,其他颜色过滤,为黑色,人行道的标志 基本出来,但是实际场景图有许多颜色干扰,所以需要进一步优化。

优化处理

模糊

#模糊blurred=cv2.blur(mask,(9,9))cv2.imshow('blurred',blurred)

这里写图片描述
模糊后旁边的小白点消失。

二值化

将模糊后图像转换为二值图,只有0和1表示颜色。

#二值化ret,binary=cv2.threshold(blurred,127,255,cv2.THRESH_BINARY)cv2.imshow('blurred binary',binary)

这里写图片描述

闭运算

目的在于封闭区域,无空隙。

#使区域闭合无空隙kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)cv2.imshow('closed',closed)

这里写图片描述

进一步去干扰

此时人行道区域已经明显呈现,且无杂色干扰。
如果场景与比较复杂,仍然存在颜色干扰,可以采用膨胀和腐蚀操作进行去除干扰。

#腐蚀和膨胀'''腐蚀操作将会腐蚀图像中白色像素,以此来消除小斑点,而膨胀操作将使剩余的白色像素扩张并重新增长回去。'''erode=cv2.erode(closed,None,iterations=4)cv2.imshow('erode',erode)dilate=cv2.dilate(erode,None,iterations=4)cv2.imshow('dilate',dilate)

利用腐蚀膨胀去除干扰色的完整实例可参考基于OpenCV-python3实现证件照换背景

裁剪目标区域

思路:此时的图像已经处理的很简单,所以进行查找轮廓,将轮廓转换为矩形,然后根据矩形的坐标,在原图进行裁剪,即可得到目标区域

# 查找轮廓image,contours, hierarchy=cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)print('轮廓个数:',len(contours))i=0res=img.copy()for con in contours:    #轮廓转换为矩形    rect=cv2.minAreaRect(con)    #矩形转换为box    box=np.int0(cv2.boxPoints(rect))    #在原图画出目标区域    cv2.drawContours(res,[box],-1,(0,0,255),2)    print([box])    #计算矩形的行列    h1=max([box][0][0][1],[box][0][1][1],[box][0][2][1],[box][0][3][1])    h2=min([box][0][0][1],[box][0][1][1],[box][0][2][1],[box][0][3][1])    l1=max([box][0][0][0],[box][0][1][0],[box][0][2][0],[box][0][3][0])    l2=min([box][0][0][0],[box][0][1][0],[box][0][2][0],[box][0][3][0])    print('h1',h1)    print('h2',h2)    print('l1',l1)    print('l2',l2)    #加上防错处理,确保裁剪区域无异常    if h1-h2>0 and l1-l2>0:        #裁剪矩形区域        temp=img[h2:h1,l2:l1]        i=i+1        #显示裁剪后的标志        cv2.imshow('sign'+str(i),temp)#显示画了标志的原图       cv2.imshow('res',res)cv2.waitKey(0)cv2.destroyAllWindows()

这里写图片描述

总结

完整代码

import cv2import numpy as np#加载原图img=cv2.imread('jd.jpg')print('img:',type(img),img.shape,img.dtype)cv2.imshow('img',img)hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)cv2.imshow('hsv',hsv)#提取蓝色区域blue_lower=np.array([100,50,50])blue_upper=np.array([124,255,255])mask=cv2.inRange(hsv,blue_lower,blue_upper)print('mask',type(mask),mask.shape)cv2.imshow('mask',mask)#模糊blurred=cv2.blur(mask,(9,9))cv2.imshow('blurred',blurred)#二值化ret,binary=cv2.threshold(blurred,127,255,cv2.THRESH_BINARY)cv2.imshow('blurred binary',binary)#使区域闭合无空隙kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)cv2.imshow('closed',closed)#腐蚀和膨胀'''腐蚀操作将会腐蚀图像中白色像素,以此来消除小斑点,而膨胀操作将使剩余的白色像素扩张并重新增长回去。'''erode=cv2.erode(closed,None,iterations=4)cv2.imshow('erode',erode)dilate=cv2.dilate(erode,None,iterations=4)cv2.imshow('dilate',dilate)# 查找轮廓image,contours, hierarchy=cv2.findContours(dilate.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)print('轮廓个数:',len(contours))i=0res=img.copy()for con in contours:    #轮廓转换为矩形    rect=cv2.minAreaRect(con)    #矩形转换为box    box=np.int0(cv2.boxPoints(rect))    #在原图画出目标区域    cv2.drawContours(res,[box],-1,(0,0,255),2)    print([box])    #计算矩形的行列    h1=max([box][0][0][1],[box][0][1][1],[box][0][2][1],[box][0][3][1])    h2=min([box][0][0][1],[box][0][1][1],[box][0][2][1],[box][0][3][1])    l1=max([box][0][0][0],[box][0][1][0],[box][0][2][0],[box][0][3][0])    l2=min([box][0][0][0],[box][0][1][0],[box][0][2][0],[box][0][3][0])    print('h1',h1)    print('h2',h2)    print('l1',l1)    print('l2',l2)    #加上防错处理,确保裁剪区域无异常    if h1-h2>0 and l1-l2>0:        #裁剪矩形区域        temp=img[h2:h1,l2:l1]        i=i+1        #显示裁剪后的标志        cv2.imshow('sign'+str(i),temp)#显示画了标志的原图       cv2.imshow('res',res)cv2.waitKey(0)cv2.destroyAllWindows()

其他场景检测效果图
这里写图片描述

在复杂场景下,经过优化处理仍然会存在干扰区域,可以在查找轮廓和裁剪区域时候进行选择性裁剪,比如首先对区域进行面积周长比等判断是否为 所想要裁剪的区域,个人认为在交通标志检测中用长宽比进行过滤比较简单高效,因为常见的标志基本形状为正三角形,圆,正方形。在轮廓进行矩形处理之后所得到的区域都会是正方形(即正三角形,圆的外接矩形都是正方形)。所以裁剪时候,长宽比接近1的保留,差距太大的直接丢弃。
仅个人想法,欢迎交流,以上。

原创粉丝点击