24 篇文章 6 订阅

# 1、原理

(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

# 2、代码实现

②、对图片提取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;

int lo = 20; int up = 20;int bins=25;
const char* window_image = "Source image";

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 )
{
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 );
createTrackbar( "Low thresh", window_image, &lo, 255, 0 );
createTrackbar( "High thresh", window_image, &up, 255, 0 );
/// Set a Mouse Callback
hue_and_Backproj(0,0);
setMouseCallback( window_image, pickPoint, 0 );

waitKey(0);
return 0;
}

/**
* @function pickPoint
*/
void pickPoint (int event, int x, int y, int, void* )
{
if( event != CV_EVENT_LBUTTONDOWN )
{ return; }
Point seed = Point( x, y );

Scalar newVal = Scalar( 120, 120, 120 );

int connectivity = 8;
int flags = connectivity + (newMaskVal << 8 ) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;

Mat mask2 = Mat::zeros( src.rows + 2, src.cols + 2, CV_8UC1 );
floodFill( src, mask2, seed, newVal, 0, Scalar( lo, lo, lo ), Scalar( up, up, up), flags );

Hist_and_Backproj( );
}

/**
* @function Hist_and_Backproj
*/
void Hist_and_Backproj( )
{
MatND hist;
hand = Scalar::all(0);
int h_bins = 30; int s_bins = 32;
int histSize[] = { h_bins, s_bins };

float h_range[] = { 0, 179 };
float s_range[] = { 0, 255 };
const float* ranges[] = { h_range, s_range };

int channels[] = { 0, 1 };

/// Get the Histogram and normalize it
calcHist( &hsv, 1, channels, mask, hist, 2, histSize, ranges, true, false );

normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );

/// Get Backprojection
Mat backproj;
calcBackProject( &hsv, 1, channels, hist, backproj, ranges, 1, true );

/// Draw the backproj
imshow( "BackProj", backproj );
src.copyTo(hand,backproj);
imshow("hand",hand);
}

void hue_and_Backproj(int, void* )
{
MatND hist;
hand1 = Scalar::all(0);
int histSize = MAX( bins, 2 );
float hue_range[] = { 0, 180 };
const float* ranges[] = { hue_range };

/// 计算直方图并归一化
calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize,ranges, true, false );
normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );

/// 计算反向投影
MatND backproj;
calcBackProject( &hue, 1, 0, hist, backproj, ranges, 1, true );

threshold(backproj,backproj,254,255,CV_THRESH_TOZERO);
/// 显示反向投影
imshow( "BackProj1", backproj );
src.copyTo(hand1,backproj);
imshow("hand1",hand1);
}

# 3、运行结果

图3、h_s通道反向投影                   图4、h通道反向投影

# 4、用到的类和函数

## mixChannels

void mixChannels(const Mat*src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs)

src：一系列输入图像的数组， 被拷贝的通道的来源一系列输入图像的数组， 被拷贝的通道的来源

nsrcs：输入图像的个数

dst：一系列目的图像的数组， 储存拷贝的通道，所有的数组必须事先分配空间（如用create），大小和深度须与输入数组等同。

ndsts：目的数组中图像的数目

fromTo：通道索引对的数组，指示如何将输入图像的某一通道拷贝到目的图像的某一通道。偶数下标的用来标识输入矩阵，奇数下标的用来标识输出矩阵。如果偶数下标为负数，那么相应的输出矩阵为零矩阵。

npairs：fromTo中的序号对数（两个算1对）。

## floodFill

int floodFill(InputOutputArray image, InputOutputArray mask, Point seed, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )

image：输入的 1- 或 3-通道, 8-比特或浮点数图像。输入的图像将被函数的操作所改变，除非你选择 CV_FLOODFILL_MASK_ONLY 选项

seed：开始填充的点

newVal：新的重新绘制的象素值

rect：可选输出参数，返回重绘区域最小边界矩形

loDiff：当前观察象素值与其部件领域象素或者待加入该部件的种子象素之负差(Lower difference)的最大值。（具体看后面公式表达）

upDiff：当前观察象素值与其部件领域象素或者待加入该部件的种子象素之正差(upper difference)的最大值。（具体看后面公式表达）

flag：操作选项. 低8位（第0-7位）比特包含连通值, 4 (缺省) 或 8, 如果为4，填充算法只考虑当前像素水平方向和垂直方向的相邻点；如果为8，除上述相邻点外，还会包括对角方向的相邻点。在函数执行连通过程中确定使用哪种邻域方式。高8位（第16-23位）比特可以是 0 或下面的开关选项的组合：
CV_FLOODFILL_FIXED_RANGE - 如果设置，则考虑当前象素与种子象素之间的差，否则考虑当前象素与其相邻象素的差。(范围是浮点数).

src(x',y')-lo_diff<=src(x,y)<=src(x',y')+up_diff, 灰度图像，浮动范围
src(seed.x,seed.y)-lo<=src(x,y)<=src(seed.x,seed.y)+up_diff, 灰度图像，固定范围
src(x',y')r-lo_diffr<=src(x,y)r<=src(x',y')r+up_diffr 和
src(x',y')g-lo_diffg<=src(x,y)g<=src(x',y')g+up_diffg 和
src(x',y')b-lo_diffb<=src(x,y)b<=src(x',y')b+up_diffb, 彩色图像，浮动范围
src(seed.x,seed.y)r-lo_diffr<=src(x,y)r<=src(seed.x,seed.y)r+up_diffr 和
src(seed.x,seed.y)g-lo_diffg<=src(x,y)g<=src(seed.x,seed.y)g+up_diffg 和
src(seed.x,seed.y)b-lo_diffb<=src(x,y)b<=src(seed.x,seed.y)b+up_diffb, 彩色图像，固定范围

## calcBackProject

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

arrays：源图像，他们有着同样的depth（CV_8U 、 CV_32F）同样的size，可以是任意的通道数。

narrays：源图像的数目

channels：用于计算反投影的通道列表。

hist：输入的直方图

backProject：输出单通道反投影图像，和arrays[0]有同样的size和depth

ranges：和calchist中的ranges一样

• 2
点赞
• 10
收藏
觉得还不错? 一键收藏
• 打赏
• 1
评论
04-02
01-22 1642
04-06 2489
03-13 1458
11-17 8827
03-26 2万+
12-09 2718
02-20 329
03-06 1732
06-21 9397
03-07 830
05-03 1342
11-13 192
03-21 1893
03-16 3328

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。