OpenCV

[OpenCV] 블러처리, 대비

바닷가쟤 2024. 9. 6. 16:07

밝기(명도) 변화

import cv2
import numpy as np

isColor = True

if not isColor:
    # grayscale
    src = cv2.imread('data/cat.jpg', cv2.IMREAD_GRAYSCALE)
    print(src.shape)

    # 밝기 변화
    dst1 = cv2.add(src, 100)
    # dst1 = src + 100
    # 범위를 0~255로 지정하고 덧셈연산을 수행
    # dst1 = np.clip(src+100, 0, 255).astype(np.uint8)
    
if isColor:
    src = cv2.imread('data/cat.jpg')
    # 채널별로 100씩 더한다. 채널의 순서는 BGR
    # 더하는 값은 튜플로 입력
    dst1 = cv2.add(src, (100, 100, 100))
    

cv2.imshow('img', src)
cv2.imshow('dst1', dst1)
cv2.waitKey()
cv2.destroyAllWindows()

add 함수를 사용하여 이미지의 밝기를 증가시킬 수 있다.

src의 행렬 값에 100을 더하는 코드인데, 밝기를 높이는 효과를 준다. 

0~255까지의 명도로 표현할 수 있다면 만약 230+100을 하여 255를 넘으면 자리 올림 후  75가 되어 어두운 이미지가 나오게 된다...!!!

이런 불상사를 막기 위해 cv2.add() 함수로 배열과 배열 또는 배열과 스칼라 값을 더할 때 사용하면 자동으로 각 픽셀 값을 255로 클램핑(clamping)하여 값이 255를 넘지 않게 한다. 


이미지 정규화 (normalize)

# cv2.normalize

import cv2, sys
import numpy as np

src = cv2.imread('data2/Hawkes.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    sys.exit("이미지 로드 실패")
    
# src 이미지에서 최소값과 최대값을 확인
#pixMin, pixMax, _, _ = cv2.minMaxLoc(src)
# print(pixMin, pixMax)

# 이미지를 정규화 0 ~ 255
dst = cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX)
pixMin, pixMax, _, _ = cv2.minMaxLoc(dst)
print(pixMin, pixMax)
# 데이터 결과를 파일로 저장
cv2.imwrite('data2/Hawkes_norm.jpg', dst)

# dst 이미지가 더 선명해짐
cv2.imshow('img', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

더 진해진 사진이 정규화 된 사진이다. 

기존 이미지의 명도는 113~213으로 좁은 범위에서 처리하여 뚜렷하게 구분되지 않았는데, 정규화처리로 명도 범위를 늘려 우리 눈에 더 선명하게 보이도록 처리 한 것이다.

 

정규화를 통해 픽셀 값의 범위를 조정한 후 정규화 된 이미지에서 최소 및 최대 픽셀 값을 출력하는 역할을 한다.

0이 최소값, 255가 최대값으로 정규화하였다.


히스토그램 평활화(Equalize)

import cv2, sys
import numpy as np
import matplotlib.pyplot as plt

src = cv2.imread('data2/Hawkes.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    sys.exit("이미지 로드 실패")
    
# equalize 전 히스토그램
hist1 = cv2.calcHist([src], [0], None, [256], [0, 256])

# equalize 실행
dst = cv2.equalizeHist(src)
dst2 = cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX)

# equalize 후 히스토그램
hist2 = cv2.calcHist([dst], [0], None, [256], [0, 256])

cv2.imshow('normal', src)
cv2.imshow('equalize', dst)
cv2.imshow('normalize', dst2)
plt.plot(hist1)
plt.plot(hist2)
plt.show()
cv2.waitKey()
cv2.destroyAllWindows()

원본 사진과 정규화(normalize), 히스토그램 평활화(equalize) 처리한 사진들 비교이고, 히스토그램은 equalize 한 것과 원본을 비교한 것이다.

상황에 맞게 구분해서 사용하면 된다.

 

평활화는 명암 대비를 향상시키는 방법으로 이미지의 히스토그램을 평활하게 하여 밝기 값이 특정 범위에 몰리지 않고 전체적으로 고르게 분포되도록 만든다. (위 사진에서 주황색 보면 댐)

 

이거 해보니까 그레이스 스케일만 됨 !!!!!!!!

그레이스 스케일 변환 후 적용하고 다시 컬러로 복원 되는지 찾아봤는데 회색 컬러 이미지로 복원 된다고 했다..  


알파값으로 투명도 조절해서 사진 합치기

import cv2
import numpy as np


src1 = cv2.imread('data2/airplane.bmp')
src2 = cv2.imread('data2/field.bmp')

# alpha값이 높을 수록 진해짐
alpha = 0.7
beta = 1 - alpha

dst1 = cv2.addWeighted(src1, alpha=alpha, src2=src2, beta=beta, gamma=0)
    
cv2.imshow('img1', src1)
cv2.imshow('img2', src2)
cv2.imshow('dst1', dst1)
cv2.waitKey()
cv2.destroyAllWindows()

두 이미지를 가중합(weight sum)을 통해 합성하였다.

두 이미지의 픽셀 값을 각각 비율에 따라 가중합하여 새로운 이미지를 만든 것이다.

 


명도 조절 히스토그램으로 나타내기

import cv2
import numpy as np
import matplotlib.pyplot as plt

isColor = False

if not isColor:
    # grayscale
    src = cv2.imread('data2/candies.png', cv2.IMREAD_GRAYSCALE)
    # print(src.shape)

    # 밝기 변화
    dst1 = cv2.add(src, 50)
    hist1 = cv2.calcHist([src], [0], None, [256], [0, 256])
    hist2 = cv2.calcHist([dst1], [0], None, [256], [0, 256])
    
if isColor:
    src = cv2.imread('data/cat.jpg')
    # 채널별로 100씩 더한다. 채널의 순서는 BGR
    # 더하는 값은 튜플로 입력
    dst1 = cv2.add(src, (100, 100, 100))
    
cv2.imshow('src', src)
cv2.imshow('dst', dst1)
plt.plot(hist1)
plt.plot(hist2)
plt.show()
cv2.waitKey()
cv2.destroyAllWindows()

명도 조절 후에는, 각 픽셀 값에 50을 더했으므로 히스토그램이 전체적으로 오른쪽으로 50만큼 이동한 모습을 볼 수 있다.

모든 픽셀값이 일정하게 증가했기 때문인데,,,

값이 255를 넘는 부분은 255로 클램핑되어 히스토그램의 오른쪽 끝(255)에서 값이 많이 쌓이게 된 모습(주황색)을 볼 수 있다.


Blur

import cv2, sys
import numpy as np

src = cv2.imread('data2/rose.bmp', cv2.IMREAD_GRAYSCALE)

if src is None:
    sys.exit("이미지 로드 실패")
    
kernel_size = 5
kernel = (kernel_size, kernel_size)
    
# blur 처리
dst = cv2.blur(src, kernel)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

극명한 차이를 위해 kernel_size를 5로 설정했다. 

dst = cv2.blur(src, (3, 3)) <- 이런 형식으로 사용하면 된다.


GaussianBlur

import cv2, sys
import numpy as np

src = cv2.imread('data2/rose.bmp', cv2.IMREAD_GRAYSCALE)

if src is None:
    sys.exit("이미지 로드 실패")
    
# GaussianBlur 처리 세 번째 인수 sigma 값으로 블러 분포 증가 시키
dst = cv2.GaussianBlur(src, (0, 0), 3)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

가우시안 블러는 kernel을 설정해서 할 필요가 없다.

dst = cv2.GaussianBlur(src, (0, 0), 3) <- 여기서 3자리의 숫자가 커질수록 블러 효과가 커진다.

 

blur와 gaussian blur의 차이

이미지의 노이즈를 줄이거나 부드럽게 만드는 데 사용되는 blur는 적용 방식에 차이가 있다.

1. blur()

주어진 커널 크기 내의 모든 픽셀 값을 평균내어 중심 픽셀에 그 값을 할당하는 방식이다.

커널 크기 안의 모든 픽셀 값을 더한 후 평균을 구해서 해당 영역의 중앙 픽셀 값을 바꾸는 방식이다.

그래서 커널의 값이 커질 수록(3 -> 5) 경계나 특징이 흐릿해진다.

빠르고 계산이 간단하지만 경계가 뚜렷한 이미지에서 세부 정보가 손실 될 수 있다.

 

2. GaussianBlur()

커널 내의 모든 픽셀 값을 가우스 분포에 따라 가중치를 부여하여 블러링한다.

중앙에 가까운 픽셀에는 더 큰 가중치를, 중앙과 먼 픽셀에는 더 작은 가중치를 부여한다.

따라서 이 방식은 자연스럽게 블러 효과를 적용하고 노이즈를 부드럽게 제거하는데 효과적이다.


medianblur

import cv2, sys
import numpy as np

src = cv2.imread('data/noise.bmp', cv2.IMREAD_GRAYSCALE)

if src is None:
    sys.exit("이미지 로드 실패")
    
dst = cv2.medianBlur(src, 3)

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

MedianBlur는 노이즈를 줄이기 위해 사용되는 필터링 기법이다. 

salt-and-pepper noise와 같은 급격한 밝기 변화가 있는 노이즈를 제거하는 데 효과적이다.

(위 사진과 같이 소금후추 뿌린 것처럼 쩜쩜쩜...)

 

커널 내의 모든 픽셀 값을 크기 순으로 정렬한 뒤, 중간값(median)을 중앙 픽셀에 할당하여 잡음을 제거하는 방식이다.

(평균값이 아님!)


 

 

728x90