영상처리_자동차 번호판 인식-실습

메카 2017-04-06 (목) 23:10 1년전 5323  

6.2 자동차 번호판 인식

  이제 실제적인 자동차 번호판 인식을 해보자. 자동번호판 인식은 크게 두 가지로 나눌 수 있다. 하나는 입력 영상으로부터 자동차 번호판을 찾는 것이고, 다른 하나는 번호판에서 문자 혹은 숫자를 인식하는 것이다. 자동차 번호판의 숫자와 문자를 인식하기 위해 KNN 방법을 사용하였다사용된 프로그램 중 가장 중요한 "main.py"의 내용은 아래와 같다.

 

■ KNN training을 사용하기위해 아래 절차를 수행 - loadKNNDataAndTrainKNN()

          Read in Training classifications "classifications.txt"

          Read in Training images "falttened_images.txt"

          Reshape "classifications.txt" -> array to 1D

          K 상수 결정 -> 여기서는 1

          kNearest.train()함수 실행

 

    먼저 KNN(K Nearest Neighbors) 알고리즘을 수행한다. 이것은 패턴인식에서 사용되는 k-최근접 이웃 알고리즘이다. 즉 어떤 특정 공간 내에 k개의 가장 가까운 훈련 데이터로 구성되어 있는 것을 의미한다. 이것은 학습 데이터 중 가장 유사한 k개의 데이터를 이용해서 값을 예측하는 방법이다. 특징은 training데이터를 classify 단계에서 바로쓰기 때문에 별다른 training 단계가 필요 없다.

 

 입력 영상 불러오기 - imread()

 

 입력 영상 내의 번호판을 검출 - detectPlatesInScene()

        전처리-preProcessing()

        컬러 영상을 그레이 영상으로 - extractValue()

        영상 필터링, 형태학적 변환 - maximizeContrast()

           GaussianBlur - 5x5, GaussianBlur()

           Threshold값 결정 - adaptiveThreshold()

        글자 가능 후보 추출 및 저장 - findPossibleCharsInScene()

        주어진 글자 후보 가운데서 매칭 하기위한 글자 그룹 생성

        매칭 문자의 각 그룹은 번호판으로써 인지될 것이다.  - findListOfListMatchingChars()

        번호판가능 영역 추출 - extractPlate()

 검출된 번호판에서 문자 검출 - detectCharsInPlates()

        번호판 가는 영역에 대한 전처리 수행 - preprocessing()

        번호판 확대 - resize()

        그레이 영역을 밝게하기위해 다시 임계값 적용 - threshold()

        주어진 모든 가능한 문자 목록이 주어지고

        번호판 내에 있는 매칭 문자들의 그룹 찾기 - findListofMatchingChars()

        매칭 문자들을 정렬(->) 및 중첩된 문자 제거 sort(), removeInnerOverlappingChar()

           potential 매칭 문자열 가운데서 가장 긴 것을 선택 listOfListOfMatchingCharInPlate()

        번호판 내에 있는 문자인식 - recognizeCharsInPlate()

 

 가장 잘 매칭된 번호판을 선택

 

 번호판 문자를 영상에 그리기 - writelicensePlateCharOnImage()

 

수행한 소스 코드와 결과 영상은 아래와 같다. 소스 프로그램이 절대적인 것은 아님.

 # Main.py

 

import cv2

import numpy as np

import os

 

import DetectChars

import DetectPlates

import PossiblePlate

 

# module level variables ########

SCALAR_BLACK = (0.0, 0.0, 0.0)

SCALAR_WHITE = (255.0, 255.0, 255.0)

SCALAR_YELLOW = (0.0, 255.0, 255.0)

SCALAR_GREEN = (0.0, 255.0, 0.0)

SCALAR_RED = (0.0, 0.0, 255.0)

 

showSteps = False

###############

def main():

 

blnKNNTrainingSuccessful = DetectChars.loadKNNDataAndTrainKNN()

# attempt KNN training

if blnKNNTrainingSuccessful == False:

# if KNN training was not successful

print "\nerror: KNN traning was not successful\n"

# show error message

return # and exit program

# end if

 

imgOriginalScene = cv2.imread("1.png") # open image

 

if imgOriginalScene is None: # if image was not read successfully

print "\nerror: image not read from file \n\n"

# print error message to std out

os.system("pause")

# pause so user can see error message

return # and exit program

# end if

 

listOfPossiblePlates = DetectPlates.detectPlatesInScene(imgOriginalScene) # detect plates

 

listOfPossiblePlates = DetectChars.detectCharsInPlates(listOfPossiblePlates) # detect chars in plates

 

cv2.imshow("imgOriginalScene", imgOriginalScene) # show scene image

 

if len(listOfPossiblePlates) == 0: # if no plates were found

print "\nno license plates were detected\n"

# inform user no plates were found

else:

listOfPossiblePlates.sort(key = lambda possiblePlate: len(possiblePlate.strChars), reverse = True)

 

licPlate = listOfPossiblePlates[0]

 

cv2.imshow("imgPlate", licPlate.imgPlate)

# show crop of plate and threshold of plate

cv2.imshow("imgThresh", licPlate.imgThresh)

 

if len(licPlate.strChars) == 0:

print "\nno characters were detected\n\n" # show message

return # and exit program

# end if

drawRedRectangleAroundPlate(imgOriginalScene, licPlate)

# draw red rectangle around plate

 

print "\nlicense plate read from image = " + licPlate.strChars + "\n" # write license plate text to std out

print "----------------------------------------"

 

writeLicensePlateCharsOnImage(imgOriginalScene, licPlate)

# write license plate text on the image

cv2.imshow("imgOriginalScene", imgOriginalScene)

# re-show scene image

cv2.imwrite("imgOriginalScene.png", imgOriginalScene)

# write image out to file

 

# end if else

 

cv2.waitKey(0) # hold windows open until user presses a key

return

# end main

 

##################################################################

def drawRedRectangleAroundPlate(imgOriginalScene, licPlate):

 

p2fRectPoints = cv2.boxPoints(licPlate.rrLocationOfPlateInScene)

# get 4 vertices of rotated rect

# draw 4 red lines

cv2.line(imgOriginalScene, tuple(p2fRectPoints[0]), tuple(p2fRectPoints[1]), SCALAR_RED, 2)

cv2.line(imgOriginalScene, tuple(p2fRectPoints[1]), tuple(p2fRectPoints[2]), SCALAR_RED, 2)

cv2.line(imgOriginalScene, tuple(p2fRectPoints[2]), tuple(p2fRectPoints[3]), SCALAR_RED, 2)

cv2.line(imgOriginalScene, tuple(p2fRectPoints[3]), tuple(p2fRectPoints[0]), SCALAR_RED, 2)

# end function

 

##################################################################

def writeLicensePlateCharsOnImage(imgOriginalScene, licPlate):

ptCenterOfTextAreaX = 0

# this will be the center of the area the text will be written to

ptCenterOfTextAreaY = 0

ptLowerLeftTextOriginX = 0

# this will be the bottom left of the area that the text will be written to

ptLowerLeftTextOriginY = 0

 

sceneHeight, sceneWidth, sceneNumChannels = imgOriginalScene.shape

plateHeight, plateWidth, plateNumChannels = licPlate.imgPlate.shape

 

intFontFace = cv2.FONT_HERSHEY_SIMPLEX

# choose a plain jane font

fltFontScale = float(plateHeight) / 30.0

# base font scale on height of plate area

intFontThickness = int(round(fltFontScale * 1.5))

# base font thickness on font scale

textSize, baseline = cv2.getTextSize(licPlate.strChars, intFontFace, fltFontScale, intFontThickness) # call getTextSize

# unpack roatated rect into center point, width and height, and angle

((intPlateCenterX, intPlateCenterY), (intPlateWidth, intPlateHeight), fltCorrectionAngleInDeg ) = licPlate.rrLocationOfPlateInScene

 

intPlateCenterX = int(intPlateCenterX) # make sure center is an integer

intPlateCenterY = int(intPlateCenterY)

 

ptCenterOfTextAreaX = int(intPlateCenterX)

# the horizontal location of the text area is the same as the plate

 

if intPlateCenterY < (sceneHeight * 0.75):

# if the license plate is in the upper 3/4 of the image

ptCenterOfTextAreaY = int(round(intPlateCenterY)) + int(round(plateHeight * 1.6))

# write the chars in below the plate

else:

# else if the license plate is in the lower 1/4 of the image

ptCenterOfTextAreaY = int(round(intPlateCenterY)) -

int(round(plateHeight * 1.6))

# write the chars in above the plate

# end if

textSizeWidth, textSizeHeight = textSize

# unpack text size width and height

 

ptLowerLeftTextOriginX = int(ptCenterOfTextAreaX - (textSizeWidth / 2)) # calculate the lower left origin of the text area

ptLowerLeftTextOriginY = int(ptCenterOfTextAreaY + (textSizeHeight / 2)) # based on the text area center, width, and height

 

# write the text on the image

cv2.putText(imgOriginalScene, licPlate.strChars, (ptLowerLeftTextOriginX, ptLowerLeftTextOriginY), intFontFace, fltFontScale, SCALAR_YELLOW, intFontThickness)

# end function

 

##################################################################

if __name__ == "__main__":

main()

 

576ec4c57aeccb922e1e2767aa87562d_1491487
                             (a)

             576ec4c57aeccb922e1e2767aa87562d_1491487
                             (b)

   576ec4c57aeccb922e1e2767aa87562d_1491487
                             (c)

576ec4c57aeccb922e1e2767aa87562d_1491487 

                             (d) 

 

 [그림 6-1] 자동차 번호판 인식 소스코드 및 결과 영상. (a) 원영상, (b) 원영상으로부터 번호판 부분만 잘라낸 결과(13개의 possible plates를 찾았음), (c) possible plate내에 문자가 있는지를 검사한 후 유효 번호판에 대해 번호판 확대 및 이진화 영상, (d) 인식된 번호판을 원영상에 쓴 결과 영상. 

 

 나머지 파일은 첨부파일을 참조하면 되며, 원 영상을 다운 받아서 사용하면 됩니다.

 


csh 2017-05-22 (월) 15:47 1년전
* 비밀글 입니다.
주소
쭈리 2018-08-06 (월) 19:54 3개월전
* 비밀글 입니다.
주소
모바일 버전으로 보기