본문 바로가기

Programming

[OpenCV] RGB Color를 Grayscale로 변환하기

출처 : http://cinema4dr12.tistory.com/entry/OpenCV-RGB-Color%EB%A5%BC-Grayscale%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0


이번 글에서는 OpenCV에서 RGB 컬러를 Grayscale로 변환하는 방법에 대하여 알아보도록 하겠다. 

우선 이론적으로 살펴보면, 가장 널리 사용되는 방법 중 하나가
Luma Coding(
https://en.wikipedia.org/wiki/Grayscale)을 이용한 방법인데, 수식은 다음과 같다:



여기서, R', G', B'은 Red, Green, Blue 채널에 대한 비디오 시스템의 Gamma-compressed 값이다.

이들로부터 계산된 Y'은 비선형 Luma 컴포넌트(Nonlinear Luma Component)이며, Grayscale된 값이다.

이 수식을 기반으로 RGB 컬러를 Grayscale로 변환하는 OpenCV Source Code는 다음과 같다.



[Source Code 1]

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
60
61
#include <iostream>
#include <opencv2/opencv.hpp>
 
#include <stdlib.h>
#include <stdio.h>
 
using namespace std;
using namespace cv;
 
/* @ function main */
int main( int argc, char** argv )
{
  /// Load an image
  cv::Mat image = cv::imread( {YOUR_IMAGE_PATH}, 1 );
  cv::Mat image_gray;
 
  /// Copy image
  image.copyTo( image_gray );
 
  int nRows = image.rows;
  int nCols = image.cols;
 
  /// Convert to gray
  float fGray = 0.0f;
  float chBlue, chGreen, chRed;
 
  for( int j = 0 ; j < nRows ; j++ ) {
 
    for( int i = 0 ; i < nCols ; i++ ) {
 
      chBlue  = (float)( image.at<cv::Vec3b>(j,i)[0] );
      chGreen = (float)( image.at<cv::Vec3b>(j,i)[1] );
      chRed = (float)( image.at<cv::Vec3b>(j,i)[2] );
 
      fGray = 0.2126f * chRed + 0.7152f * chGreen + 0.0722f * chBlue;
 
      if( fGray < 0.0 ) fGray = 0.0f;
      if( fGray > 255.0 ) fGray = 255.0f;
 
      image_gray.at<cv::Vec3b>(j,i)[0] = (int)fGray;
      image_gray.at<cv::Vec3b>(j,i)[1] = (int)fGray;
      image_gray.at<cv::Vec3b>(j,i)[2] = (int)fGray;
 
    }
 
  }
 
  /// Creates window
  cv::namedWindow( "Image Original", CV_WINDOW_AUTOSIZE );
  cv::namedWindow( "Image Grayed", CV_WINDOW_AUTOSIZE );
 
  /// Show stuff
  cv::imshow( "Image Original", image );
  cv::imshow( "Image Grayed", image_gray );
 
  /// Wait until user press some key
  cv::waitKey();
 
  return 0;
 
}


결과를 살펴보면 다음과 같다.


[Result]

위의 코드는 순전히 이론을 바탕으로 정말 충실하게 픽셀 하나하나 끄집어내어 계산한 것이다. 하지만 매우 효율면에서 떨어질뿐더러 OpenCV가 위의 연산을 수행하는 함수를 제공하지 않을리 없다.

OpenCV의 cvtColor() 함수는 상당히 다양한 Color Space 간 변환을 해주는 함수이며, 계산 속도도 매우 빠르다. 이 함수의 프로토타입은 다음과 같다:

void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 )

src: input image

dst: output image (destination image)

code: color space conversion code

dstCn: number of channels in the destination image


이 함수를 이용하여 RGB를 Grayscale로 변환하는 코드를 작성하면 다음과 같다.



[Source Code 2]

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 <iostream>
#include <opencv2/opencv.hpp>
 
#include <stdlib.h>
#include <stdio.h>
 
using namespace std;
using namespace cv;
 
/* @ function main */
int main( int argc, char** argv )
{
  cv::Mat image, image_gray;
 
  /// Load an image
  image = cv::imread( {YOUR_IMAGE_PATH}, 1 );
 
  if( !image.data ) { return -1; }
 
  /// Convert it to gray
  cv::cvtColor( image, image_gray, CV_RGB2GRAY );
 
  /// Create window
  cv::namedWindow( "Image Original", CV_WINDOW_AUTOSIZE );
  cv::namedWindow( "Image Grayed", CV_WINDOW_AUTOSIZE );
   
  /// Show stuff
  cv::imshow( "Image Original", image );
  cv::imshow( "Image Grayed", image_gray );
   
  /// Wait until user press some key
  cv::waitKey();
 
  return 0;
 
}


당연한 얘기겠지만 소스가 매우 간결해졌다. 결과는 다음과 같다.


[Result]