리매핑 & 특정 색 영역 추출

전종원·2022년 11월 2일
0

1. 리매핑

리매핑이란

  • 영상의 특정 위치 픽셀을 다른 위치에 재배치하는 일반적인 프로세스
  • 어파인 변환, 투시변환을 포함한 다양한 변환을 리매핑으로 표현 가능

OpenCV remap()

void remap(InputArray src, OutputArray dst, InputArray map1, InputArray map2, 
		   int interpolation, int borderMode = BORDER_CONSTANT, const Scalar& 
           borderValue = Scalar());
  • src: 입력영상
  • dst: 결과영상. map1과 같은 크기, src와 같은 타입.
  • map1: 결과영상의 각 픽셀이 참조할 입력영상의(x,y)좌표 또는 x좌표를 담고 있는 행렬.
  • map2: 결과영상의 (x,y) 좌표가 참조할 입력영상의 y좌표를 담고있는 행렬. CV_16UC1 또는 CV_32FC1.
  • interpolation: 보간법
  • borderMode: 가장자리 픽셀확장 방식
  • borderValue: BORDER_CONSTANT일 때 사용할 상수 값

코드

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

using namespace std;
using namespace cv;

int main()
{
	Mat src = imread("tekapo.bmp");

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

	int w = src.cols;
	int h = src.rows;

	Mat map1 = Mat::zeros(h*2, w*2, CV_32FC1);
	Mat map2 = Mat::zeros(h*2, w*2, CV_32FC1);

	for (int y = 0; y < h*2; y++) {
		for (int x = 0; x < w*2; x++) {
			map1.at<float>(y, x) = (float)x/2;
			map2.at<float>(y, x) = (float)y;
			//map2.at<float>(y, x) = (float)h - 1 - y;
			//map2.at<float>(y, x) = (float)y/2;
		}
	}

	Mat dst;
	remap(src, dst, map1, map2, INTER_LINEAR);
	//remap(src, dst, map1, map2, INTER_LINEAR, BORDER_DEFAULT);

	imshow("src", src);
	imshow("dst", dst);
	waitKey();
}

2. 특정 색영역 추출

  • 영상에서 특정 색 영역만 추출하고 싶을 때는 BGR보다 HSV, YCrCb가 더 유리하다.

OpenCV 범위선택함수

void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
  • src: 입력행렬
  • lowerb: 하한 값
  • upperb: 상한 값
  • dst: 입력 영상과 동일 크기 CV_8UC1 타입. 범위 안에 들어가는 픽셀 값만 255로 설정됨.

실습코드

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

using namespace cv;
using namespace std;

int pos_hue1 = 5, pos_hue2 = 30, pos_sat1 = 200, pos_sat2 = 255;
Mat src, src_hsv, dst, 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, dst_mask);

	cvtColor(src, dst, COLOR_BGR2GRAY);
	cvtColor(dst, dst, COLOR_GRAY2BGR);
	src.copyTo(dst, dst_mask);

	imshow("dst_mask", dst_mask);
	imshow("dst", dst);
}

int main(int argc, char* argv[])
{
	if (argc < 2) {
		src = imread("flower1.png", IMREAD_COLOR);
	} else {
		src = imread(argv[1], IMREAD_COLOR);
	}

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

	cvtColor(src, src_hsv, COLOR_BGR2HSV);

	imshow("src", src);

	namedWindow("dst");
	createTrackbar("Lower Hue", "dst", &pos_hue1, 180, on_hsv_changed);
	createTrackbar("Upper Hue", "dst", &pos_hue2, 180, 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();
	return 0;
}

결과영상

3. 히스토그램 역투영

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

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

  • 영상에서 검출하고자 하는 영역을 YCrCb 색공간으로 변경

  • Cr, Cb 좌표공간에 히스토그램 작성.

  • 해당 히스토그램에 포함되는 영역을 영상에서 추출

OpenCV 히스토그램 역투영 함수

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_8U. 발생 빈도가 높으면 원소값이 크게 나타남.
  • ranges: 히스토그램 빈 경계값 배열의 배열

실습코드

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

using namespace cv;
using namespace std;

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

	Mat src = imread("cropland.png", IMREAD_COLOR);

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

	Rect rc = selectROI(src);

	Mat src_ycrcb;
	cvtColor(src, src_ycrcb, COLOR_BGR2YCrCb);

	Mat crop = src_ycrcb(rc);

	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, 1, true);

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

	//imshow("src", src);
	imshow("dst", dst);
	waitKey();

	return 0;
}

실습코드2

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

using namespace cv;
using namespace std;

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);

#if 1
	Mat hist_norm;
	normalize(hist, hist_norm, 0, 255, NORM_MINMAX, -1);
	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, 1, true);
	GaussianBlur(backproj, backproj, Size(), 1.0); //³ëÀÌÁîÁŠ°Å¿ë
	backproj = backproj > 50; //³ëÀÌÁîÁŠ°Å¿ë

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

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

	return 0;
}

결과영상

0개의 댓글