Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

브이로그

2024년 7월 23일 Python-Morphology 본문

Python

2024년 7월 23일 Python-Morphology

황수환 2024. 7. 25. 02:31
더보기
모폴로지 처리
영상의 밝은 영역이나 어두운 영역을 축소 또는 확대하는 기법
cv2.getStructuringElement(구조 요소의 모양, 사이즈)
- 구조 요소의 모양
    1. 직사각형(cv2.MORPH_RECT)
        - 가장 단순한 형태로, 모든 요소사 같은 값을 가지는 정사각형 또는 직사각형
        - 팽창과 침식 연산에서 동일하게 작동
        - 객체 가장자리를 따라 명확한 변화를 줄 때 유용
    2. 타원형(cv2.MORPH_ELLPSE)
        - 가장자리 부분을 더 부드럽게 처리
        - 객체의 둥근 모양을 유지하면서 노이즈를 제거하 때 유용
    3. 십자형(cv2.MORPH_CROSS)
        - 중심을 기준으로 수직 및 수평 방향으로 영향
        - 얇은 라인 구조를 강화하거나 제거하는데 유용
침식(erosion) 연산
cv2.erode(영상, 구조요소, 출력영상, 고정점 위치)
- 이미지를 깍아 내는 연산
- 객체 크기가 감소되고 배경은 확대
- 작은 크기의 객체(잡음)제거 효과가 있음
- 어두운 부분의 노이즈를 제거하는 효과가 있음

팽창(dilation) 연산
cv2.dilate(영상, 구조요소, 출력영상, 고정점 위치)
- 물체의 주변을 확장하는 연산
- 팽창 연산은 객체 외곽을 확대시키는 연산
- 객체 크기가 증가되고 배경은 감소
- 객체 내부의 홀이 있다면 홀을 채울 수도 있음
- 밝은 부분의 노이즈를 제거하는 효과

열림(Opening)
- 팽창 연산과 침식 연산의 조합
- 침식 연산을 적용한 다음, 팽창 연산을 적용
- 침식 연산으로 인해 밝은 영역이 줄어들고, 어두운 영역이 늘어남
- 객체 크기 감소를 원래대로 복구할 수 있음
- 작은 객체를 제거하고 구멍을 메우는데 사용

닫힘(Closing)
- 팽창 연산과 침식 연산의 조합
- 팽창 연산을 적용한 다음, 침식 연산을 적용
- 어두운 영역이 줄어들고 밝은 영역이 늘어남
- 작은 구멍을 메우고 끊어진 객체를 연결하는데 사용

그레디언트
- 영상에 팽창 연산을 적용한 결과에서 영상에 침식 연산을 적용한 결과를 뺌
- 경계가 강조된 영상을 생성
- 엣지 검출, 객체의 윤과 추출, 영상 분할 등에 사용

레이블링
- 이진화, 모폴로지를 수행하면 객체와 배경 영역을 구분할 수 있게됨
- 객체 단위 분석을 통해서 각 객체를 분할하여 특징을 분석하고 객체의 위치, 크기 정보, 모양 분석, ROI 추출 등이 가능함
-  서로 연결되어 있는 객체 픽셀에 고유번호를 할당하여 영역 기반 모양분석, 레이블맵, 바운딩 ㅏㅂㄱ스, 픽셀 개수, 무게 중심, 좌표 등을 반환할 수 있게 함
cv.connectedComponents(영상, 레이블맵)
    레이블맵: 픽셀 연결 관계(4방향 연결, 8방향 연결)
    반환: 객체 개수, 레이블 맵 행렬

    cv2.conncetedComponentsWithStats(영상, 레이블맵)
    반환: 객체 개수, 레이블 맵 행렬(객체 위치, 가로세로 길이, 면적 등 행렬), 무게 중심 정보

객체의 외곽선 검출
cv2.findContours(영상, 검출모드, 외곽선 좌표 근사화 방법)
검출 모드
    cv2.RETR_EXTERNAL: 외부 외곽선만 검출
    cv2.RETR_LIST: 모든 외곽선을 검출하며, 계층 관계는 무시
    cv2.RETR_CCOMP: 모든 외곽선을 검출하며, 계측 관계를 2단계로 구성
        첫 번째 계층: 바깥쪽 윤곽선
        두 번째 계층: 안쪽 윤곽선
    cv2.RETR_TREE: 모든 외곽선을 검출하며, 전체 계층 관계를 구성

외곽선 좌표 근사화 방법
외곽선 점들의 저장 방식과 정확도를 정의
    cv2.CHAIN.APPROX_NONE: 모든 외곽선의 점으 저장
    cv2.CHAIN_APPROX_SIMPLE: 수평, 수직, 대각선 방향 점들은 그 점의 끝점만 저장하여 압축

외곽선 그리기
cv2.drawContours(영상, 외곽선 좌표 정보, 외곽선 인덱스, 색상, 두께)
외곽선 인덱스: -1을 지정하면 모든 외곽선을 그림

외곽선의 길이 구하기
cv2.arcLength(외곽선 좌표, 폐곡선 여부)

면적 구하기
cv2.contourArea(외곽선 좌표, False)

바운딩 박스 구하기
cv2.boundingRect(외곽선 좌표)

외곽선 근사화
검출한 외곽선 정보를 분석하여 정점수가 적은 외곽선 또는 다각형으로 표현할 수 있게 만드는 것

볼록 부분이 있는지 여부
cv2.isContourConvex()
볼록 부분이 있으면 True, 없으면 Flase

볼록 외피를 계산
cv2.convexHull()
주어진 점 집합을 둘러싸는 가장 작은 볼록 다각형을 반환

OCR(Optical Character Recognition)
- 광학 문자 인식
- 영상이나 문서에서 텍스트를 자동으로 인식하고 컴퓨터가 이행할 수 있는 텍스트 데이터로 변환하는 프로세스
- Tesseract, EastOCR, PaddleOCR, CLOVA OCR(네이버 API), Cloud Vision(구글 API)

테서렉트
- 오픈 소스 OCR 라이브러리로 구글에서 개발하고 현재는 여러 커뮤니티에 의헤 유지보수
- https://github.com/UB-Mannheim/tesseract/wiki
- tesseract-ocr-w64-setup-5.4.0.20240606.exe 다운로드 -> Choose Components에서 Addtional Script Data 트리를 내림 -> Hangul Script와 Hangul Verticcal Script 체크, Addtional Language Data 트리를 내림 -> Korean 체크

윈도우 환경설정
탐색기 -> '내 PC' 마우스 오른쪽 버튼 클릭 '속성' -> 창 최대화 후 우측 메뉴 '고급 시스템 설정' -> '환경 변수'를 선택 -> '시스템 변수' 에서 'path'를 선택하고 '편집'버튼 클릭 -> '새로 만들기' 버튼 클릭

1. morphology

import cv2
import numpy as np

img = cv2.imread('./circuit.bmp', cv2.IMREAD_GRAYSCALE)
gse = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
gse1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
dst1 = cv2.dilate(img, gse)
dst2 = cv2.erode(img, gse)
dst3 = cv2.dilate(img, gse1)
dst4 = cv2.erode(img, gse1)

cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)
cv2.imshow('dst4', dst4)
cv2.waitKey()

 

2. labeling

import cv2

img = cv2.imread('./keyboard.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cnt , labels, stats, centroids = cv2.connectedComponentsWithStats(img_bin)
print('cnt', cnt)
print('labels', labels)
print('state', stats)
print('centroids', centroids)

for i in range(1, cnt):
    (x, y, w, h, area) = stats[i]
    if area < 30:
        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. contours1

import cv2
import random

img = cv2.imread('./contours.bmp', cv2.IMREAD_GRAYSCALE)
# hierarchy: 계층 정보
contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
print(contours)
print(hierarchy)
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, 3)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()

지오메트리 대쉬~

 

4. contours2

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()

 

5. contours3

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 | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

for pts in contours:
    if cv2.contourArea(pts) < 200:
        continue
    approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)
    vtc = len(approx)


    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()

 

6. tesserect

import cv2
import pytesseract


img = cv2.imread('./hello.png')
dst = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

text = pytesseract.image_to_string(dst, lang='kor+eng')
print(text)

이 사진의 글씨를 읽어버리기~

 

7. namecard

import cv2
import pytesseract
import numpy as np

def reorderPts(pts):
    '''
    [[903. 199.]
     [179. 200.]
     [159. 593.]
     [938. 581.]]

    [[179 200]]
    [[159 593]]
    [[938 581]]
    [[903 199]]
    '''
    # print(pts)
    # print(pts[:, 1])
    # print(pts[:, 0])
    idx = np.lexsort((pts[:, 1], pts[:, 0]))
    # print(idx)
    pts = pts[idx]
    # print(pts)

    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]]
    # print(pts)
    return pts


img = cv2.imread('./namecard.jpg')

dw, dh = 700, 400
srcQuad = 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)

src_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, src_bin = cv2.threshold(src_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(src_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)
    cv2.polylines(cpy, [approx], True, (0, 255, 0), 2)
    # print(approx)

    srcQuad = reorderPts(approx.reshape(4, 2).astype(np.float32))
    pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
    dst = cv2.warpPerspective(img, pers, (dw, dh))
    dst_gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
    print(pytesseract.image_to_string(dst_gray, lang='kor+eng'))

cv2.imshow('img', img)
cv2.imshow('cpy', cpy)
cv2.imshow('dst', dst)
cv2.waitKey()

이것도 저번에 했던 달이랑 똑같아 좌표로 명함 위치를 따주고 뽑아주기~

 

7-1. lexsort

import numpy as np

ndarr1 = np.array([1, 5, 1, 4, 4])
ndarr2 = np.array([9, 4, 0, 4, 0])
result = np.lexsort((ndarr2, ndarr1))
# ndarr2 배열을 기준으로 오름차순으로 정렬
# 0, 0, 4, 4, 9
# 동일한 값의 경우 ndarr2 배열의 기준으로 ndarr1 오름차순 한 인덱스를 반환
#
print(result)

surnames = ('Hertz',    'Galilei', 'Hertz')
first_names = ('Heinrich', 'Galileo', 'Gustav') # 1 2 0
ind = np.lexsort((first_names, surnames))
print(ind)


a = [1, 5, 1, 4, 3, 4, 4]  # First sequence
b = [9, 4, 0, 4, 0, 2, 1]  # Second sequence
ind = np.lexsort((b, a))  # Sort by `a`, then by `b`
print(ind)


x = [[1, 2, 3, 4],
     [4, 3, 2, 1],
     [2, 1, 4, 3]]
y = [[2, 2, 1, 1],
     [1, 2, 1, 2],
     [1, 1, 2, 1]]
print(np.lexsort((x, y), axis=1))

?

'Python' 카테고리의 다른 글

2024년 7월 29일 Python-Object Detection  (0) 2024.07.30
2024년 7월 24일 Python-Classification  (0) 2024.07.25
2024년 7월 22일 Python-Translate  (4) 2024.07.23
2024년 7월 19일 Python-DL Task  (0) 2024.07.22
2024년 7월 17일 Python-ROI  (4) 2024.07.22