본문 바로가기
Python/openCV

Python OpenCV (영상 필터링, 블러, 가우시안, 미디안, 샤프닝, 케니)

by code2772 2023. 3. 12.

[ 목차 ]

    728x90
    반응형
    영상 필터링
    커널(filter)라고 하는 정방행렬을 정의하고, 이 커널을 이미지 위에서 이동시키면서 커널과 겹쳐진 이미지 영역과(컨벌루션 연산)
    연산을 한 후 그 결과값을 연산을 진행한 이미지 픽셀을 대신하여 새로운 이미지를 만드는 연산
    
    # 컨벌루션 곱을 하면 3바이 3행렬에서 1개가 나온다. 새로운 이미지를 만든다는 뜻이다.
    
    필터링
    - 영상에서 필요한 정보만 통과시키고 원치 않는 정보를 걸러내는 작업
    예) 노이즈를 제거하여 영상을 깔끔하게 만드는 필터. 부드러운 느낌의 성분을 제거하여 날카로운 느낌이 나도록 만들 수 있음
    - 영상의 필터링은 마스크라고 부르는 작은 크기의 행렬을 이용
    - 마스크는 필터링의 성격을 정의하는 행렬이며 커널 또는 필터라고 부름
    - 마스크의 정중앙을 고정점으로 사용
    
    ✔ OpenCV에서 필터 마스크를 사용하는 일반적인 필터릴은 filter2D 함수를 사용
    filter2D(영상, 이미지 깊이(자료형 크기, -1이면 입력과 동일), 커널 행렬, 증심정 좌표, 추가될 값, 가장자리 화소 처리)
    
    가장자리 화소 처리
    OpenCV에서는 영상을 필터링을 수행할 때 영상의 가장자리 픽셀을 확장하여 바깥쪽에 가상의 픽셀을 만듬
    - 패딩(padding)을 추가
    - 픽셀값을 어떻게 설정하느냐에 따라 필터링 연산의 결과가 달라짐
    - 가장자리 화소 처리 상수 값
        BORDER_CONSTANT : 000픽셀픽셀픽셀픽셀픽셀픽셀픽셀000
        BORDER_REPLICATE : aaaabcdefghhh
        BORDER_REFLECT : cbabcdefghgf - 3개의 픽셀 전걸

     

    ✔ 필터링

    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    
    src = cv2.imread('rose.bmp')
    dst = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
    plt.figure(figsize=(10,5))
    for i, k in enumerate([3, 6, 10]):
        # 3바퀴 i는 인덱스 k에는 3 , 6 ,9가 들어간다.
        kernel = np.ones((k, k)) / k ** 2 # 제곱을 나눠준다, 마스크만들기
        filtering = cv2.filter2D(dst, -1, kernel)
        plt.subplot(1 , 3, i+1)
        plt.imshow(filtering)
        plt.title('kernel size : {}'.format(k))
        plt.axis('off')
    
    plt.show()
    
    
    

    이미지 블러링(Image Bluring)
    - 이미지를 흐리게 만드는 기법
    - 고주파 영역을 제거함으로써 노이즈를 제거하거나 경계선을 흐리게 만듬
    - Averaging, Gaussian Filtering, Median Filtering, Bilateral Filtering
    
    Averaging
    - 가장 일반적인 필터링 방법으로 균일한 값을 정규화 된 커널을 이용한 이미지 필터링 방법
    - 커널 영역 내에서 평균 값으로 해당 픽셀을 대체함
    - cv2.blur()

     

    ✔ 블러링

    import cv2
    
    src = cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
    dst = cv2.blur(src, (3,3)) # (3,3) 내각 원하는 3*# 행렬 마스크
    
    cv2.imshow('src', src)
    cv2.imshow('dst', dst)
    cv2.waitKey()
    

    Gaussian Filtering
    - 가우시안 함수를 이용한 커널을 적용
    - 중앙 위치에 놓인 픽셀과 가까울수록 가중치가 높아지고 멀어질 수록 가중치가 작아져 중앙 픽셀과 멀어질 수록
     해당 픽셀값에 대한 영향력이 작아짐
    - 전체적으로 밀도가 동일한 노이즈, 백색노이즈를 제거하는데 효과적
    cv2.GaussianBlur(영상, 커널의 크기, 가우시안 커널의 X방향 표준편차, 가우시안 커널의 Y방향 표준편차)
    커널의 크기다 (0,0)을 지정하면 sigma값에 의해 자동으로 결정
    # 얼마만큼 범위의 표준편차가 나올지 종모양 가우시안 필터링 방식

     

    ✔ 가우시안

    import cv2
    
    src = cv2.imread('rose.bmp', cv2.IMREAD_GRAYSCALE)
    
    dst1 = cv2.GaussianBlur(src, (0,0), 3)
    # 시그마 값 3에 의해 바뀜
    dst2 = cv2.blur(src,(7,7))
    # 7,7 마스크에 따라 바뀜
    
    cv2.imshow('src', src)
    cv2.imshow('dst1', dst1)
    cv2.imshow('dst2', dst2)
    
    cv2.waitKey()

    Median Filtering
    - 따로 kernel을 만들어 합성곱하지 않고, kernel window에 있는 모든 픽셀들을 정렬한 후 중간값을 선택하여
    - 중간값 필터링의 경우에는 항상 이미지의 일부 픽셀값으로 대체됨
    - 소금-후추 잡음 제거에 효과적
    cv2.medianBlur(영상, 커널사이즈(1ㅗ다 큰 홀수를 지정))
    
    오름차순 중앙값을 선택(anchor)
    반응형

     

    ✔ 미디안

    import cv2
    
    src = cv2.imread('noise.bmp', cv2.IMREAD_GRAYSCALE)
    
    dst = cv2.medianBlur(src,3)
    
    cv2.imshow('src', src)
    cv2.imshow('dst', dst)
    
    cv2.waitKey()

    Bilateral Filtering
    - 경계선을 유지하면서 Gaussian Filtering이 하는 것처럼 Blur 처리를 해주는 기법
    - 가우시안 필터링에서는 두 픽셀의 거리 차이만 고려하지만 양방향 필터링의 경우에는 두 픽셀의 명암값 차이 또한 커널에
    넣어 가중치로 곱함
    - 픽셀의 차이가 크면 가중치가 0에 가까운 값이 되어 합쳐지지 않으므로 영역과 영역사이즈의 경계선이 잘 보전될 수 있음
    - 엣지를 보존해주고 기존에 픽셀하고 이웃 픽셀간의 거리, 픽셀간의 차이를 고려하여 블러링을 해준다.
    cv2.bilateralFilter(영상, 필터링에 사용될 이웃 픽셀의 거리(지름), 색 공간에서 필터의 표준 편차, 좌표 공간에서 표준편차)
    영상 : 8bit, 채널수가 1, 3인 이미지
    필터링에 사용될 이웃 픽셀의 거리(지름) : -1를 입력하면 sigmaSpace값에 의해 자동 결정됨
    좌표 공간에서 표준퍈치 : 값이 크면 멀리 떨어져 있는 픽셀들이 서로 영향을 미침, 지름이 양수면 sigmaSpace에 상관없이
    인접한 픽셀들에 영향을 미치지만, -1인 경우 sigmaSpace에 비례
    
    ✔ 이미지도 음성 신호처럼 주파수로 표현할 수 있음
    고주파 : 밝기 변화가 많은 곳 -> 주변 영역과 색 차이가 크게 나는 부분(모서리)
       * 고주파를 제거하면 경계선의 변화가 약해져 Blur 처리가 됨
    저주파 : 밝기 변화가 적은 곳 -> 주변 영역과 색 차리가 적은 부분(배경, 면) , 넓은 부분
        * 저주파를 제거하면 배경 영역이 흐려져 대상의 영역(Edge)를 뚜력하게 확인할 수 있음

     

    ✔ Bilateral

    import cv2
    
    src = cv2.imread('dog.jpg')
    dst = cv2.bilateralFilter(src, -1, 10, 5)
    
    cv2.imshow('src',src)
    cv2.imshow('dst',dst)
    cv2.waitKey()

    샤프닝(sharpening)
    - 영상을 날카롭게 만드는 처리
    - 영상을 선명하게 할 때 사용
    - 중심 화소값과 인접 화소값의 차이를 더 크게 만듬

     

    ✔ 샤프닝

    import cv2
    import numpy as np
    
    src = cv2.imread('dog.jpg')
    
    
    cv2.imshow('src', src)
    
    mask = np.asarray([[-1,-1,-1],
                       [-1,9,-1],
                       [-1,-1,-1]], dtype = np.float32)
    sharpening_img = cv2.filter2D(src,-1, mask)
    cv2.imshow('sharpening_img', sharpening_img)
    
    cv2.waitKey()
    

    에지(edge) 검출
    - 영상에서 화소의 밝기가 급격하게 변하는 부분
    - 영상안에서 상당한 밝기 차이가 있는 곳이고, 대게 물체의 윤곽선(경계선)에 해당
    - 에지를 검출할 수 있으면 물체의 윤곽선을 알 수 있음
    - '캐니 에지 검출' 방법처럼 상당한 수준으로 에지를 신뢰성 있게 검출하는 방법들이 존재
    
    ✔ 캐니 에지 연산자
    - 널리 사용되고 상당히 신뢰성 있는 에지 검출 알고리즘
    * 케니 에지 연산자가 적용되는 순서
        1. 잡음 억제 : 에지를 검출하기 전에 5*5 가우시안 필터를 사용하여 영상의 잡음응 제거
        2. 그라디언트 계산 : Sobel 마스크로 수평 및 수직 방향의 1차 미분값을 얻음
        3. 불필요한 에지를 제거하기 위해 그라디언트의 값이 그라디언트 방향의 인접 화소 중에서 최대값인지를 확인
            (최대값만 남기고 나머지는 제거) -> 얇은 에지 처리를 위해
        4. 모든 에지 후보들이 실제 에지인지 아닌지를 결정
    Canny(영상, 하위 임계값, 상위 임계값, sobel마스크의 크기)

     

    ✔ 캐니

    import cv2
    import numpy as np
    
    src = cv2.imread('rose.bmp')
    cv2.imshow('src',src)
    
    med_val = np.median(src)
    # 하위 임계값을 0 또는 중앙의 70%로 설정하겠다는 의미이다.
    lower = int(max(0, 0.7 * med_val))
    
    # 상위 임계값을 130% 또는 255로 설정하겠다.
    upper = int(min(255,1.3*med_val))
    
    # 임계값을(높은/낮은 값) 만든다음 에지값만 받아내기
    
    dst = cv2.GaussianBlur(src, (3,3), 0,0)
    
    # 마스크가 클 수록 얇아지고 작을수록 커진다. 에지값이
    dst = cv2.Canny(dst,lower, upper,3)
    
    
    cv2.imshow('dst', dst)
    cv2.waitKey()
    
    

    문제
    - 카메라 입력 영상을 출력
    - 스페이스바를 누를때마다 일반영상, 가우시안 피러, 케니 필터
    - 스페이스바 : ord(' ')
    - 8_fitercream.py
    

     

    ✔ 문제

    import cv2
    import numpy as np
    
    cap = cv2.VideoCapture(0)
    
    def blur_filter(img):
        img = cv2.GaussianBlur(img, (0, 0), 3)
        return img
    
    def canny_filter(img):
        med_val = np.median(img)
        lower = int(max(0, 0.7*med_val))
        upper = int(min(255, 1.3*med_val))
    
        img = cv2.GaussianBlur(img, (3, 3), 0, 0)
        img = cv2.Canny(img, lower, upper, 3)
        return img
    
    
    cam_mode = 0
    
    while True:
        ret, frame = cap.read()
    
        if cam_mode == 1:
            frame = blur_filter(frame)
        elif cam_mode == 2:
            frame = canny_filter(frame)
        cv2.imshow('frame', frame)
    
        key = cv2.waitKey(1)
    
        if key == 27:
            break
        elif key == ord(' '):
            cam_mode += 1
            if cam_mode == 3:
                cam_mode = 0
    
    cap.release()

    반응형