1. 모폴로지 처리
- 영상의 밝은 영역이나 어두운 영역을 축소 또는 확대하는 기법
- cv2.getStructuringElement(구조요소의모양, 사이즈)
- 구조요소의 모양
- 직사각형(cv2.MORPH_RECT)
- 가장 단순한 형태로, 모든 요소가 같은 값을 가지는 정사각형 또는 직사각형
- 팽창과 침식 연산에서 동일하게 작동
- 객체 가장자리를 따라 명확한 변화를 줄 때 유용
- 타원형(cv2.MORPH_ELLIPSE)
- 가장자리 부분을 더 부드럽게 처리
- 객체의 둥근 모양을 유지하면서 노이즈를 제거할 때 유용
- 십자형(cv2.MORPH_CROSS)
- 중심을 기준으로 수직 및 수평 방향으로 영향
- 얇은 라인 구조를 강화하거나 제거하는 데 유용
- 직사각형(cv2.MORPH_RECT)
1-1. 침식(erosion) 연산
- cv2.erode(영상, 구조요소, 출력영상, 고정점 위치)
- 이미지를 깎아 내는 연산
- 객체 크기가 감소되고 배경은 확대
- 작은 크기의 객체(잡음)제거 효과가 있음
- 어두운 부분의 노이즈를 제거하는 효과가 있음
1-2. 팽창(dilation) 연산
- cv2dilate(영상, 구조요소, 출력영상, 고정점 위치)
- 물체의 주변을 확장하는 연산
- 팽창 연산은 객체 외곽을 확대시키는 연산
- 객체 크기가 증가되고 배경은 감소
- 객체 내부의 홀이 있다면 홀을 채울 수도 있음
- 밝은 부분의 노이즈를 제거하는 효과
import cv2
img = cv2.imread("./circuit.bmp", cv2.IMREAD_GRAYSCALE)
gse = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))
dst1 = cv2.erode(img, gse)
dst2 = cv2.dilate(img, None)
cv2.imshow("img", img)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)
cv2.waitKey()
1-3. 열림(Opening)
- 팽창 연산과 침식 연산의 조합
- 침식 연산을 적용한 다음, 팽창 연산을 적용
- 침식 연산으로 인해 밝은 영역이 줄어들고, 어두운 영역이 늘어남
- 객체의 크기 감소를 원래대로 복구할 수 있음
1-4. 닫힘(Closing)
- 팽창 연산과 침식 연산의 조합
- 팽창 연산을 적용한 다음, 침식 연산을 적용
- 어두운 영역이 줄어 들고 밝은 영역이 늘어남
- 작은 구멍을 메우고 끊어진 객체를 연결하는 데 사용
1-5. 그래디언트(Gradient)
- 영상에 팽창 연산을 적용한 결과에서 영상에 침식 영상을 적용한 결곽를 뺌
- 경계가 강조된 영상을 생성
- 엣지 검출, 객체의 윤곽 추출, 영상 분할 등에 사용
2. 레이블링
- 이진화, 모폴로지를 수행하면 객체와 배경 영역을 구분할 수 있게됨
- 객체 단위 분석으로 통해 각 객체를 분할하여 특징을 분석하고 객체의 위치, 크기 정보, 모양 분석, ROI 추출 등이 가능함
- 서로 연결되어 있는 객체 픽셀에 고유번호를 할당하여 영역 기반 모양분석, 레이블맵, 바운딩 박스, 픽셀 개수, 무게 중심, 좌표 등을 반환할 수 있게 함
cv.connectedComponents(영상, 레이블맵)
레이블맵: 픽셀 연결 관계(4방향 연결, 8반향 연결)
반환: 객체 개수, 레이블 맵 행렬
cv2.connectedComponentsWithStats(영상, 레이블맵)
반환: 객체 개수, 레이블 맵 행렬, (객체 위치, 가로세로길이, 면적 등 행렬, 무게중심 정보)
import cv2
img = cv2.imread('keyboard.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cnt, labels, stats, centroids = cv2.connectedComponentsWithStats(img_bin)
for i in range(1, cnt):
(x, y, w, h, area) = stats[i]
if area < 20:
continue
cv2.rectangle(dst, (x, y, w, h), (0, 255, 255))
cv2.imshow('img', img)
cv2.imshow('img_bin', img_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
3. 객체의 외곽선 검출
- cv2.findContours(영상, 검출모드, 외곽선 좌표 근사화 방법)
- 검출모드:
- cv2.RETR_EXTERNAL: 외부 외곽선만 검출
- cv2.RETR_LIST: 모든 외곽선을 검출하며, 계층 관계는 무시
- cv2.RETR_CCOMP: 모든 외곽선을 검출하며, 계층 관계를 2단계로 구성
첫번째 계층: 바깥쪽 윤곽선
두번째 계층: 내부 윤곽선 - cv2.RETR_TREE: 모든 외곽선을 검출하며, 전체 계층 관계를 구성
3-1. 외각선 좌표 근사화 방법
- 외각선 점들의 저장 방식과 정확도를 정의
- cv2.CHAIN_APPROX_NONE: 모든 외곽선 점을 저장
- cv2.CHAIN_APPROX_SIMPLE:수평, 수직, 대각선 방향 점들은 그 점의 끝점만 저장하여 압축
3-2. 외곽선 그리기
- cv2.drawContours(영상, 외곽선 좌표 정보, 외곽선 인덱스, 색상, 두께)
- 외곽선 인덱스: -1을 지정하면 모든 외곽선을 그림
3-3. 외곽선의 길이 구하기
- cv2.arcLength(외곽선 좌표, 폐곡선 여부)
3-4. 면적 구하기
- cv2.contourArea(외각선 좌표, False)
3-5. 바운딩 박스 구하기
- cv2.boundingRect(외각선 좌표)
import cv2
import random
img = cv2.imread('contours.bmp', cv2.IMREAD_GRAYSCALE)
contours, _ = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # 랜덤한 색상을 뽑아주기 위해
cv2.drawContours(dst, contours, -1, color, 2)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
# milkdrop.bmp 이미지를 이용하여 이진화를 시키고, 외곽선을 검출하여 외곽선을 랜덤한 색상으로 표기
import cv2
import random
import numpy as np
img = cv2.imread('./milkdrop.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
h, w = img.shape[:2]
dst = np.zeros((h, w, 3), np.uint8)
for i in range(len(contours)):
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, i, color, 2)
cv2.imshow('img', img)
cv2.imshow('img_bin', img_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
3-6. 외곽선 근사화
- 검출한 윤곽선 정보를 분석하여 정점수가 적은 윤곽선 또는 다각형으로 표현할 수 있게 만드는 것
- cv2.approxPolyDP(외곽선 좌표, 근사화 정밀도 조절, 폐곡선 여부)
- 근사화 정밀도 조절: 입력 외곽선과 근사화된 외곽선 사이의 최대 길이. 값이 작을수로 다각형이 정확해지고, 꼭지점 수가 늘어남
- 볼록 부분이 있는지 여부
- cv2.isContourConvex()
- 볼록 부분이 있는지 True, 없으면 False
- 볼록 외피를 계산
- cv2.convexHull()
- 주어진 점 집합을 둘러싸는 가장 작은 블록 단위의
import cv2
import math
def setLabel(img, pts, label):
(x, y, w, h) = cv2.boundingRect(pts)
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(img, pt1, pt2, (0, 0, 255), 2)
cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255))
img = cv2.imread('./polygon.bmp')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# print(contours)
for pts in contours:
if cv2.contourArea(pts) < 200:
continue
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)
# print(approx)
vtc = len(approx)
print(vtc)
if vtc == 3:
setLabel(img, pts, "TRI")
elif vtc == 4:
setLabel(img, pts, 'RECT')
else:
length = cv2.arcLength(pts, True)
area = cv2.contourArea(pts)
ratio = 4. * math.pi * area / (length * length) # 원인지 여부
if ratio > 0.70:
setLabel(img, pts, 'CIR')
else:
setLabel(img, pts, 'NONAME')
cv2.imshow('img', img)
cv2.imshow('gray', gray)
cv2.imshow('img_bin', img_bin)
cv2.waitKey()
4. OCR(Optical Character Recognition)
- 광학 문자 인식
- 영상이나 문서에서 텍스트를 자동으로 인식하고 컴퓨터가 이행할 수 있는 텍스트 데이터로 변환하는 프로세스
- Tesseract, EasyOCR, PaddleOCR, CLOVA OCR(네이버 API), Cloud Vision(구글 API) ..
5. 테서렉트
- 오픈 소스 OCR 라이브러리로 구글에서 개발하고 현재는 여러 커뮤니티에 의해 유지보수
- https://github.com/UB-Mannheim/tesseract/wiki
- tesseract-ocr-w64-setup-5.4.0.20240606.exe를 다운로드
- Choose Components에서 Additional Script Data (download) 트리를 내림
- Hangul Script와 hangul Vertical Script 체크
- Additional Language Data (download) 트리를 내림
- korean 체크
- 윈도우 환경설정
- 탐색기
- 내 pc 오른쪽 버튼 속성
- 창 최대화 후 우측 메뉴 고급시스템 설정
- 환경 변수 버튼 클릭
- 시스템 변수 에서 path를 선택하고 편집 버튼 클릭
- 새로 만들기 버튼 클릭
- 테서렉트 설치 경로를 추가(예: C:\Program Files\Tesseract-OCR)
- 파이참에 pytesseract 패키지 설치하고 프로그램 재부팅
import cv2
import pytesseract
img = cv2.imread("./hello.png")
dst = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# lang='kor', lang='eng', lang='kor+eng'
text = pytesseract.image_to_string(dst, lang="kor+eng")
print(text)
이 이미지를 인식해서 아래와 같이 출력한다.
명함카드를 이용해서 OCR 해보기(명함 2개를 동시에 분석 및 결과 출력)
import cv2
import pytesseract
import numpy as np
def reorderPts(pts):
idx = np.lexsort((pts[:, 1], pts[:, 0]))
pts = pts[idx]
if pts[0, 1] > pts[1, 1]:
pts[[0, 1]] = pts[[1, 0]]
if pts[2, 1] < pts[3, 1]:
pts[[2, 3]] = pts[[3, 2]]
return pts
def process_image(img_path):
img = cv2.imread(img_path)
dw, dh = 700, 400
imgQuad = np.array([[0, 0], [0, 0], [0, 0], [0, 0]], np.float32)
dstQuad = np.array([[0, 0], [0, dh], [dw, dh], [dw, 0]], np.float32)
dst = np.zeros((dh, dw), np.uint8)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, img_bin = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cpy = img.copy()
for pts in contours:
if cv2.contourArea(pts) < 1000:
continue
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)
if not cv2.isContourConvex(approx) or len(approx) != 4:
continue
cv2.polylines(cpy, [approx], True, (0, 255, 0), 2)
imgQuad = reorderPts(approx.reshape(4, 2).astype(np.float32))
pers = cv2.getPerspectiveTransform(imgQuad, dstQuad)
dst = cv2.warpPerspective(img, pers, (dw, dh))
dst_gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
text = pytesseract.image_to_string(dst_gray, lang='kor+eng')
return dst, text
def remove_blank_lines(text):
return "\n".join([line for line in text.splitlines() if line.strip()])
img_paths = ['./namecard1.jpg', './namecard2.jpg']
results = [process_image(img_path) for img_path in img_paths]
for idx, (img, text) in enumerate(results):
window_name = f'dst{idx + 1}'
cv2.imshow(window_name, img)
clean_text = remove_blank_lines(text)
print(f'\n{"-" * 30}\nText from image {idx + 1}:\n{"-" * 30}')
print(clean_text)
cv2.waitKey(0)
cv2.destroyAllWindows()
'컴퓨터비전(CV)' 카테고리의 다른 글
8. OpenCV7 (0) | 2024.07.14 |
---|---|
7. OpenCV6 (0) | 2024.07.14 |
5. OpenCV4 (1) | 2024.07.08 |
4. Open CV3 (0) | 2024.07.08 |
3. Open CV2 (0) | 2024.07.08 |