[w6d3] 컬러 영상 처리

45110 단어 opencvopencv

컬러영상 처리

컬러영상은 흑백영상과 비교하였을 때 데이터 수가 증가한 것을 확인해 처리해주어야한다. 아래는 영상을 반전시키는 코드로, dst1과 같이 코드를 작성하면 푸른색만 반전 시키고, 나머지 좌표의 밝기가 없는 상태로 지정됨에 유의해야한다.

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

int main()
{
    cv::Mat src = cv::imread("./resources/lenna.bmp",cv::IMREAD_COLOR);

    if (src.empty()){
        std::cerr << "Image load failed!" << std::endl;
        return -1;
    }
    std::cout << src.type() << std::endl;

    cv::Mat dst1 = 255 - src;
    // dst1 = Scalar(255) - src와 동일
    cv::Mat dst2 = cv::Scalar(255,255,255) - src;
    // 세가지 수를 신경써야한다.
    cv::Mat dst3(src.rows,src.cols,CV_8UC3);
    for (int y=0; y<src.rows; y++){
        cv::Vec3b* Sptr = src.ptr<cv::Vec3b>(y);
        cv::Vec3b* Dptr = dst3.ptr<cv::Vec3b>(y);
        for (int x=0;x<src.cols;x++){
            //Dptr[x] = cv::Vec3b(255,255,255) - Sptr[x];
            dst3.at<cv::Vec3b>(y,x) = cv::Vec3b(255,255,255) - src.at<cv::Vec3b>(y,x);
            //Dptr[x][0] = 255 - Sptr[x][0]; //B
            //Dptr[x][1] = 255 - Sptr[x][1]; //G
            //Dptr[x][2] = 255 - Sptr[x][2]; //R
        }
    }
    cv::imshow("src",src);
    cv::imshow("dst1",dst1);
    cv::imshow("dst2",dst2);
    cv::imshow("dst3",dst3);
    while (cv::waitKey()!=27) continue;
    cv::destroyAllWindows();
    return 0;
}

RGB color space

TV, 모니터, 카메라 센서, 비트맵 등에서 사용한다.
Gray scale로 변환을 하기 위해서는 아래 공식을 사용한다.

두가지 색상 차이를 비교할 때, RGB space에서의 거리와 실제 눈에 보이는 색의 차이값의 정도에는 다소 차이가 있다. 이를 개선하기 위해 HSV, YCrCb를 따라서 사용할 수 있다.

https://en.wikipedia.org/wiki/RGB_color_spaces
https://docs.opencv.org/4.x/de/d25/imgproc_color_conversions.html

HSV color space // HSI, HSL

간단한 방식으로 사람이 생각하는 색을 규정할 수 있어 편의성이 높다.

  • Hue: 색상, 색의 종류
  • Saturation: 채도
  • Value: 명도, 빛 밝기

CV_8U 기준 범위
0<=H<=179, 0<=S,V<=255
CV_8U 기준 1 바이트에 360 데이터를 모두 담기 위해 2로 나누어진 데이터 사용한다.

색깔을 명확하게 보기 위해서는 S, V 값이 충분히 커야한다.

아래는 RGB 데이터와 HLS 데이터 사이의 관계식이다.

https://en.wikipedia.org/wiki/HSL_and_HSV
https://docs.opencv.org/4.x/de/d25/imgproc_color_conversions.html

YCbCr (YUV) color space

영상의 밝기 정보와 색상 정보를 따로 분리하여 부호화한 것으로 흑백 TV를 호환한다.(밝기)

  • Y: luma, brightness in image. (밝기)
  • Cr: Red-difference chroma (붉은색 색차)
  • Cb: Blue-difference chroma (푸른색 색차)

0<=Y,Cr,Cb<=255

색상 간 distance를 구할 때는 Y값은 무시하여 Cr, Cb만 사용한다.
Cr, Cb는 디테일에 대한 정보가 약한 경향이 있다.
아날로그 색상에서 사람이 인지하는 색 차이와 거리가 RGB와 비교했을 때 개선된다.

아래는 RGB 데이터와 YCrCb 데이터의 관계식이다.

https://en.wikipedia.org/wiki/YCbCr
https://docs.opencv.org/4.x/de/d25/imgproc_color_conversions.html

Split

각각의 color space를 cv::split을 이용해 나눠주고 데이터를 확인해 보았다.

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

void split_rgb(const cv::Mat& src);
void split_ycrcb(const cv::Mat& src);
void split_hsv(const cv::Mat& src);

int main()
{
    cv::Mat src = cv::imread("./resources/candy.jpg",cv::IMREAD_COLOR);
    cv::resize(src,src,cv::Size(640,478)); // 파일 크기가 커서 줄여줌.

    if (src.empty()){
        std::cerr << "Image load failed!" << std::endl;
        return -1;
    }

    split_rgb(src);
    split_hsv(src);
    split_ycrcb(src);
    return 0;
}

void split_rgb(const cv::Mat& src)
{
    std::vector<cv::Mat> dst;
    cv::split(src,dst);
    cv::putText(dst[0],"B",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[1],"G",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[2],"R",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::imshow("B",dst[0]);
    cv::imshow("G",dst[1]);
    cv::imshow("R",dst[2]);

    while (cv::waitKey()!=27) continue;
    cv::destroyAllWindows();
}

void split_hsv(const cv::Mat& src)
{
    cv::Mat temp;
    cv::cvtColor(src,temp,cv::COLOR_BGR2HSV);
    std::vector<cv::Mat> dst;
    cv::split(temp,dst);
    cv::putText(dst[0],"H",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[1],"S",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[2],"V",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::imshow("H",dst[0]);
    cv::imshow("S",dst[1]);
    cv::imshow("V",dst[2]);

    while (cv::waitKey()!=27) continue;
    cv::destroyAllWindows();
}

void split_ycrcb(const cv::Mat& src)
{
    cv::Mat temp;
    cv::cvtColor(src,temp,cv::COLOR_BGR2YCrCb);
    std::vector<cv::Mat> dst;
    cv::split(src,dst);
    cv::putText(dst[0],"Y",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[1],"Cr",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::putText(dst[2],"Cb",cv::Point(50,50),cv::FONT_HERSHEY_DUPLEX,1.0,cv::Scalar(0),2);
    cv::imshow("Y",dst[0]);
    cv::imshow("Cr",dst[1]);
    cv::imshow("Cb",dst[2]);

    while (cv::waitKey()!=27) continue;
    cv::destroyAllWindows();
}


BGR

HSV

YCrCb

컬러 영상의 히스토그램 평활화

히스토그램 평활화는 OpenCV에서 아래의 함수로 주어진다.

void cv::equalizeHist 	( 	InputArray  	src,
		OutputArray  	dst 
	) 		

컬러 영상의 히스토그램 평활화 방식은 그레이 스케일과 비교하였을 때 데이터의 개수가 차이가 있다. 아래의 코드에서는 두 가지 방법으로 평활화를 진행했다. bgr_hist는 bgr 데이터를 각각 평활화하는 방법이며, ycrcb는 y 데이터만 평활화한 것이다.

#include <iostream>
#include "opencv2/opencv.hpp"
#include <vector>
int main()
{
    cv::Mat src = cv::imread("./resources/lenna.bmp",cv::IMREAD_COLOR);

    if (src.empty()){
        std::cerr << "Image load failed!" << std::endl;
        return -1;
    }
    
    std::vector<cv::Mat> bgr;
    cv::split(src,bgr);
    std::vector<cv::Mat> ycrcb;
    cv::cvtColor(src,src,cv::COLOR_BGR2YCrCb);
    cv::split(src,ycrcb);

    cv::equalizeHist(bgr[0],bgr[0]);
    cv::equalizeHist(bgr[1],bgr[1]);
    cv::equalizeHist(bgr[2],bgr[2]);

    cv::equalizeHist(ycrcb[0],ycrcb[0]);

    cv::Mat bgr_eqhist,ycrcb_eqhist;
    cv::merge(bgr,bgr_eqhist);
    cv::merge(ycrcb,ycrcb_eqhist);
    cv::cvtColor(ycrcb_eqhist,ycrcb_eqhist,cv::COLOR_YCrCb2BGR);
    cv::cvtColor(src,src,cv::COLOR_YCrCb2BGR);

    cv::imshow("src",src);
    cv::imshow("bgr_hist",bgr_eqhist);
    cv::imshow("ycrcb",ycrcb_eqhist);
    while (cv::waitKey()!=27) continue;
    cv::destroyAllWindows();
    return 0;
}


bgr을 이용한 경우 원본과는 차이가 있는 영상이 만들어졌으며, ycrcb를 이용한 경우 원본 영상에서 대조가 강해진 형태를 볼 수 있었다. 주의할 점은 cv::imshow에 ycrcb_eqhist을 주기 전에 cv::cvtColor 함수를 이용해 bgr데이터로 만들어주어야 창에 보이는 이미지가 나타난다.

좋은 웹페이지 즐겨찾기