CS과목/디지털영상처리

[디지털영상처리] 03. 밝기 변환과 공간 필터링

johyeongseob 2024. 9. 22. 17:32

교재:디지털영상처리 제3판 (2013, Rafael C. Gonzalez)

 

3.1 배경

 

3.1.1 밝기 변환과 공간 필터링의 기초

 이 절에서 논의되는 모든 영상 처리 기법들은 단순히 영상의 화소들을 포함하는 평면인 공간 도메인에서 구현된다. 공간 도메인 기법들은 영상의 화소들에 직접 적용한다: g(x, y) = T[f(x, y)]. 여기서 f(x, y)는 입력 영상, g(x, y)는 출력 영상, T는 점 (x, y)의 이웃에 대해 정의된 f에 대한 대한 연산자이다. (x, y)가 영상의 임의의 위치일 때, 이 점을 포함하는 작은 영역이 (x, y)의 이웃이다. 보통, 이웃은 (x, y)를 중심으로 하는 직각 사각형이며 영상보다 훨씬 작은 크기이다. 가장 작은 이웃의 크기는 1x1이다. 이 경우, g가 단일 점 (x, y)에서의 f의 값에만 종속되며, s =T(r)의 T는 다음 식의 형태의 밝기(또는 그레이-레벨 또는 매핑) 변환 함수가 된다. 여기서 표기의 간편성을 위해, s와 r은 각각 점 (x, y)에서의 g와 f의 밝기를 나타내는 변수들이다.

 

3.2 기본적 밝기 변환 함수들

 

밝기 변환에 대한 소개로서, 영상 개선을 위해 자주 사용되는 세 가지 기본 함수 유형을 보여주는 아래 그림을 고려하자: 선형(Negative 및 Identity), 로가리듬(log 및 Inverse log), 거듭제곱-법칙(nth power 및 nth root).

 

3.2.1 영상 네거티브

 밝기 레벨의 범위가 [0, L - 1]인 영상의 네거티브는 다음 변환에 의해 만든다: s = L - 1 - r 이런 방식으로 영상의 밝기 레벨을 반전시킨다. 이 유형의 처리는 영상의 어두운 영역에 놓여 있는 흰색이나 그레이 디테일을 개선시키는 데 특히 적합하다.

 

3.2.2 로그 변환

 로그 변환의 일반형은 s = clog(1 + r)이다. 로그 곡선의 모양은 이 변환이 입력의 낮은 밝기 값들의 좁은 범위를 넓은 범위의 출력 레벨들로 매핑한다는 것을 보여준다. 높은 값의 입력 레벨들에 대해서는 그 반대이다. 입력의 어두운 화소들의 값들을 신장시키고, 높은 레벨의 값들을 압축하고자 할 때 이런 변환을 사용한다.

 

3.2.3 거듭제곱-법칙(Gamma) 변환

 거듭제곱-법칙 변환의 기본 형태는 $s=c \times r^{\gamma}$이다. 여기서 c와 γ는 양의 상수이다. 아래 그림은 다양한 γ에 대한 s 대 r의 곡선들을 보여준다. 로그 변환의 경우에서와 같이, 1보다 작은 γ값에 대한 거듭제곱-법칙 곡선들은 좁은 범위의 어두운 입력 값들을 넓은 범위의 출력 값들로 매핑하며, 더 큰 값의 입력 레벨들에 대해서는 그 반대이다. 관습적으로, 거듭제곱-법칙 공식의 멱 지수를 gamma라고 부른다. 이 거듭제곱-법칙 반응 현상을 보정하는 데 사용되는 프로세스를 gamma 보정이라고 부른다.

 

3.2.4 구간 선형 변환 함수

 앞의 세 개의 방법들에 대한 보완적인 접근법은 구간 선형 함수(piecewise linear function)를 사용하는 것이다. 가장 간단한 구간 선형 함수 중 하나는 콘트라스트-스트레칭 변환이다. 낮은 콘트라스트 영상의 원인은 나쁜 조명, 영상화 센서의 좁은 동적 범위, 영상 획득 시 잘못된 조리개 설정 등일 수도 있다. 콘트라스트 스트레칭은 영상의 밝기 레벨 범위를 넓혀서 기록 매체나 표시 장치의 전체 밝기 범위를 사용하게 하는 것이다.

 

 

3.3 히스토그램 처리

 

 밝기 레벨의 범위가 [0, L - 1]인 디지털 영상의 히스토그램은 이산 함수 $h(r_k)=n_k$ 이다. 여기서 rₖ는 k번째 밝기 값이며, nₖ는 영상에서 밝기 rₖ를 갖는 화소들의 수이다. 보통 히스토그램의 성분 각각을 영상의 전체 화소 수로 나누어 히스토그램을 정규화한다. 영상의 전체 화소 수는 MN이며 정규화된 히스토그램은 $p(r_k)=\frac{n_k}{MN}$ 이다. p(rₖ)는 영상에서 밝기 레벨 rₖ가 발생할 확률의 추정이다. 정규화된 히스토그램의 모든 요소의 합은 1이다.

 

3.3.1 히스토그램 평활화

 다음 형태의 변환(밝기 매핑)에 포점을 맞추자: s = T(r)    0 ≤ r ≤ L - 1. 이후 다음과 같은 가정을 하자:

T(r)은 0≤r≤L - 1 구간의 엄밀 단조 증가 함수이다.    (역변환 $r=T^{-1}(s)$에서 매핑이 가능하기 위해!)

0≤r≤L - 1에 대해 0≤T(r)≤L - 1이다.

 히스토그램 평활화 과정은 다음과 같다

 

  1. $P_s(s)=1$ (uniform distribution)
  2. $P_s(s)ds=P_r(r)dr$
  3. $\text{PDF}(r)=P_r(r)=P_s(s)\times \frac{ds}{dr}=1\times T'(r)$
  4. $s=T(r)=\int_{0}^{r}P_r(w)dw=\text{CDF}(r)=P(x\leq r)$

 

Histogram equalization transform, 그림에서 Ps(s) = 1/(L - 1) 이지만 위의 평활화 과정은 정규화로 계산하였다.

 

위의 식에서 변환의 이산 형태는 아래와 같다.

 

$s_k=T(r_k)=(L-1)\times \sum_{j=0}^{k}P_r(r_j)=\frac{L-1}{MN}\times \sum_{j=0}^{k}n_j,\quad (k=0,1,2,...,L-1)$

 

따라서 처리된 (출력) 영상은 밝기가 rₖ인 입력 영상의 각 화소를 출력 영상에서 레벨이 $s_k$인 대응 화소로 매핑해서 얻어진다. 이 식의 변환 (매핑) $T(r_k)$를 히스토그램 평활화 또는 히스토그램 선형화 변환이라고 부른다.

 

3.4 공간 필터링의 기초

 

3.4.1 공간 필터링의 매커니즘

 공간 필터가 (1)이웃(일반적으로 작은 직사각형)과 (2)이웃에 포함되는 영상 화소들에 수행되는 미리 정의된 연산으로 구현된다. 필터링은 이웃의 중심 좌표와 같은 좌표를 가지며 필터링 연산의 결과를 값으로 하는 새로운 화소를 만든다. 필터의 중앙이 입력 영상의 각 화소를 거쳐감에 따라 처리(필터링)된 영상이 생성된다. 만일 영상 화소들에 수행되는 연산이 선형적이면, 그 필터는 선형 공간 필터라고 부른다. 영상의 임의의 점 (x, y)에서의 필터 응답 g(x, y)는 필터 계수들과 필터가 덮고 있는 영상 화소들의 곱들의 합(sum of products, S-o-P)이다. 일반적으로 m x n 크기의 필터에 의한 M x N 크기의 영상의 선형 공간 필터링이 다음 식으로 주어진다:

 

$g(x,y)=\sum_{s=-a}^{a}\sum_{t=-b}^{b}w(s,t)f(x+s,y+t)$

 

여기서 w의 각 화소가 f의 모든 화소를 방문하도록 x와 y가 바뀐다.

 

3.4.2 공간 코릴레이션과 컨볼루션

 선형 공간 필터링을 수행할 때 반드시 이해하고 있어야 할 두 가지 밀접하게 관련된 개념들이 있다: 코릴레이션 컨볼루션. 코릴레이션은 필터 마스크를 영상 위로 이동시키면서 각 위치에서 S-o-P를 계산하는 것이다. 컨볼루션은 필터가 먼저 180' 회전된다는 것을 제외하고는 메커니즘이 같다. 컨볼루션의 개념은 선형 시스템 이론의 초석이 된다. 컨볼루션의 기본 특징은 어떤 함수를 단위 임펄스(하나만 1이고 나머지는 모두 0인 함수, 이산 단위 임펄스)와 컨볼루션시키면, 임펄스 위치에 그 함수가 복제되어 나온다는 것이다. 따라서, 컨볼루션을 하려면, 한 함수를 180' 회전시키고 코릴레이션 연산을 수행하면 된다. 두 함수 중 어느 것을 회전시키는가는 문제되지 않는다.

 

3.4.3 선형 필터링의 벡터 표현

 코릴레이션이든 컨볼루션이든, 마스크의 특성 응답 R에 관심이 있다면, 때때로 S-o-P를 다음과 같이 쓰는 것이 편리하다.

 

$R=w_1z_1+w_2z_2+\cdots++w_{mn}z_{mn}=\sum_{k=1}^{mn}w_kz_k=w^Tz $

 

여기서 w들은 m x n 필터의 계수들이며, z들은 필터에 의해 둘러싸인 대응 영상 밝기들이다.

 

3.4.4 공간 필터 마스크 만들기

 m x n 선형 공간 필터를 만들려면 mn개의 마스크 계수를 정해야 한다. 또한 계수들은 필터의 임무에 의거해서 선정된다. 이때 선형 필터링으로 우리가 할 수 있는 것은 S-o-P를 구현하는 것임을 명심한다. 비선형 필터를 만들려면, 이웃의 크기와 이웃에 포함되는 영상 화소들에 수행되는 연산(들)을 규정해야 한다. 예를 들면, max 연산은 비선형이며, 영상의 임의의 점 (x, y)를 중심으로 하는 5 x 5 max 필터는 25개 화소들의 최대 밝기 값을 구해서, 그 값을 처리된 영상의 (x, y)위치에 부여한다. 비선형 필터는 매우 강력하며, 어떤 응용에서는 선형 필터로 처리할 수 없는 기능들을 수행할 수 있다.

 

3.5 스무딩 공간 필터

 

 스무딩 필터는 블러링(blurring)과 노이즈 축소에 사용된다. 블러링은 (큰) 객체 추출 전에 영상으로부터 작은 디테일을 제거하거나, 선 또는 곡선의 작은 끊김을 잇는 것과 같은 전처리 작업에 사용된다.

 

3.5.1 스무딩 선형 필터 

 스무딩 선형 공간 필터의 출력(응답)은 단순히 필터 마스크의 이웃에 포함된 화소들의 평균이다. 이 필터는 평균(화) 필터 혹은 저역통과 필터라고 불린다. 스무딩 필터의 배경 개념은 간단하다. 영상의 각 화소의 값을 필터 마스크에 의해 정의되는 이웃에 있는 밝기 레벨들의 평균으로 교체함으로써, 밝기에서의 "가파른(sharp)" 이행(transition)을 감소시킨다. 랜덤 노이즈가 일반적으로 밝기 레벨에서의 가파른 이행으로 구성되기 때문에, 스무딩의 가장 두드러진 응용은 노이즈 축소이다. 그러나 에지도 가파른 밝기 이행의 특징을 가지므로, 평균 필터는 에지를 흐리게 하는 바람직스럽지 못한 부작용을 가진다. 필터링은 m x n 크기에서 계수 값을 1을 하고 전체 영상을 1/mn인 정규화 상수로 나누어진다. 모든 계수가 같은 공간 평균 필터는 상자 필터(box filter)라고도 불린다. 가중 평균 필터(weighted average)는 화소들이 서로 다른 계수들로 곱해진다. 이렇게 함으로써, 어떤 화소들에는 더 많은 중요성(가중치)을 부여하고, 그 대신에 다른 화소들의 중요성은 희생된다. 이 마스크는 중앙의 화소를 다른 것들보다 더 큰 값으로 곱해지며, 그럼으로써, 평균을 계산할 때 이 화소에 더 큰 중요성이 부여된다. 다른 화소들은 마스크의 중앙으로부터의 거리에 반비례하게 가중된다. 이는 스무딩 프로세스에서의 블러링을 축소하려는 시도이다.

 

3.5.2 순서-통계(비선형) 필터

 순서-통계 필터는, 그 응답이 필터에 의해 둘러싸인 영상 영역에 담긴 화소들을 정렬(순위를 매김)하고, 순위에 의해 결정된 값으로 중앙 화소의 값을 교체하는 것에 기반하는 비선형 공간 필터이다. 이 부류에서 가장 잘 알려져 있는 필터는 중간(값) 필터로서, 화소의 값을 그 이웃의 밝기 값들의 중간값으로 교체한다. 이는 특정 유형의 노이즈에 대해 우수한 노이즈-축소 성능을 갖고, 그러면서도 비슷한 크기의 선형 스무딩 필터보다 훨씬 덜 블러링시키기 때문이다. 중간값 필터는 영상에 흑색과 백색의 점들이 뿌려진 것 같은 모양으로 인해 소금과 후추 노이즈라고도 불리는 임펄스 노이즈에 대해 특히 효과적이다.

 

3.6 샤프닝 공간 필터

 

 샤프닝의 주요 목적은 밝기의 이행을 강조하는 것이다. 바로 앞 절에서 이웃의 화소 평균화에 의해 영상 블러링이 공간 도메인에서 달성될 수 있다는 것을 보았다. 평균화는 적분과 비슷하므로, 샤프닝이 '공간 미분에 의해 달성될 수 있다'로 결론내리는 것은 논리적이다. 이 절에서의 논의가 디지털 미분에 의한 샤프닝용 연산자들을 정의 및 구현하는 다양한 방법들을 다룬다. 근본적으로, 미분 연산자의 응답의 세기는 연산자가 적용된 점에서의 영상의 밝기 불연속 정도에 비례한다. 따라서 영상 미분은 에지 및 다른 불연속들은 강조하고, 밝기가 서서히 변하는 영역들은 경시한다.

 

3.6.1 기초

 디지털 함수의 미분은 차이에 의해 정의된다. 1-D 함수 f(x)의 1차 미분의 기본 정의는 차이이다.

 

$\frac{\partial f}{\partial x}=f(x+1)-f(x)$

 

여기에 편미분을 사용한 이유는 두 변수의 영상 함수 f(x, y)를 고찰할 때와 똑같은 표기를 사용하기 위해서이다. f(x)의 2차 미분을 다음과 같이 정의한다.

 

$\frac{\partial^2 f}{\partial x^2}=f(x+1)+f(x-1)-2f(x)$

 

디지털 영상에서의 에지는 흔히 비탈처럼 생긴 밝기 이행이다. 이때 비탈상에서 1차 미분이 0이 아니기 때문에 영상의 1차 미분은 두꺼운 에지들을 만든다. 이로부터, 2차 미분이 미세한 디테일을 1차 미분보다 훨씬 잘 개선한다고 결론짓는다. 이 특성은 영상을 선명하게 만드는 데 이상적이다. 또한 2차 미분이 1차 미분모다 구현하기에 훨씬 쉽기 때문에 우선 2차 미분에 관심을 집중하겠다.

 

3.6.2 영상 샤프닝을 위한 2차 미분의 사용 - Laplacian

 Laplacian은 다음과 같이 정의된다.

 

$\triangledown^2f(x,y)=\frac{\partial^2f}{\partial x^2}+\frac{\partial^2f}{\partial y^2}=f(x+1,y)+f(x-1,y)+f(x,y+1)+f(x,y-1)-4f(x,y)$

 

어떠한 차수의 미분이든 선형 연산이기 때문에, Laplacian은 선형 연산자이다. 그리고 미분 연산자이므로, 영상의 밝기 불연속을 돋보이게 하며, 서서히 변하는 밝기 레벨을 갖는 영역을 경시한다. 이것은 어둡고 특징 없는 배경에 포개진, 회색 에지 선들 및 다른 불연속들을 갖는 영상을 만드는 경향이 있을 것이다. 단순히 Laplacian 영상을 원래 영상에 더함으로써 Laplacian의 샤프닝 효과를 보존하면서도 배경 특징들을 "복구"할 수 있다.

 

Assignment #2: histogram equalization 구현하기

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

# 이미지 읽기
img_path = "C:/Users/johs/Desktop/DIP/assignment2/dgu_night.png"
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)

# 히스토그램 평탄화
nk, rk = np.histogram(img.flatten(), 256, [0,256])
Pr = nk/sum(nk)
cdf = Pr.cumsum()
sk = (cdf*(2**8-1)).astype('uint8')
eq_img = sk[img]

cv2.imwrite("C:/Users/johs/Desktop/DIP/assignment2/dgu_night_equalization.png", eq_img)

# 원본 이미지와 평탄화된 이미지의 히스토그램 계산
hist_orig, bins_orig = np.histogram(img.flatten(), 256, [0,256])
hist_eq, bins_eq = np.histogram(eq_img.flatten(), 256, [0,256])

 

Assignment #3: sobel filter 구현하기

import cv2
import numpy as np

dgu_gray = "C:/Users/johs/Desktop/DIP/dgu_gray.png"
img = cv2.imread(dgu_gray, 0)
row = img.shape[0]
col = img.shape[1]

# Gx와 Gy 커널 정의
Gx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=np.float32)
Gy = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=np.float32)

gradient_x = np.zeros((row-2, col-2))
gradient_y = np.zeros((row-2, col-2))

# Gx와 Gy 커널을 사용하여 2D 컨벌루션 수행
for i in range(1, row-2):
    for j in range(1, col-2):
        gradient_x[i-1, j-1] = np.sum(Gx * img[i-1:i+2, j-1:j+2])
        gradient_y[i-1, j-1] = np.sum(Gy * img[i-1:i+2, j-1:j+2])

# 그래디언트 크기 계산
gradient_magnitude = np.abs(np.sqrt(gradient_x**2 + gradient_y**2))

# 엣지 검출을 위한 임계값 설정
threshold = 225
out_image = np.where(gradient_magnitude > threshold, 255, 0).astype(np.uint8)