04-28 14:02
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[OpenCV] Histogram 본문

Programming/OpenCV

[OpenCV] Histogram

cinema4dr12 2015. 10. 3. 12:16

이번 글은 영상의 히스토그램에 대한 것입니다. 히스토그램은 데이터의 특징을 한 눈에 관찰하기 쉽도록 빈도수에 따라 표현한 막대 그래프입니다. 다음 그림은 히스토램의 한 예인데, 그림에서 보듯이 일정한 나이의 간격(10살)에 따라 각 데이터에 대한 빈도수를 표현한 것임을 알 수 있습니다. 




[그림 1.] 히스토그램 예.


디지털 영상에서도 히스토그램은 동일한 개념이며, 주로 영상의 밝기 등에 대한 특징을 알아보기 위해 사용됩니다. Adobe Photoshop 등과 같은 거의 모든 이미지 프로세싱 소프트웨어는 히스토그램 기능을 제공하고 있습니다.



 



[그림 2.] (좌)겨울왕국 이미지. (우)Photoshop의 히스토그램 기능.



디지털 영상에서 히스토그램을 이용하면 이미지가 대체적으로 밝은지 어두운지 정량적인 판단이 가능합니다.


 


[그림 3.] (좌)어두운 이미지의 히스토그램. (우)밝은 이미지의 히스토그램.



[그림 3.]에서 볼 수 있듯이 어두운 이미지의 히스토그램은 좌측으로 분포가 치우쳐져 있으며, 밝은 이미지의 히스토그램은 우측으로 분포가 치우쳐져 있습니다. 밝기의 분포 범위가 모든 범위에 걸쳐 있으면 이상적인 이미지로 여겨지며 이러한 이미지는 명암대비가 좋은 이미지라고 표현됩니다.

OpenCV를 이용한 히스토그램 계산

OpenCV에서 히스토그램을 계산하는 함수는 calcHist 이며 이 함수의 Prototype은 다음과 같습니다:


void calcHist( const Mat* images,
		   int nimages, 
		   const int* channels,
		   InputArray mask,
		   OutputArray hist,
		   int dims,
		   const int* histSize,
		   const float** ranges,
		   bool uniform = true,
		   bool accumulate = false


 

 Argument

 Description

 images

 소스 어레이(source .

 nimages

 소스 이미지 개수.

 channels

 히스토그램 계산에 사용되는 채널 리스트.

 mask

 마스크 이미지. (옵션)

 hist

 히스토그램 출력.

 dims

 히스토그램 차원.

 histSize

 각 차원의 히스토그램 사이즈 어레이(array).

 ranges

 각 차원의 히스토그램 빈(Bin) 경계의 dims 어레이.

 uniform

 히스토그램의 균일 여부를 결정하는 플래그(Flag).

 accumulate

 축적 여부를 결정하는 플래그(Flag).



Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
 
#include <iostream>
 
using namespace std;
using namespace cv;
 
/*/////////////////////////////////////
@ function: main
*//////////////////////////////////////
int main()
{
    cv::Mat gray = cv::imread( {YOUR_IMAGE_PATH}, IMREAD_GRAYSCALE );
    cv::namedWindow( "Gray"1 );
    cv::imshow( "Gray", gray );
  
    /// Initialize parameters
    int histSize = 256;    // bin size
    float range[] = { 0255 };
    const float *ranges[] = { range };
  
    /// Calculate histogram
    cv::MatND hist;
    cv::calcHist( &gray, 10, cv::Mat(), hist, 1&histSize, ranges, truefalse );
      
    /// Show the calculated histogram in command window
    double total;
    total = gray.rows * gray.cols;
     
    forint h = 0 ; h < histSize ; h++ )
    {
        float binVal = hist.at<float>( h );
        std::cout << " " << binVal;
    }
  
    /// Plot the histogram
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound( (double) hist_w/histSize );
 
    cv::Mat histImage( hist_h, hist_w, CV_8UC1, cv::Scalar( 000 ) );
    cv::normalize( hist, hist, 0, histImage.rows, NORM_MINMAX, -1, cv::Mat() );
 
    forint i = 1 ; i < histSize ; i++ )
    {
        line( histImage, cv::Point( bin_w * ( i - 1 ), hist_h - cvRound( hist.at<float>( i - 1 ) ) ) ,
                       cv::Point( bin_w * ( i ), hist_h - cvRound( hist.at<float>( i ) ) ),
                       cv::Scalar( 25500), 280  );
    }
 
    cv::namedWindow( "Result"1 );
    cv::imshow( "Result", histImage );
  
    cv::waitKey(0);
 
    return 0;
}
cs


Output


[Grey Level Image]


[Histogram from the Grey Level Image]


[Histogram Values]

히스토그램 스트레칭

이미지 프로세싱을 통해 명암 대비를 더욱 좋게 만들 수 있는데, 각 R, G, B 채널에 대하여 히스토그램을 얻을 수 있으므로 채널 별로 전 구간에 걸쳐 골루 분포될 수 있도록 처리하면 좋은 명암대비의 이미지를 얻을 수 있습니다. 이러한 기법을 히스토그램 스트레칭(Histogram Stretching)이라고 하며, 기본 명암 대비 스트레칭 기법엔드-인(End-In) 탐색 기법이 있습니다.

기본 명암 대비 스트레칭 기법

기본 명암 대비 스트레칭 기법은 특정 구간에 집중된 픽셀의 밝기 영역을 [low, high]로 지정된 범위로 확장시키는 기법입니다. 예를 들어, 8비트 그레이 레벨 영상인 경우 28 = 256 (0~255)이므로, 이 경우 이 기법이 제시하는 픽셀 밝기(pixel intensity)의 계산은 다음과 같습니다:


\( \mathrm{new \ pixel \ intensity} = \displaystyle{\frac{\mathrm{original \ pixel \ intensity} - \mathrm{low}}{\mathrm{high} - \mathrm{low}} \times 255} \)


이렇게 새로운 픽셀의 밝기를 계산하면 밝기는 집중된 범위의 밝기는 0~255의 분포로 고르게 재편성 됩니다.

엔드-인 탐색 기법

픽셀 밝기가 전 구간에 분포되기는 하였으나, 특정 부분에 대부분의 밝기가 집중되는 경우가 있습니다. 이 경우, 밝기의 최저 최고 임계값을 정의하여 임계값으로 정의된 구간을 전 구간으로 분포하게 만들고 최저 임계값 보다 작은 픽셀 밝기 값은 0으로, 최고 임계값 보다 큰 픽셀 밝기 값은 255(8비트 그레이 레벨의 경우)로 지정하게 하는 방법입니다. 따라서 엔드-인 탐색 기법은 기본 명암 대비 스트레칭 기법을 확장한 것이라 할 수 있으며, 새로운 픽셀 밝기는 다음과 같이 계산됩니다:


\( \mathrm{new \ pixel \ intensity} = \begin{cases} 0, \ \mathrm{old \ pixel} \le \mathrm{low} \\ \displaystyle{\frac{\mathrm{old \ pixel} - \mathrm{low}}{\mathrm{high} - \mathrm{low}}} \times 255, \mathrm{low} \le \mathrm{old \ pixel \ intensity} \le \mathrm{high} \\ 255, \mathrm{high} \le \mathrm{old \ pixel \ intensity} \end{cases} \)

히스토그램 평활화

히스토그램 평활화(Histogram Equalization)는, 영상의 히스토그램을 조절하여 명암 분포가 빈약한 영상을 균일하게 만들어주는 기법을 의미합니다.

히스토그램 평활화 작업은 다음과 같은 특징을 갖습니다:

(1) 영상의 밝기 분포를 재분배하여 명암 대비를 최대화 함.

(2) 명암 대비 조정을 자동으로 수행함.

(3) 각 명암의 빈도는 변경되지 않음.

계산 과정

1.  명암 값 j의 빈도 수 hist[j]를 계산하여 입력 영상의 히스토그램을 생성합니다.

2.  각 명암 값 i에서 0 - i 까지의 누적 빈도 수(누적합)를 계산합니다.


      \( \mathrm{sum}[i] = \displaystyle{ \sum_{j=0}^{i}{\mathrm{hist}[j]} } \)

    

3.  2단계에서 구한 누적 빈도 수를 정규화합니다.

      \( \mathrm{n}[i] = \mathrm{sum}[i] \times \displaystyle{\frac{1}{N}} \times I_{max} \)

OpenCV를 이용한 히스토그램 평활화

OpenCV에서의 히스토그램 평활화 함수는 equalizeHist 함수이며, Prototype은 다음과 같습니다:


void equalizeHist( InputArray src, OutputArray dst );

 

 Argument

 Description

 src

 8-비트 단일 채널 이미지.

 dst

 src와 동일한 크기와 타입의 destination 이미지.



Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
 
#include <iostream>
 
using namespace std;
using namespace cv;
 
/*/////////////////////////////////////
@ function: main
*//////////////////////////////////////
int main()
{
    cv::Mat src1;
    src1 = cv::imread( {YOUR_IMAGE_PATH}, CV_LOAD_IMAGE_COLOR );
     
    cv::Mat gray, dst;
  
    /// convert to gray
    cv::cvtColor(src1, gray, CV_BGR2GRAY);
    cv::namedWindow( "Original image", CV_WINDOW_AUTOSIZE );
    cv::imshow( "Original image", gray );
  
    /// hisogram equalization
    cv::equalizeHist( gray, dst );
  
    cv::namedWindow( "image", CV_WINDOW_AUTOSIZE );
    cv::imshow( "image", dst );
  
    cv::waitKey(0);
 
    return 0;
}
 
cs



[Before Histogram Equalization]


[After Histogram Equalization]

Comments