Thursday, August 27, 2009

Matlab morphological functions

1、dilate函数
该函数能够实现二值图像的膨胀操作,有以下形式:
BW2=dilate(BW1,SE)
BW2=dilate(BW1,SE,…,n)
其中:BW2=dilate(BW1,SE)表示使用二值结构要素矩阵SE队图像数据矩阵BW1执行膨胀操作。输入图像BW1的类型为double或unit8,输出图像BW2的类型为unit8。BW2=dilate(BW1,SE,…,n)表示执行膨胀操作n次。
 
2、erode 函数
该函数能够实现二值图像的腐蚀操作,有以下形式:
BW2= erode(BW1,SE)
BW2= erode(BW1,SE,…,n)
其中:BW2= erode(BW1,SE)表示使用二值结构要素矩阵SE队图像数据矩阵BW1执行腐蚀操作。输入图像BW1的类型为double或unit8,输出图像BW2的类型为unit8。BW2= erode(BW1,SE,…,n)表示执行腐蚀操作n次。
 
3、bwmorph函数
该函数的功能是能实现二值图像形态学运算。它的格式如下:
① BW2=bwmorph(BW1,operation)
② BW2=bwmorph(BW1,operation,n)
其中:对于格式①,bwmorph函数可对二值图像BW1采用指定的形态学运算;对于格式②,bwmorph函数可对二值图像BW1采用指定的形态学运算n次。operation为下列字符串之一:
'clean':除去孤立的像素(被0包围的1)
'close':计算二值闭合
'dilate':用结构元素计算图像膨胀
'erode':用结构元素计算图像侵蚀
 
4、imclose函数
该函数功能是对灰度图像执行形态学闭运算,即使用同样的结构元素先对图像进行膨胀操作后进行腐蚀操作。调用格式为:
IM2=imclose(IM,SE)
IM2=imclose(IM,NHOOD)
 
5、imopen函数
该函数功能是对灰度图像执行形态学开运算,即使用同样的结构元素先对图像进行腐蚀操作后进行膨胀操作。调用格式为:
IM2=imopen(IM,SE)
IM2=imopen(IM,NHOOD)

Tuesday, August 25, 2009

Gabor filter

A Gabor filter is a linear filter whose impulse response is defined by a harmonic function multiplied by a Gaussian function. Because of the multiplication-convolution property (Convolution theorem), the Fourier transform of a Gabor filter's impulse response is the convolution of the Fourier transform of the harmonic function and the Fourier transform of the Gaussian function.

g(x,y;\lambda,\theta,\psi,\sigma,\gamma)=\exp\left(-\frac{x'^2+\gamma^2y'^2}{2\sigma^2}\right)\cos\left(2\pi\frac{x'}{\lambda}+\psi\right)

where

x' = x \cos\theta + y \sin\theta\,

and

y' = -x \sin\theta + y \cos\theta\,

In this equation, λ represents the wavelength of the cosine factor, θ represents the orientation of the normal to the parallel stripes of a Gabor function, ψ is the phase offset, σ is the sigma of the Gaussian envelope and γ is the spatial aspect ratio, and specifies the ellipticity of the support of the Gabor function.

This is an example implementation in MATLAB:

function gb=gabor_fn(sigma,theta,lambda,psi,gamma)  sigma_x = sigma; sigma_y = sigma/gamma;  sz_x=fix(6*sigma_x); if mod(sz_x,2)==0, sz_x=sz_x+1;end  sz_y=fix(6*sigma_y); if mod(sz_y,2)==0, sz_y=sz_y+1;end  [x y]=meshgrid(-fix(sz_x/2):fix(sz_x/2),fix(-sz_y/2):fix(sz_y/2));  % Rotation x_theta=x*cos(theta)+y*sin(theta); y_theta=-x*sin(theta)+y*cos(theta);  gb=exp(-.5*(x_theta.^2/sigma_x^2+y_theta.^2/sigma_y^2)).*cos(2*pi/lambda*x_theta+psi);

Gabor filters are directly related to Gabor wavelets, since they can be designed for number of dilations and rotations. However, in general, expansion is not applied for Gabor wavelets, since this requires computation of biorthogonal wavelets, which may be very time-consuming. Therefore, usually, a filter bank consisting of Gabor filters with various scales and rotations is created. The filters are convolved with the signal, resulting in a so-called Gabor space. This process is closely related to processes in the primary visual cortex (Daugman, 1980). The Gabor space is very useful in e.g., image processing applications such as iris recognition and fingerprint recognition. Relations between activations for a specific spatial location are very distinctive between objects in an image. Furthermore, important activations can be extracted from the Gabor space in order to create a sparse object representation.

To visualize a 2-dimensional Gabor filter and the resulting activations after convolving it with an image, the on-line Gabor application on http://matlabserver.cs.rug.nl can be useful.

机器学习和计算机视觉相关的数学

 感觉数学似乎总是不够的。这些日子为了解决research中的一些问题,又在图书馆捧起了数学的教科书。从大学到现在,课堂上学的和自学的数学其实不算少了,可是在研究的过程中总是发现需要补充新的数学知识。Learning和Vision都是很多种数学的交汇场。看着不同的理论体系的交汇,对于一个researcher来说,往往是非常exciting的enjoyable的事情。不过,这也代表着要充分了解这个领域并且取得有意义的进展是很艰苦的。 记得在两年前的一次blog里面,提到过和learning有关的数学。今天看来,我对于数学在这个领域的作用有了新的思考。
 
1、 Linear Algebra (线性代数) 和 Statistics (统计学) 是最重要和不可缺少的。这代表了Machine Learning中最主流的两大类方法的基础。一种是以研究函数和变换为重点的代数方法,比如Dimension reduction,feature extraction,Kernel等,一种是以研究统计模型和样本分布为重点的统计方法,比如Graphical model, Information theoretical models等。它们侧重虽有不同,但是常常是共同使用的,对于代数方法,往往需要统计上的解释,对于统计模型,其具体计算则需要代数的帮助。 以代数和统计为出发点,继续往深处走,我们会发现需要更多的数学。
 
2、Calculus (微积分),只是数学分析体系的基础。其基础性作用不言而喻。Learning研究的大部分问题是在连续的度量空间进行的,无论代数还是统计,在研究优化问题的时候,对一个映射的微分或者梯度的分析总是不可避免。而在统计学中,Marginalization和积分更是密不可分――不过,以解析形式把积分导出来的情况则不多见。
 
3、Partial Differential Equation (偏微分方程),这主要用于描述动态过程,或者仿动态过程。这个学科在Vision中用得比Learning多,主要用于描述连续场的运动或者扩散过程。比如Level set, Optical flow都是这方面的典型例子。
 
4、Functional Analysis (泛函分析), 通俗地,可以理解为微积分从有限维空间到无限维空间的拓展――当然了,它实际上远不止于此。在这个地方,函数以及其所作用的对象之间存在的对偶关系扮演了非常重要的角色。Learning发展至今,也在向无限维延伸――从研究有限维向量的问题到以无限维的函数为研究对象。Kernel Learning 和 Gaussian Process 是其中典型的例子――其中的核心概念都是Kernel。很多做Learning的人把Kernel简单理解为Kernel trick的运用,这就把kernel的意义严重弱化了。在泛函里面,Kernel (Inner Product) 是建立整个博大的代数体系的根本,从metric, transform到spectrum都根源于此。
 
5、Measure Theory (测度理论),这是和实分析关系非常密切的学科。但是测度理论并不限于此。从某种意义上说,Real Analysis可以从Lebesgue Measure(勒贝格测度)推演,不过其实还有很多别的测度体系――概率本身就是一种测度。测度理论对于Learning的意义是根本的,现代统计学整个就是建立在测度理论的基础之上――虽然初级的概率论教科书一般不这样引入。在看一些统计方面的文章的时候,你可能会发现,它们会把统计的公式改用测度来表达,这样做有两个好处:所有的推导和结论不用分别给连续分布和离散分布各自写一遍了,这两种东西都可以用同一的测度形式表达:连续分布的积分基于Lebesgue测度,离散分布的求和基于计数测度,而且还能推广到那种既不连续又不离散的分布中去(这种东西不是数学家的游戏,而是已经在实用的东西,在Dirchlet Process或者Pitman-Yor Process里面会经常看到)。而且,即使是连续积分,如果不是在欧氏空间进行,而是在更一般的拓扑空间(比如微分流形或者变换群),那么传统的黎曼积分(就是大学一年级在微积分课学的那种)就不work了,你可能需要它们的一些推广,比如Haar Measure或者Lebesgue-Stieltjes积分。
 
6、Topology(拓扑学),这是学术中很基础的学科。它一般不直接提供方法,但是它的很多概念和定理是其它数学分支的基石。看很多别的数学的时候,你会经常接触这样一些概念:Open set / Closed set,set basis,Hausdauf, continuous function,metric space, Cauchy sequence, neighborhood, compactness, connectivity。很多这些也许在大学一年级就学习过一些,当时是基于极限的概念获得的。如果,看过拓扑学之后,对这些概念的认识会有根本性的拓展。比如,连续函数,当时是由epison法定义的,就是无论取多小的正数epsilon,都存在xxx,使得xxx。这是需要一种metric去度量距离的,在general topology里面,对于连续函数的定义连坐标和距离都不需要――如果一个映射使得开集的原像是开集,它就是连续的――至于开集是基于集合论定义的,不是通常的开区间的意思。这只是最简单的例子。当然,我们研究learning也许不需要深究这些数学概念背后的公理体系,但是,打破原来定义的概念的局限在很多问题上是必须的――尤其是当你研究的东西它不是在欧氏空间里面的时候――正交矩阵,变换群,流形,概率分布的空间,都属于此。
 
7、Differential Manifold (微分流形), 通俗地说它研究的是平滑的曲面。一个直接的印象是它是不是可以用来fitting一个surface什么的――当然这算是一种应用,但是这是非常初步的。本质上说,微分流形研究的是平滑的拓扑结构。一个空间构成微分流形的基本要素是局部平滑:从拓扑学来理解,就是它的任意局部都同胚于欧氏空间,从解析的角度来看,就是相容的局部坐标系统。当然,在全局上,它不要求和欧氏空间同胚。它除了可以用于刻画集合上的平滑曲面外,更重要的意义在于,它可以用于研究很多重要的集合。一个n-维线性空间的全部k-维子空间(k ……貌似不完整
 
8、Lie Group Theory (李群论),一般意义的群论在Learning中被运用的不是很多,群论在Learning中用得较多的是它的一个重要方向Lie group。定义在平滑流行上的群,并且其群运算是平滑的话,那么这就叫李群。因为Learning和编码不同,更多关注的是连续空间,因为Lie group在各种群中对于Learning特别重要。各种子空间,线性变换,非奇异矩阵都基于通常意义的矩阵乘法构成李群。在李群中的映射,变换,度量,划分等等都对于Learning中代数方法的研究有重要指导意义。
 

9、Graph Theory(图论),图,由于它在表述各种关系的强大能力以及优雅的理论,高效的算法,越来越受到Learning领域的欢迎。经典图论,在Learning中的一个最重要应用就是graphical models了,它被成功运用于分析统计网络的结构和规划统计推断的流程。Graphical model所取得的成功,图论可谓功不可没。在Vision里面,maxflow (graphcut)算法在图像分割,Stereo还有各种能量优化中也广受应用。另外一个重要的图论分支就是Algebraic graph theory (代数图论),主要运用于图的谱分析,著名的应用包括Normalized Cut和Spectral Clustering。近年来在semi-supervised learning中受到特别关注。

Delaunay triangulation

delaunay -
Delaunay triangulation
Syntax

TRI = delaunay(x,y)
TRI = delaunay(x,y,options)
Definition

image 

Given a set of data points, the Delaunay triangulation is a set of lines connecting each point to its natural neighbors. The Delaunay triangulation is related to the Voronoi diagram ― the circle circumscribed about a Delaunay triangle has its center at the vertex of a Voronoi polygon.

Description

TRI = delaunay(x,y) for the data points defined by vectors x and y, returns a set of triangles such that no data points are contained in any triangle's circumscribed circle. Each row of the m-by-3 matrix TRI defines one such triangle and contains indices into x and y. If the original data points are collinear or x is empty, the triangles cannot be computed and delaunay returns an empty matrix.

delaunay uses Qhull.

TRI = delaunay(x,y,options) specifies a cell array of strings options to be used in Qhull via delaunayn. The default options are {'Qt','Qbb','Qc'}.

If options is [], the default options are used. If options is {''}, no options are used, not even the default. For more information on Qhull and its options, see http://www.qhull.org.
Remarks

The Delaunay triangulation is used by: griddata (to interpolate scattered data), voronoi (to compute the voronoi diagram), and is useful by itself to create a triangular grid for scattered data points.

The functions dsearch and tsearch search the triangulation to find nearest neighbor points or enclosing triangles, respectively.
Visualization

Use one of these functions to plot the output of delaunay:
triplot   
Displays the triangles defined in the m-by-3 matrix TRI. See Example 1.

trisurf   
Displays each triangle defined in the m-by-3 matrix TRI as a surface in 3-D space. To see a 2-D surface, you can supply a vector of some constant value for the third dimension. For example
trisurf(TRI,x,y,zeros(size(x)))

image

See Example 2.

trimesh   
Displays each triangle defined in the m-by-3 matrix TRI as a mesh in 3-D space. To see a 2-D surface, you can supply a vector of some constant value for the third dimension. For example,
trimesh(TRI,x,y,zeros(size(x)))

image

produces almost the same result as triplot, except in 3-D space. See Example 2.

Examples
Example 1

Plot the Delaunay triangulation for 10 randomly generated points.
rand('state',0);
x = rand(1,10);
y = rand(1,10);
TRI = delaunay(x,y);
subplot(1,2,1),...
triplot(TRI,x,y)
axis([0 1 0 1]);
hold on;
plot(x,y,'or');
hold off

image

Compare the Voronoi diagram of the same points:
[vx, vy] = voronoi(x,y,TRI);
subplot(1,2,2),...
plot(x,y,'r+',vx,vy,'b-'),...
axis([0 1 0 1])

Example 2

Create a 2-D grid then use trisurf to plot its Delaunay triangulation in 3-D space by using 0s for the third dimension.
[x,y] = meshgrid(1:15,1:15);
tri = delaunay(x,y);
trisurf(tri,x,y,zeros(size(x)))

Next, generate peaks data as a 15-by-15 matrix, and use that data with the Delaunay triangulation to produce a surface in 3-D space.
z = peaks(15);
trisurf(tri,x,y,z)

You can use the same data with trimesh to produce a mesh in 3-D space.
trimesh(tri,x,y,z)

image 

Example 3

The following example illustrates the options input for delaunay.
x = [-0.5 -0.5 0.5 0.5];
       y = [-0.5 0.5 0.5 -0.5];

The command
T = delaunay(X);

returns the following error message.
qhull input error: can not scale last coordinate. Input is
cocircular
   or cospherical. Use option 'Qz' to add a point at infinity.

The error message indicates that you should add 'Qz' to the default Qhull options.
tri = delaunay(x,y,{'Qt','Qbb','Qc','Qz'})

tri =

     3     2     1
     3     4     1
Algorithm

delaunay is based on Qhull [1]. For information about Qhull, see http://www.qhull.org/. For copyright information, see http://www.qhull.org/COPYING.txt.

OpenCV统计应用-PCA主成分分析【转】

本文转载自 webuserzhy's Blog

在图形识别方面,主成分分析(Principal Comonents Analysis,PCA)算是比较快速而且又准确的方式之一,它可以对抗图形平移旋转的事件发生,并且藉由主要特征(主成分)投影过后的数据做数据的比对,在多个特征信息里面,取最主要的K个,做为它的特征依据,在这边拿前面共变量矩阵的数据来做沿用,主成分分析使用的方法为计算共变量矩阵,在加上计算共变量矩阵的特征值及特征向量,将特征值以及所对应的特征向量排序之后,取前面主要K个特征向量当做主要特征,而OpenCV也可以对高维度的向量进行主成分分析的计算。

1.5 3.0 1.2 2.1 3.1 1.3 2.0 1.0 0.5 1.0
y 2.3 1.7 2.9 2.2 3.1 2.7 1.7 2.0 0.6 0.9

数据原始的分布情况,红点代表着它的平均数

image

将坐标系位移,以红点为主要的原点

image

计算共变量矩阵以及共变量的特征值以及特征向量,将特征向量排序后投影回原始数据的结果的结果,也就是说,对照上面的图片,EigenVector的作用是找到主轴后,将原本的坐标系做旋转了

image

再来就是对它做投影,也就是降低维度的动作,将Y轴的数据全部归零,投影在X轴上

image

投影完之后,在将它转回原本的坐标系

image

PCA主成分分析,与线性回归有异曲同工之妙,也就是说,这条投影过后的直线,可以称做回归线,当它在做主轴旋转的时候,所投影的结果为最小均方误,在将它转置回来的时候,就形成了一条回归直线了
OpenCV的PCA输入必须要是单信道32位浮点数格式或是单信道64位浮点数格式的,参数为CV_32FC1或是CV_64FC1,程序写法如下

PCA程序实作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>
float Coordinates[20]={1.5,2.3,
3.0,1.7,
1.2,2.9,
2.1,2.2,
3.1,3.1,
1.3,2.7,
2.0,1.7,
1.0,2.0,
0.5,0.6,
1.0,0.9};
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
int main()
{
    CvMat *Vector1;
    CvMat *AvgVector;
    CvMat *EigenValue_Row;
    CvMat *EigenVector;
    Vector1=cvCreateMat(10,2,CV_32FC1);
    cvSetData(Vector1,Coordinates,Vector1->step);
    AvgVector=cvCreateMat(1,2,CV_32FC1);
    EigenValue_Row=cvCreateMat(2,1,CV_32FC1);
    EigenVector=cvCreateMat(2,2,CV_32FC1);
    cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW);
    printf("Original Data:\n");
    PrintMatrix(Vector1,10,2);
    printf("==========\n");
    PrintMatrix(AvgVector,1,2);
    printf("\nEigne Value:\n");
    PrintMatrix(EigenValue_Row,2,1);
    printf("\nEigne Vector:\n");
    PrintMatrix(EigenVector,2,2);
    system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
    {
for(int j=0;j<Cols;j++)
        {
            printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
        }
        printf("\n");
    }
}

细节分析

    这部份是把平均数,共变量矩阵,以及特征值及特征向量都计算出来了,全部都包在cvCalcPCA()的函式里面,因此可以不必特地的用cvCalcCovarMatrix()求得共变量矩阵,也不需要再由共变量矩阵套用cvEigenVV()求得它的EigenValue以及EigenVector了,所以说,cvCalcPCA()=cvCalcCovarMatrix()+cvEigenVV(),不仅如此,cvCalcPCA()使用上更是灵活,当向量的维度数目比输入的数据大的时候(例如Eigenface),它的共变量矩阵就会自动转成CV_COVAR_SCRAMBLED,而当输入数据量比向量维度大的时候,它亦会自动转成CV_COVAR_NORMAL的形态,而OpenCV也提供了计算投影量cvProjectPCA(),以及反向投影的函式cvBackProjectPCA(),cvCalcPCA()的计算结果如下

    详细计算方法可以参考"OpenCV统计应用-共变量矩阵"以及"OpenCV线性代数-cvEigenVV实作"这两篇,cvCalcPCA()第一个自变量为输入目标要计算的向量,整合在CvMat数据结构里,第二个自变量为空的平均数向量,第三个自变量为输出排序后的EigenValue,以列(Rows)为主的数值,第四个自变量为排序后的EigenVector,第五个自变量为cvCalcPCA()的参数,它的参数公式如下
#define CV_PCA_DATA_AS_ROW 0
#define CV_PCA_DATA_AS_COL 1
#define CV_PCA_USE_AVG 2
分别代表以列为主,以栏为主的参数设定,以及使用自己定义的平均数,CV_PCA_DATA_AS_ROW与CV_PCA_DATA_AS_COL的参数不可以同时使用,而对于主成分分析的EigenVector对原始数据投影的程序范例如下
PCA特征向量投影

cvProjectPCA(),它的公式定义如下

因此,它所呈现的结果就是将坐标旋转后的特征向量投影,cvProjectPCA()的地一个自变量为输入原始向量数据,第二个自变量为输入空的(或是以设定好的)平均数向量,第三个自变量为输入以排序好的特征向量EigenVector,第四个自变量为输出目标投影向量,而投影之外,OpenCV还可以给他做反向投影回原始的数据

PCA反向投影
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>
float Coordinates[20]={1.5,2.3,
3.0,1.7,
1.2,2.9,
2.1,2.2,
3.1,3.1,
1.3,2.7,
2.0,1.7,
1.0,2.0,
0.5,0.6,
1.0,0.9};
int main()
{
    CvMat *Vector1;
    CvMat *AvgVector;
    IplImage *Image1=cvCreateImage(cvSize(450,450),IPL_DEPTH_8U,3);
    Image1->origin=1;
    Vector1=cvCreateMat(10,2,CV_32FC1);
    cvSetData(Vector1,Coordinates,Vector1->step);
    AvgVector=cvCreateMat(1,2,CV_32FC1);
    CvMat *EigenValue_Row=cvCreateMat(2,1,CV_32FC1);
    CvMat *EigenVector=cvCreateMat(2,2,CV_32FC1);
    cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW);
    cvProjectPCA(Vector1,AvgVector,EigenVector,Vector1);
    cvBackProjectPCA(Vector1,AvgVector,EigenVector,Vector1);
    printf("Back Project Original Data:\n");
for(int i=0;i<10;i++)
    {
        printf("%.2f ",cvGetReal2D(Vector1,i,0));
       printf("%.2f ",cvGetReal2D(Vector1,i,1));
        cvCircle(Image1,cvPoint((int)(cvGetReal2D(Vector1,i,0)*100),(int)(cvGetReal2D(Vector1,i,1)*100)),0,CV_RGB(0,0,255),10,CV_AA,0);
        printf("\n");
    }
    cvCircle(Image1,cvPoint((int)((cvGetReal2D(AvgVector,0,0))*100),(int)((cvGetReal2D(AvgVector,0,1))*100)),0,CV_RGB(255,0,0),10,CV_AA,0);
    printf("==========\n");
    printf("%.2f ",cvGetReal2D(AvgVector,0,0));
    printf("%.2f ",cvGetReal2D(AvgVector,0,1));
    cvNamedWindow("Coordinates",1);
    cvShowImage("Coordinates",Image1);
    cvWaitKey(0);
}
执行结果:

而反向投影,只不过是将投影向量还原成原始数据罢了,可以用来做为新进数据反向投影后用来比对的步骤,以下是它的计算公式推导

cvBackProjectPCA()的自变量输入与cvProjectPCA()是一样的,只不过是里面的计算公式不同,其实也只是cvProjectPCA()的反运算

cvCalcPCA()
计算多笔高维度数据的主要特征值及特征向量,先自动判断维度大于数据量或维度小于数据量来选择共变量矩阵的样式,在由共变量矩阵求得已排序后的特征值及特征向量,cvCalcPCA()函式的参数为CV_PCA_DATA_AS_ROW以列为主的资料排列,CV_PCA_DATA_AS_COL以行为主的数据排列,CV_PCA_USE_AVG自行定义平均数数据,CV_PCA_DATA_AS_ROW以及CV_PCA_DATA_AS_COL不可以同时使用,cvCalcPCA()的第一个自变量为输入CvMat维度向量数据结构,第二个自变量为输入空的CvMat平均数向量数据结构(或是自行定义平均数向量),第三个自变量为输入以列为主的特征值CvMat数据结构,第四个自变量为输入特征向量CvMat数据结构,第四个自变量为输入cvCalcPCA()函式的参数
cvCalcPCA(输入目标向量数据CvMat数据结构,输入或输出向量平均数CvMat数据结构,输入以列为主EigenValue的CvMat数据结构,输入EigenVector的CvMat数据结构,目标参数或代号)
cvProjectPCA()

将计算主成分分析的结果做投影的运算,主要作用是将最具意义的k个EgienVector与位移后的原始资料做矩阵乘法,投影过后的结果将会降低维度,cvProjectPCA()第一个自变量为输入CvMat数据结构原始向量数据数据,第二个自变量为输入CvMat数据结构平均数向量,第三个自变量为输入要降维的特征向量,第四个自变量为输出CvMat数据结构原始数据投影的结果
cvProjectPCA(输入CvMat原始向量数据数据结构,输入CvMat原始向量平均数数据结构,输入CvMat降低维度的特征向量数据结构,输出CvMat投影向量数据结构)

cvBackProjectPCA()
将投影向量转回原始向量维度坐标系,cvProjectPCA()第一个自变量为输入CvMat数据结构投影向量数据,第二个自变量为输入CvMat数据结构平均数向量,第三个自变量为输入特征向量,第四个自变量为输出CvMat数据结构反向投影的结果
cvProjectPCA(输入CvMat投影向量数据结构,输入CvMat原始向量平均数数据结构,输入CvMat特征向量数据结构,输出CvMat反向投影数据结构)

BWLABEL in Matlab

BWLABEL Label connected components in 2-D binary image. L = BWLABEL(BW,N) returns a matrix L, of the same size as BW, containing labels for the connected components in BW. N can have a value of either 4 or 8, where 4 specifies 4-connected objects and 8 specifies 8-connected objects; if the argument is omitted, it defaults to 8. The elements of L are integer values greater than or equal to 0.  The pixels labeled 0 are the background.  The pixels labeled 1 make up one object, the pixels labeled 2 make up a second object, and so on. [L,NUM] = BWLABEL(BW,N) returns in NUM the number of connected objects found in BW. Note: Comparing BWLABEL and BWLABELN
------------------------------------
    BWLABEL supports 2-D inputs only, whereas BWLABELN support any
    input dimension.  In some cases you might prefer to use BWLABELN even
    for 2-D problems because it can be faster.  If you have a 2-D input
    whose objects are relatively "thick" in the vertical direction,
    BWLABEL will probably be faster; otherwise BWLABELN will probably be
    faster.
    Class Support
-------------
    BW can be logical or numeric, and it must be real, 2-D, and
    nonsparse.  L is double.
    Example
-------
 
BW = logical();
L = bwlabel(BW,4);
[r,c] = find(L == 2); 
See also bwareaopen, bweuler, bwlabeln, bwselect, label2rgb.

Reference page in Help browser
doc bwlabel

关于23种设计模式的有趣见解

转自diborve的专栏
 
创建型模式
 
1、FACTORY(工厂模式)
 
―追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说"来四个鸡翅"就行了。麦当劳和肯德基就是生产鸡翅的Factory
 
客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。
 
2、BUILDER(建造模式)
 
MM最爱听的就是"我爱你"这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出"我爱你"这句话了,国外的MM也可以轻松搞掂,这就是我的"我爱你 "builder。(这一定比美军在伊拉克用的翻译机好卖)
 
将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。
 
3、FACTORY METHOD(工厂方法模式)
 
―请MM去麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说"要一个汉堡",具体要什么样的汉堡呢,让MM直接跟服务员说就行了。
 
核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
 
4、PROTOTYPE(原始模型模式)
 
―跟MM用QQ聊天,一定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要)
 
通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。
 
5、SINGLETON(单例模式)
 
―俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,她们只要说道"老公",都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)
 
单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的"单一实例"的需求时才可使用。
 
结构型模式
 
6、ADAPTER(适配器(变压器)模式)
 
―在朋友聚会上碰到了一个美女Sarah,从香港来的,可我不会说粤语,她不会说普通话,只好求助于我的朋友kent了,他作为我和Sarah之间的Adapter,让我和Sarah可以相互交谈了(也不知道他会不会耍我)
 
把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
 
7、BRIDGE(桥梁模式)
 
―早上碰到MM,要说早上好,晚上碰到MM,要说晚上好;碰到MM穿了件新衣服,要说你的衣服好漂亮哦,碰到MM新做的发型,要说你的头发好漂亮哦。不要问我"早上碰到MM新做了个发型怎么说"这种问题,自己用BRIDGE组合一下不就行了
 
将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
 
8、COMPOSITE(合成模式)
 
Mary今天过生日。"我过生日,你要送我一件礼物。""嗯,好吧,去商店,你自己挑。""这件T恤挺漂亮,买,这条裙子好看,买,这个包也不错,买。""喂,买了三件了呀,我只答应送一件礼物的哦。""什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻烦你包起来。 ""……",MM都会用Composite模式了,你会了没有?
 
合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。
 
9、DECORATOR(装饰模式)
 
Mary过完轮到Sarly过生日,还是不要叫她自己挑了,不然这个月伙食费肯定玩完,拿出我去年在华山顶上照的照片,在背面写上"最好的的礼物,就是爱你的Fita",再到街上礼品店买了个像框(卖礼品的MM也很漂亮哦),再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来……,我们都是Decorator,最终都在修饰我这个人呀,怎么样,看懂了吗?
 
装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
 
10、FACADE(门面模式)
 
我有一个专业的Nikon相机,我就喜欢自己手动调光圈、快门,这样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式,把相机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整,这样MM也可以用这个相机给我拍张照片了。
 
外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。
 
11、FLYWEIGHT(享元模式)
 
每天跟MM发短信,手指都累死了,最近买了个新手机,可以把一些常用的句子存在手机里,要用的时候,直接拿出来,在前面加上MM的名字就可以发送了,再不用一个字一个字敲了。共享的句子就是Flyweight,MM的名字就是提取出来的外部特征,根据上下文情况使用。
 
FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。
 
12、PROXY(代理模式)
 
跟MM在网上聊天,一开头总是"hi,你好","你从哪儿来呀?""你多大了?""身高多少呀?"这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。
 
代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。
 
行为模式
 
13、CHAIN OF RESPONSIBLEITY(责任链模式)
 
晚上去上英语课,为了好开溜坐到了最后一排,哇,前面坐了好几个漂亮的MM哎,找张纸条,写上"Hi,可以做我的女朋友吗?如果不愿意请向前传",纸条就一个接一个的传上去了,糟糕,传到第一排的MM把纸条传给老师了,听说是个老处女呀,快跑!
 
在责任链模式中,很多对象由每一个对象对其下家的引用而接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。
 
14、COMMAND(命令模式)
 
俺有一个MM家里管得特别严,没法见面,只好借助于她弟弟在我们俩之间传送信息,她对我有什么指示,就写一张纸条让她弟弟带给我。这不,她弟弟又传送过来一个COMMAND,为了感谢他,我请他吃了碗杂酱面,哪知道他说:"我同时给我姐姐三个男朋友送COMMAND,就数你最小气,才请我吃面。", 
 
命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。
 
15、INTERPRETER(解释器模式)
 
俺有一个《泡MM真经》,上面有各种泡MM的攻略,比如说去吃西餐的步骤、去看电影的方法等等,跟MM约会时,只要做一个Interpreter,照着上面的脚本执行就可以了。
 
给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。
 
16、ITERATOR(迭代子模式)
 
我爱上了Mary,不顾一切的向她求婚。
 
Mary:"想要我跟你结婚,得答应我的条件"
 
我:"什么条件我都答应,你说吧"
 
Mary:"我看上了那个一克拉的钻石"
 
我:"我买,我买,还有吗?"
 
Mary:"我看上了湖边的那栋别墅"
 
我:"我买,我买,还有吗?"
 
Mary:"你的小弟弟必须要有50cm长"
 
我脑袋嗡的一声,坐在椅子上,一咬牙:"我剪,我剪,还有吗?"
 
……
 
迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。
 
17、MEDIATOR(调停者模式)
 
四个MM打麻将,相互之间谁应该给谁多少钱算不清楚了,幸亏当时我在旁边,按照各自的筹码数算钱,赚了钱的从我这里拿,赔了钱的也付给我,一切就OK啦,俺得到了四个MM的电话。
 
调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。
 
18、MEMENTO(备忘录模式)
 
同时跟几个MM聊天时,一定要记清楚刚才跟MM说了些什么话,不然MM发现了会不高兴的哦,幸亏我有个备忘录,刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存,这样可以随时察看以前的记录啦。
 
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。
 
19、OBSERVER(观察者模式)
 
想知道咱们公司最新MM情报吗?加入公司的MM情报邮件组就行了,tom负责搜集情报,他发现的新情报不用一个一个通知我们,直接发布给邮件组,我们作为订阅者(观察者)就可以及时收到情报啦
 
观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
 
20、STATE(状态模式)
 
跟MM交往时,一定要注意她的状态哦,在不同的状态时她的行为会有不同,比如你约她今天晚上去看电影,对你没兴趣的MM就会说" 有事情啦",对你不讨厌但还没喜欢上的MM就会说"好啊,不过可以带上我同事么?",已经喜欢上你的MM就会说"几点钟?看完电影再去泡吧怎么样?",当然你看电影过程中表现良好的话,也可以把MM的状态从不讨厌不喜欢变成喜欢哦。
 
状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。 
 
21、STRATEGY(策略模式)
 
跟不同类型的MM约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去海边浪漫最合适,单目的都是为了得到MM的芳心,我的追MM锦囊中有好多Strategy哦。
 
策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。
 
22、TEMPLATE METHOD(模板方法模式)
 
看过《如何说服女生上床》这部经典文章吗?女生从认识到上床的不变的步骤分为巧遇、打破僵局、展开追求、接吻、前戏、动手、爱抚、进去八大步骤(Template method),但每个步骤针对不同的情况,都有不一样的做法,这就要看你随机应变啦(具体实现);
 
模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
 
23、VISITOR(访问者模式)
 
情人节到了,要给每个MM送一束鲜花和一张卡片,可是每个MM送的花都要针对她个人的特点,每张卡片也要根据个人的特点来挑,我一个人哪搞得清楚,还是找花店老板和礼品店老板做一下Visitor,让花店老板根据MM的特点选一束花,让礼品店老板也根据每个人特点选一张卡,这样就轻松多了;
 
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。