License plate number detection using Opencv in python - 2018.10.24

Initial Study Python.Opencv, want to use it as an example to solve license number detection.

License plate number detection needs to be divided into four parts: 1. Vehicle image acquisition, 2. License plate positioning, 3. License plate character segmentation and 4. License plate character recognition

Baidu found part of license plate recognition license plate positioning and license plate character segmentation, first introduced the license plate positioning part

License plate positioning requires several open and close operations after image binarization into black and white and backward canny edge detection to eliminate small areas, preserve large areas, and then use cv2.rectangle to select rectangular box to locate the license plate position

What you need to prepare before splitting the license plate characters is to keep only the part of the license plate and turn all other parts into a black background.Here I use the cv2.grabCut method to split the image into foreground and background.After the segmentation is completed, the characters can be divided after binarization to black and white.Since there are only black and white pixels in the image, we need to split the characters by the white and black pixels in the image.That is, the characters are located by determining the position of the black and white pixel values in each row and column.Detailed Procedures Attached

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 23 20:46:45 2018

@author: Administrator
"""

import cv2
import numpy as np


def stretch(img):
    '''
    //Image Stretch Function
    '''
    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):
    '''
    //Binarization Processing Function
    '''
    maxi=float(img.max())
    mini=float(img.min())
    
    x=maxi-((maxi-mini)/2)
    #Binarization,Return threshold ret  And image after binarization thresh
    ret,thresh=cv2.threshold(img,x,255,cv2.THRESH_BINARY)
    #Return a binary black and white image
    return thresh

def find_rectangle(contour):
    '''
    //Find a rectangular outline
    '''
    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):
    '''
    //Locate license plate number
    '''
    img,contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    
    #Find the three largest areas
    block=[]
    for c in contours:
        #Find the top left and bottom right points of the outline and calculate its area-to-length ratio
        r=find_rectangle(c)
        a=(r[2]-r[0])*(r[3]-r[1])   #The measure of area
        s=(r[2]-r[0])*(r[3]-r[1])   #aspect ratio
        
        block.append([r,a,s])
    #Select the three largest areas
    block=sorted(block,key=lambda b: b[1])[-3:]
    
    #Identify the most license plate-like area using color recognition
    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 turn HSV
        hsv=cv2.cvtColor(b,cv2.COLOR_BGR2HSV)
        #Range of blue license plate
        lower=np.array([100,50,50])
        upper=np.array([140,255,255])
        #Building masks based on thresholds
        mask=cv2.inRange(hsv,lower,upper)
        #Statistical Weights
        w1=0
        for m in mask:
            w1+=m/255
        
        w2=0
        for n in w1:
            w2+=n
            
        #Select the area with the maximum weight
        if w2>maxweight:
            maxindex=i
            maxweight=w2
            
    return block[maxindex][0]

def find_license(img):
    '''
    //Preprocessing Function
    '''
    m=400*img.shape[0]/img.shape[1]
    
    #Compressed Image
    img=cv2.resize(img,(400,int(m)),interpolation=cv2.INTER_CUBIC)
    
    #BGR Convert to Grayscale Image
    gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    
    #Gray stretch
    stretchedimg=stretch(gray_img)
    
    '''Open operation to remove noise'''
    r=16
    h=w=r*2+1
    kernel=np.zeros((h,w),np.uint8)
    cv2.circle(kernel,(r,r),r,1,-1)
    #Open operation
    openingimg=cv2.morphologyEx(stretchedimg,cv2.MORPH_OPEN,kernel)
    #Get the difference map and make the difference between the two images  cv2.absdiff('Image 1','Image 2')
    strtimg=cv2.absdiff(stretchedimg,openingimg)
    
    #image binaryzation
    binaryimg=dobinaryzation(strtimg)
    
    #canny edge detection
    canny=cv2.Canny(binaryimg,binaryimg.shape[0],binaryimg.shape[1])
    
    '''Eliminate small areas and retain large areas to locate license plates'''
    #Make Closed Operations
    kernel=np.ones((5,19),np.uint8)
    closingimg=cv2.morphologyEx(canny,cv2.MORPH_CLOSE,kernel)
    
    #Perform open operations
    openingimg=cv2.morphologyEx(closingimg,cv2.MORPH_OPEN,kernel)
    
    #Open again
    kernel=np.ones((11,5),np.uint8)
    openingimg=cv2.morphologyEx(openingimg,cv2.MORPH_OPEN,kernel)
    
    #Eliminate small areas and locate license plate locations
    rect=locate_license(openingimg,img)
    
    return rect,img

def cut_license(afterimg,rect):
    '''
    //Image Segmentation Function
    '''
    #Convert to width and height
    rect[2]=rect[2]-rect[0]
    rect[3]=rect[3]-rect[1]
    rect_copy=tuple(rect.copy())
    rect=[0,0,0,0]
    #Create Mask
    mask=np.zeros(afterimg.shape[:2],np.uint8)
    #Create background model size can only be 13*5,Rows can only be 1, single channel floating point
    bgdModel=np.zeros((1,65),np.float64)
    #Create a foreground model
    fgdModel=np.zeros((1,65),np.float64)
    #split image
    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):
    '''
    //Binarization of License Plate Picture
    '''
    #License plate changes to grayscale image
    gray_img=cv2.cvtColor(licenseimg,cv2.COLOR_BGR2GRAY)
    
    #Mean filter for noise removal
    kernel=np.ones((3,3),np.float32)/9
    gray_img=cv2.filter2D(gray_img,-1,kernel)
    
    #Binary Processing
    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('../image/carnumber7.jpg',cv2.IMREAD_COLOR)
    #Preprocessing image
    rect,afterimg=find_license(img)
    
    #Frame out the license plate number
    cv2.rectangle(afterimg,(rect[0],rect[1]),(rect[2],rect[3]),(0,255,0),2)
    cv2.imshow('afterimg',afterimg)
    
    #Split license plate from background
    cutimg=cut_license(afterimg,rect)
    cv2.imshow('cutimg',cutimg)
      
    #Binarization to generate black and white maps
    thresh=deal_license(cutimg)
    cv2.imshow('thresh',thresh)
    cv2.waitKey(0)
    
    #Split Character
    '''
    //Judging background color and font color
    '''
    #Record the sum of black and white pixels
    white=[]
    black=[]
    height=thresh.shape[0]  #263
    width=thresh.shape[1]   #400
    #print('height',height)
    #print('width',width)
    white_max=0
    black_max=0
    #Calculate the sum of black and white pixels for each column
    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 by true Represents white on black, False Black on White
    arg=True
    if black_max<white_max:
        arg=False
    
    n=1
    start=1
    end=2
    while n<width-2:
        n+=1
        #Determine whether black on white or white on black 0.05 Parameter corresponds to 0 above.95 Adjustable
        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]
                cv2.imshow('cutlicense',cj)
                cv2.waitKey(0)
    
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    

The final result diagram is for reference

This is a good picture, but some pictures are still poorly recognized. I hope you can make the following improvements. However, since you are currently in the beginners'state, you should not delve into it, and wait until you learn more, then go back and solve the problems that you can't solve at present.The source code of the God on the Internet is attached below for your reference.

 

 https://blog.csdn.net/m0_38024433/article/details/78650024

 https://blog.csdn.net/sumkee911/article/details/79435983

 

 2018.10.24

Tags: Python OpenCV Lambda

Posted on Fri, 29 May 2020 16:59:36 -0700 by flhtc