당신은 주제를 찾고 있습니까 “opencv 번호판 인식 c++ – 자동차 번호판 인식기 – Python, 이미지 프로세싱“? 다음 카테고리의 웹사이트 you.tfvp.org 에서 귀하의 모든 질문에 답변해 드립니다: you.tfvp.org/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 빵형의 개발도상국 이(가) 작성한 기사에는 조회수 72,361회 및 좋아요 1,251개 개의 좋아요가 있습니다.
opencv 번호판 인식 c++ 주제에 대한 동영상 보기
여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!
d여기에서 자동차 번호판 인식기 – Python, 이미지 프로세싱 – opencv 번호판 인식 c++ 주제에 대한 세부정보를 참조하세요
실전 이미지 프로세싱 기술을 이용하여 자동차의 번호판을 인식해봅시다!
Source code(Github): https://github.com/kairess/license_plate_recognition
Dependencies:
– Python
– numpy
– pytesseract
– OpenCV
– matplotlib
tesseract: https://github.com/tesseract-ocr/tesseract
kore.traindata: https://github.com/tesseract-ocr/tessdata/blob/master/kor.traineddata
사업 및 개발문의: [email protected]
빵형의 개발도상국 후원: https://toon.at/donate/helloworld
opencv 번호판 인식 c++ 주제에 대한 자세한 내용은 여기를 참조하세요.
OpenCV 자동차 번호판 인식 – velog
자동차 번호판 인식 with OpenCV 1. … pytesseract : 글자 인식 (사진에서 번호판 숫자 추출) … THRESH_BINARY_INV, blockSize=19, C=9 ) …
Source: velog.io
Date Published: 1/17/2022
View: 7160
[C/C++] OpenCV 라이브러리로, 윤곽에 기반한 자동차 번호판 …
사진마다 이 수의 차이로 인해 잘 인식하던 번호판 영역이 나타나지 않을 수 있습니다. 15개의 자동차 이미지 중 10개가 잘 처리되고 5개가 그렇지 …
Source: mind3002.blogspot.com
Date Published: 10/23/2022
View: 285
[C++] 5장. SVM 및 신경망 을 사용한 번호판 인식 – 네이버 블로그
Mastering OpenCV with Practical Computer Vision Projects 라는 책의 5장 내용입니다. 이 장에서는 Automatic Number Plate Recognition (ANPR)을 …
Source: m.blog.naver.com
Date Published: 8/30/2022
View: 5360
차량번호 인식 Source 모음
http://mind3002.blogspot.kr/2016/01/cc-opencv-license-plates-recognition.html C/C++ OpenCV 라이브러리로, 윤곽에 기반한 자동차 번호판 영역 …
Source: creativeprm.tistory.com
Date Published: 9/26/2021
View: 4758
OpenCV 자동차 번호판 문자열 인식 – 다음블로그
OpenCV를 사용하여 자동차 번호판 인식을 위한 예제코드를 살펴보자, 자동차 번호판 … ‘C:/Users/Ysc/AppData/Local/Tesseract-OCR/tesseract.exe’
Source: blog.daum.net
Date Published: 11/9/2021
View: 7155
[C#] 자동차 번호판 인식 프로그램 with Tesseract-OCR …
안녕하세요 열코입니다! OpenCV로 영상처리 및 패턴인식을 공부하는 동안 가장 기본적인 자동차 번호판 인식 프로그램을 간단하게 제작해 보았습니다.
Source: yeolco.tistory.com
Date Published: 1/11/2022
View: 6453
[OpenCV] 영상처리를 이용한 숫자인식 프로젝트
아직 자동차 번호판을 곧바로 인식하기엔 어려움이 있기 때문에 자동차 번호판의 숫자 글꼴을 인식하는 프로젝트로 진행하였습니다. 딥러닝을 이용해 …
Source: ultrakid.tistory.com
Date Published: 5/20/2022
View: 1901
주제와 관련된 이미지 opencv 번호판 인식 c++
주제와 관련된 더 많은 사진을 참조하십시오 자동차 번호판 인식기 – Python, 이미지 프로세싱. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.
주제에 대한 기사 평가 opencv 번호판 인식 c++
- Author: 빵형의 개발도상국
- Views: 조회수 72,361회
- Likes: 좋아요 1,251개
- Date Published: 2018. 12. 16.
- Video Url link: https://www.youtube.com/watch?v=PpTl7xxGXh4
OpenCV 자동차 번호판 인식
자동차 번호판 인식 with OpenCV
1. 라이브러리 호출
import cv2 import numpy as np import matplotlib . pyplot as plt import pytesseract plt . style . use ( ‘dark_background’ )
사용한 라이브러리들은 총 4가지이다.
사용 용도는 다음과 같다.
cv2 : Opencv
numpy : 복잡한 수치계산
matplotlib : 시각화
pytesseract : 글자 인식 (사진에서 번호판 숫자 추출)
2. Read Input Image
2번째 단계에서는 이미지를 불러온 후 너비, 높이, 채널의 값을 저장한다.
matplotlib을 이용해 정상적으로 불러왔는지 출력해보고 저장된 너비, 높이, 채널을 확인한다.
img_ori = cv2 . imread ( ‘car2.png’ ) height , width , channel = img_ori . shape plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( img_ori , cmap = ‘gray’ ) print ( height , width , channel )
높이가 223, 너비가 594, 채널이 3 (RGB 이므로 3)인 것을 알 수 있다.
출력을 할 때 cmap을 gray로 설정했음에도 육안으로는 원본 사진과 큰 차이를 볼 순 없었다.
3. Convert Image to Grayscale
위에서는 gray로 출력만 해보았을 뿐 실제로 변환한 것은 아니다.
3번째 단계에서는 opencv의 cvtColor 메소드를 이용해 RGB를 GRAY로 변환한다.
변환하는 방법은 2가지이다.
gray = cv2 . cvtColor ( img_ori , cv2 . COLOR_BGR2GRAY ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( gray , cmap = ‘gray’ )
hsv = cv2 . cvtColor ( img_ori , cv2 . COLOR_BGR2HSV ) gray = hsv [ : , : , 2 ] plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( gray , cmap = ‘gray’ )
위 두 코드의 동작은 완전히 동일하므로 마음에 드는 것으로 작성하면 된다.
출력 결과는 아래와 같다.
4. Adaptive Thresholding
Thresholding을 해주기 전에 가우시안 블러를 해주는 것이 번호판을 더 잘 찾게 만들어 줄 수 있다.
가우시안 블러는 사진의 노이즈를 없애는 작업이다.
가우시안 블러를 적용해야하는 이유는 아래 4-1에서 설명한다.
그럼 먼저 Thresholding을 살펴보자.
Thresholding 이란 지정한 threshold 값을 기준으로 정하고
이보다 낮은 값은 0, 높은 값은 255로 변환한다. 즉 흑과 백으로만 사진을 구성하는 것이다.
이걸 해주는 이유는 5번째 단계에서 Contours를 찾으려면 검은색 배경에 흰색 바탕이어야 한다.
또 육안으로 보기에도 객체를 더 뚜렷하게 볼 수 있다.
아래 Thresholding을 적용한 사진을 보면 이해가 쉽다.
img_blurred = cv2 . GaussianBlur ( gray , ksize = ( 5 , 5 ) , sigmaX = 0 ) img_blur_thresh = cv2 . adaptiveThreshold ( img_blurred , maxValue = 255.0 , adaptiveMethod = cv2 . ADAPTIVE_THRESH_GAUSSIAN_C , thresholdType = cv2 . THRESH_BINARY_INV , blockSize = 19 , C = 9 )
4-1. Gaussian Blur 비적용 / 적용 비교
Thresholding 적용을 보았으니 가우시안 블러를 사용하는 이유를 알기위해
적용했을 때와 적용하지 않았을 때를 출력해본다.
img_thresh = cv2 . adaptiveThreshold ( gray , maxValue = 255.0 , adaptiveMethod = cv2 . ADAPTIVE_THRESH_GAUSSIAN_C , thresholdType = cv2 . THRESH_BINARY_INV , blockSize = 19 , C = 9 )
plt . figure ( figsize = ( 20 , 20 ) ) plt . subplot ( 1 , 2 , 1 ) plt . title ( ‘Threshold only’ ) plt . imshow ( img_thresh , cmap = ‘gray’ ) plt . subplot ( 1 , 2 , 2 ) plt . title ( ‘Blur and Threshold’ ) plt . imshow ( img_blur_thresh , cmap = ‘gray’ )
왼쪽이 가우시안 블러를 적용하지 않은 사진, 오른쪽이 적용한 사진이다.
언뜻보기엔 큰 차이를 못느낄 수 있지만 번호판 밑부분을 보면 좀 더 검은색 부분이 많아졌다.
5. Find Contours
Contours란 동일한 색 또는 동일한 강도를 가지고 있는 영역의 경계선을 연결한 선이다.
findContours()는 이런 Conturs들을 찾는 opencv 메소드이다.
위 메소드는 검은색 바탕에서 흰색 대상을 찾는다.
그래서 4번째 단계에서 Thresholding을 해주고 가우시안 블러를 적용해준 것이다.
그런데 공식문서에는 findCountours의 리턴 값으로
image, contours, hierachy 이렇게 3개가 나온다고 나와있지만
현재 첫번째 리턴 값인 image가 사라진 듯하다.
그래서 contours와 로 리턴을 받았다. hierachy는 쓸 일이 없어 로 받음
사진의 윤곽선을 모두 딴 후 opencv의 drawContours() 메소드로
원본사진이랑 크기가 같은 temp_result란 변수에 그려보았다
contours , _ = cv2 . findContours ( img_blur_thresh , mode = cv2 . RETR_LIST , method = cv2 . CHAIN_APPROX_SIMPLE ) temp_result = np . zeros ( ( height , width , channel ) , dtype = np . uint8 ) cv2 . drawContours ( temp_result , contours = contours , contourIdx = – 1 , color = ( 255 , 255 , 255 ) ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( temp_result )
Contours를 찾아서 그린 결과를 볼 수 있다.
6. Prepare Data
원본 사진과 동일한 크기에다가 찾은 Countours들의 좌표를 이용해
사각형 형태로 그려본다. 동시에 딕셔너리를 하나 만들어 contours들의 정보를 저장한다.
temp_result = np . zeros ( ( height , width , channel ) , dtype = np . uint8 ) contours_dict = [ ] for contour in contours : x , y , w , h = cv2 . boundingRect ( contour ) cv2 . rectangle ( temp_result , pt1 = ( x , y ) , pt2 = ( x + w , y + h ) , color = ( 255 , 255 , 255 ) , thickness = 2 ) contours_dict . append ( { ‘contour’ : contour , ‘x’ : x , ‘y’ : y , ‘w’ : w , ‘h’ : h , ‘cx’ : x + ( w / 2 ) , ‘cy’ : y + ( h / 2 ) } ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( temp_result , cmap = ‘gray’ )
찾은 모든 Contours들을 사격형 형태로 볼 수 있다.
이제 번호판 글자인 것 같은 Contours들을 추려내야한다.
많은 방법이 있겠지만 단순히 생각해서
번호판의 숫자들을 손글씨처럼 다 다르지 않고 일정한 비율을 가진다.
때문에 이 비율을 이용하면 대충은 번호판 같은 contours들을 추려낼 수 있다.
아래 코드에서는 최소 비율을 0.25와 최대 비율을 1.0으로 설정한 후
contours의 너비와 높이를 이용해 비율을 구하고
우리가 정한 기준에 맞는 contours들만 따로 저장하였다.
MIN_AREA = 80 MIN_WIDTH , MIN_HEIGHT = 2 , 8 MIN_RATIO , MAX_RATIO = 0.25 , 1.0 possible_contours = [ ] cnt = 0 for d in contours_dict : area = d [ ‘w’ ] * d [ ‘h’ ] ratio = d [ ‘w’ ] / d [ ‘h’ ] if area > MIN_AREA \ and d [ ‘w’ ] > MIN_WIDTH and d [ ‘h’ ] > MIN_HEIGHT \ and MIN_RATIO < ratio < MAX_RATIO : d [ 'idx' ] = cnt cnt += 1 possible_contours . append ( d ) temp_result = np . zeros ( ( height , width , channel ) , dtype = np . uint8 ) for d in possible_contours : cv2 . rectangle ( temp_result , pt1 = ( d [ 'x' ] , d [ 'y' ] ) , pt2 = ( d [ 'x' ] + d [ 'w' ] , d [ 'y' ] + d [ 'h' ] ) , color = ( 255 , 255 , 255 ) , thickness = 2 ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( temp_result , cmap = 'gray' ) 위 사진은 추려낸 contours들이다. 번호판 위치에 contours들이 선별된 걸 볼 수 있지만 전혀 관련 없는 영역의 contours들도 저장되었다. 이제 더 기준을 강화하여 번호판 글자들을 찾아야한다. 8번째 단계에서는 남은 contours 중에 확실하게 번호판을 찾기 위해 기준을 강화한다. 번호판의 특성을 고려했을 때 세울 수 있는 기준은 아래와 같다. 번호판 Contours의 width와 height의 비율은 모두 동일하거나 비슷하다. 번호판 Contours 사이의 간격은 일정하다. 최소 3개 이상 Contours가 인접해 있어야한다. (대한민국 기준) 이 특성들을 고려하여 아래와 같이 코드를 작성한다. 최종적으로 얻어야 할 것은 번호판에 대한 후보군이다. MAX_DIAG_MULTIPLYER = 5 MAX_ANGLE_DIFF = 12.0 MAX_AREA_DIFF = 0.5 MAX_WIDTH_DIFF = 0.8 MAX_HEIGHT_DIFF = 0.2 MIN_N_MATCHED = 3 def find_chars ( contour_list ) : matched_result_idx = [ ] for d1 in contour_list : matched_contours_idx = [ ] for d2 in contour_list : if d1 [ 'idx' ] == d2 [ 'idx' ] : continue dx = abs ( d1 [ 'cx' ] - d2 [ 'cx' ] ) dy = abs ( d1 [ 'cy' ] - d2 [ 'cy' ] ) diagonal_length1 = np . sqrt ( d1 [ 'w' ] ** 2 + d1 [ 'h' ] ** 2 ) distance = np . linalg . norm ( np . array ( [ d1 [ 'cx' ] , d1 [ 'cy' ] ] ) - np . array ( [ d2 [ 'cx' ] , d2 [ 'cy' ] ] ) ) if dx == 0 : angle_diff = 90 else : angle_diff = np . degrees ( np . arctan ( dy / dx ) ) area_diff = abs ( d1 [ 'w' ] * d1 [ 'h' ] - d2 [ 'w' ] * d2 [ 'h' ] ) / ( d1 [ 'w' ] * d1 [ 'h' ] ) width_diff = abs ( d1 [ 'w' ] - d2 [ 'w' ] ) / d1 [ 'w' ] height_diff = abs ( d1 [ 'h' ] - d2 [ 'h' ] ) / d1 [ 'h' ] if distance < diagonal_length1 * MAX_DIAG_MULTIPLYER \ and angle_diff < MAX_ANGLE_DIFF and area_diff < MAX_AREA_DIFF \ and width_diff < MAX_WIDTH_DIFF and height_diff < MAX_HEIGHT_DIFF : matched_contours_idx . append ( d2 [ 'idx' ] ) matched_contours_idx . append ( d1 [ 'idx' ] ) if len ( matched_contours_idx ) < MIN_N_MATCHED : continue matched_result_idx . append ( matched_contours_idx ) unmatched_contour_idx = [ ] for d4 in contour_list : if d4 [ 'idx' ] not in matched_contours_idx : unmatched_contour_idx . append ( d4 [ 'idx' ] ) unmatched_contour = np . take ( possible_contours , unmatched_contour_idx ) recursive_contour_list = find_chars ( unmatched_contour ) for idx in recursive_contour_list : matched_result_idx . append ( idx ) break return matched_result_idx result_idx = find_chars ( possible_contours ) matched_result = [ ] for idx_list in result_idx : matched_result . append ( np . take ( possible_contours , idx_list ) ) temp_result = np . zeros ( ( height , width , channel ) , dtype = np . uint8 ) for r in matched_result : for d in r : cv2 . rectangle ( temp_result , pt1 = ( d [ 'x' ] , d [ 'y' ] ) , pt2 = ( d [ 'x' ] + d [ 'w' ] , d [ 'y' ] + d [ 'h' ] ) , color = ( 255 , 255 , 255 ) , thickness = 2 ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( temp_result , cmap = 'gray' ) 출력 결과는 번호판으로 추정되는 후보군이며 원본과 비교했을 때 번호판 부분임을 확인할 수 있다. 9. Rotate Plate Images 현재 우리 사진은 자동차가 정방향에서 찍혔기 때문에 번호판이 가지런하지만 대부분의 사진에서는 번호판이 기울어진 경우가 많을 것이다. 때문에 pytesseract를 이용하여 번호판 글자를 인식하기 위해 번호판 부분을 정방향으로 만들어 줄 필요가 있다. 9번째 단계에서는 해당 작업을 수행한다. 먼저 단계에서 얻은 모든 후보군에 대해 Affine Transform을 적용한다. 이후 번호판 부분만 Crop 하여 출력한다. 코드가 길기 때문에 Github 코드 참고! 보면 2개의 후보군이 출력된 걸 볼 수 있고 모두 정방향으로 잘 보인다. 10. Another Thresholding 하지만 만약 9번째 단계에서 번호판 Contours 가 없었을 때를 대비하여 10번째 단계에서는 처음에 선별되지 못한 Contours에 대해서도 후보군을 추린다. 로직은 위에서 했던 것과 동일하다. longest_idx , longest_text = - 1 , 0 plate_chars = [ ] for i , plate_img in enumerate ( plate_imgs ) : plate_img = cv2 . resize ( plate_img , dsize = ( 0 , 0 ) , fx = 1.6 , fy = 1.6 ) _ , plate_img = cv2 . threshold ( plate_img , thresh = 0.0 , maxval = 255.0 , type = cv2 . THRESH_BINARY | cv2 . THRESH_OTSU ) contours , _ = cv2 . findContours ( plate_img , mode = cv2 . RETR_LIST , method = cv2 . CHAIN_APPROX_SIMPLE ) plate_min_x , plate_min_y = plate_img . shape [ 1 ] , plate_img . shape [ 0 ] plate_max_x , plate_max_y = 0 , 0 for contour in contours : x , y , w , h = cv2 . boundingRect ( contour ) area = w * h ratio = w / h if area > MIN_AREA \ and w > MIN_WIDTH and h > MIN_HEIGHT \ and MIN_RATIO < ratio < MAX_RATIO : if x < plate_min_x : plate_min_x = x if y < plate_min_y : plate_min_y = y if x + w > plate_max_x : plate_max_x = x + w if y + h > plate_max_y : plate_max_y = y + h img_result = plate_img [ plate_min_y : plate_max_y , plate_min_x : plate_max_x ]
11. Find Chars
이제 11번째 단계에서는 추린 후보군을 이용하여 글자를 찾는다.
pytesseract를 사용해야 하는데 몇 가지 사전 준비가 필요하다.
먼저 tesseract를 다운받는다.
공식 다운로드 사이트 : 공식 사이트에서 다운받으면 2시간 가량 소요된다;;
시간을 단축하고 싶다면 어떤 분이 분할 압축하여 올려 놓은 아래 깃에 가서 다운받자.
tesseract 분할 압축 Git tesseract를 다운받은 경로를 기억해야한다.
나는 하드디스크(D 드라이브)에 다운받았다. 오른쪽 사이트에서 trained data 데이터를 다운받는다 -> trained data 다운받은 tesseart 경로에 tessdata에 trained data를 옮겨준다. 아래 코드를 pytesseract.image_to_string() 메소드 위에 추가한다.
pytesseract.pytesseract.tesseract_cmd = ‘본인 tesseract 경로/tesseract.exe’
이렇게 하면 pytesseract를 사용할 준비를 마쳤다.
이제 아래와 같이 코드를 작성 후 실행하고 결과를 출력한다.
img_result = cv2 . GaussianBlur ( img_result , ksize = ( 3 , 3 ) , sigmaX = 0 ) _ , img_result = cv2 . threshold ( img_result , thresh = 0.0 , maxval = 255.0 , type = cv2 . THRESH_BINARY | cv2 . THRESH_OTSU ) img_result = cv2 . copyMakeBorder ( img_result , top = 10 , bottom = 10 , left = 10 , right = 10 , borderType = cv2 . BORDER_CONSTANT , value = ( 0 , 0 , 0 ) ) pytesseract . pytesseract . tesseract_cmd = ‘D:/tesseract/tesseract.exe’ chars = pytesseract . image_to_string ( img_result , lang = ‘kor’ , config = ‘–psm 7 –oem 0’ ) result_chars = ” has_digit = False for c in chars : if ord ( ‘가’ ) <= ord ( c ) <= ord ( '힣' ) or c . isdigit ( ) : if c . isdigit ( ) : has_digit = True result_chars += c print ( result_chars ) plate_chars . append ( result_chars ) if has_digit and len ( result_chars ) > longest_text : longest_idx = i plt . subplot ( len ( plate_imgs ) , 1 , i + 1 ) plt . imshow ( img_result , cmap = ‘gray’ )
2개의 후보군을 문자로 변환하였을 때 위에건 이상한 글자가 출력되었고
아래건 정확하게 출력된 걸 확인할 수 있다.
코드에서 특수문자 나오거나 이상한 문자가 나올 경우 걸러주는 코드를 작성해줬기 때문에
최종적으로는 아래의 후보가 최종 번호판으로 선정된다.
12. Result
이제 우리는 최종 번호판 좌표를 얻었으니 원본 이미지에 cv2.rectangle() 메소드를 이용해
사각형을 그린 후 출력을 하면 끝난다.
아래와 같이 코드 작성 후 출력해보자.
info = plate_infos [ longest_idx ] chars = plate_chars [ longest_idx ] print ( chars ) img_out = img_ori . copy ( ) cv2 . rectangle ( img_out , pt1 = ( info [ ‘x’ ] , info [ ‘y’ ] ) , pt2 = ( info [ ‘x’ ] + info [ ‘w’ ] , info [ ‘y’ ] + info [ ‘h’ ] ) , color = ( 255 , 0 , 0 ) , thickness = 2 ) cv2 . imwrite ( chars + ‘.jpg’ , img_out ) plt . figure ( figsize = ( 12 , 10 ) ) plt . imshow ( img_out )
번호판이 아주 잘 인식되어 텍스트로 변환되었고
주변에 rectangle도 잘 나온 것을 확인할 수 있다.
[C++] 5장. SVM 및 신경망 을 사용한 번호판 인식
Mastering OpenCV with Practical Computer Vision Projects 라는 책의 5장 내용입니다.
이 장에서는 Automatic Number Plate Recognition (ANPR)을 만드는 데 필요한 단계를 소개합니다.
예를 들어, IR 카메라, 고정 된 자동차 위치, 조명 조건 같은 기반을 이용해서 진행 할 수 있는 다양한 접근법과 기술들이 있습니다.
모호한 빛 상태, 그리고 비평 행 위치 및 자동차 번호판의 왜곡 같은 미미한 고려점을 가지고 자동차로부터 2-3 미터 사이에서 찍은 사진의 자동차 번호판을 감지 할 수 있는 ANPR 애플리케이션을 만드는 것을 진행 할 수 있습니다.
.
이 장의 주요 목적은 이미지 세분화와 피쳐 추출, 패턴 인식 기본 및 두 가지 중요한 패턴 인식 알고리즘인 벡터 머신(Support Vector Machines) 및 인공 신경망(Artificial Neural Networks )을 소개 하는 것입니다.
이 장에서 다음 부분들을 다루도록 하겠습니다 :
• ANPR
• Plate detection
• Plate recognition
ANPR 소개
자동 번호 플레이트 인식 (ANPR)은 자동 ALPR (License-Plate Recognition), AVI (자동 차량 식별) 또는 자동차 판 인식 (CPR)로 알려져 있으며, 광학 인식(Optical
Character Recognition (OCR) ) 과 문자 인식 (OCR) 및 세그먼트 화 및 차량 등록 번호판을 읽는 감지 같은 방법들을 사용합니다
ANPR 시스템의 최상의 결과는 적외선 (IR) 카메라로 얻을 수 있는데 이는, 탐지 및 OCR 세그먼트 화를 위한 세분화 단계가 쉽고 정리되어 있으며, 오류를 최소화 할 수 있기 때문입니다.
이것은 입사각은 반사각과 동일하다는 빛의 법칙에 그 이유를 찾을 수 있습니다; 우리는 평면 거울과 같은 매끄러운 표면을 보았을 때 이 기본 반사 법칙을 알 수 있습니다.
다음 그림에서도 볼 수 있듯이, 소스광원으로 되 반사 되는 빛을 일으키는 수 천개의 작은 반구로 덮여있는 물질로 만들어진 표지판의 표면으로 인해 – 번호판의 대다수는 복고반사(retro-reflection)라고 불리는 특별한 성질을 가집니다
OpenCV 자동차 번호판 문자열 인식
※파이선 코딩 초보자를 위한 텐서플로우∙OpenCV 머신 러닝 2차 개정판 발행
http://blog.daum.net/ejleep1/1175
OpenCV를 사용하여 자동차 번호판 인식을 위한 예제코드를 살펴보자, 자동차 번호판 문자열 인식을 위한 알고리듬이 많겠지만 그 중에서도 간단한 번호판의 4 코너를 찾는 알고리듬을 사용하기로 한다. 아울러 차량의 측면에서 번호판을 찍되 그 문자열의 원근이 그다지 심하지 않은 경우를 대상으로 하자.
특히 차량 속도가 빠른 도로에서 사용할 수 있기 위해서는 코드의 알고리듬이 단순하며 처리 속도가 빠를수록 유리할 것이다. 이 예제는 아래의 url 사이트 내용을 참조하였다.
License Plate Recognition using OpenCV in Python
헤더 영역에서 필요한 라이브러리는 cv2, imutils, numpy, Image 및 pytesseract 이다. 마지막의 pytesseract 는 반드시 사용자가 그 경로를 정확히 알아 지정해 주어야 한다.
이미지 파일을 읽어서 파일의 해상도를 확인 출력 후 다시 이미지의 가로 해상도 값을 500 으로 설정하자. 비전 Edge 처리를 위해서 흑백영상으로 변환하고 널은 면적에 나타나는 컬러 노이즈를 제거할 수 있도록 blurring 필터 작업을 실행한다. 3-~200 사이의 밝기가 변하는 구간을 대상으로 Canny Edge 처리한다.
아래 사진의 Canny Edge 처리 결과를 살펴보자. 특히 어둔 부분은 Edge 처리가 되지 않는다. 자동차 번호판은 차량 시동 거는 시점에서 항상 번호판 등이 켜지므로 주야에 상관 없이 밝기가 밝은 영역으로서 Canny Edge 처리가 가능하다.
번호판을 인식하기 위해서는 Canny Edge 처리된 이미지를 대상으로 Contour(폐곡선)들을 찾아서(find) 모조리 작도(draw)한다.
몇 개의 Contour 가 발견될지는 알 수 없으나 의외로 그 수는 많다. 그 중에서 경험적으로 면적 기준으로 큰 순서대로 30개를 작도하도록 한다. 물론 번호판도 포함되어 있어야 한다.
30개의 Contour를 대상으로 정확하게 4개의 코너를 가지는 Edge Contoure를 찾는 간결한 알고리듬이다.
찾아낸 사각형 Contour를 Crop 작업에 의해서 잘라내고 마지막으로 Tesseract-OCR 라이브러리를 사용하여 문자열을 추출한다.
자동차 번호판 문자열 추출 작업에서 차량 번호판을 카메라로 찍는 각도에 따라 번호판 문자열에 원근감이 생길 수도 있는데 이런 경우에는 Tesseract 루틴으로 문자열 추출이 불가능하다는 점에 유의하자.
#Canny_car_plate_01.py
import imutils
import cv2
import numpy as np
import pytesseract
from PIL import Image
pytesseract.pytesseract.tesseract_cmd = ‘C:/Users/Ysc/AppData/Local/Tesseract-OCR/tesseract.exe’
image = cv2.imread(“carplate7.jpg”)
(h, w, d) = image.shape
print(“width={}, height={}, depth={}”.format(w, h, d))
cv2.imshow(“Image”, image)
img = imutils.resize(image, width=500 )
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert to grey scale
gray = cv2.bilateralFilter(gray, 11, 17, 17) #Blur to reduce noise
edged = cv2.Canny(gray, 30, 200)
cv2.imshow(“Canny”,edged)
cnts,new = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
img1=img.copy()
cv2.drawContours(img1,cnts,-1,(0,255,0),3)
cv2.imshow(“img1”,img1)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:30]
screenCnt = None #will store the number plate contour
img2 = img.copy()
cv2.drawContours(img2,cnts,-1,(0,255,0),3)
cv2.imshow(“img2”,img2) #top 30 contours
count=0
idx=7
# loop over contours
for c in cnts:
# approximate the contour
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.018 * peri, True)
if len(approx) == 4: #chooses contours with 4 corners
screenCnt = approx
x,y,w,h = cv2.boundingRect(c) #finds co-ordinates of the plate
new_img=img[y:y+h,x:x+w]
cv2.imwrite(‘./’+str(idx)+’.png’,new_img) #stores the new image
idx+=1
break
#draws the selected contour on original image
cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 3)
cv2.imshow(“Final image with plate detected”,img)
Cropped_loc=’./7.png’ #the filename of cropped image
cv2.imshow(“cropped”,cv2.imread(Cropped_loc))
text=pytesseract.image_to_string(Cropped_loc,lang=’kor’, config=”) #converts image characters to string
print(“Number is:” ,text)
cv2.waitKey(0)
cv2.destroyAllWindows()
[C#] 자동차 번호판 인식 프로그램 with Tesseract-OCR, OpenALPR
안녕하세요 열코입니다!
OpenCV로 영상처리 및 패턴인식을 공부하는 동안 가장 기본적인 자동차 번호판 인식 프로그램을
간단하게 제작해 보았습니다.
* 개발 환경
개발 툴 : Visual Studio 2017
개발 언어 : C#
* 기능
– IplImage Load(불러오기) 및 Save(저장)
– Web Image Load 및 Save
– Image GrayScale(흑백)
– Image Binary(이진화)
– Image CannyEdge(에지 검출)
– Templet Match 및 ROI(관심 영역 추출)
– Mouse Drag Event로 ROI
– Tesseract-OCR(API)
– OpenALPR(API)
* 소스 코드
전체 소스코드는 300줄가량 되며, 부분 소스코드만 공개하고 설명합니다.
– Binary 함수
1 2 3 4 5 6 7 8 9 IplImage gray = new IplImage(src.Size, BitDepth.U8, 1 ); // GrayScale 수행 Cv.CvtColor(src, gray, ColorConversion.BgrToGray); IplImage bina = new IplImage(src.Size, BitDepth.U8, 1 ); int temp = trackBar1.Value * 20 ; // track bar 값을 받아와 적절한 수치로 변환 Binarizer.SauvolaFast(gray, bina, temp, 0. 2 , 64 ); // Sauvola 방법으로 이진화 수행 cs
– Tesseract 함수
1 2 3 4 5 6 7 8 9 Bitmap img = new Bitmap(pictureBoxIpl2.Image); var ocr = new TesseractEngine( “./tessdata” , “kor” , EngineMode.Default); // ./tessdata : tesseract 문자 인식 훈련 데이터, kor : 한글 or eng : 영문 var texts = ocr.Process(img); textBox1.AppendText(texts.GetText()); Colored by Color Scripter cs
– OpenALPR
1 2 3 4 5 6 7 8 9 10 11 12 13 Task < string > recognizeTask = Task.Run(() = > ProcessImage(savePath)); recognizeTask.Wait(); string task_result = recognizeTask.Result; string result = task_result.Split( ‘:’ )[ 11 ].Split( ‘,’ )[ 0 ]; result = result.Replace( “\”” , “” ); result = result.Trim(); // 결과 값을 적절히 파싱 textBox1.AppendText(result); Colored by Color Scripter cs
* 실행 화면
프로그램을 실행하면 아래 사진과 같은 화면이 실행됩니다.
Load Image를 눌러 로컬 컴퓨터 내 이미지를 불러오거나 Capture를 눌러 연결된 카메라로 사진을 불러올 수 있습니다. 먼저 Capture를 눌러 사진을 찍어보겠습니다.
제 책상 위의 아이폰을 한번 찍어봤습니다…
캡처된 이미지를 불러오기 성공했다는 로그가 뜨고 화면에 이미지를 불러옵니다.
이 사진은 딱히 패턴인식할 사진이 아니므로 Load Image로 자동차 사진을 불러오겠습니다.
자동차 이미지를 불러왔습니다.
자동차 번호판을 인식해야 하는데 먼저 전처리 과정을 거쳐야 인식률이 많이 높아집니다.
(사진 선명도 및 노이즈를 제거하기 위해 처리하는 과정입니다.)
– GrayScale은 RGB 컬러사진은 흑백 사진으로 변환해주는 버튼입니다.
– CannyEdge는 사진의 Edge(모서리) 영역만 감지하여 나타내주는 버튼입니다.
– Init은 작업한 사진을 초기화하는 버튼입니다.
– Binary Degree는 Track Bar로 구현했습니다. 수치의 degree( 정도) 값에 의해 Binary(이진화) 처리를 해줍니다.
120 degree로 Binary 처리한 결과입니다.
번호판 부분이 선명하게 처리되었습니다.
마우스 이벤트를 이용하여 마우스 드래그를 하여 마우스 X, Y좌표를 받아온 후 좌표 크기만큼 잘라서 따로 표시해줍니다. (패턴 인식 알고리즘 속도 향상을 위해)
패턴인식 알고리즘은 2가지를 사용했습니다.
Logic 1은 Open Library인 Tesseract 알고리즘을 사용했고,
Logic 2는 OpenALPR API를 사용했습니다.
(OpenALPR은 유료 라이브러리로 2000회 무료로 사용 가능합니다.)
두 라이브러리 모두 인식률은 상용적으로 사용할 정도로 높진 않았습니다.
하지만 전처리 과정과 알고리즘 수정을 통해 어느 정도 인식률을 높이는 것이 가능합니다.
Logic 1 버튼을 눌러 결과를 확인하니 번호판을 정확히 인식하는 모습입니다.
실행 시간은 두 로직 모두 1~3초 정도 소요합니다. (더 많은 최소화 작업이 필요)
Templet Match는 미리 저장해 둔 Templet 사진을 통해 기존 사진과 비교하여 번호판을 찾아내는 방법입니다. 번호판 모양이 제각각이기 때문에 인식률이 많이 낮았습니다.
Logic 2(OpenALPR) 실행 결과입니다.
실행 시간은 Logic 1(Tesseract) 조금(0.5초~1초) 더 걸리는 정도였습니다.
OpenALPR 홈페이지에서 데모 프로그램 실행 시 한글 인식이 잘 되는 걸로 확인했는데
소스코드로 구현하니 한글 인식이 안되는 걸로 나옵니다… (아시는 분 댓글로 부탁드립니다)
* 수정
– OpenALPR 한글지원 가능합니다.
PostAsync에서 API주소에 country를 us에서 kr로 변경하면 한글도 인식됩니다.
한글을 unicode로 처리하기 때문에 한글이 \ud638 이런식으로 출력됩니다.
유니코드를 한글로 변경하는 알고리즘을 따로 구현하여 처리하였습니다.
유니코드 한글로 변환하기
또 다른 차량 번호판 인식 결과입니다.
다른 차량 역시 번호판을 잘 인식하는 모습입니다.
위 사진처럼 깨끗하고 깔끔하게 번호판이 나온 경우 따로 전처리 작업을 해주지 않아도 인식하는 모습입니다.
알고리즘 및 전처리 과정을 수정하여 실시간 CCTV에서 번호판 인식이 가능하고, 자율 주행 자동차에서 도로 인식 및 표지판, 신호등을 인식하는 알고리즘을 만들어 볼 수 있겠네요
질문 또는 오타나 잘못된 정보가 있는 경우 댓글로 달아주세요!
공감♡ 버튼을 눌러주시면 더욱 유용하고 좋은 포스팅으로 찾아 뵙겠습니다.
브라보 마이라이프 :: [OpenCV] 영상처리를 이용한 숫자인식 프로젝트
안녕하세요. 요새 코로나도 심해지는 와중에 건강 조심하시기 바랍니다.
집에서 코딩하는 것을 추천드려요~
이번 게시물에서는 딥러닝을 이용하지 않고
OpenCV를 이용하여 자동차 번호판 글꼴의 숫자를 인식하는 프로젝트를 작성합니다.
아직 자동차 번호판을 곧바로 인식하기엔 어려움이 있기 때문에 자동차 번호판의 숫자 글꼴을 인식하는 프로젝트로 진행하였습니다.
딥러닝을 이용해보신적이 있으시다면 숫자인식은 어떻게보면 “Hello World”같은 예제일정도로 쉬운 일입니다.
숫자나 어떤 이미지를 인식한다고 하면, 딥러닝에서는 데이터에서 특징을 추출하여 학습을 하여 인식을합니다.
그러나 OpenCV 라이브러리만을 이용하여 인식한다면 꽤나 생각해야할 부분이 많습니다..
본 게시물에서 진행한 숫자인식은 이런방법으로도 접근할 수 있구나라고 생각하고 봐주시면 감사하겠습니다.
제가 진행한 프로젝트의 흐름도는 다음과 같습니다.
우선 간단하게 요약하자면 숫자인식을 하기 위해 이미지 전처리, 관심영역 추출, 히스토그램 생성의 과정을 거칩니다.
표준 숫자 0~9 까지에 대해 위의 세과정을 거쳐서 표본을 만든후에
테스트할 숫자를 넣어 위와 같은 과정을 거쳐 표본 히스토그램의 픽셀수와 테스트 이미지 히스토그램의 픽셀수를 비교하여 가장 적게 차이나는 히스토그램을 가진 숫자를 인식된 숫자로 판정합니다.
이미지 전처리
#define _CRT_SECURE_NO_WARNINGS #include
#include #include #include using namespace std; using namespace cv; int main() { Mat original_image; //image read(grayscale) Mat binary_image; //binary image original_image = imread(“1.jpg”, IMREAD_GRAYSCALE); //grayscale threshold(original_image, binary_image, 127, 255, THRESH_BINARY); //threshold imshow(“grayscale”, original_image); imshow(“binary”, binary_image); waitKey(0); } OpenCV를 이용하면 간단하게 이미지를 불러와서 그레이스케일 변환과 이진화를 진행할 수 있습니다.
이진화를 진행할때 threshold 값을 정해주어야 합니다. 그림에서 보이는 것과 같이 0이라는 숫자에
이미지의 quality가 좋지않아 noise가 발생되어있는데 0과 255 두개로만 픽셀을 깔끔하게 표현하기 위해서는
0의 윤곽쪽을 제외하고는 모두 255(흰색)으로 만들어줍니다.
입력된 기본 original image를 그레이스케일 변환과 이진화를 진행한 사진입니다.
컬러 이미지를 흑백으로 전환하여 1채널(0~255)의 값으로 변경후 숫자 이미지의 픽셀을 0과 255로만 이루어지게 이진화를 거쳐 연산에 효율성과 인식율을 향상할 수 있었습니다.
이렇게 전처리를 진행함으로써 이미지의 픽셀에 접근하여 연산하는 과정 및 픽셀을 확인하는 과정을 효율적으로
진행할 수 있습니다.
관심 영역 추출
이제 이진화까지의 과정을 거쳐서 0과 255로만 구성된 이미지를 얻었습니다.
다음 단계는 숫자 이외의 불필요한 배경들을 제거하여 숫자의 해당하는 픽셀의 연산에 조금더 정확하고 효율적으로
진행할 수 있도록 관심 영역의 x축 최소,최대 y축 최소,최대 좌표를 구하여 자르는 과정입니다.
아래의 그림을 보면 이해가 쉽게 될 것 같습니다.
그림의 가로축을 X, 세로축 Y으로 놓았을때 좌측 상하단 우측 상하단을 순차적으로 돌면서 0의 라인에 해당하는
최솟값 최대값을 찾아냅니다. X-MIN ,X-MAX, Y-MIN , Y-MAX 값만 찾아내면 그값을 기준으로 자르면 되니까요.
#define _CRT_SECURE_NO_WARNINGS #include
#include #include #include using namespace std; using namespace cv; int main() { Mat original_image; //image read Mat binary_image; //binary image Mat roi_image; //roi image int x_count[200] = { 0, }; int y_count[200] = { 0, }; int x_min = 0, x_max = 0, y_min = 0, y_max = 0; int status = 0, pixel_count = 0; original_image = imread(“0.jpg”, IMREAD_GRAYSCALE); //grayscale threshold(original_image, binary_image, 127, 255, THRESH_BINARY); //threshold /************************** ROI 좌표 찾기 *****************************/ for (int x = 0; x < binary_image.rows; x++) //x좌표 최솟값 { for (int y = 0; y < binary_image.cols; y++) { if (binary_image.at (y, x) == 0) { x_min = x; status = 1; break; } if (status == 1) break; } } status = 0; for (int y = binary_image.cols – 1; y >= 0; y–) //x좌표 최댓값 { for (int x = binary_image.rows – 1; x >= 0; x–) { if (binary_image.at (y, x) == 0) { x_max = x; y_max = y; status = 1; break; } if (status == 1) break; } } status = 0; for (int y = 0; y < binary_image.cols; y++) //y좌표 최솟값 { for (int x = 0; x < binary_image.rows; x++) { if (binary_image.at (y, x) == 0) { y_min = y; status = 1; break; } if (status == 1) break; } } status = 0; for (int x = binary_image.rows – 1; x >= 0; x–) //y좌표 최댓값 { for (int y = binary_image.cols – 1; y >= 0; y–) { if (binary_image.at (y, x) == 0) { if (y >= y_max) y_max = y; if (x >= x_max) x_max = x; status = 1; break; } if (status == 1) break; } } status = 0; /************************** ROI 좌표 찾기 *****************************/ roi_image = binary_image(Rect(Point(x_min, y_min), Point(x_max, y_max))); resize(roi_image, roi_image, Size(200, 200), 0, 0, INTER_LINEAR); rectangle(binary_image, Rect(Point(x_min, y_min), Point(x_max, y_max)), Scalar(0, 0, 100), 1, 4, 0); imshow(“original”, original_image); imshow(“bin”, binary_image); imshow(“roi_image”, roi_image); waitKey(0); } 본 코드에는 나와있지 않지만 테스트겸 line을 그려주는 함수를 이용한 사진입니다.
위의 코드를 숫자 0을 입력하여 얻은 이미지입니다.
좌표가 올바르게 찾아졌는지 rectangle 함수를 이용하여 관심영역에 사각형을 그려보았습니다.
좌상하단 , 우상하단 = 4번의 연산이 필요합니다.
이중 for문을 이용하여 간단하게(?) 구현할 수 있습니다.
좌표를 찾았을때 break문을 걸어 탈출하며 flag를 바꾸는 방식으로 구현해보았습니다.
사실 코딩실력이 좋은편이 아니기 때문에 다소 난잡할 수 있으나,
구현적인 측면도 중요했기 떄문에 코드가 난잡하더라도 귀엽게 주니어 개발자 를 봐주시면 감사하겠습니다.
roi_image = binary_image(Rect(Point(x_min, y_min), Point(x_max, y_max))); resize(roi_image, roi_image, Size(200, 200), 0, 0, INTER_LINEAR);
주의할 코드부분은 관심영역을 자르고 나서 원본 사진의 해상도와 맞게 resize를 시켜주었습니다.
OpenCV에서는 resize 진행시 보간법(interpolation methods)을 지정해줄 수 있습니다.
대표적으로 INTER_CUBIC ,INTER_LINEAR 등이 있습니다만, INTER_CUBIC을 사용하면 보다 더 선명한 이미지를 얻을수 있다고 합니다. 그러나 저는 INTER_LINEAR 방식으로 진행하였습니다.
히스토그램 생성
관심영역이 추출된 이미지를 가지고 본격적으로 인식에 가장 필요한 히스토그램을 생성하는 파트입니다.
히스토그램이란?
히스토그램(Histogram)은 표로 되어 있는 도수 분포를 정보 그림으로 나타낸 것입니다.
그러나 이미지 히스토그램은 이야기가 조금 다릅니다.
이미지 히스토그램은 가로축(x축) 에는 이미지의 픽셀 값을 나타내는 좌표값이고, 세로축(y축)으로는 픽셀의 수를 나타내는 좌표값입니다. 히스토그램으로 이미지의 대비(Contrast)나 빛의 강도 등을 나타낼 수도 있기 때문에, 이미지에서 어떤 특징점이 어느정도 분포하고 있는지 알 수 있는 그래프라고 볼 수 있습니다.
0과 9에대한 히스토그램… 별 차이가 없다.
저는 본 프로젝트를 진행하면서, 그레이스케일 변환한 숫자에 대해 히스토그램을이용하여 숫자 0~9 까지의 히스토그램을 모두 그려보았으나 뚜렷한 특징을 찾을 수가 없었습니다. 따라서 아래의 그림과 같이 진행하였습니다.
x축좌표에 대한 0에 해당하는 픽셀 개수를 표현
y축좌표에 대한 0에 해당하는 픽셀 개수를 표현
가로, 세로 축 좌표를 기준으로 숫자의 픽셀(검정색)의 개수를 카운팅하여, 빈 검정색 이미지에 line함수로 픽셀의 개수만큼 그려주었습니다. 축의 기준을 나눠서 히스토그램을 생성한 이유는 기존 히스토그램 사용시에, 밝은 픽셀과 어두운 픽셀의 분포를 표시하기 때문에 입력되는 이미지의 숫자의 크기에 따라 오인식 하는 확률이 크기 때문에 위와 같이 진행했었습니다.
x축 좌표에 대한 히스토그램 을 보면 가로축은 x가 0부터 image의 rows까지 , 세로축은 픽셀의 개수를 나타내었고
y축 좌표에 대한 히스토그램 역시 보면 가로축은 y가 0부터 image의 cols까지, 세로축은 픽셀의 개수를 나타내었습니다.
/************************** ROI 좌표 찾기 *****************************/ roi_image = binary_image(Rect(Point(x_min, y_min), Point(x_max, y_max))); resize(roi_image, roi_image, Size(200, 200), 0, 0, INTER_LINEAR); Mat x_hist_image = Mat::zeros(roi_image.rows, roi_image.cols, CV_8U); Mat y_hist_image = Mat::zeros(roi_image.rows, roi_image.cols, CV_8U); Mat total_hist_image = Mat::zeros(roi_image.cols, roi_image.rows * 2, CV_8U); /************************** histogram ****************************/ for (int y = 0; y < roi_image.rows; y++) //y축 히스토그램 { pixel_count = 0; for (int x = 0; x < roi_image.cols; x++) { if (roi_image.at
(x, y) == 0) { pixel_count++; } } y_count[y] = pixel_count; } for (int x = 0; x < roi_image.cols; x++) //x축 히스토그램 { pixel_count = 0; for (int y = 0; y < roi_image.rows; y++) { if (roi_image.at (x, y) == 0) { pixel_count++; } } x_count[x] = pixel_count; } for (int x = 0; x < roi_image.rows; x++) //x축 히스토그램 그리기 line(x_hist_image, Point(x, roi_image.rows), Point(x, roi_image.rows - x_count[x]), Scalar(255, 255, 255), 0); for (int y = 0; y < roi_image.cols; y++) //y축 히스토그램 그리기 line(y_hist_image, Point(y, roi_image.cols), Point(y, roi_image.cols - y_count[y]), Scalar(255, 255, 255), 0); /* 통합 히스토그램 그리기 */ for (int x= 0; x < roi_image.rows; x++) line(total_hist_image , Point(x + 200, roi_image.rows), Point(x+200, roi_image.rows - x_count[x]), Scalar(255, 255, 255), 0); for (int y = 0; y < roi_image.cols; y++) line(total_hist_image, Point(y, roi_image.cols), Point(y, roi_image.cols - y_count[y]), Scalar(255, 255, 255), 0); /************************** histogram ****************************/ imshow("x_hist", x_hist_image); imshow("y_hist", y_hist_image); imshow("original", original_image); imshow("bin", binary_image); imshow("roi_image", roi_image); imshow("total", total_hist_image); waitKey(0); } 코드 중 가로 세로축 히스토그램을 그리는 코드의 일부입니다. 위의 코드 역시 이중 for문을 이용하여 이미지의 행 ,열을 훑어 연산하면서 픽셀의 카운트를 진행하였습니다. 테스트할 이미지의 데이터와 비교할 표준 숫자 데이터 0~9까지의 히스토그램을 모두 생성하여 저장하였습니다. 그림과 같이 각 숫자마다 모두 다른 히스토그램을 확인할 수 있습니다. 이제 표준 데이터의 히스토그램을 모두 저장하였으니, 테스트할 숫자 이미지 역시 지금까지 진행했던 방식으로 히스토그램을 생성합니다. 테스트할 숫자 데이터는 인터넷에서 자동차 번호판의 숫자를 찾아서 아래 그림과 같이 크기와 위치가 다르게 저장하여 진행하였습니다. /* compare */ for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { for (int y = 0; y < total_hist_image[i].cols; y++) //y축 히스토그램 { for (int x = 0; x < total_hist_image[i].rows; x++) { if (total_hist_image[i].at (x, y) != test_total_hist_image[j].at (x, y)) test_check_sum[i]++; } } if (check_sum[i] <= min) min = test_check_sum[i]; } if (test_check_sum[i] == min) min = i; detect_num[i] = min; } /* compare */ 표준 히스토그램 데이터와의 픽셀차이를 계산하는 코드중 일부입니다. 본 코드가 관심영역 추출이 올바르게 되는지, 글자의 크기에 영향을 미치지 않는지 테스트를 진행해보았습니다. youtu.be/1li7GSmIwqk 테스트할 숫자 이미지가 입력이 되면 표준 숫자 데이터 0~9 를 각각 비교하면서 픽셀차이가 가장 적은 숫자를 인식하는 숫자로 판정하였습니다. 위의 사진과 같이 똑같은 글꼴이지만 위치와 숫자의 크기를 달리 하여도 표준 히스토그램의 특징과 뚜렷하게 다른점이 거의 없습니다. 테스트 숫자의 픽셀이 관심영역을 추출하면서 resize되어 글꼴이 깨져도 숫자의 본 모습은 크게 바뀌지 않아서 그런것 같습니다. 한계점.. ㄴ 본 프로젝트에서 진행한 숫자인식 방법은 가로 세로축을 기준으로 픽셀의 개수를 측정하였기 때문에 숫자가 조금만 회전이 되어도 오인식 하는 경우가 많았습니다.. 회전이나 글꼴 차이에 해당하는 경우의 수는 고려하지 않고 반영하였기 때문에 본프로젝트는 추후에 더욱 좋은 구상을 통해 보완해야할 것 같습니다. 추후에 더욱 좋은 구상을 통해 보완하게 된다면 비교적 무거운 딥러닝을 사용하지 않고도 자동차 번호판을 인식할 수 있는 프로그램을 만들 수 있기 때문에 제한된 하드웨어 성능내에서 효율적인 시스템을 만들수 있을 것 같습니다. 본 프로젝트는 자동차 번호판 숫자 인식을 위한 프로젝트의 일부로 진행하였습니다. 막상 딥러닝을 이용할때는 몰랐는데 딥러닝의 필요성을 알게되는 프로젝트 중 하나였습니다. 영상처리에 대한 공부를 진행하면서 숫자 인식을 위해 진행했던 부분들이 흥미로운점이 많았던 것 같습니다. 긴 게시물 읽어주셔서 감사합니다.
키워드에 대한 정보 opencv 번호판 인식 c++
다음은 Bing에서 opencv 번호판 인식 c++ 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.
이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!
사람들이 주제에 대해 자주 검색하는 키워드 자동차 번호판 인식기 – Python, 이미지 프로세싱
- 개발
- 인공지능
- 파이썬
- 이미지처리
- python
- imageprocessing
- 영상처리
자동차 #번호판 #인식기 #- #Python, #이미지 #프로세싱
YouTube에서 opencv 번호판 인식 c++ 주제의 다른 동영상 보기
주제에 대한 기사를 시청해 주셔서 감사합니다 자동차 번호판 인식기 – Python, 이미지 프로세싱 | opencv 번호판 인식 c++, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.