HUNNISH 注：

图像处理

梯度、边缘和角点

Sobel

void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );


src

dst

xorder
x  方向上的差分阶数
yorder
y  方向上的差分阶数
aperture_size

| -3 0  3|
|-10 0 10|
| -3 0  3|


dst(x,y) = dxorder+yodersrc/dxxorder•dyyorder |(x,y)


  |-1  0  1|
|-2  0  2|
|-1  0  1|


  |-1 -2 -1|
| 0  0  0|
| 1  2  1|
or
| 1  2  1|
| 0  0  0|
|-1 -2 -1|


Laplace

void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 );


src

dst

aperture_size

dst(x,y) = d2src/dx2 + d2src/dy2


aperture_size=1 则给出最快计算结果，相当于对图像采用如下内核做卷积：

|0  1  0|
|1 -4  1|
|0  1  0|


Canny

void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
double threshold2, int aperture_size=3 );


image

edges

threshold1

threshold2

aperture_size
Sobel 算子内核大小 (见 cvSobel).

PreCornerDetect

void cvPreCornerDetect( const CvArr* image, CvArr* corners, int aperture_size=3 );


image

corners

aperture_size
Sobel 算子的核大小(见cvSobel).

// 假设图像格式为浮点数
IplImage* corners = cvCloneImage(image);
IplImage* dilated_corners = cvCloneImage(image);
IplImage* corner_mask = cvCreateImage( cvGetSize(image), 8, 1 );
cvPreCornerDetect( image, corners, 3 );
cvDilate( corners, dilated_corners, 0, 1 );
cvSubS( corners, dilated_corners, corners );
cvCmpS( corners, 0, corner_mask, CV_CMP_GE );
cvReleaseImage( &corners );
cvReleaseImage( &dilated_corners );


CornerEigenValsAndVecs

void cvCornerEigenValsAndVecs( const CvArr* image, CvArr* eigenvv,
int block_size, int aperture_size=3 );


image

eigenvv

block_size

aperture_size
Sobel 算子的核尺寸(见 cvSobel).

    | sumS(p)(dI/dx)2   sumS(p)(dI/dx•dI/dy)|
M = |                                 |
| sumS(p)(dI/dx•dI/dy)  sumS(p)(dI/dy)2 |


λ1, λ2 - M 的特征值，没有排序
(x1, y1) - 特征向量，对 λ1
(x2, y2) - 特征向量，对 λ2

CornerMinEigenVal

void cvCornerMinEigenVal( const CvArr* image, CvArr* eigenval, int block_size, int aperture_size=3 );


image

eigenval

block_size

aperture_size
Sobel 算子的核尺寸(见 cvSobel). 当输入图像是浮点数格式时，该参数表示用来计算差分固定的浮点滤波器的个数.

FindCornerSubPix

void cvFindCornerSubPix( const CvArr* image, CvPoint2D32f* corners,
int count, CvSize win, CvSize zero_zone,
CvTermCriteria criteria );


image

corners

count

win

zero_zone

criteria

εi=DIpiT•(q-pi)


sumi(DIpi•DIpiT)•q - sumi(DIpi•DIpiT•pi) = 0


q=G-1•b


GoodFeaturesToTrack

void cvGoodFeaturesToTrack( const CvArr* image, CvArr* eig_image, CvArr* temp_image,
CvPoint2D32f* corners, int* corner_count,
double quality_level, double min_distance,
const CvArr* mask=NULL );


image

eig_image

temp_image

corners

corner_count

quality_level

min_distance

ROI:感兴趣区域。函数在ROI中计算角点，如果 mask 为 NULL，则选择整个图像。

采样、差值和几何变换

InitLineIterator

int cvInitLineIterator( const CvArr* image, CvPoint pt1, CvPoint pt2,
CvLineIterator* line_iterator, int connectivity=8 );


image

pt1

pt2

line_iterator

connectivity

例子：使用线段迭代器计算彩色线上象素值的和

    CvScalar sum_line_pixels( IplImage* image, CvPoint pt1, CvPoint pt2 )
{
CvLineIterator iterator;
int blue_sum = 0, green_sum = 0, red_sum = 0;
int count = cvInitLineIterator( image, pt1, pt2, &iterator, 8 );

for( int i = 0; i < count; i++ ){
blue_sum += iterator.ptr[0];
green_sum += iterator.ptr[1];
red_sum += iterator.ptr[2];
CV_NEXT_LINE_POINT(iterator);

/* print the pixel coordinates: demonstrates how to calculate the coordinates */
{
int offset, x, y;
/* assume that ROI is not set, otherwise need to take it into account. */
offset = iterator.ptr - (uchar*)(image->imageData);
y = offset/image->widthStep;
x = (offset - y*image->widthStep)/(3*sizeof(uchar) /* size of pixel */);
printf("(%d,%d)/n", x, y );
}
}
return cvScalar( blue_sum, green_sum, red_sum );
}


SampleLine

int cvSampleLine( const CvArr* image, CvPoint pt1, CvPoint pt2,
void* buffer, int connectivity=8 );


image

pt1

pt2

buffer

connectivity

GetRectSubPix

void cvGetRectSubPix( const CvArr* src, CvArr* dst, CvPoint2D32f center );


src

dst

center

dst(x, y) = src(x + center.x - (width(dst)-1)*0.5, y + center.y - (height(dst)-1)*0.5)


void cvGetQuadrangleSubPix( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
int fill_outliers=0, CvScalar fill_value=cvScalarAll(0) );


src

dst

map_matrix
3 × 2 变换矩阵 [A|b] （见讨论）.
fill_outliers

fill_value

dst(x+width(dst)/2, y+height(dst)/2)= src( A11x+A12y+b1, A21x+A22y+b2),

w其中 A和 b 均来自映射矩阵(译者注：A, b为几何形变参数) map_matrix
| A11 A12  b1 |
map_matrix = |            |
| A21 A22  b2 |


#include "cv.h"
#include "highgui.h"
#include "math.h"

int main( int argc, char** argv )
{
IplImage* src;
/* the first command line parameter must be image file name */
if( argc==2 && (src = cvLoadImage(argv[1], -1))!=0)
{
IplImage* dst = cvCloneImage( src );
int delta = 1;
int angle = 0;

cvNamedWindow( "src", 1 );
cvShowImage( "src", src );

for(;;)
{
float m[6];
double factor = (cos(angle*CV_PI/180.) + 1.1)*3;
CvMat M = cvMat( 2, 3, CV_32F, m );
int w = src->width;
int h = src->height;

m[0] = (float)(factor*cos(-angle*2*CV_PI/180.));
m[1] = (float)(factor*sin(-angle*2*CV_PI/180.));
m[2] = w*0.5f;
m[3] = -m[1];
m[4] = m[0];
m[5] = h*0.5f;

cvGetQuadrangleSubPix( src, dst, &M, 1, cvScalarAll(0));

cvNamedWindow( "dst", 1 );
cvShowImage( "dst", dst );

if( cvWaitKey(5) == 27 )
break;

angle = (angle + delta) % 360;
}
}
return 0;
}


Resize

void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR );


src

dst

interpolation

• CV_INTER_NN - 最近邻差值,
• CV_INTER_LINEAR - 双线性差值 (缺省使用)
• CV_INTER_AREA - 使用象素关系重采样。当图像缩小时候，该方法可以避免波纹出现。当图像放大时，类似于 CV_INTER_NN 方法..
• CV_INTER_CUBIC - 立方差值.

WarpAffine

void cvWarpAffine( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,
CvScalar fillval=cvScalarAll(0) );


src

dst

map_matrix
2×3 变换矩阵
flags

• CV_WARP_FILL_OUTLIERS - 填充所有缩小图像的象素。如果部分象素落在输入图像的边界外，那么它们的值设定为 fillval.
• CV_WARP_INVERSE_MAP - 指定 matrix 是输出图像到输入图像的反变换，因此可以直接用来做象素差值。否则, 函数从 map_matrix 得到反变换。
fillval

dst(x&apos;,y&apos;)<-src(x,y)



2DRotationMatrix

CvMat* cv2DRotationMatrix( CvPoint2D32f center, double angle,
double scale, CvMat* map_matrix );


center

angle

scale

map_matrix

[  α  β  |  (1-α)*center.x - β*center.y ]
[ -β  α  |  β*center.x + (1-α)*center.y ]

where α=scale*cos(angle), β=scale*sin(angle)


WarpPerspective

void cvWarpPerspective( const CvArr* src, CvArr* dst, const CvMat* map_matrix,
int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,
CvScalar fillval=cvScalarAll(0) );


src

dst

map_matrix
3×3 变换矩阵
flags

• CV_WARP_FILL_OUTLIERS - 填充所有缩小图像的象素。如果部分象素落在输入图像的边界外，那么它们的值设定为 fillval.
• CV_WARP_INVERSE_MAP - 指定 matrix 是输出图像到输入图像的反变换，因此可以直接用来做象素差值。否则, 函数从 map_matrix 得到反变换。
fillval

dst(x&apos;,y&apos;)<-src(x,y)



WarpPerspectiveQMatrix

4个对应点计算透视变换矩阵

CvMat* cvWarpPerspectiveQMatrix( const CvPoint2D32f* src,
const CvPoint2D32f* dst,
CvMat* map_matrix );


src

dst

map_matrix

(tix'i,tiy'i,ti)T=matrix•(xi,yi,1)T


形态学操作

CreateStructuringElementEx

IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y,
int shape, int* values=NULL );


cols

rows

anchor_x

anchor_y

shape

• CV_SHAPE_RECT, 长方形元素;
• CV_SHAPE_CROSS, 交错元素 a cross-shaped element;
• CV_SHAPE_ELLIPSE, 椭圆元素;
• CV_SHAPE_CUSTOM, 用户自定义元素。这种情况下参数 values 定义了 mask,即象素的那个邻域必须考虑。
values

ReleaseStructuringElement

void cvReleaseStructuringElement( IplConvKernel** element );


element

Erode

void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );


src

dst

element

iterations

dst=erode(src,element):  dst(x,y)=min((x',y') in element))src(x+x',y+y')


Dilate

void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );


src

dst

element

iterations

dst=dilate(src,element):  dst(x,y)=max((x',y') in element))src(x+x',y+y')


MorphologyEx

void cvMorphologyEx( const CvArr* src, CvArr* dst, CvArr* temp,
IplConvKernel* element, int operation, int iterations=1 );


src

dst

temp

element

operation

CV_MOP_OPEN - 开运算
CV_MOP_CLOSE - 闭运算
CV_MOP_GRADIENT - 形态梯度
CV_MOP_TOPHAT - "顶帽"
CV_MOP_BLACKHAT - "黑帽"
iterations

开运算:
dst=open(src,element)=dilate(erode(src,element),element)

dst=close(src,element)=erode(dilate(src,element),element)

"顶帽":
dst=tophat(src,element)=src-open(src,element)

"黑帽":
dst=blackhat(src,element)=close(src,element)-src


滤波器与彩色变换

Smooth

void cvSmooth( const CvArr* src, CvArr* dst,
int smoothtype=CV_GAUSSIAN,
int param1=3, int param2=0, double param3=0 );


src

dst

smoothtype

• CV_BLUR_NO_SCALE (简单不带尺度变换的模糊) - 对每个象素的 param1×param2 领域求和。如果邻域大小是变化的，可以事先利用函数 cvIntegral 计算积分图像。
• CV_BLUR (simple blur) - 对每个象素param1×param2邻域  求和并做尺度变换 1/(param1param2).
• CV_GAUSSIAN (gaussian blur) - 对图像进行核大小为 param1×param2 的高斯卷积
• CV_MEDIAN (median blur) - 对图像进行核大小为param1×param1 的中值滤波 (i.e. 邻域是方的).
• CV_BILATERAL (双向滤波) - 应用双向 3x3 滤波，彩色 sigma=param1，空间 sigma=param2. 关于双向滤波，可参考 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html
param1

param2

param3

              sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 对应水平核,
n=param2 对应垂直核.


Filter2D

void cvFilter2D( const CvArr* src, CvArr* dst,
const CvMat* kernel,
CvPoint anchor=cvPoint(-1,-1));
#define cvConvolve2D cvFilter2D


src

dst

kernel

anchor

Integral

void cvIntegral( const CvArr* image, CvArr* sum, CvArr* sqsum=NULL, CvArr* tilted_sum=NULL );


image

sum

sqsum

tilted_sum

sum(X,Y)=sumx<X,y<Yimage(x,y)

sqsum(X,Y)=sumx<X,y<Yimage(x,y)2

tilted_sum(X,Y)=sumy<Y,abs(x-X)<yimage(x,y)


sumx1<=x<x2,y1<=y<y2image(x,y)=sum(x2,y2)-sum(x1,y2)-sum(x2,y1)+sum(x1,x1)

CvtColor

void cvCvtColor( const CvArr* src, CvArr* dst, int code );


src

dst

code

• RGB 空间内部的变换，如增加/删除 alpha 通道，反相通道顺序，到16位  RGB彩色或者15位RGB彩色的正逆转换(Rx5:Gx6:Rx5),以及到灰度图像的正逆转换，使用：
RGB[A]->Gray: Y=0.212671*R + 0.715160*G + 0.072169*B + 0*A
Gray->RGB[A]: R=Y G=Y B=Y A=0


所有可能的图像色彩空间的相互变换公式列举如下：

• RGB<=>XYZ (CV_BGR2XYZ, CV_RGB2XYZ, CV_XYZ2BGR, CV_XYZ2RGB):
|X|   |0.412411  0.357585  0.180454| |R|
|Y| = |0.212649  0.715169  0.072182|*|G|
|Z|   |0.019332  0.119195  0.950390| |B|

|R|   | 3.240479  -1.53715  -0.498535| |X|
|G| = |-0.969256   1.875991  0.041556|*|Y|
|B|   | 0.055648  -0.204043  1.057311| |Z|


• RGB<=>YCrCb (CV_BGR2YCrCb, CV_RGB2YCrCb, CV_YCrCb2BGR, CV_YCrCb2RGB)
Y=0.299*R + 0.587*G + 0.114*B
Cr=(R-Y)*0.713 + 128
Cb=(B-Y)*0.564 + 128

R=Y + 1.403*(Cr - 128)
G=Y - 0.344*(Cr - 128) - 0.714*(Cb - 128)
B=Y + 1.773*(Cb - 128)


• RGB=>HSV (CV_BGR2HSV,CV_RGB2HSV)
V=max(R,G,B)
S=(V-min(R,G,B))*255/V   if V!=0, 0 otherwise

(G - B)*60/S,  if V=R
H= 180+(B - R)*60/S,  if V=G
240+(R - G)*60/S,  if V=B

if H<0 then H=H+360


使用上面从 0° 到 360° 变化的公式计算色调（hue）值，确保它们被 2 除后能适用于8位。

• RGB=>Lab (CV_BGR2Lab, CV_RGB2Lab)
|X|   |0.433910  0.376220  0.189860| |R/255|
|Y| = |0.212649  0.715169  0.072182|*|G/255|
|Z|   |0.017756  0.109478  0.872915| |B/255|

L = 116*Y1/3      for Y>0.008856
L = 903.3*Y      for Y<=0.008856

a = 500*(f(X)-f(Y))
b = 200*(f(Y)-f(Z))
where f(t)=t1/3              for t>0.008856
f(t)=7.787*t+16/116   for t<=0.008856

上面的公式可以参考 http://www.cica.indiana.edu/cica/faq/color_spaces/color.spaces.html

• Bayer=>RGB (CV_BayerBG2BGR, CV_BayerGB2BGR, CV_BayerRG2BGR, CV_BayerGR2BGR,
CV_BayerBG2RGB, CV_BayerRG2BGR, CV_BayerGB2RGB, CV_BayerGR2BGR,
CV_BayerRG2RGB, CV_BayerBG2BGR, CV_BayerGR2RGB, CV_BayerGB2BGR)

Bayer 模式被广泛应用于 CCD 和 CMOS 摄像头. 它允许从一个单独平面中得到彩色图像，该平面中的 R/G/B 象素点被安排如下：

 R G R G R G B G B G R G R G R G B G B G R G R G R G B G B G

对象素输出的RGB分量由该象素的1、2或者4邻域中具有相同颜色的点插值得到。以上的模式可以通过向左或者向上平移一个像素点来作一些修改。转换常量CV_BayerC1C22{RGB|RGB}中的两个字母C1和C2表示特定的模式类型：颜色分量分别来自于第二行，第二和第三列。比如说，上述的模式具有很流行的"BG"类型。

Threshold

void cvThreshold( const CvArr* src, CvArr* dst, double threshold,
double max_value, int threshold_type );


src

dst

threshold

max_value

threshold_type

threshold_type=CV_THRESH_BINARY:
dst(x,y) = max_value, if src(x,y)>threshold
0, otherwise

threshold_type=CV_THRESH_BINARY_INV:
dst(x,y) = 0, if src(x,y)>threshold
max_value, otherwise

threshold_type=CV_THRESH_TRUNC:
dst(x,y) = threshold, if src(x,y)>threshold
src(x,y), otherwise

threshold_type=CV_THRESH_TOZERO:
dst(x,y) = src(x,y), if (x,y)>threshold
0, otherwise

threshold_type=CV_THRESH_TOZERO_INV:
dst(x,y) = 0, if src(x,y)>threshold
src(x,y), otherwise


void cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value,
int threshold_type=CV_THRESH_BINARY,
int block_size=3, double param1=5 );


src

dst

max_value

threshold_type

• CV_THRESH_BINARY,
• CV_THRESH_BINARY_INV
block_size

param1

threshold_type=CV_THRESH_BINARY:
dst(x,y) = max_value, if src(x,y)>T(x,y)
0, otherwise

threshold_type=CV_THRESH_BINARY_INV:
dst(x,y) = 0, if src(x,y)>T(x,y)
max_value, otherwise


金字塔及其应用

PyrDown

void cvPyrDown( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 );


src

dst

filter

PyrUp

void cvPyrUp( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 );

src

dst

filter

PyrSegmentation

void cvPyrSegmentation( IplImage* src, IplImage* dst,
CvMemStorage* storage, CvSeq** comp,
int level, double threshold1, double threshold2 );


src

dst

storage
Storage: 存储连通部件的序列结果
comp

level

threshold1

threshold2

    p(c¹,c²)=|c¹-c²|

    p(c¹,c²)=0,3·(c¹r-c²r)+0,59·(c¹g-c²g)+0,11·(c¹b-c²b)

连接部件

CvConnectedComp

    typedef struct CvConnectedComp
{
double area; /* 连通域的面积 */
float value; /* 分割域的灰度缩放值 */
CvRect rect; /* 分割域的 ROI */
} CvConnectedComp;


FloodFill

void cvFloodFill( CvArr* image, CvPoint seed_point, CvScalar new_val,
CvScalar lo_diff=cvScalarAll(0), CvScalar up_diff=cvScalarAll(0),
CvConnectedComp* comp=NULL, int flags=4, CvArr* mask=NULL );
#define CV_FLOODFILL_FIXED_RANGE (1 << 16)
#define CV_FLOODFILL_MASK_ONLY   (1 << 17)


image

seed_point

new_val

lo_diff

up_diff

comp

flags

• CV_FLOODFILL_FIXED_RANGE - 如果设置，则考虑当前象素与种子象素之间的差，否则考虑当前象素与其相邻象素的差。(范围是浮点数).
• CV_FLOODFILL_MASK_ONLY - 如果设置，函数不填充原始图像 (忽略 new_val), 但填充面具图像 (这种情况下 MASK 必须是非空的).

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, 彩色图像，固定范围

• 它的邻域象素的彩色/亮度值，当该邻域点已经被认为属于浮动范围情况下的连通域。
• 固定范围情况下的种子点的彩色/亮度值

FindContours

int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,
int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );


image

storage

first_contour

mode

• CV_RETR_EXTERNAL - 只提取最外层的轮廓
• CV_RETR_LIST - 提取所有轮廓，并且放置在 list 中
• CV_RETR_CCOMP - 提取所有轮廓，并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界，次层为洞的内层边界。
• CV_RETR_TREE - 提取所有轮廓，并且重构嵌套轮廓的全部 hierarchy
method

• CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).
• CV_CHAIN_APPROX_NONE - 将所有点由链码形式翻译为点序列形式
• CV_CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角分割，即函数只保留末端的象素点;
• CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链逼近算法.
• CV_LINK_RUNS - 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用.

offset

StartFindContours

CvContourScanner cvStartFindContours( CvArr* image, CvMemStorage* storage,
int mode=CV_RETR_LIST,
int method=CV_CHAIN_APPROX_SIMPLE,
CvPoint offset=cvPoint(0,0) );


image

storage

mode

method

offset
ROI 偏移量，见 cvFindContours.

FindNextContour

Finds next contour in the image

CvSeq* cvFindNextContour( CvContourScanner scanner );


scanner

SubstituteContour

void cvSubstituteContour( CvContourScanner scanner, CvSeq* new_contour );


scanner

new_contour

EndFindContours

CvSeq* cvEndFindContours( CvContourScanner* scanner );


scanner

图像与轮廓矩

Moments

void cvMoments( const CvArr* arr, CvMoments* moments, int binary=0 );


arr

moments

binary
(仅对图像) 如果标识为非零，则所有零象素点被当成零，其它的被看成 1.

GetSpatialMoment

double cvGetSpatialMoment( CvMoments* moments, int x_order, int y_order );


moments

x_order

y_order

Mx_order,y_order=sumx,y(I(x,y)•xx_order•yy_order)


GetCentralMoment

double cvGetCentralMoment( CvMoments* moments, int x_order, int y_order );


moments

x_order

y_order

μx_order,y_order=sumx,y(I(x,y)•(x-xc)x_order•(y-yc)y_order),


GetNormalizedCentralMoment

double cvGetNormalizedCentralMoment( CvMoments* moments, int x_order, int y_order );


moments

x_order

y_order

ηx_order,y_order= μx_order,y_order/M00((y_order+x_order)/2+1)


GetHuMoments

void cvGetHuMoments( CvMoments* moments, CvHuMoments* hu_moments );


moments

hu_moments
Hu 矩结构的指针.

 h1=η20+η02

h2=(η20-η02)²+4η11²

h3=(η30-3η12)²+ (3η21-η03)²

h4=(η30+η12)²+ (η21+η03)²

h5=(η30-3η12)(η30+η12)[(η30+η12)²-3(η21+η03)²]+(3η21-η03)(η21+η03)[3(η30+η12)²-(η21+η03)²]

h6=(η20-η02)[(η30+η12)²- (η21+η03)²]+4η11(η30+η12)(η21+η03)

h7=(3η21-η03)(η21+η03)[3(η30+η12)²-(η21+η03)²]-(η30-3η12)(η21+η03)[3(η30+η12)²-(η21+η03)²]


特殊图像变换

HoughLines

CvSeq* cvHoughLines2( CvArr* image, void* line_storage, int method,
double rho, double theta, int threshold,
double param1=0, double param2=0 );


image

line_storage

method
Hough 变换变量，是下面变量的其中之一：
• CV_HOUGH_STANDARD - 传统或标准 Hough 变换. 每一个线段由两个浮点数  (ρ, θ) 表示，其中 ρ 是点与原点 (0,0) 之间的距离，θ 线段与 x-轴之间的夹角。因此，矩阵类型必须是 CV_32FC2 type.
• CV_HOUGH_PROBABILISTIC - 概率 Hough 变换(如果图像包含一些长的线性分割，则效率更高). 它返回线段分割而不是整个线段。每个分割用起点和终点来表示，所以矩阵（或创建的序列）类型是 CV_32SC4.
• CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。
rho

theta

threshold

param1

• 对传统 Hough 变换，不使用(0).
• 对概率 Hough 变换，它是最小线段长度.
• 对多尺度 Hough 变换，它是距离精度  rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ).
param2

• 对传统 Hough 变换，不使用 (0).
• 对概率 Hough 变换，这个参数表示在同一条直线上进行碎线段连接的最大间隔值(gap), 即当同一条直线上的两条碎线段之间的间隔小于param2时，将其合二为一。
• 对多尺度 Hough 变换，它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2).

Example. 用 Hough transform 检测线段

/* This is a standalone program. Pass an image name as a first parameter of the program.
Switch between standard and probabilistic Hough transform by changing "#if 1" to "#if 0" and back */
#include <cv.h>
#include <highgui.h>
#include <math.h>

int main(int argc, char** argv)
{
IplImage* src;
if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0)
{
IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* lines = 0;
int i;
cvCanny( src, dst, 50, 200, 3 );
cvCvtColor( dst, color_dst, CV_GRAY2BGR );
#if 1
lines = cvHoughLines2( dst, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 150, 0, 0 );

for( i = 0; i < lines->total; i++ )
{
float* line = (float*)cvGetSeqElem(lines,i);
float rho = line[0];
float theta = line[1];
CvPoint pt1, pt2;
double a = cos(theta), b = sin(theta);
if( fabs(a) < 0.001 )
{
pt1.x = pt2.x = cvRound(rho);
pt1.y = 0;
pt2.y = color_dst->height;
}
else if( fabs(b) < 0.001 )
{
pt1.y = pt2.y = cvRound(rho);
pt1.x = 0;
pt2.x = color_dst->width;
}
else
{
pt1.x = 0;
pt1.y = cvRound(rho/b);
pt2.x = cvRound(rho/a);
pt2.y = 0;
}
cvLine( color_dst, pt1, pt2, CV_RGB(255,0,0), 3, 8 );
}
#else
lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 80, 30, 10 );
for( i = 0; i < lines->total; i++ )
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8 );
}
#endif
cvNamedWindow( "Source", 1 );
cvShowImage( "Source", src );

cvNamedWindow( "Hough", 1 );
cvShowImage( "Hough", color_dst );

cvWaitKey(0);
}
}


DistTransform

void cvDistTransform( const CvArr* src, CvArr* dst, int distance_type=CV_DIST_L2,


src

dst

distance_type

CV_DIST_C (3×3):
a=1, b=1

CV_DIST_L1 (3×3):
a=1, b=2

CV_DIST_L2 (3×3):
a=0.955, b=1.3693

CV_DIST_L2 (5×5):
a=1, b=1.4, c=2.1969


用户自定义 3×3 mask (a=1, b=1.5)

 4.5 4 3.5 3 3.5 4 4.5 4 3 2.5 2 2.5 3 4 3.5 2.5 1.5 1 1.5 2.5 3.5 3 2 1 0 1 2 3 3.5 2.5 1.5 1 1.5 2.5 3.5 4 3 2.5 2 2.5 3 4 4.5 4 3.5 3 3.5 4 4.5

用户自定义 5×5 mask (a=1, b=1.5, c=2)

 4.5 3.5 3 3 3 3.5 4.5 3.5 3 2 2 2 3 3.5 3 2 1.5 1 1.5 2 3 3 2 1 0 1 2 3 3 2 1.5 1 1.5 2 3 3.5 3 2 2 2 3 3.5 4 3.5 3 3 3 3.5 4

直方图

CvHistogram

    typedef struct CvHistogram
{
int header_size; /* 头尺寸 */
CvHistType type; /* 直方图类型 */
int flags; /* 直方图标识 */
int c_dims; /* 直方图维数 */
int dims[CV_HIST_MAX_DIM]; /* 每一维的尺寸 */
int mdims[CV_HIST_MAX_DIM]; /* 快速访问元素的系数 */
/* &m[a,b,c] = m + a*mdims[0] + b*mdims[1] + c*mdims[2] */
float* thresh[CV_HIST_MAX_DIM]; /* 每一维的直方块边界数组 */
float* array; /* 所有的直方图数据，扩展为单行 */
struct CvNode* root; /* 存储直方块的平衡树的根结点 */
CvSet* set; /* 内存存储仓的指针 (对平衡树而言) */
int* chdims[CV_HIST_MAX_DIM]; /* 快速计算的缓存 */
} CvHistogram;


CreateHist

CvHistogram* cvCreateHist( int dims, int* sizes, int type,
float** ranges=NULL, int uniform=1 );


dims

sizes

type

ranges

uniform

SetHistBinRanges

void cvSetHistBinRanges( CvHistogram* hist, float** ranges, int uniform=1 );


hist

ranges

uniform

ReleaseHist

void cvReleaseHist( CvHistogram** hist );


hist

ClearHist

void cvClearHist( CvHistogram* hist );


hist

CvHistogram*  cvMakeHistHeaderForArray( int dims, int* sizes, CvHistogram* hist,
float* data, float** ranges=NULL, int uniform=1 );


dims

sizes

hist

data

ranges

uniform

QueryHistValue_1D

#define cvQueryHistValue_1D( hist, idx0 ) /
cvGetReal1D( (hist)->bins, (idx0) )
#define cvQueryHistValue_2D( hist, idx0, idx1 ) /
cvGetReal2D( (hist)->bins, (idx0), (idx1) )
#define cvQueryHistValue_3D( hist, idx0, idx1, idx2 ) /
cvGetReal3D( (hist)->bins, (idx0), (idx1), (idx2) )
#define cvQueryHistValue_nD( hist, idx ) /
cvGetRealND( (hist)->bins, (idx) )


hist

idx0, idx1, idx2, idx3

idx

cvQueryHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块的值。对稀疏直方图，如果方块在直方图中不存在，函数返回 0, 而且不创建新的直方块。

GetHistValue_1D

#define cvGetHistValue_1D( hist, idx0 ) /
((float*)(cvPtr1D( (hist)->bins, (idx0), 0 ))
#define cvGetHistValue_2D( hist, idx0, idx1 ) /
((float*)(cvPtr2D( (hist)->bins, (idx0), (idx1), 0 ))
#define cvGetHistValue_3D( hist, idx0, idx1, idx2 ) /
((float*)(cvPtr3D( (hist)->bins, (idx0), (idx1), (idx2), 0 ))
#define cvGetHistValue_nD( hist, idx ) /
((float*)(cvPtrND( (hist)->bins, (idx), 0 ))


hist

idx0, idx1, idx2, idx3

idx

cvGetHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块的指针。对稀疏直方图，函数创建一个新的直方块，且设置其为 0，除非它已经存在。

GetMinMaxHistValue

void cvGetMinMaxHistValue( const CvHistogram* hist,
float* min_value, float* max_value,
int* min_idx=NULL, int* max_idx=NULL );


hist

min_value

max_value

min_idx

max_idx

NormalizeHist

void cvNormalizeHist( CvHistogram* hist, double factor );


hist

factor

ThreshHist

void cvThreshHist( CvHistogram* hist, double threshold );


hist

threshold

CompareHist

double cvCompareHist( const CvHistogram* hist1, const CvHistogram* hist2, int method );


hist1

hist2

method

• CV_COMP_CORREL
• CV_COMP_CHISQR
• CV_COMP_INTERSECT

相关 (method=CV_COMP_CORREL):
d(H1,H2)=sumI(H'1(I)•H'2(I))/sqrt(sumI[H'1(I)2]•sumI[H'2(I)2])

H'k(I)=Hk(I)-1/N•sumJHk(J) (N=number of histogram bins)

Chi-square(method=CV_COMP_CHISQR):
d(H1,H2)=sumI[(H1(I)-H2(I))/(H1(I)+H2(I))]

d(H1,H2)=sumImax(H1(I),H2(I))


CopyHist

void cvCopyHist( const CvHistogram* src, CvHistogram** dst );


src

dst

CalcHist

void cvCalcHist( IplImage** image, CvHistogram* hist,
int accumulate=0, const CvArr* mask=NULL );


image

hist

accumulate

Sample. 计算和显示彩色图像的 2D 色调－饱和度图像

#include <cv.h>
#include <highgui.h>

int main( int argc, char** argv )
{
IplImage* src;
if( argc == 2 && (src=cvLoadImage(argv[1], 1))!= 0)
{
IplImage* h_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* s_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* v_plane = cvCreateImage( cvGetSize(src), 8, 1 );
IplImage* planes[] = { h_plane, s_plane };
IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 );
int h_bins = 30, s_bins = 32;
int hist_size[] = {h_bins, s_bins};
float h_ranges[] = { 0, 180 }; /* hue varies from 0 (~0°red) to 180 (~360°red again) */
float s_ranges[] = { 0, 255 }; /* saturation varies from 0 (black-gray-white) to 255 (pure spectrum color) */
float* ranges[] = { h_ranges, s_ranges };
int scale = 10;
IplImage* hist_img = cvCreateImage( cvSize(h_bins*scale,s_bins*scale), 8, 3 );
CvHistogram* hist;
float max_value = 0;
int h, s;

cvCvtColor( src, hsv, CV_BGR2HSV );
cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
hist = cvCreateHist( 2, hist_size, CV_HIST_ARRAY, ranges, 1 );
cvCalcHist( planes, hist, 0, 0 );
cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
cvZero( hist_img );

for( h = 0; h < h_bins; h++ )
{
for( s = 0; s < s_bins; s++ )
{
float bin_val = cvQueryHistValue_2D( hist, h, s );
int intensity = cvRound(bin_val*255/max_value);
cvRectangle( hist_img, cvPoint( h*scale, s*scale ),
cvPoint( (h+1)*scale - 1, (s+1)*scale - 1),
CV_RGB(intensity,intensity,intensity), /* graw a grayscale histogram.
if you have idea how to do it
nicer let us know */
CV_FILLED );
}
}

cvNamedWindow( "Source", 1 );
cvShowImage( "Source", src );

cvNamedWindow( "H-S Histogram", 1 );
cvShowImage( "H-S Histogram", hist_img );

cvWaitKey(0);
}
}


CalcBackProject

void cvCalcBackProject( IplImage** image, CvArr* back_project, const CvHistogram* hist );


image

back_project

hist

1. 对红色物体计算色调直方图，假设图像仅仅包含该物体。则直方图有可能有极值，对应着红颜色。
2. 对将要搜索目标的输入图像，使用直方图计算其色调平面的反向投影，然后对图像做阈值操作。
3. 在产生的图像中发现连通部分，然后使用某种附加准则选择正确的部分，比如最大的连同部分。

CalcBackProjectPatch

void cvCalcBackProjectPatch( IplImage** image, CvArr* dst,
CvSize patch_size, CvHistogram* hist,
int method, float factor );


image

dst

patch_size

hist

method

factor

CalcProbDensity

void  cvCalcProbDensity( const CvHistogram* hist1, const CvHistogram* hist2,
CvHistogram* dst_hist, double scale=255 );


hist1

hist2

dst_hist

scale

dist_hist(I)=0      if hist1(I)==0
scale  if hist1(I)!=0 && hist2(I)>hist1(I)
hist2(I)*scale/hist1(I) if hist1(I)!=0 && hist2(I)<=hist1(I)


匹配

MatchTemplate

void cvMatchTemplate( const CvArr* image, const CvArr* templ,
CvArr* result, int method );


image

templ

result

method

method=CV_TM_SQDIFF:
R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2

method=CV_TM_SQDIFF_NORMED:
R(x,y)=sumx',y'[T(x',y')-I(x+x',y+y')]2/sqrt[sumx',y'T(x',y')2•sumx',y'I(x+x',y+y')2]

method=CV_TM_CCORR:
R(x,y)=sumx',y'[T(x',y')•I(x+x',y+y')]

method=CV_TM_CCORR_NORMED:
R(x,y)=sumx',y'[T(x',y')•I(x+x',y+y')]/sqrt[sumx',y'T(x',y')2•sumx',y'I(x+x',y+y')2]

method=CV_TM_CCOEFF:
R(x,y)=sumx',y'[T'(x',y')•I'(x+x',y+y')],

where T'(x',y')=T(x',y') - 1/(w•h)•sumx",y"T(x",y") (mean template brightness=>0)
I'(x+x',y+y')=I(x+x',y+y') - 1/(w•h)•sumx",y"I(x+x",y+y") (mean patch brightness=>0)

method=CV_TM_CCOEFF_NORMED:
R(x,y)=sumx',y'[T'(x',y')•I'(x+x',y+y')]/sqrt[sumx',y'T'(x',y')2•sumx',y'I'(x+x',y+y')2]



MatchShapes

double cvMatchShapes( const void* object1, const void* object2,
int method, double parameter=0 );


object1

object2

method

parameter

method=CV_CONTOUR_MATCH_I1:
I1(A,B)=sumi=1..7abs(1/mAi - 1/mBi)

method=CV_CONTOUR_MATCH_I2:
I2(A,B)=sumi=1..7abs(mAi - mBi)

method=CV_CONTOUR_MATCH_I3:
I3(A,B)=sumi=1..7abs(mAi - mBi)/abs(mAi)

mAi=sign(hAi)•log(hAi),
mBi=sign(hBi)•log(hBi),
hAi, hBi - A 和 B的Hu矩.


CalcEMD2

float cvCalcEMD2( const CvArr* signature1, const CvArr* signature2, int distance_type,
CvDistanceFunction distance_func=NULL, const CvArr* cost_matrix=NULL,
CvArr* flow=NULL, float* lower_bound=NULL, void* userdata=NULL );
typedef float (*CvDistanceFunction)(const float* f1, const float* f2, void* userdata);


signature1

signature2

distance_type

distance_func

cost_matrix

flow

lower_bound

userdata

结构分析

轮廓处理函数

ApproxChains

CvSeq* cvApproxChains( CvSeq* src_seq, CvMemStorage* storage,
int method=CV_CHAIN_APPROX_SIMPLE,
double parameter=0, int minimal_perimeter=0, int recursive=0 );


src_seq

storage

method

parameter

minimal_perimeter

recursive

void cvStartReadChainPoints( CvChain* chain, CvChainPtReader* reader );


chain

链的指针

链的读取状态

CvPoint cvReadChainPoint( CvChainPtReader* reader );


ApproxPoly

CvSeq* cvApproxPoly( const void* src_seq, int header_size, CvMemStorage* storage,
int method, double parameter, int parameter2=0 );


src_seq

storage

method

parameter

parameter2

BoundingRect

CvRect cvBoundingRect( CvArr* points, int update=0 );


points

update

• update=0, contour ~ CvContour*: 不计算矩形边界，但直接由轮廓头的 rect 域得到。
• update=1, contour ~ CvContour*: 计算矩形边界，而且将结果写入到轮廓头的 rect 域中 header.
• update=0, contour ~ CvSeq* or CvMat*: 计算并返回边界矩形
• update=1, contour ~ CvSeq* or CvMat*: 产生运行错误 （runtime error is raised）

ContourArea

double cvContourArea( const CvArr* contour, CvSlice slice=CV_WHOLE_SEQ );


contour

slice

NOTE: 轮廓的方向影响面积的符号。因此函数也许会返回负的结果。应用函数 fabs() 得到面积的绝对值。

ArcLength

double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );


curve

slice

is_closed

• is_closed=0 - 假设曲线不闭合
• is_closed>0 - 假设曲线闭合
• is_closed<0 - 若曲线是序列，检查 ((CvSeq*)curve)->flags 中的标识 CV_SEQ_FLAG_CLOSED 来确定曲线是否闭合。否则 (曲线由点集的数组 (CvMat*) 表示) 假设曲线不闭合。

CreateContourTree

CvContourTree* cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold );


contour

storage

threshold

ContourFromContourTree

CvSeq* cvContourFromContourTree( const CvContourTree* tree, CvMemStorage* storage,
CvTermCriteria criteria );


tree

storage

criteria

MatchContourTrees

double cvMatchContourTrees( const CvContourTree* tree1, const CvContourTree* tree2,
int method, double threshold );


tree1

tree2

method

threshold

计算几何

MaxRect

CvRect cvMaxRect( const CvRect* rect1, const CvRect* rect2 );


rect1

rect2

CvBox2D

typedef struct CvBox2D
{
CvPoint2D32f center;  /* 盒子的中心 */
CvSize2D32f  size;    /* 盒子的长和宽 */
float angle;          /* 水平轴与第一个边的夹角，用弧度表示*/
}
CvBox2D;


BoxPoints

void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] );


box

pt

void cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
{
float a = (float)cos(box.angle)*0.5f;
float b = (float)sin(box.angle)*0.5f;

pt[0].x = box.center.x - a*box.size.height - b*box.size.width;
pt[0].y = box.center.y + b*box.size.height - a*box.size.width;
pt[1].x = box.center.x + a*box.size.height - b*box.size.width;
pt[1].y = box.center.y - b*box.size.height - a*box.size.width;
pt[2].x = 2*box.center.x - pt[0].x;
pt[2].y = 2*box.center.y - pt[0].y;
pt[3].x = 2*box.center.x - pt[1].x;
pt[3].y = 2*box.center.y - pt[1].y;
}


FitEllipse

CvBox2D cvFitEllipse2( const CvArr* points );


points

FitLine

2D 或 3D 点集的直线拟合

void  cvFitLine( const CvArr* points, int dist_type, double param,
double reps, double aeps, float* line );


points
2D 或 3D 点集，32-比特整数或浮点数坐标
dist_type

param

reps, aeps

line

dist_type=CV_DIST_L2 (L2):
ρ(r)=r2/2 (最简单和最快的最小二乘法)

dist_type=CV_DIST_L1 (L1):
ρ(r)=r

dist_type=CV_DIST_L12 (L1-L2):
ρ(r)=2•[sqrt(1+r2/2) - 1]

dist_type=CV_DIST_FAIR (Fair):
ρ(r)=C2•[r/C - log(1 + r/C)],  C=1.3998

dist_type=CV_DIST_WELSCH (Welsch):
ρ(r)=C2/2•[1 - exp(-(r/C)2)],  C=2.9846

dist_type=CV_DIST_HUBER (Huber):
ρ(r)= r2/2,   if r < C
C•(r-C/2),   otherwise;   C=1.345



ConvexHull2

CvSeq* cvConvexHull2( const CvArr* input, void* hull_storage=NULL,
int orientation=CV_CLOCKWISE, int return_points=0 );


points
2D 点集的序列或数组，32-比特整数或浮点数坐标
hull_storage

orientation

return_points

例子. 由点集序列或数组创建凸外形

#include "cv.h"
#include "highgui.h"
#include <stdlib.h>

#define ARRAY  0 /* switch between array/sequence method by replacing 0<=>1 */

void main( int argc, char** argv )
{
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
cvNamedWindow( "hull", 1 );

#if !ARRAY
CvMemStorage* storage = cvCreateMemStorage();
#endif

for(;;)
{
int i, count = rand()%100 + 1, hullcount;
CvPoint pt0;
#if !ARRAY
CvSeq* ptseq = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour),
sizeof(CvPoint), storage );
CvSeq* hull;

for( i = 0; i < count; i++ )
{
pt0.x = rand() % (img->width/2) + img->width/4;
pt0.y = rand() % (img->height/2) + img->height/4;
cvSeqPush( ptseq, &pt0 );
}
hull = cvConvexHull2( ptseq, 0, CV_CLOCKWISE, 0 );
hullcount = hull->total;
#else
CvPoint* points = (CvPoint*)malloc( count * sizeof(points[0]));
int* hull = (int*)malloc( count * sizeof(hull[0]));
CvMat point_mat = cvMat( 1, count, CV_32SC2, points );
CvMat hull_mat = cvMat( 1, count, CV_32SC1, hull );

for( i = 0; i < count; i++ )
{
pt0.x = rand() % (img->width/2) + img->width/4;
pt0.y = rand() % (img->height/2) + img->height/4;
points[i] = pt0;
}
cvConvexHull2( &point_mat, &hull_mat, CV_CLOCKWISE, 0 );
hullcount = hull_mat.cols;
#endif
cvZero( img );
for( i = 0; i < count; i++ )
{
#if !ARRAY
pt0 = *CV_GET_SEQ_ELEM( CvPoint, ptseq, i );
#else
pt0 = points[i];
#endif
cvCircle( img, pt0, 2, CV_RGB( 255, 0, 0 ), CV_FILLED );
}

#if !ARRAY
pt0 = **CV_GET_SEQ_ELEM( CvPoint*, hull, hullcount - 1 );
#else
pt0 = points[hull[hullcount-1]];
#endif

for( i = 0; i < hullcount; i++ )
{
#if !ARRAY
CvPoint pt = **CV_GET_SEQ_ELEM( CvPoint*, hull, i );
#else
CvPoint pt = points[hull[i]];
#endif
cvLine( img, pt0, pt, CV_RGB( 0, 255, 0 ));
pt0 = pt;
}

cvShowImage( "hull", img );

int key = cvWaitKey(0);
if( key == 27 ) // 'ESC'
break;

#if !ARRAY
cvClearMemStorage( storage );
#else
free( points );
free( hull );
#endif
}
}


CheckContourConvexity

int cvCheckContourConvexity( const CvArr* contour );


contour

CvConvexityDefect

typedef struct CvConvexityDefect
{
CvPoint* start; /* 缺陷开始的轮廓点 */
CvPoint* end; /* 缺陷结束的轮廓点 */
CvPoint* depth_point; /* 缺陷中距离凸形最远的轮廓点(谷底) */
float depth; /* 谷底距离凸形的深度*/
} CvConvexityDefect;


ConvexityDefects

CvSeq* cvConvexityDefects( const CvArr* contour, const CvArr* convexhull,
CvMemStorage* storage=NULL );


contour

convexhull
cvConvexHull2 得到的凸外形，它应该包含轮廓的定点或下标，而不是外形点的本身，即cvConvexHull2 中的参数 return_points 应该设置为 0.
storage

MinAreaRect2

CvBox2D  cvMinAreaRect2( const CvArr* points, CvMemStorage* storage=NULL );


points

storage

MinEnclosingCircle

int cvMinEnclosingCircle( const CvArr* points, CvPoint2D32f* center, float* radius );


points

center

CalcPGH

void cvCalcPGH( const CvSeq* contour, CvHistogram* hist );


contour

hist

平面划分

CvSubdiv2D

#define CV_SUBDIV2D_FIELDS()    /
CV_GRAPH_FIELDS()           /
int  is_geometry_valid;     /
CvSubdiv2DEdge recent_edge; /
CvPoint2D32f  topleft;      /
CvPoint2D32f  bottomright;

typedef struct CvSubdiv2D
{
CV_SUBDIV2D_FIELDS()
}
CvSubdiv2D;


OpenCV 使用Delaunay's 算法将平面分割成小的三角形区域。分割的实现通过从一个假定的三角形(该三角形确保包括所有的分割点)开始不断迭代来完成。在这种情况下，对偶划分就是输入的2d点集的 Voronoi图表。这种划分可以用于对一个平面的3d分段变换、形态变换、平面点的快速定位以及建立特定的图结构 (比如 NNG,RNG等等)。

/* quad-edge中的一条边缘，低两位表示该边缘的索引号，其它高位表示边缘指针。 */
typedef long CvSubdiv2DEdge;

/* 四方边缘的结构场 */
int flags;                     /
struct CvSubdiv2DPoint* pt[4]; /
CvSubdiv2DEdge  next[4];

{
}


Quad-edge(译者注：以下称之为四方边缘结构)是平面划分的基元，其中包括四个边缘 (e, eRot 以及它们的逆)。

CvSubdiv2DPoint

#define CV_SUBDIV2D_POINT_FIELDS()/
int            flags;      /
CvSubdiv2DEdge first;      /
CvPoint2D32f   pt;

#define CV_SUBDIV2D_VIRTUAL_POINT_FLAG (1 << 30)

typedef struct CvSubdiv2DPoint
{
CV_SUBDIV2D_POINT_FIELDS()
}
CvSubdiv2DPoint;


Subdiv2DGetEdge

CvSubdiv2DEdge  cvSubdiv2DGetEdge( CvSubdiv2DEdge edge, CvNextEdgeType type );
#define cvSubdiv2DNextEdge( edge ) cvSubdiv2DGetEdge( edge, CV_NEXT_AROUND_ORG )


edge

type

• CV_NEXT_AROUND_ORG - 边缘原点的下一条 (eOnext on the picture above if e is the input edge)
• CV_NEXT_AROUND_DST - 边缘顶点的下一条 (eDnext)
• CV_PREV_AROUND_ORG - 边缘原点的前一条 (reversed eRnext)
• CV_PREV_AROUND_DST - 边缘终点的前一条 (reversed eLnext)
• CV_NEXT_AROUND_LEFT - 左区域的下一条 (eLnext)
• CV_NEXT_AROUND_RIGHT - 右区域的下一条(eRnext)
• CV_PREV_AROUND_LEFT - 左区域的前一条 (reversed eOnext)
• CV_PREV_AROUND_RIGHT - 右区域的前一条 (reversed eDnext)

Subdiv2DRotateEdge

CvSubdiv2DEdge  cvSubdiv2DRotateEdge( CvSubdiv2DEdge edge, int rotate );


edge

type

• 0 - 输入边缘 (上图中的e，如果e是输入边缘)
• 1 - 旋转边缘 (eRot)
• 2 -逆边缘 ( e的反向边缘)
• 3 - 旋转边缘的反向边缘(eRot的反向边缘， 图中绿色)

Subdiv2DEdgeOrg

CvSubdiv2DPoint* cvSubdiv2DEdgeOrg( CvSubdiv2DEdge edge );


edge

Subdiv2DEdgeDst

Returns edge destination

CvSubdiv2DPoint* cvSubdiv2DEdgeDst( CvSubdiv2DEdge edge );


edge

CreateSubdivDelaunay2D

CvSubdiv2D* cvCreateSubdivDelaunay2D( CvRect rect, CvMemStorage* storage );


rect
Rectangle包括所有待加入划分操作的2d点的四方形。
storage

SubdivDelaunay2DInsert

CvSubdiv2DPoint*  cvSubdivDelaunay2DInsert( CvSubdiv2D* subdiv, CvPoint2D32f pt);


subdiv

pt

Subdiv2DLocate

CvSubdiv2DPointLocation  cvSubdiv2DLocate( CvSubdiv2D* subdiv, CvPoint2D32f pt,
CvSubdiv2DEdge* edge,
CvSubdiv2DPoint** vertex=NULL );


subdiv
Delaunay 或者是其它分割结构.
pt

edge

vertex

• 输入点落入某小区域内。 函数返回参数　CV_PTLOC_INSIDE 且*edge 中包含小区域的边缘之一。
• 输入点落p在边缘之上。 函数返回参数 CV_PTLOC_ON_EDGE 且 *edge 包含此边缘。
• 输入点与划分的顶点之一相对应。 函数返回参数 CV_PTLOC_VERTEX 且 *vertex 中包括指向该顶点的指针；
• 输入点落在划分的参考区域之外。 函数返回参数 CV_PTLOC_OUTSIDE_RECT且不填写任何指针。
• 输入参数之一有误。函数报运行错误(如果已经选则了沉默或者父母出错模式，则函数返回CV_PTLOC_ERROR) 。

FindNearestPoint2D

CvSubdiv2DPoint* cvFindNearestPoint2D( CvSubdiv2D* subdiv, CvPoint2D32f pt );


subdiv
Delaunay或者其它划分方式
pt

CalcSubdivVoronoi2D

void cvCalcSubdivVoronoi2D( CvSubdiv2D* subdiv );


subdiv
Delaunay 划分,其中所有的点已经添加 。

ClearSubdivVoronoi2D

void cvClearSubdivVoronoi2D( CvSubdiv2D* subdiv );


subdiv
Delaunay 划分

运动分析与对象跟踪

背景统计量的累积

Acc

void cvAcc( const CvArr* image, CvArr* sum, const CvArr* mask=NULL );


image

sum

sum(x,y)=sum(x,y)+image(x,y) if mask(x,y)!=0


SquareAcc

void cvSquareAcc( const CvArr* image, CvArr* sqsum, const CvArr* mask=NULL );


image

sqsum

sqsum(x,y)=sqsum(x,y)+image(x,y)2 if mask(x,y)!=0


MultiplyAcc

void cvMultiplyAcc( const CvArr* image1, const CvArr* image2, CvArr* acc, const CvArr* mask=NULL );


image1

image2

acc

acc(x,y)=acc(x,y) + image1(x,y)•image2(x,y) if mask(x,y)!=0


RunningAvg

void cvRunningAvg( const CvArr* image, CvArr* acc, double alpha, const CvArr* mask=NULL );


image

acc

alpha

acc(x,y)=(1-α)•acc(x,y) + α•image(x,y) if mask(x,y)!=0


运动模板

UpdateMotionHistory

void cvUpdateMotionHistory( const CvArr* silhouette, CvArr* mhi,
double timestamp, double duration );


silhouette

mhi

timestamp

duration

mhi(x,y)=timestamp  if silhouette(x,y)!=0
0          if silhouette(x,y)=0 and mhi(x,y)<timestamp-duration
mhi(x,y)   otherwise


void cvCalcMotionGradient( const CvArr* mhi, CvArr* mask, CvArr* orientation,
double delta1, double delta2, int aperture_size=3 );


mhi

orientation

delta1, delta2

min(delta1,delta2) <= M(x,y)-m(x,y) <= max(delta1,delta2).
aperture_size

orientation(x,y)=arctan(Dy(x,y)/Dx(x,y))


CalcGlobalOrientation

double cvCalcGlobalOrientation( const CvArr* orientation, const CvArr* mask, const CvArr* mhi,
double timestamp, double duration );


orientation

mhi

timestamp

duration

SegmentMotion

CvSeq* cvSegmentMotion( const CvArr* mhi, CvArr* seg_mask, CvMemStorage* storage,
double timestamp, double seg_thresh );


mhi

storage

timestamp

seg_thresh

对象跟踪

MeanShift

int cvMeanShift( const CvArr* prob_image, CvRect window,
CvTermCriteria criteria, CvConnectedComp* comp );


prob_image

window

criteria

comp

CamShift

int cvCamShift( const CvArr* prob_image, CvRect window, CvTermCriteria criteria,
CvConnectedComp* comp, CvBox2D* box=NULL );


prob_image

window

criteria

comp

box

CvCamShiftTracker 类在 cv.hpp 中被声明，函数实现了彩色目标的跟踪。

SnakeImage

void cvSnakeImage( const IplImage* image, CvPoint* points, int length,
float* alpha, float* beta, float* gamma, int coeff_usage,
CvSize win, CvTermCriteria criteria, int calc_gradient=1 );


image

points

length

alpha

beta

gamma

coeff_usage

• CV_VALUE 表示每个 alpha, beta, gamma 都是指向为所有点所用的一个单独数值;
• CV_ARRAY 表示每个 alpha, beta, gamma 是一个指向系数数组的指针，snake 上面各点的系数都不相同。因此，各个系数数组必须与轮廓具有同样的大小。所有数组必须与轮廓具有同样大小
win

criteria

光流

CalcOpticalFlowHS

void cvCalcOpticalFlowHS( const CvArr* prev, const CvArr* curr, int use_previous,
CvArr* velx, CvArr* vely, double lambda,
CvTermCriteria criteria );


prev

curr

use_previous

velx

vely

lambda
Lagrangian 乘子
criteria

CalcOpticalFlowLK

void cvCalcOpticalFlowLK( const CvArr* prev, const CvArr* curr, CvSize win_size,
CvArr* velx, CvArr* vely );


prev

curr

win_size

velx

vely

CalcOpticalFlowBM

void cvCalcOpticalFlowBM( const CvArr* prev, const CvArr* curr, CvSize block_size,
CvSize shift_size, CvSize max_range, int use_previous,
CvArr* velx, CvArr* vely );


prev

curr

block_size

shift_size

max_range

use_previous

velx

vely

CalcOpticalFlowPyrLK

void cvCalcOpticalFlowPyrLK( const CvArr* prev, const CvArr* curr, CvArr* prev_pyr, CvArr* curr_pyr,
const CvPoint2D32f* prev_features, CvPoint2D32f* curr_features,
int count, CvSize win_size, int level, char* status,
float* track_error, CvTermCriteria criteria, int flags );


prev

curr

prev_pyr

curr_pyr
prev_pyr 类似， 用于第二帧
prev_features

curr_features

features

count

win_size

level

status

error

criteria

flags

• CV_LKFLOW_PYR_A_READY , 在调用之前，先计算第一帧的金字塔
• CV_LKFLOW_PYR_B_READY , 在调用之前，先计算第二帧的金字塔
• CV_LKFLOW_INITIAL_GUESSES , 在调用之前，数组 B 包含特征的初始坐标 （Hunnish: 在本节中没有出现数组 B，不知是指的哪一个）

预估器

CvKalman

Kalman 滤波器状态

typedef struct CvKalman
{
int MP;                     /* 测量向量维数 */
int DP;                     /* 状态向量维数 */
int CP;                     /* 控制向量维数 */

/* 向后兼容字段 */
#if 1
float* PosterState;         /* =state_pre->data.fl */
float* PriorState;          /* =state_post->data.fl */
float* DynamMatr;           /* =transition_matrix->data.fl */
float* MeasurementMatr;     /* =measurement_matrix->data.fl */
float* MNCovariance;        /* =measurement_noise_cov->data.fl */
float* PNCovariance;        /* =process_noise_cov->data.fl */
float* KalmGainMatr;        /* =gain->data.fl */
float* PriorErrorCovariance;/* =error_cov_pre->data.fl */
float* PosterErrorCovariance;/* =error_cov_post->data.fl */
float* Temp1;               /* temp1->data.fl */
float* Temp2;               /* temp2->data.fl */
#endif

CvMat* state_pre;           /* 预测状态 (x'(k)):
x(k)=A*x(k-1)+B*u(k) */
CvMat* state_post;          /* 矫正状态 (x(k)):
x(k)=x'(k)+K(k)*(z(k)-H*x'(k)) */
CvMat* transition_matrix;   /* 状态传递矩阵 state transition matrix (A) */
CvMat* control_matrix;      /* 控制矩阵 control matrix (B)
(如果没有控制，则不使用它)*/
CvMat* measurement_matrix;  /* 测量矩阵 measurement matrix (H) */
CvMat* process_noise_cov;   /* 处理噪声相关矩阵 process noise covariance matrix (Q) */
CvMat* measurement_noise_cov; /* 测量噪声相关矩阵 measurement noise covariance matrix (R) */
CvMat* error_cov_pre;       /* 先验错误估计相关矩阵 priori error estimate covariance matrix (P'(k)):
P'(k)=A*P(k-1)*At + Q)*/
CvMat* gain;                /* Kalman 增益矩阵 gain matrix (K(k)):
K(k)=P'(k)*Ht*inv(H*P'(k)*Ht+R)*/
CvMat* error_cov_post;      /* 后验错误估计相关矩阵 posteriori error estimate covariance matrix (P(k)):
P(k)=(I-K(k)*H)*P'(k) */
CvMat* temp1;               /* 临时矩阵 temporary matrices */
CvMat* temp2;
CvMat* temp3;
CvMat* temp4;
CvMat* temp5;
}
CvKalman;


Hunnish: 害怕有翻译上的不准确，因此在翻译注释时，保留了原来的英文术语，以便大家对照）

xk=A•xk-1+B•uk+wk　　　　　译者注：系统运动方程
zk=H•xk+vk,　　　　　　　　译者注：系统观测方程


xk (xk-1) - 系统在时刻 k (k-1) 的状态向量 （state of the system at the moment k (k-1)）
zk - 在时刻 k 的系统状态测量向量 （measurement of the system state at the moment k）
uk - 应用于时刻 k 的外部控制 (external control applied at the moment k)

wk 和 vk 分别为正态分布的运动和测量噪声
p(w) ~ N(0,Q)
p(v) ~ N(0,R),

Q - 运动噪声的相关矩阵，常量或变量
R - 测量噪声的相关矩阵，常量或变量


CreateKalman

CvKalman* cvCreateKalman( int dynam_params, int measure_params, int control_params=0 );


dynam_params

measure_params

control_params

ReleaseKalman

void cvReleaseKalman( CvKalman** kalman );


kalman

KalmanPredict

const CvMat* cvKalmanPredict( CvKalman* kalman, const CvMat* control=NULL );
#define cvKalmanUpdateByTime cvKalmanPredict


kalman
Kalman 滤波器状态
control

    x'k=A•xk+B•uk
P'k=A•Pk-1*AT + Q,

x'k 是预测状态 (kalman->state_pre),
xk-1 是前一步的矫正状态 (kalman->state_post)
(应该在开始的某个地方初始化，即缺省为零向量),
uk 是外部控制(control 参数),
P'k 是先验误差相关矩阵 (kalman->error_cov_pre)
Pk-1 是前一步的后验误差相关矩阵(kalman->error_cov_post)
(应该在开始的某个地方初始化，即缺省为单位矩阵),


KalmanCorrect

const CvMat* cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement );
#define cvKalmanUpdateByMeasurement cvKalmanCorrect


kalman

measurement

Kk=P'k•HT•(H•P'k•HT+R)-1
xk=x'k+Kk•(zk-H•x'k)
Pk=(I-Kk•H)•P'k

zk - 给定测量(mesurement parameter)
Kk - Kalman "增益" 矩阵


例子. 使用 Kalman 滤波器跟踪一个旋转的点

#include "cv.h"
#include "highgui.h"
#include <math.h>

int main(int argc, char** argv)
{
/* A matrix data */
const float A[] = { 1, 1, 0, 1 };

IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
CvKalman* kalman = cvCreateKalman( 2, 1, 0 );
/* state is (phi, delta_phi) - angle and angle increment */
CvMat* state = cvCreateMat( 2, 1, CV_32FC1 );
CvMat* process_noise = cvCreateMat( 2, 1, CV_32FC1 );
/* only phi (angle) is measured */
CvMat* measurement = cvCreateMat( 1, 1, CV_32FC1 );
CvRandState rng;
int code = -1;

cvRandInit( &rng, 0, 1, -1, CV_RAND_UNI );

cvZero( measurement );
cvNamedWindow( "Kalman", 1 );

for(;;)
{
cvRandSetRange( &rng, 0, 0.1, 0 );
rng.disttype = CV_RAND_NORMAL;

cvRand( &rng, state );

memcpy( kalman->transition_matrix->data.fl, A, sizeof(A));
cvSetIdentity( kalman->measurement_matrix, cvRealScalar(1) );
cvSetIdentity( kalman->process_noise_cov, cvRealScalar(1e-5) );
cvSetIdentity( kalman->measurement_noise_cov, cvRealScalar(1e-1) );
cvSetIdentity( kalman->error_cov_post, cvRealScalar(1));
/* choose random initial state */
cvRand( &rng, kalman->state_post );

rng.disttype = CV_RAND_NORMAL;

for(;;)
{
#define calc_point(angle)                                      /
cvPoint( cvRound(img->width/2 + img->width/3*cos(angle)),  /
cvRound(img->height/2 - img->width/3*sin(angle)))

float state_angle = state->data.fl[0];
CvPoint state_pt = calc_point(state_angle);

/* predict point position */
const CvMat* prediction = cvKalmanPredict( kalman, 0 );
float predict_angle = prediction->data.fl[0];
CvPoint predict_pt = calc_point(predict_angle);
float measurement_angle;
CvPoint measurement_pt;

cvRandSetRange( &rng, 0, sqrt(kalman->measurement_noise_cov->data.fl[0]), 0 );
cvRand( &rng, measurement );

/* generate measurement */
cvMatMulAdd( kalman->measurement_matrix, state, measurement, measurement );

measurement_angle = measurement->data.fl[0];
measurement_pt = calc_point(measurement_angle);

/* plot points */
#define draw_cross( center, color, d )                                 /
cvLine( img, cvPoint( center.x - d, center.y - d ),                /
cvPoint( center.x + d, center.y + d ), color, 1, 0 ); /
cvLine( img, cvPoint( center.x + d, center.y - d ),                /
cvPoint( center.x - d, center.y + d ), color, 1, 0 )

cvZero( img );
draw_cross( state_pt, CV_RGB(255,255,255), 3 );
draw_cross( measurement_pt, CV_RGB(255,0,0), 3 );
draw_cross( predict_pt, CV_RGB(0,255,0), 3 );
cvLine( img, state_pt, predict_pt, CV_RGB(255,255,0), 3, 0 );

/* adjust Kalman filter state */
cvKalmanCorrect( kalman, measurement );

cvRandSetRange( &rng, 0, sqrt(kalman->process_noise_cov->data.fl[0]), 0 );
cvRand( &rng, process_noise );
cvMatMulAdd( kalman->transition_matrix, state, process_noise, state );

cvShowImage( "Kalman", img );
code = cvWaitKey( 100 );

if( code > 0 ) /* break current simulation by pressing a key */
break;
}
if( code == 27 ) /* exit by ESCAPE */
break;
}

return 0;
}


CvConDensation

ConDensaation 状态

    typedef struct CvConDensation
{
int MP;     // 测量向量的维数： Dimension of measurement vector
int DP;     // 状态向量的维数： Dimension of state vector
float* DynamMatr;       // 线性动态系统矩阵：Matrix of the linear Dynamics system
float* State;           // 状态向量： Vector of State
int SamplesNum;         // 粒子数： Number of the Samples
float** flSamples;      // 粒子向量数组： array of the Sample Vectors
float** flNewSamples;   // 粒子向量临时数组： temporary array of the Sample Vectors
float* flConfidence;    // 每个粒子的置信度(译者注：也就是粒子的权值)：Confidence for each Sample
float* flCumulative;    // 权值的累计： Cumulative confidence
float* Temp;            // 临时向量：Temporary vector
float* RandomSample;    // 用来更新粒子集的随机向量： RandomVector to update sample set
CvRandState* RandS;     // 产生随机向量的结构数组： Array of structures to generate random vectors
} CvConDensation;


CreateConDensation

CvConDensation* cvCreateConDensation( int dynam_params, int measure_params, int sample_count );


dynam_params

measure_params

sample_count

ReleaseConDensation

void cvReleaseConDensation( CvConDensation** condens );


condens

ConDensInitSampleSet

void cvConDensInitSampleSet( CvConDensation* condens, CvMat* lower_bound, CvMat* upper_bound );


condens

lower_bound

upper_bound

ConDensUpdateByTime

void cvConDensUpdateByTime( CvConDensation* condens );


condens

模式识别

目标检测

CvHaarFeature, CvHaarClassifier, CvHaarStageClassifier, CvHaarClassifierCascade

Boosted Haar 分类器结构

#define CV_HAAR_FEATURE_MAX  3

/* 一个 harr 特征由 2－3 个具有相应权重的矩形组成a haar feature consists of 2-3 rectangles with appropriate weights */
typedef struct CvHaarFeature
{
int  tilted;  /* 0 means up-right feature, 1 means 45--rotated feature */

/* 2-3 rectangles with weights of opposite signs and
with absolute values inversely proportional to the areas of the rectangles.
if rect[2].weight !=0, then
the feature consists of 3 rectangles, otherwise it consists of 2 */
struct
{
CvRect r;
float weight;
} rect[CV_HAAR_FEATURE_MAX];
}
CvHaarFeature;

/* a single tree classifier (stump in the simplest case) that returns the response for the feature
at the particular image location (i.e. pixel sum over subrectangles of the window) and gives out
a value depending on the responce */
typedef struct CvHaarClassifier
{
int count;  /* number of nodes in the decision tree */

/* these are "parallel" arrays. Every index i
corresponds to a node of the decision tree (root has 0-th index).

left[i] - index of the left child (or negated index if the left child is a leaf)
right[i] - index of the right child (or negated index if the right child is a leaf)
threshold[i] - branch threshold. if feature responce is <= threshold, left branch
is chosen, otherwise right branch is chosed.
alpha[i] - output value correponding to the leaf. */
CvHaarFeature* haar_feature;
float* threshold;
int* left;
int* right;
float* alpha;
}
CvHaarClassifier;

/* a boosted battery of classifiers(=stage classifier):
the stage classifier returns 1
if the sum of the classifiers' responces
is greater than threshold and 0 otherwise */
typedef struct CvHaarStageClassifier
{
int  count;  /* number of classifiers in the battery */
float threshold; /* threshold for the boosted classifier */
CvHaarClassifier* classifier; /* array of classifiers */

/* these fields are used for organizing trees of stage classifiers,
rather than just stright cascades */
int next;
int child;
int parent;
}
CvHaarStageClassifier;

/* cascade or tree of stage classifiers */
{
int  flags; /* signature */
int  count; /* number of stages */
CvSize orig_window_size; /* original object size (the cascade is trained for) */

/* these two parameters are set by cvSetImagesForHaarClassifierCascade */
CvSize real_window_size; /* current object size */
double scale; /* current scale */
CvHaarStageClassifier* stage_classifier; /* array of stage classifiers */
created by cvSetImagesForHaarClassifierCascade */
}



    Cascade:
Stage1:
Classifier11:
Feature11
Classifier12:
Feature12
...
Stage2:
Classifier21:
Feature21
...
...


CvHaarClassifierCascade* cvLoadHaarClassifierCascade(
const char* directory,
CvSize orig_window_size );


directory

orig_window_size

void cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** cascade );


cvHaarDetectObjects

typedef struct CvAvgComp
{
CvRect rect; /* bounding rectangle for the object (average rectangle of a group) */
int neighbors; /* number of neighbor rectangles in the group */
}
CvAvgComp;

CvSeq* cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade,
CvMemStorage* storage, double scale_factor=1.1,
int min_neighbors=3, int flags=0,
CvSize min_size=cvSize(0,0) );


image

harr 分类器级联的内部标识形式
storage

scale_factor

min_neighbors

flags

min_size

例子:利用级联的Haar classifiers寻找检测目标(e.g. faces).

#include "cv.h"
#include "highgui.h"

{
}

void detect_and_draw_objects( IplImage* image,
int do_pyramids )
{
IplImage* small_image = image;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* faces;
int i, scale = 1;

/* if the flag is specified, down-scale the 输入图像 to get a
performance boost w/o loosing quality (perhaps) */
if( do_pyramids )
{
small_image = cvCreateImage( cvSize(image->width/2,image->height/2), IPL_DEPTH_8U, 3 );
cvPyrDown( image, small_image, CV_GAUSSIAN_5x5 );
scale = 2;
}

/* use the fastest variant */
faces = cvHaarDetectObjects( small_image, cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING );

/* draw all the rectangles */
for( i = 0; i < faces->total; i++ )
{
/* extract the rectanlges only */
CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i, 0 );
cvRectangle( image, cvPoint(face_rect.x*scale,face_rect.y*scale),
cvPoint((face_rect.x+face_rect.width)*scale,
(face_rect.y+face_rect.height)*scale),
CV_RGB(255,0,0), 3 );
}

if( small_image != image )
cvReleaseImage( &small_image );
cvReleaseMemStorage( &storage );
}

/* takes image filename and cascade path from the command line */
int main( int argc, char** argv )
{
IplImage* image;
if( argc==3 && (image = cvLoadImage( argv[1], 1 )) != 0 )
{
detect_and_draw_objects( image, cascade, 1 );
cvNamedWindow( "test", 0 );
cvShowImage( "test", image );
cvWaitKey(0);
cvReleaseImage( &image );
}

return 0;
}


void cvSetImagesForHaarClassifierCascade( CvHaarClassifierCascade* cascade,
const CvArr* sum, const CvArr* sqsum,
const CvArr* tilted_sum, double scale );


sum
32－比特，单通道图像的积分图像（Integral (sum) 单通道 image of 32-比特 integer format）. 这幅图像以及随后的两幅用于对快速特征的评价和亮度/对比度的归一化。 它们都可以利用函数 cvIntegral从8-比特或浮点数 单通道的输入图像中得到。
sqsum

tilted_sum

scale
cascade的窗口比例. 如果 scale=1, 就只用原始窗口尺寸检测 (只检测同样尺寸大小的目标物体) - 原始窗口尺寸在函数cvLoadHaarClassifierCascade中定义 (在 "<default_face_cascade>"中缺省为24x24), 如果scale=2, 使用的窗口是上面的两倍 (在face cascade中缺省值是48x48 )。 这样尽管可以将检测速度提高四倍，但同时尺寸小于48x48的人脸将不能被检测到。

int cvRunHaarClassifierCascade( CvHaarClassifierCascade* cascade,
CvPoint pt, int start_stage=0 );


Haar 级联分类器
pt

start_stage

照相机定标和三维重建

照相机定标

CalibrateCamera

void cvCalibrateCamera( int image_count, int* point_counts, CvSize image_size,
CvPoint2D32f* image_points, CvPoint3D32f* object_points,
CvVect32f distortion_coeffs, CvMatr32f camera_matrix,
CvVect32f translation_vectors, CvMatr32f rotation_matrixes,
int use_intrinsic_guess );


image_count

point_counts

image_size

image_points

object_points

distortion_coeffs

camera_matrix

translation_vectors

rotation_matrixes

use_intrinsic_guess

CalibrateCamera_64d

void cvCalibrateCamera_64d( int image_count, int* point_counts, CvSize image_size,
CvPoint2D64d* image_points, CvPoint3D64d* object_points,
CvVect64d distortion_coeffs, CvMatr64d camera_matrix,
CvVect64d translation_vectors, CvMatr64d rotation_matrixes,
int use_intrinsic_guess );


image_count

point_counts

image_size

image_points

object_points

distortion_coeffs

camera_matrix

translation_vectors

rotation_matrixes

use_intrinsic_guess
Intrinsic guess. If equal to 1, intrinsic guess is needed.

Rodrigues

void  cvRodrigues( CvMat* rotation_matrix, CvMat* rotation_vector,
CvMat* jacobian, int conv_type);


rotation_matrix

rotation_vector

jacobian

conv_type

UnDistortOnce

void cvUnDistortOnce( const CvArr* src, CvArr* dst,
const float* intrinsic_matrix,
const float* distortion_coeffs,
int interpolate=1 );


src

dst

intrinsic_matrix

distortion_coeffs

interpolate

UnDistortInit

void cvUnDistortInit( const CvArr* src, CvArr* undistortion_map,
const float* intrinsic_matrix,
const float* distortion_coeffs,
int interpolate=1 );


src

undistortion_map
32-比特整数的图像，如果interpolate=0，与输入图像尺寸相同，如果interpolate=1，是输入图像的3倍
intrinsic_matrix

distortion_coeffs

interpolate

UnDistort

void cvUnDistort( const CvArr* src, CvArr* dst,
const CvArr* undistortion_map, int interpolate=1 );


src

dst

undistortion_map

interpolate

FindChessBoardCornerGuesses

int cvFindChessBoardCornerGuesses( const CvArr* image, CvArr* thresh,
CvMemStorage* storage, CvSize board_size,
CvPoint2D32f* corners, int* corner_count=NULL );


image

thresh

storage

board_size

corners

corner_count

姿态估计

FindExtrinsicCameraParams

void cvFindExtrinsicCameraParams( int point_count, CvSize image_size,
CvPoint2D32f* image_points, CvPoint3D32f* object_points,
CvVect32f focal_length, CvPoint2D32f principal_point,
CvVect32f distortion_coeffs, CvVect32f rotation_vector,
CvVect32f translation_vector );


point_count

ImageSize

image_points

object_points

focal_length

principal_point

distortion_coeffs

rotation_vector

translation_vector

FindExtrinsicCameraParams_64d

void cvFindExtrinsicCameraParams_64d( int point_count, CvSize image_size,
CvPoint2D64d* image_points, CvPoint3D64d* object_points,
CvVect64d focal_length, CvPoint2D64d principal_point,
CvVect64d distortion_coeffs, CvVect64d rotation_vector,
CvVect64d translation_vector );


point_count

ImageSize

image_points

object_points

focal_length

principal_point

distortion_coeffs

rotation_vector

translation_vector

CreatePOSITObject

CvPOSITObject* cvCreatePOSITObject( CvPoint3D32f* points, int point_count );


points

point_count

POSIT

void cvPOSIT( CvPOSITObject* posit_object, CvPoint2D32f* image_points, double focal_length,
CvTermCriteria criteria, CvMatr32f rotation_matrix, CvVect32f translation_vector );


posit_object

image_points

focal_length

criteria
POSIT迭代算法程序终止的条件
rotation_matrix

translation_vector

ReleasePOSITObject

void cvReleasePOSITObject( CvPOSITObject** posit_object );


posit_object

CalcImageHomography

void cvCalcImageHomography( float* line, CvPoint3D32f* center,
float* intrinsic, float* homography );


line

center

intrinsic

homography

外极线几何

FindFundamentalMat

int cvFindFundamentalMat( CvMat* points1,
CvMat* points2,
CvMat* fundamental_matrix,
int    method,
double param1,
double param2,
CvMat* status=0);


points1

points2

fundamental_matrix

method

CV_FM_7POINT - for 7-point algorithm. Number of points == 7
CV_FM_8POINT - for 8-point algorithm. Number of points >= 8
CV_FM_RANSAC - for RANSAC algorithm. Number of points >= 8
CV_FM_LMEDS - for LMedS algorithm. Number of points >= 8
param1

param2

status
N个元素的数组, 在计算过程中没有被舍弃的点，元素被被置为1。否则置为0。数组由方法RANSAC and LMedS 计算。其它方法的时候status被置为1's。这个参数是可选的。 Th

p2T*F*p1=0,

7点法使用确定的7个点。这种方法能找到1个或者3个基本矩阵，返回矩阵的个数；如果目标数组中有足够的空间存储所有检测到的矩阵，该函数将所有矩阵存储，否则，只存贮其中之一。其它方法使用8点或者更多点并且返回一个基本矩阵。

Example. Fundamental matrix calculation

int point_count = 100;
CvMat* points1;
CvMat* points2;
CvMat* status;
CvMat* fundamental_matrix;

points1  = cvCreateMat(2,point_count,CV_32F);
points2  = cvCreateMat(2,point_count,CV_32F);
status   = cvCreateMat(1,point_count,CV_32F);

/* Fill the points here ... */

fundamental_matrix = cvCreateMat(3,3,CV_32F);
int num = cvFindFundamentalMat(points1,points2,fundamental_matrix,CV_FM_RANSAC,1.0,0.99,status);
if( num == 1 )
{
printf("Fundamental matrix was found/n");
}
else
{
}

/*====== Example of code for three matrixes ======*/
CvMat* points1;
CvMat* points2;
CvMat* fundamental_matrix;

points1  = cvCreateMat(2,7,CV_32F);
points2  = cvCreateMat(2,7,CV_32F);

/* Fill the points here... */

fundamental_matrix = cvCreateMat(9,3,CV_32F);
int num = cvFindFundamentalMat(points1,points2,fundamental_matrix,CV_FM_7POINT,0,0,0);
printf("Found %d matrixes/n",num);


ComputeCorrespondEpilines

void cvComputeCorrespondEpilines( const CvMat* points,
int which_image,
const CvMat* fundamental_matrix,
CvMat* correspondent_lines);


points

which_image

fundamental_matrix

correspondent_lines

l2=F*p1

l1=FT*p2

a*x + b*y + c = 0

按字母顺序的函数列表

A

 Acc ApproxChains ArcLength AdaptiveThreshold ApproxPoly

B

 BoundingRect BoxPoints

C

 CalcBackProject CalibrateCamera ConvexityDefects CalcBackProjectPatch CalibrateCamera_64d CopyHist CalcEMD2 CamShift CornerEigenValsAndVecs CalcGlobalOrientation Canny CornerMinEigenVal CalcHist CheckContourConvexity CreateConDensation CalcImageHomography ClearHist CreateContourTree CalcMotionGradient ClearSubdivVoronoi2D CreateHist CalcOpticalFlowBM CompareHist CreateKalman CalcOpticalFlowHS ComputeCorrespondEpilines CreatePOSITObject CalcOpticalFlowLK ConDensInitSampleSet CreateStructuringElementEx CalcOpticalFlowPyrLK ConDensUpdateByTime CreateSubdivDelaunay2D CalcPGH ContourArea CvtColor CalcProbDensity ContourFromContourTree CalcSubdivVoronoi2D ConvexHull2

D

 Dilate DistTransform

E

 EndFindContours Erode

F

 Filter2D FindExtrinsicCameraParams FindNextContour FindChessBoardCornerGuesses FindExtrinsicCameraParams_64d FitEllipse FindContours FindFundamentalMat FitLine2D FindCornerSubPix FindNearestPoint2D FloodFill

G

 GetCentralMoment GetMinMaxHistValue GetRectSubPix GetHistValue_1D GetNormalizedCentralMoment GetSpatialMoment GetHuMoments GetQuadrangleSubPix GoodFeaturesToTrack

H

 HaarDetectObjects HoughLines

I

 InitLineIterator Integral

K

 KalmanCorrect KalmanPredict

M

 MakeHistHeaderForArray MaxRect Moments MatchContourTrees MeanShift MorphologyEx MatchShapes MinAreaRect2 MultiplyAcc MatchTemplate MinEnclosingCircle

P

 POSIT PyrDown PyrUp PreCornerDetect PyrSegmentation

R

 ReadChainPoint ReleaseKalman Rodrigues ReleaseConDensation ReleasePOSITObject RunHaarClassifierCascade ReleaseHaarClassifierCascade ReleaseStructuringElement RunningAvg ReleaseHist Resize

S

 SampleLine Sobel Subdiv2DGetEdge SegmentMotion SquareAcc Subdiv2DLocate SetHistBinRanges StartFindContours Subdiv2DRotateEdge SetImagesForHaarClassifierCascade StartReadChainPoints SubdivDelaunay2DInsert Smooth Subdiv2DEdgeDst SubstituteContour SnakeImage Subdiv2DEdgeOrg

T

 ThreshHist Threshold

U

 UnDistort UnDistortOnce UnDistortInit UpdateMotionHistory

W

 WarpAffine WarpPerspective WarpPerspectiveQMatrix

参考书目

1. [Borgefors86] Gunilla Borgefors, "Distance Transformations in Digital Images". Computer Vision, Graphics and Image Processing 34, 344-371 (1986).
2. [Bouguet00] Jean-Yves Bouguet. Pyramidal Implementation of the Lucas Kanade Feature Tracker.
The paper is included into OpenCV distribution (algo_tracking.pdf)
3. [Bradski98] G.R. Bradski. Computer vision face tracking as a component of a perceptual user interface. In Workshop on Applications of Computer Vision, pages 214?19, Princeton, NJ, Oct. 1998.
Updated version can be found at http://www.intel.com/technology/itj/q21998/articles/art_2.htm.
Also, it is included into OpenCV distribution (camshift.pdf)
4. [Bradski00] G. Bradski and J. Davis. Motion Segmentation and Pose Recognition with Motion History Gradients. IEEE WACV'00, 2000.
5. [Burt81] P. J. Burt, T. H. Hong, A. Rosenfeld. Segmentation and Estimation of Image Region Properties Through Cooperative Hierarchical Computation. IEEE Tran. On SMC, Vol. 11, N.12, 1981, pp. 802-809.
6. [Canny86] J. Canny. A Computational Approach to Edge Detection, IEEE Trans. on Pattern Analysis and Machine Intelligence, 8(6), pp. 679-698 (1986).
7. [Davis97] J. Davis and Bobick. The Representation and Recognition of Action Using Temporal Templates. MIT Media Lab Technical Report 402, 1997.
8. [DeMenthon92] Daniel F. DeMenthon and Larry S. Davis. Model-Based Object Pose in 25 Lines of Code. In Proceedings of ECCV '92, pp. 335-343, 1992.
9. [Fitzgibbon95] Andrew W. Fitzgibbon, R.B.Fisher. A Buyer's Guide to Conic Fitting. Proc.5th British Machine Vision Conference, Birmingham, pp. 513-522, 1995.
10. [Horn81] Berthold K.P. Horn and Brian G. Schunck. Determining Optical Flow. Artificial Intelligence, 17, pp. 185-203, 1981.
11. [Hu62] M. Hu. Visual Pattern Recognition by Moment Invariants, IRE Transactions on Information Theory, 8:2, pp. 179-187, 1962.
12. [Iivarinen97] Jukka Iivarinen, Markus Peura, Jaakko Srel, and Ari Visa. Comparison of Combined Shape Descriptors for Irregular Objects, 8th British Machine Vision Conference, BMVC'97.
http://www.cis.hut.fi/research/IA/paper/publications/bmvc97/bmvc97.html
13. [Jahne97] B. Jahne. Digital Image Processing. Springer, New York, 1997.
14. [Lucas81] Lucas, B., and Kanade, T. An Iterative Image Registration Technique with an Application to Stereo Vision, Proc. of 7th International Joint Conference on Artificial Intelligence (IJCAI), pp. 674-679.
15. [Kass88] M. Kass, A. Witkin, and D. Terzopoulos. Snakes: Active Contour Models, International Journal of Computer Vision, pp. 321-331, 1988.
16. [Lienhart02] Rainer Lienhart and Jochen Maydt. An Extended Set of Haar-like Features for Rapid Object Detection. IEEE ICIP 2002, Vol. 1, pp. 900-903, Sep. 2002.
This paper, as well as the extended technical report, can be retrieved at http://www.lienhart.de/Publications/publications.html
17. [Matas98] J.Matas, C.Galambos, J.Kittler. Progressive Probabilistic Hough Transform. British Machine Vision Conference, 1998.
18. [Rosenfeld73] A. Rosenfeld and E. Johnston. Angle Detection on Digital Curves. IEEE Trans. Computers, 22:875-878, 1973.
19. [RubnerJan98] Y. Rubner. C. Tomasi, L.J. Guibas. Metrics for Distributions with Applications to Image Databases. Proceedings of the 1998 IEEE International Conference on Computer Vision, Bombay, India, January 1998, pp. 59-66.
20. [RubnerSept98] Y. Rubner. C. Tomasi, L.J. Guibas. The Earth Mover's Distance as a Metric for Image Retrieval. Technical Report STAN-CS-TN-98-86, Department of Computer Science, Stanford University, September 1998.
21. [RubnerOct98] Y. Rubner. C. Tomasi. Texture Metrics. Proceeding of the IEEE International Conference on Systems, Man, and Cybernetics, San-Diego, CA, October 1998, pp. 4601-4607. http://robotics.stanford.edu/~rubner/publications.html
22. [Serra82] J. Serra. Image Analysis and Mathematical Morphology. Academic Press, 1982.
23. [Schiele00] Bernt Schiele and James L. Crowley. Recognition without Correspondence Using Multidimensional Receptive Field Histograms. In International Journal of Computer Vision 36 (1), pp. 31-50, January 2000.
24. [Suzuki85] S. Suzuki, K. Abe. Topological Structural Analysis of Digital Binary Images by Border Following. CVGIP, v.30, n.1. 1985, pp. 32-46.
25. [Teh89] C.H. Teh, R.T. Chin. On the Detection of Dominant Points on Digital Curves. - IEEE Tr. PAMI, 1989, v.11, No.8, p. 859-872.
26. [Trucco98] Emanuele Trucco, Alessandro Verri. Introductory Techniques for 3-D Computer Vision. Prentice Hall, Inc., 1998.
27. [Viola01] Paul Viola and Michael J. Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. IEEE CVPR, 2001.
The paper is available online at http://www.ai.mit.edu/people/viola/
28. [Welch95] Greg Welch, Gary Bishop. An Introduction To the Kalman Filter. Technical Report TR95-041, University of North Carolina at Chapel Hill, 1995.
Online version is available at http://www.cs.unc.edu/~welch/kalman/kalman_filter/kalman.html
29. [Williams92] D. J. Williams and M. Shah. A Fast Algorithm for Active Contours and Curvature Estimation. CVGIP: Image Understanding, Vol. 55, No. 1, pp. 14-26, Jan., 1992. http://www.cs.ucf.edu/~vision/papers/shah/92/WIS92A.pdf.
30. [Yuille89] A.Y.Yuille, D.S.Cohen, and P.W.Hallinan. Feature Extraction from Faces Using Deformable Templates in CVPR, pp. 104-109, 1989.
31. [Zhang96] Z. Zhang. Parameter Estimation Techniques: A Tutorial with Application to Conic Fitting, Image and Vision Computing Journal, 1996.
32. [Zhang99] Z. Zhang. Flexible Camera Calibration By Viewing a Plane From Unknown Orientations. International Conference on Computer Vision (ICCV'99), Corfu, Greece, pages 666-673, September 1999.
33. [Zhang00] Z. Zhang. A Flexible New Technique for Camera Calibration. IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000.

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客