Fogeaters, Light The World.

12

2016-Mar

[OpenCV] 영상 이진화 & 레이블링(Blob Labeling)

작성자: title: MoonBlonix IP ADRESS: *.148.87.98 조회 수: 1536

아래 문자인식 강좌와 동일한 블로그의 글이다.


출처 :: http://martinblog.net/824


예제파일

http://fogeaters.cafe24.com/xe/board11/13777



IplImage 타입의 영상을 이진화 하기 위해 사용하는 함수는 cvThreshold라는 함수이며,
이는 입력으로 들어가는 영상의 각 채널을 이진화 한다.
이런 이유로 컬러영상(3개 채널)을 이진화 하는 경우, R, G, B 각각을 이진화 하기 때문에
아래와 같이 의도하지 않은 영상을 얻게 될 수도 있다.



그런 이유 때문에 이진화 전에는 cvCvtColor()를 이용하여 Gray로 변환 후 이진화 한다.
cvCvtColor()의 세 번 째 인수는 어떤 컬러맵으로 변환할 것인지 선택할 수 있으며,
OpenCV에서 제공하는 방법들은 CV_BGR2GRAY 뿐만 아니라 
CV_BGR2YCrCbCV_BGR2HSVCV_BGR2Lab 등 여러가지이며 이는 cv.h 파일에서 확인할 수 있다.


cvThreshold() 함수는 실제로 이진화를 수행하는 함수로,
세 번 째 인수는 문턱치를 설정하고,
네 번 째 인수는 문턱치를 넘어선 픽셀들을 어떤 값으로 설정할 것인지를,
다섯 번 째 인수는 이진화 알고리즘을 선택할 수 있다.


  cvThreshold(gray, output, threshold, 255, CV_THRESH_BINARY); 

위 함수는 입력된 gray 이미지에서 threshold 값을 초과한 값은 255 로 변환하고 이하는 0 으로 변환하여 output 이미지를 만들어 냅니다. 이와는 반대로 적용되게 한다거나 일정 값 이하는 0 으로 변환하고 초과되는 값만 보여주는 등의 옵션이 있습니다. 옵션을 변화 시켜가며 변화되는 모습을 익혀 보도록 합시다. 

  CV_THRESH_BINARY        : threshold 값 초과는 255, 이하는 0
  CV_THRESH_BINARY_INV  : threshold 값 초과는 0, 이하는 255
  CV_THRESH_TRUNC         : threshold 값 초과는 threshold, 이하는 그대로
  CV_THRESH_TOZERO       : threshold 값 초과는 그대로, 이하는 0
  CV_THRESH_TOZERO_INV : threshold 값 초과는 0, 이하는 그대로 

이번 프로그램에는 Trackbar 가 추가되었는데 이는 나중에도 유용하게 쓰이므로 잘 익혀 두시기 바랍니다. 아래 함수는 "T9-camera" 이름의 윈도우에 0 부터 255 범위를 같는 "T" 이름의 Trackbar 를 붙입니다. Trackbar 의 초기 위치는 threshold 값이 결정하며 bar 를 조절하여도 그 값은 threshold 변수에 들어가게 됩니다. 그리고 현재는 NULL 로 되어 있지만 이부분에 함수명을 적으면 bar 가 변경될 때마다 해당하는 함수를 호출하게 됩니다. 이 함수는 반드시 int 형 변수 하나를 가지고 있어야 하고 이 변수에 Trackbar 의 값이 넘어 오므로 함수에서 값을 가지고 영상처리를 해주면 됩니다. 

  cvCreateTrackbar("T", "T9-camera", &threshold, 255, NULL);

cvCvtColor() 함수는 Color 변환을 해주는 함수입니다. 아래 함수는 RGB 채널을 가지고 있는 image 를 Gray 채널로 바꾸어서 gray 에 넣어주는 역할을 합니다. 마지막 인자는 Color 변환 모드인데 여기에도 다양한 옵션이 존재하므로 필요한 모델을 사용하시면 됩니다. 

cvCvtColor(image, gray, CV_RGB2GRAY);
 

  CV_RGB2GRAY  : 흑백으로 변환
  CV_RGB2YCrCb : 주로 Skin Color 모델을 할때 변환( 손 제스쳐 인식, 얼굴 인식 )
  CV_RGB2HLS
  CV_RGB2HSV
  CV_RGB2Lab
  CV_RGB2Luv 



5. 결과



ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

K-20160312-514397.png

이론 참고 :: http://fornangman.tistory.com/19

K-20160312-515594.png

K-20160312-515675.png

K-20160312-515743.png

작성한 레이블링 알고리즘은 흰색(255의 값을 갖는 픽셀)을 Foreground로 판단하기 때문에,
앞서 이진화된 영상을 반전시킨다.

미리 작성해둔 레이블링 클래스를 이용 레이블링을 수행한 뒤,
각 레이블의 정보를 담고 있는 m_recBlobs 변수로 부터 각 레이블의 정보를 가져와
화면출력을 위해 만들어둔 이미지에 각각의 영역을 빨간색으로 표시한다.


K-20160312-515862.png
profile

title: MoonBlonix

2016.03.24 18:15
*.148.87.98

영상 이진화 고급편

http://darkpgmr.tistory.com/115

profile

title: MoonBlonix

2016.03.25 00:07
*.148.87.98
       //adaptive threshold (영상 adaptive 이진화 함수)  
       cvAdaptiveThreshold(src_gray, addap_thr, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 21, 10);
       //세번째 255는 최대값.  이렇게 하면 0과 255로 이루어진 영상으로 됨
       //마지막에서 두번째값은 threshold 계산 때 주변 픽셀 사용하는 크기.  3,5,7 식으로 홀수로 넣어줌
       //마지막은 Constant subtracted from mean or weighted mean. It may be negative
  
profile

title: MoonBlonix

2016.03.26 17:25
*.148.87.98

출처 :: http://webnautes.tistory.com/823


openCV 3.0부터 라벨링 알고리즘이 추가되었습니다.. 이미지를 라벨링하고 원하는 라벨을 색으로 표현한다든가.. 각각의 영역들을 박스치는 것등이 쉽게되네요.. 해당 영역의 크기도 각각 계산되서 나옵니다.. 자세한건 아래 소스코드를 읽어 보세요...




  1. #include <iostream>  
  2. #include <opencv2/core/mat.hpp>  
  3. #include <opencv2/imgcodecs.hpp>  
  4. #include <opencv2/imgproc.hpp>  
  5. #include <opencv2/highgui.hpp>  
  6.   
  7. using namespace cv;  
  8. using namespace std;  
  9.   
  10. int main() {  
  11.     Mat img_gray, img_color, img_binary;  
  12.   
  13.     img_gray = imread("art8.jpg", IMREAD_GRAYSCALE );  
  14.   
  15.     threshold(img_gray, img_binary, 127, 255, THRESH_BINARY);  
  16.     cvtColor( img_gray, img_color, COLOR_GRAY2BGR );  
  17.   
  18.   
  19.     Mat img_labels,stats, centroids;  
  20.     int numOfLables = connectedComponentsWithStats(img_binary, img_labels,   
  21.                                                    stats, centroids, 8,CV_32S);  
  22.   
  23.   
  24.     //라벨링된 이미지중 특정 라벨을 컬러로 표현해주기  
  25.     for ( int y=0; y<img_labels.rows; ++y ) {  
  26.   
  27.         int *label = img_labels.ptr<int>(y);  
  28.         Vec3b* pixel = img_color.ptr<Vec3b>(y);  
  29.   
  30.   
  31.         for (int x = 0; x < img_labels.cols; ++x) {  
  32.   
  33.   
  34.             if (label[x] == 3 ) {  
  35.                 pixel[x][2] = 0;  
  36.                 pixel[x][1] = 255;  
  37.                 pixel[x][0] = 0;  
  38.             }  
  39.         }  
  40.     }  
  41.   
  42.   
  43.     //라벨링 된 이미지에 각각 직사각형으로 둘러싸기 
  44.     for (int j = 1; j < numOfLables; j++) {  
  45.         int area = stats.at<int>(j, CC_STAT_AREA);  
  46.         int left = stats.at<int>(j, CC_STAT_LEFT);  
  47.         int top  = stats.at<int>(j, CC_STAT_TOP);  
  48.         int width = stats.at<int>(j, CC_STAT_WIDTH);  
  49.         int height  = stats.at<int>(j, CC_STAT_HEIGHT);  
  50.   
  51.   
  52.         rectangle( img_color, Point(left,top), Point(left+width,top+height),  
  53.                    Scalar(0,0,255),1 );  
  54.           
  55.         putText(img_color, to_string(j), Point(left+20,top+20), 
  56.                           FONT_HERSHEY_SIMPLEX, 1, Scalar(255,0,0), 2);  
  57.     }  
  58.   
  59.   
  60.     imshow( "result", img_color );  
  61.     waitKey(0);  
  62. }  






centroids를 이용하여 라벨링 된 영역의 중심을 출력해보았습니다..





  1. #include <iostream>  
  2. #include <opencv2/core/mat.hpp>  
  3. #include <opencv2/imgcodecs.hpp>  
  4. #include <opencv2/imgproc.hpp>  
  5. #include <opencv2/highgui.hpp>  
  6.   
  7. using namespace cv;  
  8. using namespace std;  
  9.   
  10. int main() {  
  11.     Mat img_gray, img_color, img_binary;  
  12.   
  13.     img_gray = imread("art8.jpg", IMREAD_GRAYSCALE );  
  14.   
  15.     threshold(img_gray, img_binary, 127, 255, THRESH_BINARY);  
  16.     cvtColor( img_gray, img_color, COLOR_GRAY2BGR );  
  17.   
  18.   
  19.     Mat img_labels,stats, centroids;  
  20.     int numOfLables = connectedComponentsWithStats(img_binary, img_labels,  
  21.                                                    stats, centroids, 8,CV_32S);  
  22.   
  23.   
  24.     //라벨링된 이미지중 특정 라벨을 컬러로 표현해주기  
  25.     for ( int y=0; y<img_labels.rows; ++y ) {  
  26.   
  27.         int *label = img_labels.ptr<int>(y);  
  28.         Vec3b* pixel = img_color.ptr<Vec3b>(y);  
  29.   
  30.   
  31.         for (int x = 0; x < img_labels.cols; ++x) {  
  32.   
  33.   
  34.             if (label[x] == 3 ) {  
  35.                 pixel[x][2] = 0;  
  36.                 pixel[x][1] = 255;  
  37.                 pixel[x][0] = 0;  
  38.             }  
  39.         }  
  40.     }  
  41.   
  42.   
  43.     //라벨링 된 이미지에 각각 직사각형으로 둘러싸기  
  44.     for (int j = 1; j < numOfLables; j++) {  
  45.         int area = stats.at<int>(j, CC_STAT_AREA);  
  46.         int left = stats.at<int>(j, CC_STAT_LEFT);  
  47.         int top  = stats.at<int>(j, CC_STAT_TOP);  
  48.         int width = stats.at<int>(j, CC_STAT_WIDTH);  
  49.         int height  = stats.at<int>(j, CC_STAT_HEIGHT);  
  50.   
  51.         double *centroid = &centroids.at<double>(j, 0); //중심좌표  
  52.         int x = centroid[0];  
  53.         int y = centroid[1];  
  54.   
  55.         circle( img_color, Point(x,y), 5,  Scalar(255,0,0), 1);  
  56.   
  57.         rectangle( img_color, Point(left,top), Point(left+width,top+height),  
  58.                    Scalar(0,0,255),1 );  
  59.   
  60.         putText(img_color, to_string(j), Point(left+20,top+20), FONT_HERSHEY_SIMPLEX,  
  61.                 1, Scalar(255,0,0), 2);  
  62.     }  
  63.   
  64.   
  65.     imshow( "result", img_color );  
  66.     waitKey(0);  
  67. }  
List of Articles
번호 제목 글쓴이 날짜 조회 수
공지 [Web] 클라우드 IDE + 2 title: MoonBlonix 2017-06-25 15128
72 [VS] 다중 프로젝트 dll로 연결하기 title: MoonBlonix 2016-11-13 1627
71 [VS] DllMain 에서 DLL 호출하기 title: MoonBlonix 2016-11-13 1593
70 [Win API] 유니코드, 멀티바이트, TCHAR 문자열함수 title: MoonBlonix 2016-11-08 1458
69 [AVR] LED 입출력을 제어해보자 - 1 file title: Zwei츠바이 2016-09-16 1602
68 [알고리즘] 문자열 검색 title: MoonBlonix 2016-04-17 1700
67 [AVR] ATTiny13A 그리고 ADC에 대해 + 2 title: MoonBlonix 2016-04-01 1545
66 [OpenCV] 32bit(x86) 빌드 및 초기설정(GPU, TBB, IPP 등) title: MoonBlonix 2016-03-29 1544
65 [OpenCV] Mat 픽셀 접근방법 title: MoonBlonix 2016-03-26 1678
64 [OpenCV] Mat 구조를 Tesseract 에서 쓸 수 있게 title: MoonBlonix 2016-03-24 1454
63 [영상처리] Bitmap 구조 분석 title: MoonBlonix 2016-03-24 1705
62 [OpenCV] 3.x - 캠 사용 & 얼굴 인식 title: MoonBlonix 2016-03-24 1682
61 [tesseract] (3.0.4) vs2013으로 빌드하기 title: MoonBlonix 2016-03-23 1606
60 [OpenCV] 3.1 설치하기 file title: MoonBlonix 2016-03-17 1426
59 AVR / ARM / DSP 비교 file + 2 title: MoonBlonix 2016-03-12 1737
58 (작성중)[OpenCV/ARM/DSP] 임베디드 환경에서의 OpenCV 사용 title: MoonBlonix 2016-03-12 1604
57 [OpenCV] 예제 코드 모음 file title: MoonBlonix 2016-03-12 1792
56 [OpenCV] 마커 추출 file title: MoonBlonix 2016-03-12 1405
» [OpenCV] 영상 이진화 & 레이블링(Blob Labeling) file + 3 title: MoonBlonix 2016-03-12 1536
54 [OpenCV] 문자 인식 file + 1 title: MoonBlonix 2016-03-12 1467
53 [AVR] ATTiny13A 에 대한 숨겨진 사실들 title: MoonBlonix 2016-03-10 1629