서로 다른 조건에서 생성이 된 두 개의 영상을 비교하기 위해서는 먼저 영상을 정규화시키어야 한다. 쉽게 생각할 수 있는 정규화의 방법은 두 개의 영상이 동일한 히스토그램을 같도록 만들면 된다. 어떻게 동일한 히스토그램을 만들 수 있는가? 간단히 생각할 수 있는 방법은 주어진 영상의 히스토그램을 전 픽셀에 걸쳐서 균일한 빈도를 보이는 히스토그램이 되도록 변환을 하는 것이다. 즉, 히스토그램을 평탄화시키는 것이다. 이 변환을 $F(x)$라고 하면, 입력 영상의 픽셀 값 $x$는 새로운 픽셀 값 $y = F(x)$로 바뀐다. 영상의 히스토그램은 픽셀 값의 빈도를 나타내므로 확률 밀도 함수로 해석할 수 있고 (픽셀 값을 연속 변수로 볼 때) 주어진 영상의 확률 밀도 함수를 $P(x)$라고 하자. 그러면 $P(x) dx$는 픽셀 값이 $[x, x+dx]$인 픽셀이 영상에서 나타날 확률을 의미한다. 변환 후에서는 임의의 픽셀 값이 균일해야 하므로 확률 밀도 함수는 상수 $a$이고, 픽셀 값의 구간이 $[0,255]$ 이므로 $a = 1/ 255$로 주어진다. 따라서, 변환이 확률을 보존하기 위해서는 $$P(x) dx = a dy$$을 만족해야 하므로 변환 후 픽셀 값 y와 변환 전 픽셀 값 x사이의 관계를 알 수 있다. $$\frac {dy}{ dx} = \frac {1}{a} P(x) $$ 이 식을 적분하면, $$y = F(x) = \frac {1}{a} \int_0^x P(x') dx' = 255\times \text {cumulative sum of } P(x)$$ 즉, 히스토그램을 평탄화시키는 변환은 원래 영상 히스토그램의 누적합을 전체 픽셀 수로 나눈 값,
$$k \rightarrow F(k)=255 \times \frac {\sum_{i=0}^{k} H [i] - H[0]}{ \sum_{i=0}^{255} H [i] - H[0]}$$으로 결정된다($0\to 0$이도록 $H[0]$을 뺀다). 영상의 히스토그램은 이산적이기 때문에 실제로 모든 픽셀 값에서 균일하게 나타나지 않지만, 구간 변환은 거의 일정하게 나타난다. 이 변환을 거친 영상의 누적 히스토그램(cumulative histogram)을 $y$-축 픽셀 값을 $x$-축으로 해서 그리면 거의 일직선으로 증가하는 모양을 나타낸다.
이 히스토그램의 평탄화는 픽셀 값이 좁은 영역에 몰려있는 영상을 전 영역에 분포하도록 한다. 인간은 영상의 밝기에 의해서 보다는 밝고 어두움의 변화의 크기에 의해서 인지도가 증가하게 되는데, 평탄화된 영상은 보다 쉽게 인식이 될 수 있는 구조를 가진다.
std::vector<BYTE> histogram_eq(const std::vector<BYTE> &src) {
int hist[256] = {0}, cum[256], map[256];
for (int k = src.size(); k-->0;) ++hist[src[k]];
for (int k = 0, s = 0; k < 256; k++) {
s += hist[k]; cum[k] = s;
}
double factor = double(255) / (cum[255] - cum[0]) ;
for (int k = 0; k < 256; k++) {
int x = int(factor * (cum[k] - cum[0]));
map[k] = x > 255 ? 255: x;
}
std::vector<BYTE> dst(src.size());
for (int k = src.size(); k-->0;) dst[k] = map[src[k]];
return dst;
}
'Image Recognition > Fundamental' 카테고리의 다른 글
2차원 Gaussian 분포 생성 (0) | 2020.12.10 |
---|---|
PCA Line Fitting (0) | 2020.11.12 |
Least Squares Fitting of Circles (0) | 2020.11.11 |
Integer Sqrt (0) | 2020.11.11 |
Parabolic Interpolation in Peak Finding (3) | 2020.11.10 |