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();
}
2. 히스토그램 역투영
주어진 히스토그램 모델에 영상의 픽셀들이 얼마나 일치하는 지 검사하는 방법
임의의 색상 영역을 검출할 떄 효과적
조명의 밝기 변화의 영향 줄이고자 보통 HSV 색 공간에서 HS성분만 사용하거나, YCrCb 색 공간에서 CrCb 성분만 사용
논과 나무 부분들의 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 |