📄 camshift.cpp
字号:
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include <windows.h>
#include <CvCVcpp.h>
#include <math.h>
#include "CamShift.h"
//
// Constructor
//
CCamShift::CCamShift()
{
m_trackFace.m_ShowBackProject = 0;
m_trackFace.m_Track = 0;
m_Size.width = 0;
m_Size.height = 0;
m_Window.x = 0;
m_Window.y = 0;
m_Window.width = 10;
m_Window.height = 10;
m_Histogram = 0;
m_trackFace.m_Pins = 10;
m_trackFace.m_Threshold = 0;
m_BackProject = 0;
m_Colour = 0;
m_Stride = 0;
m_StrideProject = 0;
m_CalcHist = 0;
m_Criteria.epsilon = 2;
m_Criteria.maxIter = 10;
m_Criteria.type = CVL_TERMCRIT_ITER | CVL_TERMCRIT_EPS;
m_Lenght = 0;
m_Width = 0;
m_Orientation = 0;
} // CamShift
//
// Transform
//
// 'In place' adjust the CamShift of this sample
//
void CCamShift::TrackFace( BYTE* pData, CvSize size, int stride )
{
RGBQUAD* prgb; // Holds a pointer to the current pixel
// Get the image properties from the BITMAPINFOHEADER
int cxImage = size.width;
int cyImage = size.height;
int x, y;
PrepareData( cxImage, cyImage );
calc_hue_image( pData, cxImage, cyImage, stride, m_Colour, m_Stride );
if( m_CalcHist )
{
int temp = ((m_Stride >> 2) * m_Window.y) + m_Window.x;
m_CalcHist = 0;
ippiClearOutAllDataHist1D( m_Histogram );
ippiCalcHist1D32fC1( m_Colour + temp,
m_Window.width,
m_Window.height,
m_Stride,
m_Histogram );
ippiNormHist1D( m_Histogram );
}
ippiBackProject1D8uC1R( m_Histogram,
m_Colour,
m_Size,
m_Stride,
m_BackProject,
m_StrideProject );
ippiThreshold8uC1S( m_BackProject,
m_trackFace.m_Threshold,
m_Size.width * sizeof( *m_BackProject ) * m_Size.height,
IPPI_THRESH_TOZERO );
if( m_trackFace.m_ShowBackProject )
{
for( y = 0; y < cyImage; y++ )
{
prgb = (RGBQUAD*)(pData + y * stride);
for( x = 0; x < cxImage; x++ )
{
prgb[x].rgbBlue = prgb[x].rgbGreen = prgb[x].rgbRed =
max( *(m_BackProject + y * m_StrideProject + x), 0 );
}
}
}
if( m_trackFace.m_Track )
{
if( m_Histogram->inputcount > 0 )
{
ippiCamShift8uC1R( m_BackProject,
m_Size,
m_StrideProject,
m_Window,
m_Criteria,
&m_Window,
&m_Orientation,
&m_Lenght,
&m_Width,
0,
0 );
x = m_Window.x + m_Window.width / 2;
y = m_Window.y + m_Window.height / 2;
line( pData,
cxImage * sizeof( *prgb ),
(int)(x + m_Lenght * cos( m_Orientation ) / 2),
(int)(y + m_Lenght * sin( m_Orientation ) / 2),
(int)(x - m_Lenght * cos( m_Orientation ) / 2),
(int)(y - m_Lenght * sin( m_Orientation ) / 2),
-1 );
line( pData,
cxImage * sizeof( *prgb ),
(int)(x + m_Width * sin( m_Orientation ) / 2),
(int)(y - m_Width * cos( m_Orientation ) / 2),
(int)(x - m_Width * sin( m_Orientation ) / 2),
(int)(y + m_Width * cos( m_Orientation ) / 2),
-1 );
}
else
{
box( pData,
cxImage * sizeof( *prgb ),
max( m_Window.x, 0 ),
max( m_Window.y, 0 ),
max( m_Window.x + m_Window.width, 0 ),
max( m_Window.y + m_Window.height, 0 ),
-1 );
}
}
return;
}
void CCamShift::GetTrackingParams(CamShiftParam* trackFace)
{
*trackFace = m_trackFace;
return;
}
void CCamShift::SetTrackingParams(CamShiftParam trackFace)
{
m_trackFace = trackFace;
return;
}
void CCamShift::SetRecalcHistogramFlag()
{
m_CalcHist = 1;
return;
}
void CCamShift::ResetHistogram()
{
ippiClearOutAllDataHist1D( m_Histogram );
return;
}
void CCamShift::SetWindow( CvRect window )
{
m_Window = window;
m_Window.x = max( 0, min( m_Size.width - 1, m_Window.x ) );
m_Window.y = max( 0, min( m_Size.height - 1, m_Window.y ) );
m_Window.width = max( 0, min( m_Size.width - 1 - m_Window.x, m_Window.width ) );
m_Window.height = max( 0, min( m_Size.height - 1 - m_Window.y, m_Window.height ) );
return;
}
void CCamShift::GetWindow( CvRect* window )
{
*window = m_Window;
return;
}
void CCamShift::PrepareData( int cx, int cy )
{
if( cx != m_Size.width ||
cy != m_Size.height )
{
m_Stride = cx * sizeof( *m_Colour );
m_StrideProject = (cx + 8) & (int)(-8);
m_Size.width = cx;
m_Size.height = cy;
m_Colour = (float*)realloc( (void*)m_Colour, m_Stride * cy);
m_BackProject = (BYTE*)realloc( (void*)m_BackProject, m_StrideProject * cy );
}
if( m_Histogram == NULL )
{
ippiCreateHist1D( m_trackFace.m_Pins, &m_Histogram );
for( int i = 0; i < m_trackFace.m_Pins; i++ )
m_Histogram->thresh[i] = (float)i * 255 / m_trackFace.m_Pins;
m_Histogram->thresh[m_trackFace.m_Pins] = 255;
ippiClearOutAllDataHist1D( m_Histogram );
} else if( m_trackFace.m_Pins != m_Histogram->len )
{
ippiReleaseHist1D( &m_Histogram );
ippiCreateHist1D( m_trackFace.m_Pins, &m_Histogram );
for( int i = 0; i < m_trackFace.m_Pins; i++ )
m_Histogram->thresh[i] = (float)i * 255 / m_trackFace.m_Pins;
m_Histogram->thresh[m_trackFace.m_Pins] = 255;
ippiClearOutAllDataHist1D( m_Histogram );
}
}
void CCamShift::line( BYTE* src,
int stride,
int x1,
int y1,
int x2,
int y2,
int colour )
{
x1 = max( 0, min( m_Size.width - 1, x1 ) );
x2 = max( 0, min( m_Size.width - 1, x2 ) );
y1 = max( 0, min( m_Size.height - 1, y1 ) );
y2 = max( 0, min( m_Size.height - 1, y2 ) );
int* array;
float size;
int vx = x2 - x1;
int vy = y2 - y1;
if( vx ==0 && vy == 0 ) return;
float step = 1.0f / max( abs(vx), abs(vy) );
int x, y;
for( size = 0; size <= 1; size += step )
{
x = (int)(x1 + vx * size);
y = (int)(y1 + vy * size);
array = (int*)(src + y * stride);
array[x] = colour;
}
}
void CCamShift::box( BYTE* src,
int stride,
int x1,
int y1,
int x2,
int y2,
int colour )
{
line( src, stride, x1, y1, x2, y1, colour ); // up
line( src, stride, x2, y1, x2, y2, colour ); // right
line( src, stride, x1, y2, x2, y2, colour ); // down
line( src, stride, x1, y1, x1, y2, colour ); // left
}
//////////////////// conversion ///////////////////////
#define SHIFT 12
static const int div_table[] =
{
0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211,
130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632,
65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412,
43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693,
32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782,
26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223,
21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991,
18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579,
16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711,
14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221,
13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006,
11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995,
10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141,
10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410,
9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777,
8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224,
8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737,
7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304,
7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917,
6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569,
6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254,
6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968,
5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708,
5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468,
5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249,
5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046,
5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858,
4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684,
4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522,
4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370,
4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229,
4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096
};
#define mmax(a,b) ((b) + (((a)-(b))&((a)>(b)?-1:0)))
#define mmin(a,b) ((a) - (((a)-(b))&((a)>(b)?-1:0)))
void CCamShift::calc_hue_image( BYTE *src,
int w,
int hh,
int src_pitch,
float *dst,
int dst_pitch )
{
const planes = 4;
int x, y, x1;
dst_pitch >>= 2;
//for( int i = 0; i < dst_pitch * h; i++ ) dst[i] = -1;
for( y = 0; y < hh; y++, src += src_pitch, dst += dst_pitch )
for( x = 0, x1 = 0; x < w * planes; x+=planes, x1++ )
{
int b, g, r;
b = src[x];
g = src[x+1];
r = src[x+2];
// convert rgb->hsv
int h, s, v;
{
int vmin, diff;
int vr, vg;
v = mmax(r,g);
v = mmax(v,b);
vmin = mmin(r,g);
vmin = mmin(vmin,b);
diff = v - vmin;
vr = v == r ? -1 : 0;
vg = v == g ? -1 : 0;
s = diff*div_table[v]>>SHIFT;
h = (vr&(g-b)) + (~vr&((vg&(b-r+2*diff)) + ((~vg)&(r-g+4*diff))));
h = ((h*div_table[diff]*15+(1<<(SHIFT+6)))>>(7+SHIFT)) + (h < 0 ? 30*6 : 0);
}
if( s > 30 && v > 10 /*&& v < 220*/ )
dst[x1] = (float)h;
else
dst[x1] = -1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -