본문 바로가기
컴퓨터비전(CV)

6. Open CV5

by 곽정우 2024. 7. 14.

1. 모폴로지 처리

  • 영상의 밝은 영역이나 어두운 영역을 축소 또는 확대하는 기법
  • cv2.getStructuringElement(구조요소의모양, 사이즈)
  • 구조요소의 모양
    • 직사각형(cv2.MORPH_RECT)
      • 가장 단순한 형태로, 모든 요소가 같은 값을 가지는 정사각형 또는 직사각형
      • 팽창과 침식 연산에서 동일하게 작동
      • 객체 가장자리를 따라 명확한 변화를 줄 때 유용
    • 타원형(cv2.MORPH_ELLIPSE)
      • 가장자리 부분을 더 부드럽게 처리
      • 객체의 둥근 모양을 유지하면서 노이즈를 제거할 때 유용
    • 십자형(cv2.MORPH_CROSS)
      • 중심을 기준으로 수직 및 수평 방향으로 영향
      • 얇은 라인 구조를 강화하거나 제거하는 데 유용

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
    1. tesseract-ocr-w64-setup-5.4.0.20240606.exe를 다운로드
    2. Choose Components에서 Additional Script Data (download) 트리를 내림
    3. Hangul Script와 hangul Vertical Script 체크
    4. Additional Language Data (download) 트리를 내림
    5. korean 체크
 

Home

Tesseract Open Source OCR Engine (main repository) - UB-Mannheim/tesseract

github.com

  • 윈도우 환경설정
    1. 탐색기
    2. 내 pc 오른쪽 버튼 속성
    3. 창 최대화 후  우측 메뉴 고급시스템 설정
    4. 환경 변수 버튼 클릭
    5. 시스템 변수 에서 path를 선택하고 편집 버튼 클릭
    6. 새로 만들기 버튼 클릭
    7. 테서렉트 설치 경로를 추가(예: C:\Program Files\Tesseract-OCR)
    8. 파이참에 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