您的位置:首页 > 运维架构

【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 D】

2018-03-04 08:56 696 查看

3.5反向投射

3.5.1反向投射概述及原理

反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。简单的讲, 所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征。例如, 你有一个肤色直方图 ( Hue-Saturation 直方图 ),你可以用它来寻找图像中的肤色区域。

我们使用肤色直方图为例来解释反向投影的工作原理。假设你已经通过下图得到一个肤色直方图(Hue-Saturation), 旁边的直方图就是 模型直方图 ( 代表手掌的皮肤色调).你可以通过掩码操作来抓取手掌所在区域的直方图:



图1

下图是另一张手掌图(测试图像) 以及对应的整张图像的直方图。



图2

我们要做的就是使用模型直方图(代表手掌的皮肤色调) 来检测测试图像中的皮肤区域。以下是检测的步骤

【第一步】对测试图像中的每个像素 ( P(i,j)),获取色调数据并找到该色调( h_(i.j),s_(i,j))在直方图中的bin的位置。

【第二步】查询模型直方图 中对应的bin - ( h_(i.j),s_(i,j))并读取该bin的数值。

【第三步】将此数值储存在新的图像中(BackProjection)。 你也可以先归一化 模型直方图 ,这样测试图像的输出就可以在屏幕显示了。

【第四步】通过对测试图像中的每个像素采用以上步骤, 我们得到了下面的 BackProjection 结果图。



图3

【第五步】使用统计学的语言, BackProjection 中储存的数值代表了测试图像中该像素属于皮肤区域的 概率 。比如以上图为例, 亮起的区域是皮肤区域的概率更大(事实确实如此),而更暗的区域则表示更低的概率(注意手掌内部和边缘的阴影影响了检测的精度)。

3.5.2反向投射相关API及源码

计算反向投影:calcBackProject()函数

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


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


【参数】

第一个参数,arrays – Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same size. Each of them can have an arbitrary number of channels.

第二个参数,narrays – Number of source arrays.

第三个参数,channels – The list of channels used to compute the back projection. The number of channels must match the histogram dimensionality. The first array channels are numerated from 0 to arrays[0].channels()-1 , the second array channels are counted from arrays[0].channels() to arrays[0].channels() + arrays[1].channels()-1, and so on.

第四个参数,hist – Input histogram that can be dense or sparse.

第五个参数,backProject – Destination back projection aray that is a single-channel array of the same size and depth as arrays[0] .

第六个参数,ranges – Array of arrays of the histogram bin boundaries in each dimension. See calcHist() .

第七个参数,scale – Optional scale factor for the output back projection.

第八个参数,uniform – Flag indicating whether the histogram is uniform or not (see above).

calcBackProject()函数源代码

/*【calcBackProject ( )源代码】*********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)
* @源码路径:…\opencv\sources\modules\imgproc\src\histogram.cpp
* @起始行数: 2039行
********************************************************************************/
void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
const SparseMat& hist, OutputArray _backProject,
const float** ranges, double scale, bool uniform )
{
std::vector<uchar*> ptrs;
std::vector<int> deltas;
std::vector<double> uniranges;
Size imsize;
int dims = hist.dims();

CV_Assert( dims > 0 );
_backProject.create( images[0].size(), images[0].depth() );
Mat backProject = _backProject.getMat();
histPrepareImages( images, nimages, channels, backProject,
dims, hist.hdr->size, ranges,
uniform, ptrs, deltas, imsize, uniranges );
const double* _uniranges = uniform ? &uniranges[0] : 0;

int depth = images[0].depth();
if( depth == CV_8U )
calcSparseBackProj_8u(ptrs, deltas, imsize, hist, dims, ranges,
_uniranges, (float)scale, uniform);
else if( depth == CV_16U )
calcSparseBackProj_<ushort, ushort>(ptrs, deltas, imsize, hist, dims, ranges,
_uniranges, (float)scale, uniform );
else if( depth == CV_32F )
calcSparseBackProj_<float, float>(ptrs, deltas, imsize, hist, dims, ranges,
_uniranges, (float)scale, uniform );
else
CV_Error(CV_StsUnsupportedFormat, "");
}


/*【calcBackProject ( )源代码】*********************************************************
* @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下)
* @源码路径:…\opencv\sources\modules\imgproc\src\histogram.cpp
* @起始行数: 2217行
********************************************************************************/
void cv::calcBackProject( InputArrayOfArrays images, const std::vector<int>& channels,
InputArray hist, OutputArray dst,
const std::vector<float>& ranges,
double scale )
{
#ifdef HAVE_OPENCL
Size histSize = hist.size();
bool _1D = histSize.height == 1 || histSize.width == 1;
size_t histdims = _1D ? 1 : hist.dims();
#endif

CV_OCL_RUN(dst.isUMat() && hist.type() == CV_32FC1 &&
histdims <= 2 && ranges.size() == histdims * 2 && histdims == channels.size(),
ocl_calcBackProject(images, channels, hist, dst, ranges, (float)scale, histdims))

Mat H0 = hist.getMat(), H;
int hcn = H0.channels();

if( hcn > 1 )
{
CV_Assert( H0.isContinuous() );
int hsz[CV_CN_MAX+1];
memcpy(hsz, &H0.size[0], H0.dims*sizeof(hsz[0]));
hsz[H0.dims] = hcn;
H = Mat(H0.dims+1, hsz, H0.depth(), H0.ptr());
}
else
H = H0;

bool _1d = H.rows == 1 || H.cols == 1;
int i, dims = H.dims, rsz = (int)ranges.size(), csz = (int)channels.size();
int nimages = (int)images.total();

CV_Assert(nimages > 0);
CV_Assert(rsz == dims*2 || (rsz == 2 && _1d) || (rsz == 0 && images.depth(0) == CV_8U));
CV_Assert(csz == 0 || csz == dims || (csz == 1 && _1d));

float* _ranges[CV_MAX_DIM];
if( rsz > 0 )
{
for( i = 0; i < rsz/2; i++ )
_ranges[i] = (float*)&ranges[i*2];
}

AutoBuffer<Mat> buf(nimages);
for( i = 0; i < nimages; i++ )
buf[i] = images.getMat(i);

calcBackProject(&buf[0], nimages, csz ? &channels[0] : 0,
hist, dst, rsz ? (const float**)_ranges : 0, scale, true);
}


通道复制:mixChannels()函数

C++: void mixChannels(const Mat* src,
int nsrc,
Mat* dst,
int ndst,
const int* fromTo,
size_t npairs)


C++: void mixChannels(const vector<Mat>& src,
vector<Mat>& dst,
const int* fromTo,
int npairs)


【参数】

第一个参数,src – Input array or vector of matrices. All the matrices must have the same size and the same depth.

第二个参数,nsrc – Number of matrices in src .

第三个参数,dst – Output array or vector of matrices. All the matrices must be allocated . Their size and depth must be the same as in src[0] .

第四个参数,ndst – Number of matrices in dst .

第五个参数,fromTo – Array of index pairs specifying which channels are copied and where. fromTo[k*2] is a 0-based index of the input channel in src . fromTo[k*2+1] is an index of the output channel in dst . The continuous channel numbering is used: the first input image channels are indexed from 0 to src[0].channels()-1 , the second input image channels are indexed from src[0].channels() to src[0].channels() + src[1].channels()-1, and so on. The same scheme is used for the output image channels. As a special case, when fromTo[k*2] is negative, the corresponding output channel is filled with zero .

第六个参数,npairs – Number of index pairs in fromTo.

3.5.3反向投射实例

代码参考附件【demo1】。



图4



图5直方图



图6反向投射图

参考:

中文

英文

本章参考附件

点击进入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐