交通标志检测(OpenCV&Python)

简述

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

颜色过滤

加载图像

import cv2
import 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=0
res=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 cv2
import 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=0
res=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的保留,差距太大的直接丢弃。
仅个人想法,欢迎交流,以上。

  • 46
    点赞
  • 367
    收藏
    觉得还不错? 一键收藏
  • 51
    评论
评论 51
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值