1. 색상범위 지정

1)  RGB, HSV, YCrCb 등 색공간에서  검출하고자 하는 색상 성분의 범위의 값을 추출

 

**hsv 에서 s를 높은 범위로 지정해야 탁하지 않은 색상을 추출 할 수 있다.

RGB 색공간 사용시 조명에 민감하지만 이에 반해, HSV 색공간의 경우 V 를 무시하고 YCrCb 에선 Y 를 무시함으로써 특정 색상 검출 시  조명 영향을 받지 않음으로써 안정된 출력영상을 얻을 수 있다.

 

void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);

 src: color든 gray든 모두 입력 가능

lowerb: 하한값(Mat 또는 Scalar)

upperb: 상한값(Mat 또는 Scalar)

dst: 입력영상과 동일크기. CV_8UC1 Gray Scale 형식을 따른다.  lowerb ~ upperb  범위 안에 들어가는 픽셀 값만 255로 설정됨  ,  범위 이외의 값은 0으로 설정됨.

단일 채널의 경우 dst[I] = lowerb(I) <= src[I]  <= upper(I)    1채널만 해당 범위에 있으면 255로 설정됨

다중 채널의 경우 & 연산자를 사용함으로서 다중채널 모두 해당 범위 내 들어올 시 (모두 참)  255 로 설정됨

 

2) 색상 범위 지정 기능을 이용한 컬러필터 만들기

  a) 입력 컬러 영상에서 특정 색상 영역은 그대로 유지하고, 나머지 영역은 그레이스케일 형식으로 변환하는 효과 구현

녹색영역 추출:  

Hue :  50<=H <=80

Saturation : 150 <= S <=255

Value :  0<= V <=255  // V는 상관 하지 않는다는 의미.

초록색만 흰색 나머지는 검정색으로 추출.

 

해당 범위 내 있는 경우 원본에 픽셀값을 가져오고, 그  범위이외의 경우 그레이스케일 이미지로부터 픽셀값가져와 보자.

 

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

using namespace std;
using namespace cv;

int pos_hue1 = 50, pos_hue2 = 80, pos_sat1 = 150, pos_sat2 = 255;  // range
Mat src, src_hsv, dst, mask;

void on_hsv_changed(int, void*) {
	Scalar lowerb(pos_hue1, pos_sat1, 0);
	Scalar upperb(pos_hue2, pos_sat2, 255);
	inRange(src_hsv, lowerb, upperb, mask);  //  inRange의 출력영상 : mask, Gray scale 영상

	cvtColor(src, dst, COLOR_BGR2GRAY);  // 주어진 입력 영상을 dst로 만듦. src는 컬러, dst는 그레이 
	cvtColor(dst, dst, COLOR_GRAY2BGR); //  dst를 변환해서 자기 자신으로 업데이트  (Gray -> BGR).  색상은 이미 훼손됬기에 의미없으나 주요 목적은 그레이 색상 (3채널) 만들기 위함이다.  CV8UC3 형태

	src.copyTo(dst, mask); // src영상에서 dst 영상으로 픽셀값을 copy 하나 mask 영상에서 흰색 으로 지정된 부분(픽셀값 0아닌 부분들)만 copy함.

	imshow("mask", mask);
	imshow("dst", dst); // 컬러필터가 적용된 영상이 출력됨
}

int main()
{
	src = imread("candies.png");

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

	cvtColor(src, src_hsv, COLOR_BGR2HSV);

	namedWindow("src");
	namedWindow("mask");
	namedWindow("dst");

	imshow("src", src);

	createTrackbar("Lower Hue", "dst", &pos_hue1, 179, on_hsv_changed);
	createTrackbar("Upper Hue", "dst", &pos_hue2, 179, on_hsv_changed);
	createTrackbar("Lower Sat", "dst", &pos_sat1, 255, on_hsv_changed);
	createTrackbar("Upper Sat", "dst", &pos_sat2, 255, on_hsv_changed);
	on_hsv_changed(0, 0); //이건 왜 해주는걸까?   프로그램이 실행되자 마자 무조건 한번 해당 함수 실행되기 위함이다. 
	//대부분 해당 함수는 트랙바 움직일때 자동으로 해당 함수 호출됨)

	waitKey();
}

candies.png
0.69MB
flower1.png
0.36MB
flower2.png
0.85MB

 

2. 히스토그램 역투영

주어진 히스토그램 모델에 영상의 픽셀들이 얼마나 일치하는 지 검사하는 방법

임의의 색상 영역을 검출할 떄 효과적

조명의 밝기 변화의 영향 줄이고자 보통 HSV 색 공간에서 HS성분만 사용하거나, YCrCb 색 공간에서 CrCb 성분만 사용

 

cropland.png
0.50MB

논과 나무 부분들의 roi를 설정함으로써 추출된 dst 영상

 

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

using namespace std;
using namespace cv;

int main()
{
	//cropland.png 이미지로부터 CrCb 히스토그램 계산
	Mat src = imread("cropland.png");

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

	Rect rc = selectROI(src);  // 마우스 통해 특정 ROI영역 설정하는 인터페이스 기능
	//해당함수가 호출 될 시 src화면이 출력되어 해당 src에서 마우스 로 드래그하여  ROI 영역 설정.
	// 엔터나 스페이스바 입력시 ROI영역이 rc에 전달됨
	Mat src_ycrcb;
	cvtColor(src, src_ycrcb, COLOR_BGR2YCrCb); 

	Mat crop = src_ycrcb(rc); // rc사이즈면서 YCrCb 색상정보를 그대로 crop에 얕은 복사
	
	Mat hist;
	int channels[] = { 1,2 };
	int cr_bins = 128; int cb_bins = 128;
	int histSize[] = { cr_bins, cb_bins };
	float cr_range[] = { 0,256 };
	float cb_range[] = { 0,256 };
	const float* ranges[] = { cr_range, cb_range };

	// 부분 영상에 대한 히스토그램 계산
	calcHist(&crop, 1, channels, Mat(), hist, 2, histSize, ranges);

	// 전체 영상에 대해 히스토그램 역투영
	Mat backproj;
	calcBackProject(&src_ycrcb, 1, channels, hist, backproj, ranges); //사용자와 선택한 픽셀들의 유사한 픽셀들을 찾아서

	Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
	src.copyTo(dst, backproj);

	imshow("dst", dst); //dst로 출력
	waitKey();

}

 

 

3) 히스토그램 역투영 함수

void calcBackProject(const Mat* images, int nimages, const int* channels,
	InputArray hist, OutputArray backProject, const float** ranges, double scale = 1,
	bool uniform = true);

images: 입력 영상 주소 ( 또는 입력 영상 배열 주소)

nimages: 입력영상 개수

channels: 역투영 계산에 사용할 채널 목록(배열)

hist: 입력 히스토그램

backProject: (출력) 히스토그램 역투영 결과 행렬. 입력 영상과 동일 크기, CV_8UC1.

                   발생 빈도가 높으면 원소 값이 크게 나타남.

(inrange에서는 0또는 1 과 같이 마스크영상으로 반환 , 반면 backProject 영상은 그레이스케일 영상으로 반환 ( 0~255)

ranges: 히스토그램 빈 경계값 배열의 배열. 

 

 

2) 히스토그램 역투영을 이용한 살색 검출

  a) 기준 영상으로부터 살색에 대한 컬러 히스토그램 미리계산

  b) 입력 영상에서 미리 구한 살색 히스토그램에 부합하는 픽셀 선별

 

 

[다시]

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

using namespace std;
using namespace cv;

int main()
{
	// Calculate CrCb histogram from a reference image

	Mat ref, ref_ycrcb, mask;
	ref = imread("ref.png", IMREAD_COLOR);
	mask = imread("mask.bmp", IMREAD_GRAYSCALE);
	cvtColor(ref, ref_ycrcb, COLOR_BGR2YCrCb);

	Mat hist;
	int channels[] = { 1, 2 };
	int cr_bins = 128; int cb_bins = 128;
	int histSize[] = { cr_bins, cb_bins };
	float cr_range[] = { 0, 256 };
	float cb_range[] = { 0, 256 };
	const float* ranges[] = { cr_range, cb_range };

	calcHist(&ref_ycrcb, 1, channels, mask, hist, 2, histSize, ranges);
	/*
	출력: hist
	*/
#if 1
	Mat hist_norm;
	normalize(hist, hist_norm, 0, 255, NORM_MINMAX, CV_8UC1);
	imshow("hist_norm", hist_norm);
#endif

	Mat src, src_ycrcb;
	src = imread("kids.png", IMREAD_COLOR);
	cvtColor(src, src_ycrcb, COLOR_BGR2YCrCb);

	Mat backproj;
	calcBackProject(&src_ycrcb, 1, channels, hist, backproj, ranges);
	/*
	입력: hist
	출력: backproj
	*/

	GaussianBlur(backproj, backproj, Size(), 1.0);
	backproj = backproj > 50;

	Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
	src.copyTo(dst, backproj); // backproj에서 0이아닌 값(흰색) 들만  복사.

	imshow("ref", ref);
	imshow("mask", mask);
	imshow("src", src);
	imshow("backproj", backproj);
	imshow("dst", dst);
	waitKey();
}

'프로그래머스 > OPENCV' 카테고리의 다른 글

에지검출과 소벨필터(1)  (0) 2022.12.07
색상범위 관련  (0) 2022.12.07
컬러영상처리  (0) 2022.12.07
색 공간  (0) 2022.12.06
리매핑(remapping)  (0) 2022.12.05

+ Recent posts