ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • OpenCV를 이용하여 특정색 (빨간색) 검출
    OpenCV/OpenCV C++ 강좌 2018. 6. 10. 14:34
    아래 유튜브 영상에 본 포스팅을 개선한 내용이 포함되어 있습니다.




    최종업데이트 - 2018. 6. 10



    OpenCV를 이용하여 카메라로부터 캡쳐되는 영상은 BGR 영상입니다.

    RGB가 아니라 BGR이라고 부르는 것은 Blue, Green, Red 순으로 한 픽셀이 구성되기 때문입니다.


    코드에서는 HSV 영상으로 변환한 후,  영상에서 원하는 색을 분리하고 있습니다.

    HSV 영상에서 Hue 성분은 다음처럼 특정 색의 컬러가 일정한 범위를 갖기 때문에 분리해내기가 쉽습니다.


    이미지 출처 : https://www.dreamstime.com/stock-illustration-color-colors-wheel-names-degrees-rgb-hsb-hsv-hue-image78027630




    참고 [2]에 따르면  cvtColor 함수를 사용하여 변화하면 0 < Hue < 179,  0 < Saturation < 255, 0 < Value < 255 의 범위를 갖습니다.

    위 그림의 값에 0.5를 곱하면 원하는 색의 hue 값입니다.



    예제 코드에서는 Scalar 객체로 원하는 색의 값을 B, G , R 순으로 선언한 후,   Hue 값의 범위에 맞추어 마스크 영상을 만들어줍니다.

    현재는 빨간색, 파란색, 노란색, 자홍색만 코드에 포함되어 있습니다.



    아래 영상은 노란색을 검출해본 결과입니다. 검출된 노란 물체 주변으로 빨간색 사각형이 보입니다.

    단순히 구현하기 위해서 형태를 보지 않고 가장 큰 물체를 기준으로 사각형이 그려집니다.





    테스트에 사용된 영상입니다.  실제 카메라로 할 경우에는 조명이 너무 어둡거나 너무 밝으면 안좋은 결과가 보일 수 도 있습니다.


    test.mp4




    #include <opencv2/opencv.hpp>
    #include <iostream>

    using namespace cv;
    using namespace std;

    int main()
    {
    int range_count = 0;

    Scalar red(0, 0, 255);
    Scalar blue(255, 0, 0);
    Scalar yellow(0, 255, 255);

    Scalar magenta(255, 0, 255);


    Mat rgb_color = Mat(1, 1, CV_8UC3, red);
    Mat hsv_color;

    cvtColor(rgb_color, hsv_color, COLOR_BGR2HSV);


    int hue = (int)hsv_color.at<Vec3b>(0, 0)[0];
    int saturation = (int)hsv_color.at<Vec3b>(0, 0)[1];
    int value = (int)hsv_color.at<Vec3b>(0, 0)[2];


    cout << "hue = " << hue << endl;
    cout << "saturation = " << saturation << endl;
    cout << "value = " << value << endl;


    int low_hue = hue - 10;
    int high_hue = hue + 10;

    int low_hue1 = 0, low_hue2 = 0;
    int high_hue1 = 0, high_hue2 = 0;

    if (low_hue < 10 ) {
    range_count = 2;

    high_hue1 = 180;
    low_hue1 = low_hue + 180;
    high_hue2 = high_hue;
    low_hue2 = 0;
    }
    else if (high_hue > 170) {
    range_count = 2;

    high_hue1 = low_hue;
    low_hue1 = 180;
    high_hue2 = high_hue - 180;
    low_hue2 = 0;
    }
    else {
    range_count = 1;

    low_hue1 = low_hue;
    high_hue1 = high_hue;
    }


    cout << low_hue1 << "  " << high_hue1 << endl;
    cout << low_hue2 << "  " << high_hue2 << endl;


    VideoCapture cap("test.mp4");
    Mat img_frame, img_hsv;


    if (!cap.isOpened()) {
    cerr << "ERROR! Unable to open camera\n";
    return -1;
    }


    for (;;)
    {
    // wait for a new frame from camera and store it into 'frame'
    cap.read(img_frame);

    // check if we succeeded
    if (img_frame.empty()) {
    cerr << "ERROR! blank frame grabbed\n";
    break;
    }


    //HSV로 변환
    cvtColor(img_frame, img_hsv, COLOR_BGR2HSV);


    //지정한 HSV 범위를 이용하여 영상을 이진화
    Mat img_mask1, img_mask2;
    inRange(img_hsv, Scalar(low_hue1, 50, 50), Scalar(high_hue1, 255, 255), img_mask1);
    if (range_count == 2) {
    inRange(img_hsv, Scalar(low_hue2, 50, 50), Scalar(high_hue2, 255, 255), img_mask2);
    img_mask1 |= img_mask2;
    }


    //morphological opening 작은 점들을 제거
    erode(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
    dilate(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));


    //morphological closing 영역의 구멍 메우기
    dilate(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
    erode(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));


    //라벨링
    Mat img_labels, stats, centroids;
    int numOfLables = connectedComponentsWithStats(img_mask1, img_labels,
    stats, centroids, 8, CV_32S);


    //영역박스 그리기
    int max = -1, idx = 0;
    for (int j = 1; j < numOfLables; j++) {
    int area = stats.at<int>(j, CC_STAT_AREA);
    if (max < area)
    {
    max = area;
    idx = j;
    }
    }


    int left = stats.at<int>(idx, CC_STAT_LEFT);
    int top = stats.at<int>(idx, CC_STAT_TOP);
    int width = stats.at<int>(idx, CC_STAT_WIDTH);
    int height = stats.at<int>(idx, CC_STAT_HEIGHT);


    rectangle(img_frame, Point(left, top), Point(left + width, top + height),
    Scalar(0, 0, 255), 1);


    imshow("이진화 영상", img_mask1);
    imshow("원본 영상", img_frame);


    if (waitKey(5) >= 0)
    break;
    }


    return 0;
    }




    참고


    [1] https://stackoverflow.com/questions/32522989/opencv-better-detection-of-red-color


    [2] https://docs.opencv.org/3.4.1/df/d9d/tutorial_py_colorspaces.html


    [3] https://github.com/opencv/opencv/blob/master/samples/cpp/videocapture_basic.cpp



    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구독하기


    댓글 66

    • 이전 댓글 더보기
    • 2018.05.15 21:00


      비밀댓글입니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.05.16 00:31 신고


        검출하기 원하는 색상별로 HSV 범위를 찾아서 미리 코드에 넣어주면 됩니다.

        다음 링크에 있는 컬러맵을 보고
        가로축에서 H범위, 세로축에서 S범위를 선택하여 원하는 색상이 잘보이는 영역을 결정하세요.
        V 범위는 20~255 정도로 하면 될듯합니다.

        https://stackoverflow.com/a/48367205


        너무 어둡거나 너무 밝은 조명 상태만 아니면 결과가 괜찮을듯 싶지만.

        이 방법은 조명에 따라 검출 결과가 달라질 수 있기 때문에 테스트 환경에 맞추어 범위 조정이 필요할 수 있습니다.

    • 조은샘 2018.07.09 16:45


      안녕하세요 .
      위에 코드를 이미지를 가져와 라벨링을 한 후 그 중심점 좌표를 이용해서 ,
      물체의 변화를 감지하는 프로그램을 만드는 중입니다.
      현재 물체가 한개만 라벨링을 하는데 여러 물체를 라벨링 할 수 있나요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.07.09 17:06 신고


        현재는 가장 큰 물체만 찾도록 되어 있습니다..

        특징을 부여해서
        여러 개 찾도록 하면 가능합니다

        예를 들어 원 물체 또는 사각햘 물체만 찾게 한다든가 하면 됩니다.

    • aaa 2018.09.12 20:12


      connectedComponentsWithStats때문에 #include <opencv2/imgproc.hpp>를 추가했는데
      COLOR_BGR2HSV, MORPH_ELLIPSE, rectangle 에서 에러가나는데 괜찮으시다면 해결방법좀 알려주세요

    • aaa 2018.09.13 19:27


      심각도 코드 설명 프로젝트 파일 줄 비표시 오류(Suppression) 상태
      오류(활성) E0020 식별자 "connectedComponentsWithStats"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 119
      오류(활성) E0020 식별자 "CC_STAT_WIDTH"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 136
      오류(활성) E0020 식별자 "CC_STAT_TOP"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 135
      오류(활성) E0020 식별자 "CC_STAT_LEFT"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 134
      오류(활성) E0020 식별자 "CC_STAT_HEIGHT"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 137
      오류(활성) E0020 식별자 "CC_STAT_AREA"이(가) 정의되어 있지 않습니다. ComputerVision c:\Users\kccistc\Desktop\CV_Platform_Test\Mosaic\ComputerVision\new.cpp 125
      오류 C3861 'connectedComponentsWithStats': 식별자를 찾을 수 없습니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 119
      오류 C2065 'CC_STAT_WIDTH': 선언되지 않은 식별자입니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 136
      오류 C2065 'CC_STAT_TOP': 선언되지 않은 식별자입니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 135
      오류 C2065 'CC_STAT_LEFT': 선언되지 않은 식별자입니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 134
      오류 C2065 'CC_STAT_HEIGHT': 선언되지 않은 식별자입니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 137
      오류 C2065 'CC_STAT_AREA': 선언되지 않은 식별자입니다. ComputerVision c:\users\kccistc\desktop\cv_platform_test\mosaic\computervision\new.cpp 125



      --------------------------------------------------------------------------------------------------------------------
      이렇게 에러가 나는데 위에 어느분께 답변주신 #include <opencv2/imgproc.hpp> 를 추가 하였더니 전체적으로 700개의 에러가 납니다..

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.09.13 19:34 신고


        OpenCV 3점대 버전이면 이상없이 동작합니다.

        다음 포스팅을 참고하여 다시 OpenCV를 위한 프로젝트를 생성후 해보는게 좋을듯합니다.

        Visual Studio 2017에서 OpenCV 3.4.3을 사용하는 방법
        http://webnautes.tistory.com/1132

    • nkj2829 2018.10.11 17:56


      안녕하세요.
      댓글을 보고 코드에서 카메라 접근하는 부분을 라즈베리파이 캠 사용하는 코드로 대체했는데
      (test:1003): GStreamer-CRITICAL **: gst_element_get_state: assertion 'GST_IS_ELEMENT (element)' failed
      이런 오류가 뜨면서 실행이 안되는거 같습니다. 어떤 오류인지 가르쳐 주실수 있나요?

    • nkj2829 2018.10.11 19:07


      pi@raspberrypi:~ $ ls /dev/video0*
      /dev/video0

      만들고 했는데도 똑같은 현상이 반복됩니다.

      pi@raspberrypi:~/color_test $ ./test
      hue = 0
      saturation = 255
      value = 255
      170 180
      0 10

      (test:1106): GStreamer-CRITICAL **: gst_element_get_state: assertion 'GST_IS_ELEMENT (element)' failed
      여기까지 나오고 무한 반복은 안빠집니다.

    • nkj2829 2018.10.11 20:41


      감사합니다 소스에서 괄호를 하나 생략했었네요
      파이캠을 통해 실시간으로 빨간색은 인식을 했습니다.
      그런데 혹시 시리얼 통신을 통해서 각 색마다 다른 값을 보낼려고 하는데 실시간으로 빨간색 이나 초록색,파란색을 동시에 구분할수 있을까요?

    • 김강영 2018.10.12 14:29


      int low_hue = hue - 10;
      int high_hue = hue + 10;

      int low_hue1 = 0, low_hue2 = 0;
      int high_hue1 = 0, high_hue2 = 0;

      if (low_hue < 10 ) {
      range_count = 2;

      high_hue1 = 180;
      low_hue1 = low_hue + 180;
      high_hue2 = high_hue;
      low_hue2 = 0;
      }
      else if (high_hue > 170) {
      range_count = 2;

      high_hue1 = low_hue;
      low_hue1 = 180;
      high_hue2 = high_hue - 180;
      low_hue2 = 0;
      }
      else {
      range_count = 1;

      low_hue1 = low_hue;
      high_hue1 = high_hue;
      }
      블로그 보고 많이 참고하고 있습니다. 감사합니다 :)
      응용으로 색 분류까지 할려고 하는데요. 이 코드의 의미를 잘 모르겠습니다..; 그래서 질문드리고 싶은데요
      1. range_count 가 뭔지 알고싶습니다.
      2. 180이란 숫자는 어떻게 나온건지두요.
      3. if 문에서 10과 170을 잡으신 이유가 뭔지..
      4. low hue1/high hue1, low hue2/high hue2 는 뒤에 mask1,mask2에 쓰이는 건 알겠는데 그것들의 의미가 뭔지 모르겠네요
      질문이 많았네요 감사합니다!

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.10.12 15:11 신고


        포스팅에 있는 코드가 잘못되서 수정해야합니다.

        다음 파이썬 코드에 있는 걸로 대체해야 합니다.

        http://webnautes.tistory.com/1246


        원래 HSV 공간에서 hue가 0 ~ 359 범위를 갖는데 OpenCV에서는 0 ~ 179 범위를 갖습니다.

        hue 범위 0~179내에서 일정 범위마다 색이 부여되어 있는데 ..

        위 코드는 rgb 색을 바로 hsv로 바꿀려고 추가한 코드입니다.

        아래 링크에 있는 동영상을 보면 이해하기 쉬울듯합니다

        http://webnautes.tistory.com/1246

    • 김강영 2018.10.12 16:24


      감사합니다. 다시 해보겠습니다

    • nkj2829 2018.10.12 17:52


      포스팅에 있는 코드가 잘못되서 수정해야합니다.

      다음 파이썬 코드에 있는 걸로 대체해야 합니다.

      http://webnautes.tistory.com/1246


      원래 HSV 공간에서 hue가 0 ~ 359 범위를 갖는데 OpenCV에서는 0 ~ 179 범위를 갖습니다.

      hue 범위 0~179내에서 일정 범위마다 색이 부여되어 있는데 ..

      위 코드는 rgb 색을 바로 hsv로 바꿀려고 추가한 코드입니다.

      아래 링크에 있는 동영상을 보면 이해하기 쉬울듯합니다

      http://webnautes.tistory.com/1246

      이 댓글을 봤는데 c++코드와 python의 코드에서 hue값의 범위가 다른지 모르겠습니다
      현재 이 포스팅에 어떤게 잘못된건지 가르쳐 주시면 감사하겠습니다

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.10.12 18:56 신고


        rgb를 hsv로 바꾸는 걸 쉽게하려했는데 C++코드에는 오류가 있습니다. python처럼 변환해야 합니다.

        또는 hue값을 직접 사용해도 됩니다

    • 아라리 2018.11.23 01:00


      읽을 값을 초록색으로 잡고 초록색이 검출될 경우 cout으로 초록색이 나온다고 실시간으로 알려줄 수 있을까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.11.23 09:50 신고


        다음 포스팅을 참고하세요..


        텐서플로우 색 인식 테스트 ( Tensorflow Color Recognition Test )
        https://webnautes.tistory.com/1256

    • Favicon of https://dodohan-horangii.tistory.com BlogIcon 도도한호랑이 2018.12.07 17:45 신고


      안녕하세요~ 올리시는 글 항상 잘 보고있습니다.

      궁금한게 하나 있는데, S와 V의 lower bound 값을 50으로 하신 거 조금 자세하게 설명 가능할까요?

      0으로 해서 돌리니까 온갖 값이 다 검출되서 별로긴해서.. 저도 50으로 사용하려고 하는데,
      사실 이론적으로 생각해보면, 오로지 색깔(hue)에 의해서만 검출할거니까 S랑V는 0~255 다 포함하는게 맞잖아요. 근데 막상 해보면 이상하고..

      감사합니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2018.12.07 17:51 신고


        다음 유튜브에 관련 설명 및 개선방법이 포함되어 있습니다.
        참고하시면 좋을듯 합니다..


        OpenCV 강좌 - 3. OpenCV를 사용하여 특정색 오브젝트 추적하기 
        https://youtu.be/kOqUw7t5bYk

    • Favicon of https://webnautes.tistory.com/942 BlogIcon 영상처리 2019.02.08 15:23


      안녕하세요 강의를 보다가 이렇게 적게 됬는데 혹시 맨 위에 포스팅되어있는 동영상 코드를 혹시 알수 있을까요??

    • Favicon of http://https://webnautes.tistory.com/942 BlogIcon 영상처리 2019.02.08 16:16


      지금은 하나씩 지정을 해주어서 인식을 해주었는데 지정을 하지않고 빨간색이면 빨간색 노란색이면 노란색 파란색이면 파란색 지정을 하지않아도 알아서 인식하는 방법은 없나요??

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.02.08 16:20 신고


        hsv 컬러 서클을 보고 색깔별로 hue값은 정해줄수 있지만 saturation과 value값은 테스트 환경따라 조정해줘야 좋은 결과를 얻을 수 있습니다. 미리 테스트해보고 코드에 입력해놓으면 됩니다.

    • Favicon of http://https://webnautes.tistory.com/942 BlogIcon 영상처리 2019.02.15 15:12


      혹시 제가 영상에서 원하는 부분에서만 색깔을 인식하고 싶은데 특정 부분에서만 색깔을 검출할수있는 법이 있을까요???

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.02.15 15:26 신고


        이미지의 일부 영역을 사각형으로 설정하여 할 수 있습니다.

        ROI라고 하는데 사용 방법은 다음 글을 참고하세요

        http://answers.opencv.org/question/10364/set-roi-in-cvmat/?answer=10365#post-id-10365

    • 1234 2019.02.21 18:54


      현재 올려주신 언어를 통해서 소스를 작성하고 있는데 검은색 식별은 어느정도 되었는데
      동그라미를 감싸려고 하는데 circle(img,point,반지름,) 여기서 반지름을 어떻게 하여야
      원을 거의 비슷하게 영역박스를 그릴 수 있을까요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.02.21 19:05 신고


        다음 포스팅에서 소개하는 영역 주변에 사각형 그리는 데 사용하는 값과 영역 중심좌표로부터 반지름을 계산하면 되지 않을까 싶습니다.

        openCV 라벨링 예제 ( connectedComponentsWithStats )
        https://webnautes.tistory.com/823


        또는 허프 써클을 사용해도 될듯합니다. 원이 제대로 검출된다면 정확한 반지름을 얻을 수 있을듯합니다.

        OpenCV Python 강좌 - Hough Circle Transform( 원 검출 )
        https://webnautes.tistory.com/949

    • opencv 2019.05.23 10:44


      혹시 test.mp4파일은 어디에 저장해야 하나요?

    • 백두현 2019.07.06 13:23


      위 코드가 색을 검출하는 코드인가요????

    • KIm_H 2019.08.02 00:53


      포스트들 잘 보고 열심히 배우고 있습니다. 감사합니다.

      현재 빨간색과 초록색을 인식하게 코드를 짜 놓았고, 빨간색이나 초록색 중 더 크게 인식되는 것에 rectangle 함수가 적용되는 것 같습니다.

      혹시 여기에서, rectangle 함수가 적용되는 색에 따라 각각의 string 출력값을 뽑아 낼 수 있을까요??

      감사합니다.

    • carrot_d 2019.11.24 16:40


      포스트가 정말 유익한것같아요! 제가 친구들끼리 신호등을 감지해서 빨간색이 들어와있을 때 그에 맞는 소리가 나고, 또 초록색이 들어왔을 때는 초록불에 맞는 소리를 나게 하는 코딩을 작성해보고 있는데 색깔을 인식하는것과 그것을 라벨링 하는 부분이 막막해서요ㅠㅠ RGB값의 범위를 설정하고 범위내의 값이 들어왔을 때 그 색깔로 인식하는 방식으로 해야 할까요? 그렇다면 어떤식으로 해야할까요?..

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.11.24 18:16 신고


        다음 포스트의 코드와 유튜브 영상을 참고하세요

        OpenCV 강좌 - 3. OpenCV를 사용하여 특정색 오브젝트 추적하기
        https://webnautes.tistory.com/1266

Designed by Tistory.