OPENCV用户手册之图像处理(网络资料搜集整理)

使用扩展 Sobel 算子计算一阶、二阶、三阶或混合图像差分

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

 src 

输入图像. 
dst 
输出图像. 
xorder 
x? 方向上的差分阶数 
yorder 
y? 方向上的差分阶数
aperture_size 
扩展 Sobel 核的大小,必须是 1, 3, 5 或 7。 除了尺寸为 1, 其它情况下, aperture_size ×aperture_size 可分离内核将用来计算差分。对 aperture_size=1的情况, 使用 3x1 或 1x3 内核 (不进行高斯平滑操作)。有一个特殊变量? CV_SCHARR (=-1),对应 3x3 Scharr 滤波器,可以给出比 3x3 Sobel 滤波更精确的结果。Scharr 滤波器系数是:
| -3 0  3|
|-10 0 10|
| -3 0  3|
x-方向 以及转置矩阵对 y-方向。

函数 cvSobel 通过对图像用相应的内核进行卷积操作来计算图像差分:

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

Sobel 算子结合 Gaussian 平滑和微分,以提高计算结果对噪声的抵抗能力。通常情况,函数调用采用如下参数 (xorder=1, yorder=0, aperture_size=3) 或 (xorder=0, yorder=1, aperture_size=3) 来计算一阶 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|

核,它依赖于图像原点的定义 (origin 来自IplImage 结构的定义)。不进行图像尺度变换。所以输出图像通常比输入图像大。为防止溢出,当输入图像是 8 位的,要求输出图像是 16 位的。产生的图像可以用函数 cvConvertScale 或 cvConvertScaleAbs 转换为 8 位的。除了 8-比特 图像,函数也接受 32-位 浮点数图像。所有输入和输出图像都必须是单通道,且图像大小或ROI尺寸一致。


计算图像的 Laplacian?

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

 src 

输入图像. 
dst 
输出图像. 
aperture_size 
核大小 (与 cvSobel 中定义一样).

函数 cvLaplace 计算输入图像的 Laplacian,方法是对用 sobel 算子计算的二阶 x- 和 y- 差分求和:

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

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

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

类似于 cvSobel 函数,也不作图像的尺度变换,而且支持输入、输出图像类型一致。


采用 Canny 算法做边缘检测

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

 image 

输入图像. 
edges 
输出的边缘图像 
threshold1 
第一个阈值 
threshold2 
第二个阈值 
aperture_size 
Sobel 算子内核大小 (见 cvSobel).

函数 cvCanny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。小的阈值 threshold1 用来控制边缘连接,大的阈值用来控制强边缘的初始分割。


计算特征图,用于角点检测

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

 image 

输入图像. 
corners 
保存角点座标的数组 
aperture_size 
Sobel 算子的核大小(见cvSobel).

函数 cvPreCornerDetect 计算函数 Dx2Dyy+Dy2Dxx - 2DxDyDxy 其中 D? 表示一阶图像差分,D?? 表示二阶图像差分。 角点被认为是函数的局部最大值:

// assuming that the image is 浮点数
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 );

计算图像块的特征值和特征向量,用于角点检测

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

 image 

输入图像. 
eigenvv 
保存结果的数组。必须比输入图像宽 6 倍。
block_size 
邻域大小 (见讨论).
aperture_size 
Sobel 算子的核尺寸(见 cvSobel).

对每个象素,函数 cvCornerEigenValsAndVecs 考虑 block_size ×block_size 大小的邻域 S(p),然后在邻域上计算差分的相关矩阵:

    | 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, x1, y1, x2, y2)存储这些值到输出图像中,其中

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


计算梯度矩阵的最小特征值,用于角点检测

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

 image 

输入图像. 
eigenval 
保存最小特征值的图像. 与输入图像大小一致
block_size 
邻域大小 (见讨论 cvCornerEigenValsAndVecs). 
aperture_size 
Sobel 算子的核尺寸(见 cvSobel). 当输入图像是浮点数格式时,该参数表示用来计算差分的浮点滤波器的个数.

函数 cvCornerMinEigenVal 与 cvCornerEigenValsAndVecs 类似,但是它仅仅计算和存储每个象素点差分相关矩阵的最小特征值,即前一个函数的 min(λ1, λ2)


精确角点位置

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

 image 

输入图像. 
corners 
输入角点的初始座标,也存储精确的输出座标 
count 
角点数目 
win 
搜索窗口的一半尺寸。如果 win=(5,5) 那么使用 5*2+1 × 5*2+1 = 11 × 11 大小的搜索窗口
zero_zone 
死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。它是用来避免自相关矩阵出现的某些可能的奇异性。当值为 (-1,-1) 表示没有死区。
criteria 
求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确度达到某个设定值。 criteria 可以是最大迭代数目,也可以是精确度

函数 cvFindCornerSubPix 通过迭代来发现具有子象素精度的角点位置,或如图所示的放射鞍点(radial saddle points)。

 Sub-pixel accurate corner locator is based on the observation that every vector from the centerq to a pointp located within a neighborhood ofq is orthogonal to the image gradient atp subject to image and measurement noise. Consider the expression:

εi=DIpiT•(q-pi)

where DIpi is the image gradient at the one of the pointspi in a neighborhood ofq. The value of q is to be found such that εi is minimized. A system of equations may be set up withεi' set to zero:

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

where the gradients are summed within a neighborhood ("search window") of q. Calling the first gradient term G and the second gradient termb gives:

q=G-1•b

The algorithm sets the center of the neighborhood window at this new center q and then iterates until the center keeps within a set threshold.


确定图像的强角点

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 

输入图像,8-位或浮点32-比特,单通道
eig_image 
临时浮点32-位图像,大小与输入图像一致
temp_image 
另外一个临时图像,格式与尺寸与 eig_image 一致
corners 
输出参数,检测到的角点 
corner_count 
输出参数,检测到的角点数目 
quality_level 
最大最小特征值的乘法因子。定义可接受图像角点的最小质量因子。 
min_distance 
限制因子。得到的角点的最小距离。使用 Euclidian 距离
mask 
ROI:感兴趣区域。函数在ROI中计算角点,如果 mask 为 NULL,则选择整个图像。

函数 cvGoodFeaturesToTrack 在图像中寻找具有大特征值的角点。该函数,首先用cvCornerMinEigenVal 计算输入图像的每一个象素点的最小特征值,并将结果存储到变量eig_image 中。然后进行非最大值压缩(仅保留3x3邻域中的局部最大值)。下一步将最小特征值小于quality_level•max(eig_image(x,y)) 排除掉。最后,函数确保所有发现的角点之间具有足够的距离,(最强的角点第一个保留,然后检查新的角点与已有角点之间的距离大于min_distance )。

 

初始化线段迭代器

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

 image 

带线段的图像. 
pt1 
线段起始点 
pt2 
线段结束点 
line_iterator 
指向线段迭代器结构的指针 
connectivity 
被扫描线段的连通数,4 或 8.

函数 cvInitLineIterator 初始化线段迭代器,并返回两点之间的象素点数目。两个点必须在图像内。当迭代器初始化后,连接两点的光栅线上所有点,都可以连续通过调用CV_NEXT_LINE_POINT 来得到。线段上的点是使用 4-连通或8-连通利用 Bresenham 算法逐点计算的。

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

    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 );
    }

将光栅线读入缓冲区

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

 image 

带线段图像 
pt1 
起点 
pt2 
终点 
buffer 
存储线段点的缓存区,必须有足够大小来存储点 max( |pt2.x-pt1.x|+1, |pt2.y-pt1.y|+1 ) :8-连通情况下,以及 |pt2.x-pt1.x|+|pt2.y-pt1.y|+1 : 4-连通情况下.
connectivity 
The line connectivity, 4 or 8.

函数 cvSampleLine 实现了线段迭代器的一个特殊应用。它读取由两点 pt1 和 pt2 确定的线段上的所有图像点,包括终点,并存储到缓存中。


从图像中提取象素矩形,使用子象素精度

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

 src 

输入图像. 
dst 
提取的矩形. 
center 
提取的象素矩形的中心,浮点数座标。中心必须位于图像内部.

函数 cvGetRectSubPix 从图像 src 中提取矩形:

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

其中非整数象素点座标采用双线性差值提取。对多通道图像,每个通道独立单独完成提取。矩形中心必须位于图像内部,而整个矩形可以部分不在图像内。这种情况下,复制的边界模识用来得到图像边界外的象素值(Hunnish:令人费解)


提取象素四边形,使用子象素精度

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_outliers=0)进行差值或者将其设置为指定值(fill_outliers=1)。 
fill_value 
对原始图像边界外面的象素设定固定值,当 fill_outliers=1.

函数 cvGetQuadrangleSubPix 从图像 src 中提取四边形,使用子象素精度,并且将结果存储于dst ,计算公式是:

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

where A and b are taken from map_matrix
             | A11 A12  b1 |
map_matrix = |            |
             | A21 A22  b2 |

其中在非整数座标 A•(x,y)T+b 的象素点值通过双线性变换得到。多通道图像的每一个通道都单独计算.

例子:使用 cvGetQuadrangleSubPix进行图像旋转

#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;
}

图像大小变换

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 - 立方差值.

函数 cvResize 将图像 src 改变尺寸得到与dst 同样大小。若设定 ROI,函数将按常规支持 ROI.


对图像做仿射变换

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 
用来填充边界外面的值

函数 cvWarpAffine 利用下面指定的矩阵变换输入图像:

dst(x',y')<-src(x,y)
如果没有指定 CV_WARP_INVERSE_MAP , (x',y')T=map_matrix•(x,y,1)T+b ,
否则, (x, y)T=map_matrix•(x',y',1)T+b

函数与 cvGetQuadrangleSubPix 类似,但是不完全相同。 cvWarpAffine 要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对大图像不太合适)而且输出图像的部分可以保留不变。而 cvGetQuadrangleSubPix 可以精确地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。

要变换稀疏矩阵,使用 cxcore 中的函数 cvTransform 。


计算二维旋转的仿射变换矩阵

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

 center 

输入图像的旋转中心 
angle 
旋转角度(度)。正值表示逆时针旋转(座标原点假设在左上角).
scale 
各项同性的尺度因子 
map_matrix 
输出 2×3 矩阵的指针

函数 cv2DRotationMatrix 计算矩阵:

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

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

该变换映射旋转中心到它本身。如果这不是目的的话,应该调整平移(Hunnish: 这段话令人费解:The transformation maps the rotation center to itself. If this is not the purpose, the shift should be adjusted)


对图像进行透视变换

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 
用来填充边界外面的值

函数 cvWarpPerspective 利用下面指定矩阵变换输入图像:

dst(x',y')<-src(x,y)
若指定 CV_WARP_INVERSE_MAP, (tx',ty',t)T=map_matrix•(x,y,1)T+b
否则, (tx, ty, t)T=map_matrix•(x',y',1)T+b

要变换稀疏矩阵,使用 cxcore 中的函数 cvTransform 。


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

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

 src 

输入图像的四边形的4个点座标
dst 
输出图像的对应四边形的4个点座标
map_matrix 
输出的 3×3 矩阵

函数 cvWarpPerspectiveQMatrix 计算透视变换矩阵,使得:

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

where dst(i)=(x'i,y'i), src(i)=(xi,yi), i=0..3.

 

HUNNISH 注:

本翻译是直接根据 OpenCV Beta 4.0 版本的用户手册翻译的,原文件是:<opencv_directory>/doc/ref/opencvref_cv.htm, 可以从 SOURCEFORG 上面的OpenCV 项目下载。

翻译中肯定有不少错误,另外也有些术语和原文语义理解不透导致翻译不准确或者错误,也请有心人赐教。翻译这些英文参考手册的目的是想与国内 OPENCV 的爱好者一起提高 OPENCV 在计算机视觉、模式识别和图像处理方面的实际应用水平。


创建结构元素

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 
指向结构元素的指针,它是一个平面数组,表示对元素矩阵逐行扫描。非零值的点表示该点属于该元素。如果点为 NULL,那么所有值都被认为是非零,即元素是一个长方形。该参数仅仅当形状是CV_SHAPE_CUSTOM 时才予以考虑。

函数 cv CreateStructuringElementEx 分配和填充结构 IplConvKernel, 它可作为形态操作中的结构元素。


删除结构元素

void cvReleaseStructuringElement( IplConvKernel** element );

 element 

被删除的结构元素的指针

函数 cvReleaseStructuringElement 释放结构 IplConvKernel 。如果*elementNULL, 则函数不作用。


使用结构元素腐蚀图像

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

 src 

输入图像. 
dst 
输出图像. 
element 
用于腐蚀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素 
iterations 
腐蚀的次数

函数 cvErode 对输入图像使用指定的结构元素进行腐蚀,该结构决定每个具有最小值象素点的邻域形状:

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

函数支持(in-place)模式。腐蚀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。


使用结构元素膨胀图像

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

 src 

输入图像. 
dst 
输出图像. 
element 
用于膨胀的结构元素。若为 NULL, 则使用 3×3 长方形的结构元素 
iterations 
膨胀的次数

函数 cvErode 对输入图像使用指定的结构元素进行腐蚀,该结构决定每个具有最小值象素点的邻域形状:

函数 cvDilate 对输入图像使用指定的结构元素进行膨胀,该结构决定每个具有最小值象素点的邻域形状:

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

函数支持(in-place)模式。膨胀可以重复进行 (iterations) 次. 对彩色图像,每个彩色通道单独处理。


高级形态变换

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 
膨胀和腐蚀次数.

函数 cvMorphologyEx 在膨胀和腐蚀基本操作的基础上,完成一些高级的形态变换:

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

闭口:
dst=close(src,element)=erode(dilate(src,element),element)

形态梯度
dst=morph_grad(src,element)=dilate(src,element)-erode(src,element)

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

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

临时图像 temp 在形态梯度以及对“顶帽”和“黑帽”操作时的 in-place 模式下需要。


各种方法的图像平滑

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 
平滑操作的第二个参数. param2 为零对应简单的尺度变换和高斯模糊。 
param3 
对应高斯参数的 Gaussian sigma (标准差). 如果为零,这由下面的核尺寸计算:
              sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 对应水平核,
                                                n=param2 对应垂直核.
              
对小的卷积核 (3×3 to 7×7) 使用标准 sigma 速度会快。如果 param3 不为零,而 param1param2 为零,则核大小有 sigma 计算 (以保证足够精确的操作).

函数 cvSmooth 可使用上面任何一种方法平滑图像。每一种方法都有自己的特点以及局限。

没有缩放的图像平滑仅支持单通道图像,并且支持8位、16位、32位和32位浮点格式。

简单模糊和高斯模糊支持 1- 或 3-通道, 8-比特 和 32-比特 浮点图像。这两种方法可以(in-place)方式处理图像。

中值和双向滤波工作于 1- 或 3-通道, 8-位图像,但是不能以 in-place 方式处理图像.


对图像做卷积

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

 src 

输入图像. 
dst 
输出图像. 
kernel 
卷积核, 单通道浮点矩阵. 如果想要应用不同的核于不同的通道,先用 cvSplit 函数分解图像到单个色彩通道上,然后单独处理。 
anchor 
核的锚点表示一个被滤波的点在核内的位置。 锚点应该处于核内部。缺省值 (-1,-1) 表示锚点在核中心。

函数 cvFilter2D 对图像进行线性滤波,支持 In-place 操作。当开孔部分位于图像外面时,函数从最近邻的图像内部象素差值得到边界外面的象素值。


计算积分图像

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

 image 

输入图像, W×H, 单通道,8位或浮点 (32f 或 64f). 
sum 
积分图像, W+1×H+1, 单通道,32位整数或 double 精度的浮点数(64f). 
sqsum 
对象素值平方的积分图像,W+1×H+1, 单通道,32位整数或 double 精度的浮点数 (64f). 
tilted_sum 
旋转45度的积分图像,单通道,32位整数或 double 精度的浮点数 (64f).

函数 cvIntegral 计算一次或高次积分图像:

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)

利用积分图像,可以方便得到某个区域象素点的和、均值、标准方差或在 0(1) 的选择角度。例如:


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

因此可以在变化的窗口内做快速平滑或窗口相关。


色彩空间转换

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

 src 

输入的 8-比特 或浮点图像. 
dst 
输出的 8-比特 或浮点图像. 
code 
色彩空间转换,通过定义 CV_<src_color_space>2<dst_color_space> 常数 (见下面).

函数 cvCvtColor 将输入图像从一个色彩空间转换为另外一个色彩空间。函数忽略 IplImage 头中定义的 colorModelchannelSeq 域,所以输入图像的色彩空间应该正确指定 (包括通道的顺序,对RGB空间而言,BGR 意味着 24-位格式,其排列为 B0 G0 R0 B1 G1 R1 ... 层叠,而 RGB 意味着 24-位格式,其排列为 R0 G0 B0 R1 G1 B1 ... 层叠). 函数做如下变换:

  • RGB 空间内部的变换,如增加/删除 alpha 通道,反相通道顺序,16位  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

     

    The output RGB components of a pixel are interpolated from 1, 2 or 4 neighbors of the pixel having the same color. There are several modifications of the above pattern that can be achieved by shifting the pattern one pixel left and/or one pixel up. The two letters C1 and C2 in the conversion constants CV_BayerC1C22{BGR|RGB} indicate the particular pattern type - these are components from the second row, second and third columns, respectively. For example, the above pattern has very popular "BG" type.


对数组元素进行固定阈值操作

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

 src 

原始数组 (单通道, 8-比特 of 32-比特 浮点数). 
dst 
输出数组,必须与 src 的类型一致,或者为 8-比特. 
threshold 
阈值 
max_value 
使用 CV_THRESH_BINARYCV_THRESH_BINARY_INV 的最大值. 
threshold_type 
阈值类型 (见讨论)

函数 cvThreshold 对单通道数组应用固定阈值操作。典型的是对灰度图像进行阈值操作得到二值图像。(cvCmpS 也可以达到此目的) 或者是去掉噪声,例如过滤很小或很大象素值的图像点。有好几种对图像取阈值的方法,本函数支持的方法由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 adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C,
                          int threshold_type=CV_THRESH_BINARY,
                          int block_size=3, double param1=5 );

 src 

输入图像. 
dst 
输出图像. 
max_value 
使用 CV_THRESH_BINARYCV_THRESH_BINARY_INV 的最大值. 
adaptive_method 
自适应阈值算法使用:CV_ADAPTIVE_THRESH_MEAN_CCV_ADAPTIVE_THRESH_GAUSSIAN_C (见讨论). 
threshold_type 
取阈值类型:必须是下者之一
  • CV_THRESH_BINARY,
  • CV_THRESH_BINARY_INV
block_size 
用来计算阈值的象素邻域大小: 3, 5, 7, ... 
param1 
与方法有关的参数。对方法 CV_ADAPTIVE_THRESH_MEAN_CCV_ADAPTIVE_THRESH_GAUSSIAN_C, 它是一个从均值或加权均值提取的常数(见讨论), 尽管它可以是负数。

函数 cvAdaptiveThreshold 将灰度图像变换到二值图像,采用下面公式:

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

其中 TI 是为每一个象素点单独计算的阈值

对方法 CV_ADAPTIVE_THRESH_MEAN_C,它是 block_size × block_size 块中的象素点,被参数 param1 所减,得到的均值,

对方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C 它是 block_size × block_size 块中的象素点,被参数 param1 所减,得到的加权和(gaussian)。

 CamShift算法

采用 CAMSHIFT 算法快速跟踪和检测运动目标的 C/C++ 源代码,OPENCV BETA 4.0 版本在其 SAMPLE 中给出了这个例子。算法的简单描述如下(英文):

This application demonstrates a fast, simple color tracking algorithm that can be used to track faces, hands . The CAMSHIFT algorithm is a modification of the Meanshift algorithm which is a robust statistical method of finding the mode (top) of a probability distribution. Both CAMSHIFT and Meanshift algorithms exist in the library. While it is a very fast and simple method of tracking, because CAMSHIFT tracks the center and size of the probability distribution of an object, it is only as good as the probability distribution that you produce for the object. Typically the probability distribution is derived from color via a histogram, although it could be produced from correlation, recognition scores or bolstered by frame differencing or motion detection schemes, or joint probabilities of different colors/motions etc.

In this application, we use only the most simplistic approach: A 1-D Hue histogram is sampled from the object in an HSV color space version of the image. To produce the probability image to track, histogram "back projection" (we replace image pixels by their histogram hue value) is used.

算法的详细情况,请看论文:

http://www.assuredigit.com/incoming/camshift.pdf

 

CamShift算法,即"Continuously Apative Mean-Shift"算法,是一种运动跟踪算法。它主要通过视频图像中运动物体的颜色信息来达到跟踪的目的。把这个算法分解成三个部分:

  • Back Projection计算。
  • Mean Shift算法
  • CamShift算法

1 Back Projection计算
计算Back Projection的步骤是这样的:

1. 计算被跟踪目标的色彩直方图。在各种色彩空间中,只有HSI空间(或与HSI类似的色彩空间)中的H分量可以表示颜色信息。所以在具体的计算过程中,首先将其他的色彩空间的值转化到HSI空间,然后会其中的H分量做1D直方图计算。

2. 根据获得的色彩直方图将原始图像转化成色彩概率分布图像,这个过程就被称作"Back Projection"。

OpenCV中的直方图函数中,包含Back Projection的函数,函数原型是:

   void cvCalcBackProject(IplImage** img, CvArr** backproject, const CvHistogram* hist);

传递给这个函数的参数有三个:

1. IplImage** img:存放原始图像,输入。

2. CvArr** backproject:存放Back Projection结果,输出。

3. CvHistogram* hist:存放直方图,输入

下面就给出计算Back Projection的OpenCV代码。

1.准备一张只包含被跟踪目标的图片,将色彩空间转化到HSI空间,获得其中的H分量:

  IplImage* target=cvLoadImage("target.bmp",-1);  //装载图片

  IplImage* target_hsv=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  IplImage* target_hue=cvCreateImage( cvGetSize(target), IPL_DEPTH_8U, 3 );

  cvCvtColor(target,target_hsv,CV_BGR2HSV);       //转化到HSV空间

  cvSplit( target_hsv, target_hue, NULL, NULL, NULL );    //获得H分量

2.计算H分量的直方图,即1D直方图:

  IplImage* h_plane=cvCreateImage( cvGetSize(target_hsv),IPL_DEPTH_8U,1 );

  int hist_size[]={255};          //将H分量的值量化到[0,255]

  float* ranges[]={ {0,360} };    //H分量的取值范围是[0,360)

  CvHistogram* hist=cvCreateHist(1, hist_size, ranges, 1);

  cvCalcHist(&target_hue, hist, 0, NULL);

在这里需要考虑H分量的取值范围的问题,H分量的取值范围是[0,360),这个取值范围的值不能用一个byte来表示,为了能用一个byte表示,需要将H值做适当的量化处理,在这里我们将H分量的范围量化到[0,255].

4.计算Back Projection:

  1. IplImage* rawImage;
  2. //----------------------------------------------
  3. //get from video frame,unsigned byte,one channel
  4. //----------------------------------------------
  5. IplImage* result=cvCreateImage(cvGetSize(rawImage),IPL_DEPTH_8U,1);
  6. cvCalcBackProject(&rawImage,result,hist);

5.结果:result即为我们需要的.

2) Mean Shift算法

这里来到了CamShift算法,OpenCV实现的第二部分,这一次重点讨论Mean Shift算法。

在讨论Mean Shift算法之前,首先讨论在2D概率分布图像中,如何计算某个区域的重心(Mass Center)的问题,重心可以通过以下公式来计算:

1.计算区域内0阶矩

  1. for(int i=0;i<height;i++)
  2. for(int j=0;j<width;j++)
  3. M00+=I(i,j)

2.区域内1阶矩:

  1. for(int i=0;i<height;i++)
  2. for(int j=0;j<width;j++)
  3. {
  4. M10+=i*I(i,j);
  5. M01+=j*I(i,j);
  6. }

3.则Mass Center为:

Xc=M10/M00; Yc=M01/M00

接下来,讨论Mean Shift算法的具体步骤,Mean Shift算法可以分为以下4步:

1.选择窗的大小和初始位置.

2.计算此时窗口内的Mass Center.

3.调整窗口的中心到Mass Center.

4.重复2和3,直到窗口中心"会聚",即每次窗口移动的距离小于一定的阈值。

OpenCV中,提供Mean Shift算法的函数,函数的原型是:

int cvMeanShift(IplImage* imgprob,CvRect windowIn, CvTermCriteria criteria,CvConnectedComp* out);

需要的参数为:

1.IplImage* imgprob:2D概率分布图像,传入;

2.CvRect windowIn:初始的窗口,传入;

3.CvTermCriteria criteria:停止迭代的标准,传入;

4.CvConnectedComp* out:查询结果,传出。

(注:构造CvTermCriteria变量需要三个参数,一个是类型,另一个是迭代的最大次数,最后一个表示特定的阈值。例如可以这样构造 criteria:criteria=cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,10,0.1)。)

返回的参数:

1.int:迭代的次数。

实现代码:暂时缺

3) CamShift算法
1.原理

在了解了MeanShift算法以后,我们将MeanShift算法扩展到连续图像序列(一般都是指视频图像序列),这样就形成了CamShift 算法。CamShift算法的全称是"Continuously Apaptive  Mean-SHIFT",它的基本思想是视频图像的所有帧作MeanShift运算,并将上一帧的结果(即Search  Window的中心和大小)作为下一帧MeanShift算法的Search  Window的初始值,如此迭代下去,就可以实现对目标的跟踪。整个算法的具体步骤分5步:

Step 1:将整个图像设为搜寻区域。

Step 2:初始话Search Window的大小和位置。

Step 3:计算Search Window内的彩色概率分布,此区域的大小比Search Window要稍微大一点。

Step 4:运行MeanShift。获得Search Window新的位置和大小。

Step 5:在下一帧视频图像中,用Step 3获得的值初始化Search Window的位置和大小。跳转到Step 3继续运行。

2.实现

OpenCV中,有实现CamShift算法的函数,此函数的原型是:

  cvCamShift(IplImage* imgprob, CvRect windowIn,CvTermCriteria criteria,CvConnectedComp* out, CvBox2D* box=0);

其中:

   imgprob:色彩概率分布图像。

   windowIn:Search Window的初始值。

   Criteria:用来判断搜寻是否停止的一个标准。

   out:保存运算结果,包括新的Search Window的位置和面积。

   box:包含被跟踪物体的最小矩形。

说明:

1.在OpenCV 4.0 beta的目录中,有CamShift的例子。遗憾的是这个例子目标的跟踪是半自动的,即需要人手工选定一个目标。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章