opencv 图像匹配python
OpenCV+Python识别车牌和字符分割的实现本篇文章主要基于python语言和opencv库(cv2)进行车牌区域识别和字符分割,开篇之前针对在python中安装opencv的环境这里不做介绍,可以自行安装配置!
车牌号检测需要大致分为四个部分:
1.车辆图像获取
2.车牌定位、
3.车牌字符分割
4.车牌字符识别
具体介绍
车牌定位需要用到的是图片二值化为黑白后进canny边缘检测后多次进行开运算与闭运算用于消除小块的区域,保留大块的区域,后用cv2.rectangle选取矩形框,从而定位车牌位置
车牌字符的分割前需要准备的是只保留车牌部分,将其他部分均变为黑色背景。这里我采用cv2.grabcut方法,可将图像分割成前景与背景。分割完成后,再经过二值化为黑白图后即可进行字符分割。由于图像中只有黑色和白色像素,因此我们需要通过图像的白色像素和黑色像素来分割开字符。即分别通过判断每一行每一列的黑色白色像素值的位置,来定位出字符。
具体步骤如下:
1.灰度转换:将彩色图片转换为灰度图像,常见的r=g=b=像素平均值。
2.高斯平滑和中值滤波:去除噪声。
3.sobel算子:提取图像边缘轮廓,x方向和y方向平方和开跟。
4.二值化处理:图像转换为黑白两色,通常像素大于127设置为255,小于设置为0。
5.膨胀和细化:放大图像轮廓,转换为一个个区域,这些区域内包含车牌。
6.通过算法选择合适的车牌位置,通常将较小的区域过滤掉或寻找蓝色底的区域。
7.标注车牌位置
8.图像切割和识别
通过代码实现:
|
# -*- coding: utf-8 -*- """ @email:cuiran2001@163.com @author: cuiran """ import cv2 import numpy as np from pil import image import os.path from skimage import io,data def stretch(img): ''' 图像拉伸函数 ''' maxi = float (img. max ()) mini = float (img. min ()) for i in range (img.shape[ 0 ]): for j in range (img.shape[ 1 ]): img[i,j] = ( 255 / (maxi - mini) * img[i,j] - ( 255 * mini) / (maxi - mini)) return img def dobinaryzation(img): ''' 二值化处理函数 ''' maxi = float (img. max ()) mini = float (img. min ()) x = maxi - ((maxi - mini) / 2 ) #二值化,返回阈值ret 和 二值化操作后的图像thresh ret,thresh = cv2.threshold(img,x, 255 ,cv2.thresh_binary) #返回二值化后的黑白图像 return thresh def find_rectangle(contour): ''' 寻找矩形轮廓 ''' y,x = [],[] for p in contour: y.append(p[ 0 ][ 0 ]) x.append(p[ 0 ][ 1 ]) return [ min (y), min (x), max (y), max (x)] def locate_license(img,afterimg): ''' 定位车牌号 ''' img,contours,hierarchy = cv2.findcontours(img,cv2.retr_external,cv2.chain_approx_simple) #找出最大的三个区域 block = [] for c in contours: #找出轮廓的左上点和右下点,由此计算它的面积和长度比 r = find_rectangle(c) a = (r[ 2 ] - r[ 0 ]) * (r[ 3 ] - r[ 1 ]) #面积 s = (r[ 2 ] - r[ 0 ]) * (r[ 3 ] - r[ 1 ]) #长度比 block.append([r,a,s]) #选出面积最大的3个区域 block = sorted (block,key = lambda b: b[ 1 ])[ - 3 :] #使用颜色识别判断找出最像车牌的区域 maxweight,maxindex = 0 , - 1 for i in range ( len (block)): b = afterimg[block[i][ 0 ][ 1 ]:block[i][ 0 ][ 3 ],block[i][ 0 ][ 0 ]:block[i][ 0 ][ 2 ]] #bgr转hsv hsv = cv2.cvtcolor(b,cv2.color_bgr2hsv) #蓝色车牌的范围 lower = np.array([ 100 , 50 , 50 ]) upper = np.array([ 140 , 255 , 255 ]) #根据阈值构建掩膜 mask = cv2.inrange(hsv,lower,upper) #统计权值 w1 = 0 for m in mask: w1 + = m / 255 w2 = 0 for n in w1: w2 + = n #选出最大权值的区域 if w2>maxweight: maxindex = i maxweight = w2 return block[maxindex][ 0 ] def find_license(img): ''' 预处理函数 ''' m = 400 * img.shape[ 0 ] / img.shape[ 1 ] #压缩图像 img = cv2.resize(img,( 400 , int (m)),interpolation = cv2.inter_cubic) #bgr转换为灰度图像 gray_img = cv2.cvtcolor(img,cv2.color_bgr2gray) #灰度拉伸 stretchedimg = stretch(gray_img) '''进行开运算,用来去除噪声''' r = 16 h = w = r * 2 + 1 kernel = np.zeros((h,w),np.uint8) cv2.circle(kernel,(r,r),r, 1 , - 1 ) #开运算 openingimg = cv2.morphologyex(stretchedimg,cv2.morph_open,kernel) #获取差分图,两幅图像做差 cv2.absdiff('图像1','图像2') strtimg = cv2.absdiff(stretchedimg,openingimg) #图像二值化 binaryimg = dobinaryzation(strtimg) #canny边缘检测 canny = cv2.canny(binaryimg,binaryimg.shape[ 0 ],binaryimg.shape[ 1 ]) '''消除小的区域,保留大块的区域,从而定位车牌''' #进行闭运算 kernel = np.ones(( 5 , 19 ),np.uint8) closingimg = cv2.morphologyex(canny,cv2.morph_close,kernel) #进行开运算 openingimg = cv2.morphologyex(closingimg,cv2.morph_open,kernel) #再次进行开运算 kernel = np.ones(( 11 , 5 ),np.uint8) openingimg = cv2.morphologyex(openingimg,cv2.morph_open,kernel) #消除小区域,定位车牌位置 rect = locate_license(openingimg,img) return rect,img def cut_license(afterimg,rect): ''' 图像分割函数 ''' #转换为宽度和高度 rect[ 2 ] = rect[ 2 ] - rect[ 0 ] rect[ 3 ] = rect[ 3 ] - rect[ 1 ] rect_copy = tuple (rect.copy()) rect = [ 0 , 0 , 0 , 0 ] #创建掩膜 mask = np.zeros(afterimg.shape[: 2 ],np.uint8) #创建背景模型 大小只能为13*5,行数只能为1,单通道浮点型 bgdmodel = np.zeros(( 1 , 65 ),np.float64) #创建前景模型 fgdmodel = np.zeros(( 1 , 65 ),np.float64) #分割图像 cv2.grabcut(afterimg,mask,rect_copy,bgdmodel,fgdmodel, 5 ,cv2.gc_init_with_rect) mask2 = np.where((mask = = 2 )|(mask = = 0 ), 0 , 1 ).astype( 'uint8' ) img_show = afterimg * mask2[:,:,np.newaxis] return img_show def deal_license(licenseimg): ''' 车牌图片二值化 ''' #车牌变为灰度图像 gray_img = cv2.cvtcolor(licenseimg,cv2.color_bgr2gray) #均值滤波 去除噪声 kernel = np.ones(( 3 , 3 ),np.float32) / 9 gray_img = cv2.filter2d(gray_img, - 1 ,kernel) #二值化处理 ret,thresh = cv2.threshold(gray_img, 120 , 255 ,cv2.thresh_binary) return thresh def find_end(start,arg,black,white,width,black_max,white_max): end = start + 1 for m in range (start + 1 ,width - 1 ): if (black[m] if arg else white[m])>( 0.98 * black_max if arg else 0.98 * white_max): end = m break return end if __name__ = = '__main__' : img = cv2.imread( 'test_images/car001.jpg" alt="opencv 图像匹配python(OpenCV+Python识别车牌和字符分割的实现)" border="0" /> #预处理图像 rect,afterimg = find_license(img) #框出车牌号 cv2.rectangle(afterimg,(rect[ 0 ],rect[ 1 ]),(rect[ 2 ],rect[ 3 ]),( 0 , 255 , 0 ), 2 ) cv2.imshow( 'afterimg' ,afterimg) #分割车牌与背景 cutimg = cut_license(afterimg,rect) cv2.imshow( 'cutimg' ,cutimg) #二值化生成黑白图 thresh = deal_license(cutimg) cv2.imshow( 'thresh' ,thresh) cv2.waitkey( 0 ) #分割字符 ''' 判断底色和字色 ''' #记录黑白像素总和 white = [] black = [] height = thresh.shape[ 0 ] #263 width = thresh.shape[ 1 ] #400 #print('height',height) #print('width',width) white_max = 0 black_max = 0 #计算每一列的黑白像素总和 for i in range (width): line_white = 0 line_black = 0 for j in range (height): if thresh[j][i] = = 255 : line_white + = 1 if thresh[j][i] = = 0 : line_black + = 1 white_max = max (white_max,line_white) black_max = max (black_max,line_black) white.append(line_white) black.append(line_black) print ( 'white' ,white) print ( 'black' ,black) #arg为true表示黑底白字,false为白底黑字 arg = true if black_max<white_max: arg = false n = 1 start = 1 end = 2 s_width = 28 s_height = 28 while n<width - 2 : n + = 1 #判断是白底黑字还是黑底白字 0.05参数对应上面的0.95 可作调整 if (white[n] if arg else black[n])>( 0.02 * white_max if arg else 0.02 * black_max): start = n end = find_end(start,arg,black,white,width,black_max,white_max) n = end if end - start> 5 : cj = thresh[ 1 :height,start:end] # new_image = cj.resize((s_width,s_height),image.bilinear) # cj=cj.reshape(28, 28) print ( "result/%s.jpg" alt="opencv 图像匹配python(OpenCV+Python识别车牌和字符分割的实现)" border="0" /> #保存分割的图片 by cayden # cj.save("result/%s.jpg" alt="opencv 图像匹配python(OpenCV+Python识别车牌和字符分割的实现)" border="0" /> infile = "result/%s.jpg" alt="opencv 图像匹配python(OpenCV+Python识别车牌和字符分割的实现)" border="0" /> io.imsave(infile,cj) # im = image.open(infile) # out=im.resize((s_width,s_height),image.bilinear) # out.save(infile) cv2.imshow( 'cutlicense' ,cj) cv2.waitkey( 0 ) cv2.waitkey( 0 ) cv2.destroyallwindows() |
运行效果如图所示
车牌定位并进行处理
车牌分割如图所示
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持开心学习网。
原文链接:https://blog.csdn.net/cuiran/article/details/86706441