본문 바로가기
Python/openCV

Python OpenCV (영상의 이진화, 자동 이진화, 지역 이진화, 적응형 이진화, 모폴로지)

by code2772 2023. 3. 10.

[ 목차 ]

    728x90
    반응형

    영상의 이진화(Binarization)
    - 픽셀을 검은색 또는 흰색 같이 두 개의 값으로 나누는 작업
    - 영상에서 의미있는 관심 영역(ROI)과 비관심 영역으로 구분할 때 이진화를 사용
    - 배경(background)과 객체(object)를 나눌 때
    - 그레이스케일에서는 영상을 이진화 시킬 때 특정값을 정해놓고 픽셀값이 특정값보다 크면 255, 작으면 0으로 설정
    - 영상을 연산할 때 255 또는 0으로 나누는 특정값을 임계값이라고 함
    
    cv2.treshold(영상, 임계값, 최대값, cv2.THRESH_로 시작하는 플래그)
    
    플래그
    cv2.THRESH_BINARY : 이진화 시키는 상수
    cv2.THRESH_BINARY_INV : 임계값보다 작으면 배경영상, 크면 검은색을 출력
    
    ✔ treshold 함수는 영상의 이진화 뿐 아니라 모든 임계값에 대해 지원하는 함수
    ✔ 최대값은 255로 입력하는 것이 일반적임 - 범위를 빠저 나갈 수 있기 때문에 일반적으로 255을 준다.

    ✔ threshold 예제1

    import cv2
    import matplotlib.pyplot as plt
    
    src = cv2.imread('cell.png', cv2.IMREAD_GRAYSCALE)
    
    hist = cv2.calcHist([src],[0],None,[256],[0, 255])
    
    _, dst1 = cv2.threshold(src, 100, 255, cv2.THRESH_BINARY) # 사용된 임계값, 출력영상
    # 100부터 255까지 나눠주고 나머지는 따로 처리를 한다.
    _, dst2 = cv2.threshold(src, 210, 255, cv2.THRESH_BINARY)
    # 210부터 255까지 나눠주고 나머지는 따로 처리를 한다.
    # (210~ 255는 배경이며 흰색에 가까운 부분을 제외하고 오브젝트로 처리를 한가. 그렇기 때문에 검은색 따른부분이 잡히게 된다.)
    # _ 는 임계값을 넣는것을 의미하고 따로 변수를 안만든다는 의미이다.
    
    cv2.imshow('src', src)
    cv2.imshow('dst1', dst1)
    cv2.imshow('dst2', dst2)
    
    plt.plot(hist)
    plt.show()
    cv2.waitKey()

     

    ✔ threshold 예제1

    import cv2
    
    # 그레이 스케일로 읽어들이기
    src = cv2.imread('cell.png', cv2.IMREAD_GRAYSCALE)
    
    # 함수만들기
    def on_threshold(pos):
        _, dst = cv2.threshold(src, pos, 255, cv2.THRESH_BINARY)
        cv2.imshow('dst',dst)
    
    
    cv2.imshow('src',src)
    
    # 창에데한 이름을 지정하기
    cv2.namedWindow('dst')
    # createTrackbar('트랙바이름', '창이름', '최소값', '최대값', '이벤트핸들러)
    cv2.createTrackbar('Threshold', 'dst', 0 , 255, on_threshold)
    # setTrackbarPos('트랙바이름', '창이름', 시작포지션값)
    cv2.setTrackbarPos('Threshold', 'dst', 100)
    cv2.waitKey()
    
    

    반응형
    자동 이진화
    Otsu 이진화 방법
    - 자동으로 임계값을 구하는 알고리즘. 임계값을 구분하는 가장 좋은 방법으로 많이 사용
    - 입력 영상이 배경과 객체 두개로 구성되어 있을 때 임의의 임계값에 의해 나눠지는 두 픽셀릐 분포 그룹의 분산이 최소가
      되는 임계값을 선택해 줌
    - OpenCV에서 cv2.threshold 함수에 플래그를 cv2.THRESH_OTSU를 입력하여 사용

    ✔ 자동 이진화 예제

    import cv2
    
    # 그레이 스케일로 읽어들이기
    src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)
    
    th, dst = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    # 임계값을 받는 th
    print('otsu: ', th)
    # 131 ~ 255 배경으로 찾고 나머지를 오브젝트로 잡고있다.
    
    cv2.imshow('src',src)
    cv2.imshow('dst',dst)
    
    cv2.waitKey()
    
    

    ✔ 지역 이진화

    지역 이진화
    - 균일하지 않은 조명 환경에서 사용하는 이진화 방법
    - 전체 구역을 N등분하고 각각의 구역에 이진화를 한 뒤에 이어 붙이는 방법
    - 여러개의 임계값을 이용할 수 있음
    import cv2
    import numpy as np
    
    src = cv2.imread('rice.png', cv2.IMREAD_GRAYSCALE)
    
    # 전역 이진화
    _, dst1 = cv2.threshold(src, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    
    # 지역 이진화
    dst2 = np.zeros(src.shape, np.uint8)
    # 0으로 체운 shape 의 행렬을 만등 - 영상을 만듬
    
    bw = src.shape[1] // 4
    # 위드는 1번 자리에 있다.
    bh = src.shape[0] // 4
    # 높이는 0번 자리에 있다.
    
    # 가로 세로 4등분 하기위해 이중포문을 사용
    for y in range(4):
        for x in range(4):
            # : 부터 시작해서
            # 0이 나오지 않기 위해 ,threshold 입력값으로 주기 위해 입력 영상도 4등분
            src_ = src[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
            # 지역 이진화도 똑같이 4등분을 해준다.
            dst_ = dst2[y*bh:(y+1)*bh, x*bw:(x+1)*bw]
    
            # cv2 ~ 맨 마지막에오는 dst는 출력영상을 의미한다, 대신 출력영상과 입력영상의 크기는 동일해야한다
            # 앞에 src_ 는 입력영상이다
            cv2.threshold(src_, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU, dst_)
    
    cv2.imshow('src', src)
    cv2.imshow('dst1', dst1)
    cv2.imshow('dst2', dst2)
    
    cv2.waitKey()

    적응형 이진화
    - 노이즈를 제거한 뒤에 Otsu 이진화를 적용
    - 가우시안 블러를 적용히며 속도가 느린편
    cv2.adaptiveThreshold(영상, 최대값, 메소드, cv2.THRESH_로 시작하는 플래그, 블록 크기, C)
    메소드 : 블록 평균 계산 방법
        cv2.ADAPTIVE_THRESH_MEAN_C(산술평균) : 블록 사이즈 영역의 모든 픽셀에 평균 가중치를 적용
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C(가우시안 가중치 평균) : 블록 사이즈 영역의 모든 픽셀에 중심점으로부터
          거리에 대한 가우시안 가중치를 적용
          (노이즈를 제거하기 위해 사용하는 경우가 있으며 이 후 에는 이진화로 나눈다.)
    
         블록 크기 : 3이상의 홀수. 블록 사이즈가 클수록 연산 시간이 오래 걸림
         C : 블록 내 평균값 또는 블록 내 가중 평균값에서 뺼 값.
    
    ✔ 블록 사이즈를 너무 작게 주면 블록 안에 배경이나 객체만 존재하는 상황이 발생. 이 경우 픽셀값의 차이가
    적어 지저분한 결과가 출력될 수 있음

    ✔ 적응형 이진화 예제

    import cv2
    
    # 그레이 스케일로 읽어들이기
    src = cv2.imread('sudoku.jpg', cv2.IMREAD_GRAYSCALE)
    
    # 함수만들기
    def on_trackbar(pos):
        bsize = pos
        if bsize < 3:
            bsize = 3
        if bsize % 2 == 0:
            bsize += 1
        dst = cv2.adaptiveThreshold(src, 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, bsize, 1)
        cv2.imshow('dst',dst)
    
    cv2.imshow('src',src)
    cv2.namedWindow('dst')
    cv2.createTrackbar('Block size', 'dst', 0 , 200, on_trackbar)
    cv2.setTrackbarPos('Block size', 'dst', 10)
    cv2.waitKey()
    
    
    

    모폴로지 처리
    - 영상의 밝은 영역이나 어두운 영역을 축소, 확대하는 기법
    
    이진 영상의 모폴로지 처리
    - 여러가지 영상 이진화 기법을 사용한 후 결과 영상에서 흰색 영역이나 검은색 영역기 원하는 의도와 다르게 얻었을 경우
    - 다양한 영상 처리 시스템에서 전처리 또는 후처리 형태로 많이 사용
    
    1. 이진 영상의 침식(erosion) 연산
    - 구조 요소가 객체 영역 내부에 완전히 포함될 경우 고정점 픽셀을 255 설정
    - 침식 연산은 객체 외각을 깍아내는 연산
    - 객체 크기는 감소하고 배경은 확대
    - 작은 크기의 객체(잡음)제거 효과가 있음
    cv2.erode(영상, 구조 요소, 출력 영상, 고정점 위치)
    
    2. 이진 영상의 팽창(dilation) 연산
    - 구조 요소와 객체 영역이 한 픽셀이라도 만날 경우 고정점 픽셀을 255로 설정
    - 객체가 커지는 연산
    - 팽창 연산은 객체 외곽을 확대시키는 연산
    - 객체 크기는 증가되고 배경은 감소
    - 객체 영역(흰색)이 점점 커짐
    - 객체 내부가 홀(구멍)이 채원지게 됨
    cv2.dilate(영상, 구조 요소, 출력 영상, 고정점 위치)
    
    모폴로지 구조 요소를 생성
    cv2.getStructuringElement(구조 요소의 모양, 사이즈)
    
    구조 요소의 모양
    - cv2.MORPH_RECT : 사각형 모향
    - cv2.MORPH_CROSS : 십자가 모양
    - cv2.MORPH_ELLIPSE : 사각형의 내접하는 타원

    ✔ 모폴로지 예제

    import cv2
    
    # 그레이 스케일로 읽어들이기
    src = cv2.imread('circuit.bmp', cv2.IMREAD_GRAYSCALE)
    # 마스크 얻어내는 함수
    # 가로5, 세로3 의 마스크를 사용하겠다
    se = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))
    dst1 = cv2.erode(src, se) # 깨진부분 축소
    dst2 = cv2.dilate(src, None) # 깨진부분 확대, None 3*3
    
    # 만약 수직선이 단선됐을 때 위 아래로 연결하고 싶은경우
    # 1*5 커널을 생성하면 됨 - 마스크 사이즈라고 생각하고(1*5)로
    
    cv2.imshow('src', src)
    cv2.imshow('dst1', dst1)
    cv2.imshow('dst2', dst2)
    cv2.waitKey()

    반응형