본문 바로가기

C계열/C#

[C#] 히스토그램으로 동일 이미지 판별하기

먼저 히스토그램은 그림을 구성하는 각 화소점들의 갯수를 카운트한 것이다. 

 

즉, 100이란 그림이 있을 때 그 100이란 그림을 구성하고 있는 화소점들이 0~255까지 값을 갖고 있는데

 

그 0~255가 각각 몇개인지 세는 것이다.

 

예를 들자면 이 작은 이미지에도 RGB 3개의 화소점 값들이 들어있고 

 

64*64개의 화소에 *3개의 RGB값이 들어있다는 것이다. 

 

각 RGB는 0~255까지의 정수만 포함하고 있기 때문에 히스토그램화하기 위해서는 그림 배열을 읽기만 하면 된다.

 

// 그림의 RGB값을 불러왔다고 하자.

byte[,] ImageR= new byte[64,64];    //64*64크기의 이미지의 Red정보를 불러올 배열을 만든다.
byte[,] ImageG= new byte[64,64];    //64*64크기의 이미지의 Green정보를 불러올 배열을 만든다.
byte[,] ImageB= new byte[64,64];    //64*64크기의 이미지의 blue정보를 불러올 배열을 만든다.

// 각자 방법으로 ImageR, G, B 배열에 그림의 RGB값을 받았다고 할 때.

// RGB의 0~255 값의 갯수를 저장할 배열 생성

byte HistoR= new byte[256];    //0~255까지 값을 저장해야 하므로 당연히 256개여야 한다.
byte HistoG= new byte[256];
byte HistoB= new byte[256];

for(int i = 0; i<64;i++)    // 그림의 크기에 맞게 반복문 실행
{
   for(int k=0; k<64;k++)
   {
       HistroR[ImageR[i,k]]++;    //각 화소점 값의 갯수를 HistroR에 저장한다.
       HistroG[ImageG[i,k]]++;
       HistroB[ImageB[i,k]]++;
   }
}

  히스토그램을 생성했다면 히스토그램을 대조하기만 하면 된다. 

 

히스토그램의 대조는 역시 for문을 이용한다.

 

// 이미 만든 그림의 히스토그램을 Histo 비교할 그림의 히스토그램을 CHisto라고 한다면

for(int i=0; i<256;i++)    //어차피 히스토그램은 0~255까지 밖에 없다.
{
    if((HistR[i]==CHistroR[i])&&(HistG[i]==CHistroG[i])&&(HistB[i]==CHistroB[i]))
    {
        MessageBox.Show("두 개의 그림은 같습니다.");
    }
    else
    {
        MessageBox.Show("두개의 그림은 다릅니다!");
    }
    
}

 이렇게 비교하는 이유는 그림 크기가 아무리 커져도 RGB의 값은 0~255를 넘어갈 수가 없고 

 

각 화소점의 값의 갯수가 같지만 전혀 다른 그림일 가능성은 낮은 편이기 때문이다. 

 

상당히 고전적이고 지금도 많이 사용하는 기법이라고 한다.

 

거기에 같은 그림의 상하좌우반전과 180도 회전을 시켜도 같은 그림으로 인식하는 문제가 있다. 

 

위아래가 바뀌어도 화소점 값의 정보는 같은 히스토그램으로는 다른 그림이라 인식할 수 없다.

 

이 문제를 간단하게 해결하는 방법은 그림의 1/4영역을 히스토그램화하여 비교하는 것이다. 

 

이것으로 상하좌우반전 180도 회전과 같은 문제

 

그리고 극소수의 화소점 값의 갯수가 같은 그림의 문제도 벗어날 수 있을 것이다. 

 

// 이미 만든 그림의 히스토그램을 Histo 비교할 그림의 히스토그램을 CHisto라고 한다면

// 그림의 1/4영역의 히스토그램을 저장할 배열 QHisto 
byte[] QHistoR=new byte[256];    // 그림의 1/4영역의 히스토그램을 저장할 배열
byte[] QHistoG=new byte[256];
byte[] QHistoB=new byte[256];

for(int i=0; i<256;i++)    //어차피 히스토그램은 0~255까지 밖에 없다.
{
    if((HistoR[i]==CHistoR[i])&&(HistoG[i]==CHistoG[i])&&(HistoB[i]==CHistoB[i]))
    {
        for(int ni=0;ni<64/2;ni++)
        {
            for(int nk=0;nk<64/2;nk++)
            {
                QHistoR[ImageR[i,k]]++
                QHistoG[ImageG[i,k]]++
                QHistoB[ImageB[i,k]]++                                
            }
        }        
//비교할 그림의 1/4히스토그램을 QCHisto로 저장했다고 가정한다.        
    if((QHistoR[i] == QCHistoR[i])&&(QHistoG[i] == QCHistoG[i])&&(QHistoB[i] == QCHistoB[i]))
    {
        MessageBox.Show("두 개의 그림은 같습니다.");
    }
                      
    }
    else
    {
        MessageBox.Show("두개의 그림은 다릅니다!");
    }
    
}

 그러나 남은 2/4, 3/4, 4/4영역 중 한 곳의 그림이 같은 경우도 있다. 

 

예를 들자면 영국의 유니언 잭의 2/4영역에 커피자국을 났다면 상하좌우, 180회전을 인지하게 되버린다.

 

그렇다면 경우에 따라선 설정한 1/4영역에 대한 히스토그램이 같은 일이 일어난다.

 

이런 경우는 매우 드물겠지만 남은 영역의 히스토그램을 만들어 대조하는 방법이 있다. 

 

거기는 알아서 하자