本次要讲的范例是反向投影,反向投影如果是按照字面上的理解,还有书本上的理解可能会比较困难,但是如果是举一些具体的简单的例子,那可能就比较容易接受了,应用的话,可以检测出肤色区域,例如,你有一个肤色直方图 ( Hue-Saturation 直方图 ),你可以用它来寻找图像中的肤色区域,现在我们来看看反向变换吧。
1、原理
图像的反向投影图是用输入图像的某一位置上像素值(多维或灰度)对应在直方图的一个bin上的值来代替该像素值,所以得到的反向投影图是单通的。
举个小例
(1)例如灰度图像如下
Image=
0 1 2 3
4 5 6 7
8 9 10 11
8 9 14 15
(2)该灰度图的直方图为(bin指定的区间为[0,3),[4,7),[8,11),[12,16))
Histogram=
4 4 6 2
(3)反向投影图
Back_Projection=
4 4 4 4
4 4 4 4
6 6 6 6
6 6 2 2
例如位置(0,0)上的像素值为0,对应的bin为[0,3),所以反向直方图在该位置上的值这个bin的值4。
这个操作与前面介绍的LUT()方法非常类似,只不过是将LUT()参数中的查找表改成直方图而已。
2、代码实现
①、代码运用了floodfull()函数,点击图片的位置,得到填充的联通图,赋值给mask,计算mask所对应图片部位的直方图,再对图片进行反向投影。
②、对图片提取hue通道值,再进行反向投影,显示结果。
#include "stdafx.h"
/**
* @file BackProject_Demo2.cpp
* @brief Sample code for backproject function usage ( a bit more elaborated )
* @author OpenCV team
*/
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/// Global Variables
Mat src; Mat hsv;Mat hand;Mat hue;Mat hand1;
Mat mask;
int lo = 20; int up = 20;int bins=25;
const char* window_image = "Source image";
/// Function Headers
void Hist_and_Backproj( );
void pickPoint (int event, int x, int y, int, void* );
void hue_and_Backproj(int, void* );
/**
* @function main
*/
int main( int, char** argv )
{
/// Read the image
src = imread( "hand_sample2.jpg", 1 );
/// Transform it to HSV
cvtColor( src, hsv, COLOR_BGR2HSV );
/// 分离 Hue 通道
hue.create( hsv.size(), hsv.depth() );
int ch[] = { 0, 0 };
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
hand.create(src.size(),src.type());
hand1.create(src.size(),src.type());
/// Show the image
namedWindow( window_image, WINDOW_AUTOSIZE );
imshow( window_image, src );
/// Set Trackbars for floodfill thresholds
createTrackbar("* Hue bins: ", window_image, &bins, 180, hue_and_Backproj );
createTra