图像处理 局部扭曲_图像局部扭曲 python - CSDN
  • Androidk开发之图像局部扭曲算法(瘦脸算法)和之前的相同,这次是图像局部扭曲算法,参照的文章是浙江某所大学两个教授的论文,具体是哪个忘了,弄了一整天,搞出来了。这个算法还不够严谨,主要处理大图片时效率不...

    Androidk开发之图像局部扭曲算法(瘦脸算法)

    和之前的相同,这次是图像局部扭曲算法,参照的文章是浙江某所大学两个教授的论文,具体是哪个忘了,弄了一整天,搞出来了。这个算法还不够严谨,主要处理大图片时效率不高,算法本来就不是我喜欢的,有能力的同学可以优化下,别忘了在回复里贴上。


    直接贴出代码,如下

    public static Bitmap smallFace(Bitmap bitmap, int tempX, int tempY,
                int PointX, int PointY, int Radius) {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            // int[] pixNew = new int[width * height];
            // int[] pixOld = new int[width * height];
            int Left = tempX - Radius < 0 ? 0 : tempX - Radius; // 计算边界值
            int Top = tempY - Radius < 0 ? 0 : tempY - Radius;
            int Bottom = tempY + Radius >= height ? height - 1 : tempY + Radius;
            int Right = tempX + Radius >= width ? width - 1 : tempX + Radius;
            Bitmap newBitmap = bitmap.copy(Bitmap.Config.RGB_565, true);
            // bitmap.getPixels(pixNew, Top * width + Left, width, Left, Top,
            // Radius * 2, Radius * 2);
            // bitmap.getPixels(pixOld, Top * width + Left, width, Left, Top,
            // Radius * 2, Radius * 2);
            int disX = PointX - tempX;
            int disY = PointY - tempY;
            int PowRadius = Radius * Radius;
            int distance = disY * disY + disX * disX;
            if (distance > Radius * Radius / 4)
                return newBitmap;
    
            for (int Y = Top; Y <= Bottom; Y++) {
                int offSetY = Y - PointY;
                for (int X = Left; X <= Right; X++) {
                    int offSetX = X - PointX;
                    double XY = offSetX * offSetX + offSetY * offSetY;
                    int PosX = (int) (X + disX * B(XY / PowRadius));
                    int PosY = (int) (Y + disY * B(XY / PowRadius));
                    if (PosX < 0) { // 放置越界
                        PosX = 0;
                    } else if (PosX >= width) {
                        PosX = width - 1;
                    }
                    if (PosY < 0) {
                        PosY = 0;
                    } else if (PosY >= height) {
                        PosY = height - 1;
                    }
                    // int Speed = Y * width + X;
                    // int Index = PosY * width + PosX;
                    newBitmap.setPixel(X, Y, bitmap.getPixel(PosX, PosY));
                    // pixNew[Speed] = pixOld[Index];
                }
            }
            // bitmap.setPixels(pixNew, Top * width + Left, width, Left, Top,
            // Radius * 2, Radius * 2);
            return newBitmap;
        }

    不做注释了,这还要注释就是真正的伸手党了。

    展开全文
  • 图像的缩放和扭曲。采取独特的插值算法实现。
  • OpenCV是跨平台的强大的计算机视觉识别和图像处理的开源库,...基本的图像处理算法(图像灰阶化、二值化、仿射变换、缩放变换以及各种插值方法)在百度或者谷歌上就能随便找到算法,但是我想找到一种可以进行局部...

    http://www.cnblogs.com/wonderchief/p/6656915.html

    OpenCV是跨平台的强大的计算机视觉识别和图像处理的开源库,可以利用他来实现:模式识别、构建神经网络、深度学习,总之用途多多,入门级就先做一下图像处理吧!

    基本的图像处理算法(图像灰阶化、二值化、仿射变换、缩放变换以及各种插值方法)在百度或者谷歌上就能随便找到算法,但是我想找到一种可以进行局部球状或者弧形状梯级式变形,找了很久没有,嗯。。。。关键问题还是得靠自己

    问题分析:

    如果我要实现想现实中如下的变形,应该怎么办?(本人文化很低,不懂得这种叫什么现象,暂且叫:弧形变形吧)

    嗯,通过观察一下,这个形状有点像2次函数,也像sin函数,经过对比,还是sin会接近一些

    于是打开octive手动画一下:

    通过观察可知,调整sin函数的系数可以调整震幅,那么,我们假设:

    v(i,j)是矩阵任意一点

    v(i,j)=v(i - sin(j/H/PI),j)进行变换

    那么就可以对图像进行sin函数扭曲

     

    如果要实现可变振幅,还要进一步处理:

    v(i,j)=v(i - (i/W)*sin(j/H/PI),j)

     

    如果要实现四边都是完美过度,还要进行调整:

    具体代码如下:

    复制代码
    //image longitudinal warping changeable amplitudes
    int xWarp(cv::Mat mat, int dst)
    {
        int w = mat.cols;
        int h = mat.rows;
        cv::Mat t = mat.clone();
        //cols
        for (int i = 0; i < w; i++)
        {
            //rows
            for (int j = 0; j < h; j++)
            {
                double delta;
                if (i < (w / 2))
                    delta = (double)i / (double)w * dst * sin(((double)j / (double)h) * pi);
                else
                    delta = (1 - (double)i / (double)w) * dst * sin(((double)j / (double)h) * pi);
                mat.at(j, i) = t.at(j, i - delta);
            }
        }
        return 0;
    }
    复制代码

    转载于:https://www.cnblogs.com/jukan/p/7444790.html

    展开全文
  • 图像变形可以说是很多图像、动画领域的一个非常常见的功能,就说ps、天天P图、美图秀秀、可牛等这些每个软件,有好多个功能都要用到图像变形,比如瘦脸眼睛放大、图像方向校正、图像全景等,在我的另外一篇博文全景...

    保刚性图像变形算法

    原文地址http://blog.csdn.net/hjimce/article/details/45766321 

    作者:hjimce

    一、相关理论

    图像变形可以说是很多图像、动画领域的一个非常常见的功能,就说ps、天天P图、美图秀秀、可牛等这些每个软件,有好多个功能都要用到图像变形,比如图像方向校正、图像全景、视频防抖等,在我的另外一篇博文全景矩形还原,就要用到图像变形算法。


    变形算法实现图像姿态调整


    变形算法实现物体方向位置调整

    可以说ps中的一些图像扭曲都是通过变形方法实现的,比如这篇paper:《As-Rigid-As-Possible Image Registration for Hand-drawn Cartoon Animations》就有讲到它的变形算法与ps的效果分析,然而我今天要讲的算法无论是在视屏防抖《Content-Preserving Warps for 3D Video Stabilization》《Bundled Camera Paths for Video Stabilization》,还是在图像全景《Rectangling Panoramic Images via Warping》等都用到这个算法,这几篇都是siggraph上的文献,对于搞图形图像的人来说,siggraph上的paper是每年必看的文章。保相似的变形算法就相当于是一个经典又好用的图像变形算法,具有保相似性,避免图像变形过程中,发生严重错切变换。好了到底是哪篇文献这么好用,那就是2005 siggraph上的一篇文献《As-Rigid-As-Possible Shape Manipulation》,这篇文献在三维网格曲面图形变形方面也具有重要的作用。

    好了废话不多说,这里开始讲解As-Rigid-As-Possible Shape Manipulation》,因为这篇paper分为两个步骤,

    第一步主要是实现尽量保证变形前后,每个三角形都于原来的对应三角形相似,又称之为网格模型的保相似变形。

    第二步主要是为了尽量保证每个三角形与原三角形尽量全等。由于第一步中算法只是保相似,这样变形后三角形会有的被放大,有的被缩小,出现图像的局部放大与缩小,所以需要对每个三角形进行适合的缩放调整,这一步又称为拟合步,拟合变形后的每个三角形与原网格三角形全等。

    一、理论讲解

    (1)相对坐标的概念。开始这个算法之前,我需要先给讲解一个三角形中相对坐标的概念:给定一个三角形v0v1v2,如下图所示:


    那么我们定义,v2相对于v0、v1的坐标为(x01,y01),满足:


    也就是说,我们可以通过已知的一个三角形,然后建立一个以三角形的一个顶点为原点,以其邻接边、及其对应的垂直旋转90度后的方向分别作为x轴、y轴,求取三角形另外一个顶点的相对于这个坐标系的坐标。OK,如果我给你一个三角形,我要你计算出(x01,y01),你要怎么计算?这个是一个简单的数学问题,同时也是本文算法开始的第一步,具体x01、y01怎么计算,那是高中问题了,不解释

    (2)整体保相似。保相似图像变形算法的原理很简单,说白了就是尽量保证变形前后,相对坐标不变,也就是说保证每个三角形的相对坐标(x12,y12)、(x20,y20)、(x01,y01)不变。因为如果两个三角形的这个相对坐标一样,那么这两个三角形就是相似三角形。那么算法具体是怎么实现尽量保证,每个三角形变形前后的这三个相对坐标不变的呢?

    假设变形后的三角形顶点坐标为v0',v1',v2'。因为我们是要尽量的保证相对坐标不变,我们可以根据下面的计算公式:


    计算出v2desired,然后使得如下误差最小化:



    上面的能量公式越小,就代表变形后的三角形与原三角形越相似。而对于有多个三角面片的网格模型,那么总误差能量公式为:


    这个问题其实归结为求解一个最小二乘问题,大家还记得吗,最小二乘其实就是使得误差能量最小化,因此到了这里其实我们就可以猜到,这个算法最后归结为求解一个稀疏的线性系统。我们的目的是使得上面的总能量最小化,设相对坐标v'=,那么:


    我们的问题是要使得E1{v’}最小化,而最小化说白了就是使得其偏导数为0,因此我们需要对E1{v’}求偏导。开始前先把公式5,换另外一种形式来表达:


    其中,q表示控制顶点,u表示自由顶点。对上面的式子求偏导:


    把上面的式子简写为:


    需要注意的是:对于控制顶点不变的模型,G'、B是一个固定的稀疏矩阵,因此我们可以通过上式求解u,得到自由顶点的坐标。

    (3)局部完全保相似,及局部缩放调整。每个三角形分开重新调整,使得其与原三角形更为相似,同时对其做缩放调整。

    首先,在经过上面的整体相似变换后,三角形可能进行放大或者缩小,因为我们用了三角形的内在属性相对坐标,这样只能保证所有三角形的尽量相似,并不能保证全等。如果算法直到这里就结束了,那么变形后的图像将会出现局部放大与缩小。就拿上面的瘦脸图片来说,如果只经过上面相似变换步骤,我们只是要移动脸型轮廓的特征点,而最后变形出来的结果可能就会出现眼睛等局部位置的放大,或缩小,因此我们要进行大小调整,瘦脸后,眼睛的大小与原来图像的大小相等。


    就像上面图像中,图(a)是原图,图(c)的结果就是只经过相似变换后的结果,可以看到(c)中的右手部变粗了许多,而左手部变细了许多,因此我们接着这一步要做的事就是调整大小,使得(a)变形后,使得图像变形后不会出现局部放大与缩小的情况,得到如(d)结果图。

    另一方面,在经过上面的整体相似变换后,因为我们用了整个三角网格模型进行整体调整,使得能量最小化,这个就像最小二乘一样,最后求解出来的结果并不能保证每个三角形与原三角形完全相似,也会发生错切变换,误差还是存在的。就像最小二乘,求解出来的结果并不能保证最后每个方程的残差为0。


    在经过(2)中的相似变换后,因为我们是对网格模型的所有三角形一起调整的,保证总三角形错切变形能最小化,这个时候得到的每个三角形也不全是完全相似的一个三角形,且大小也发生了变化,如上图所示。我们得到了v0'v1'v2',这个三角形我们称之为中介三角形,接着我们要把每个三角形分开拟合成跟原三角形v0v1v2完全全等的三角形,我们定义拟合阶段的三角形变形能为:


    当然我们还需要保证变形前后的也与原三角形相似:


    这样联立公式(9)、(10),同时对其求偏导,使得变形能最小化:


    记住,这一步是对每个三角形进行分开调整,这样才能得到与原网格模型的三角形完全相似。同时在满是上面式子后,对整个三角形以重心坐标为缩放原点,对每个三角形进行缩放调整

    (4)整体拟合

    上面那一部是对每个三角形分开调整,这个时候,每个三角形是完全独立的,我们需要对齐对整体连接调整,否则两个邻接三角形的共用边的两个顶点的位置各不一样,这样根本是不是三角网格模型。




    整个三角网格模型的总能量为:


    H是一个表示整个网格模型拓扑连接关系的矩阵,对上式换另外一种表达方式,并对其求偏导,求取最小值:

    简化为:


    然后重新求解,可得到自由顶点u的坐标。

    二、算法流程

    输入:原三角网格模型,控制顶点

    输出:变形后的三角网格模型

    Algorithm

    1、整体相似变换

    (1)计算原网格模型的相对坐标。根据给定的原三角网格模型,遍历每一个三角面片,


    并计算每个顶点,相对于另外两个顶点的坐标。以计算v2相对于边v0v1的坐标为例:


    (x01,y01)表示的是一个相对坐标,如果三角形的三个顶点的坐标已知v0,v1,v2,其实计算这个相对坐标是非常容易的。

    (1)建立局部坐标轴。先求出边向量v0v1,然后利用v0v1求出其单位向量即为局部坐标系的x轴,接着只需要把x轴旋转90度,就可以得到y轴了。

    (2)计算相对坐标(x01,y01),这一步首先需要把向量v0v2投影到x轴,y轴。这里需要注意的是我们上面的公式中x轴指的是v0v1,y轴指的是把v0v1旋转90度后的向量,因此我们需要对投影结果做一个缩放处理

    相关代码实现如下:

    	// 遍历网格模型的每个三角面片
    	for ( unsigned int i = 0; i < nTris; ++i ) {
    		Triangle & t = m_vTriangles[i];//第i个三角面片
    		//计算当前三角形每个顶点相对于另外两个顶点的坐标
    		for ( int j = 0; j < 3; ++j ) {
    			unsigned int n0 = j;
    			unsigned int n1 = (j+1)%3;
    			unsigned int n2 = (j+2)%3;//三角面片三个顶点的索引
    
    			Eigen::Vector2d v0 = GetInitialVert( t.nVerts[n0] );
    			Eigen::Vector2d v1 = GetInitialVert( t.nVerts[n1] );
    			Eigen::Vector2d v2 = GetInitialVert( t.nVerts[n2] );//三角面片三个顶点的坐标
    
    			//建立局部坐标系的 x轴 与y 轴
    			Eigen::Vector2d v01( v1 - v0 );
    			Eigen::Vector2d v01N( v01 );  
    			v01N.normalize();//边向量v0v1的方向向量   x轴
    			Eigen::Vector2d v01Rot90( v01(1), -v01(0) );
    			Eigen::Vector2d v01Rot90N( v01Rot90 );  v01Rot90N.normalize();//垂直于边v0v1的方向向量    y轴
    
    			//计算局部相对坐标
    			Eigen::Vector2d vLocal(v2 - v0);
    			float fX = vLocal.dot(v01) /SquaredLength(v01);//计算局部相对坐标x01
    			float fY = vLocal.dot(v01Rot90) /SquaredLength(v01Rot90);//计算局部相对坐标y01
    
    			
    			Eigen::Vector2d v2test(v0 + fX * v01 + fY * v01Rot90);
    			float fLength = Length(v2test - v2);
    			t.vTriCoords[j] = Eigen::Vector2d(fX,fY);//局部相对坐标(x01,y01)
    		}
    	}

    (2)构造公式(7)的相关矩阵。

    void RigidMeshDeformer2D::PrecomputeOrientationMatrix()
    {
    
    	std::vector<Constraint,Eigen::aligned_allocator<Constraint> > vConstraintsVec;
    	std::set<Constraint>::iterator cur(m_vConstraints.begin()), end(m_vConstraints.end());
    	while ( cur != end )
    		vConstraintsVec.push_back( *cur++ );
    
    
    	unsigned int nVerts = (unsigned int)m_vDeformedVerts.size();
    	m_mFirstMatrix.resize( 2*nVerts, 2*nVerts);
    	for ( unsigned int i = 0; i < 2*nVerts; ++i )
    		for ( unsigned int j = 0; j < 2*nVerts; ++j )
    			m_mFirstMatrix(i,j) = 0.0;
    
    	size_t nConstraints = vConstraintsVec.size();
    	unsigned int nFreeVerts = nVerts - nConstraints;
    
    
    	unsigned int nRow = 0;
    	m_vVertexMap.resize(nVerts);
    	for ( unsigned int i = 0; i < nVerts; ++i ) {
    		Constraint c(i, vec2(0,0));
    		if ( m_vConstraints.find(c) != m_vConstraints.end() )
    			continue;
    		m_vVertexMap[i] = nRow++;
    	}
    	for ( unsigned int i = 0 ; i < nConstraints; ++i )
    		m_vVertexMap[vConstraintsVec[i].nVertex ] = nRow++;
    
    
    
    
    
    
    	size_t nTriangles = m_vTriangles.size();
    	for ( unsigned int i = 0; i < nTriangles; ++i ) {
    		Triangle & t = m_vTriangles[i];
    		
    		double fTriSumErr = 0;
    		for ( int j = 0; j < 3; ++j ) {
    			double fTriErr = 0;
    
    			int n0x = 2 * m_vVertexMap[ t.nVerts[j] ];
    			int n0y = n0x + 1;
    			int n1x = 2 * m_vVertexMap[ t.nVerts[(j+1)%3] ];
    			int n1y = n1x + 1;
    			int n2x = 2 * m_vVertexMap[ t.nVerts[(j+2)%3] ];
    			int n2y = n2x + 1;
    			float x = t.vTriCoords[j](0);
    			float y = t.vTriCoords[j](1);
    
    
    
    
    			m_mFirstMatrix(n0x,n0x)+= 1 - 2*x + x*x + y*y;
    			m_mFirstMatrix(n0x,n1x)+= 2*x - 2*x*x - 2*y*y;	
    			m_mFirstMatrix(n0x,n1y)+= 2*y;		
    			m_mFirstMatrix(n0x,n2x)+= -2 + 2*x;	
    			m_mFirstMatrix(n0x,n2y)+= -2 * y;	
    
    
    
    		
    			m_mFirstMatrix(n0y,n0y)+= 1 - 2*x + x*x + y*y;
    			m_mFirstMatrix(n0y,n1x)+= -2*y;			
    			m_mFirstMatrix(n0y,n1y)+= 2*x - 2*x*x - 2*y*y;
    			m_mFirstMatrix(n0y,n2x)+= 2*y;		
    			m_mFirstMatrix(n0y,n2y)+= -2 + 2*x;	
    
    
    			
    			m_mFirstMatrix(n1x,n1x)+= x*x + y*y;
    			m_mFirstMatrix(n1x,n2x)+= -2*x;		
    			m_mFirstMatrix(n1x,n2y)+= 2*y;		
    
    
    
    			m_mFirstMatrix(n1y,n1y)+= x*x + y*y;
    			m_mFirstMatrix(n1y,n2x)+= -2*y;				
    			m_mFirstMatrix(n1y,n2y)+= -2*x;				
    
    
    
    	
    			m_mFirstMatrix(n2x,n2x)+= 1;
    			m_mFirstMatrix(n2y,n2y)+= 1;
    
    		}
    	}
    
    
    
    
    	Eigen::MatrixXd mG00( 2*nFreeVerts, 2*nFreeVerts );
    	ExtractSubMatrix( m_mFirstMatrix, 0, 0, mG00 );
    
    	
    	Eigen::MatrixXd mG01( 2 * (int)nFreeVerts, 2 * (int)nConstraints );
    	ExtractSubMatrix( m_mFirstMatrix, 0, 2*nFreeVerts, mG01 );
    	Eigen::MatrixXd mG10( 2 * (int)nConstraints, 2 * (int)nFreeVerts );
    	ExtractSubMatrix( m_mFirstMatrix, 2*nFreeVerts, 0, mG10 );
    
    	// 
    	Eigen::MatrixXd mGPrime = mG00 + mG00.transpose();
    	Eigen::MatrixXd mB = mG01 + mG10.transpose();
    
    	
    	Eigen::MatrixXd mGPrimeInverse=mGPrime.inverse();
    
    
    	Eigen::MatrixXd mFinal = mGPrimeInverse * mB;
    	mFinal *= -1;
    
    	m_mFirstMatrix = mFinal;	
    }

    2、局部完全相似,及大小缩放调整。

    计算公式(11)的F、C矩阵:

    //计算公式11 F、C矩阵
    void RigidMeshDeformer2D::PrecomputeScalingMatrices( unsigned int nTriangle )
    {
    	 //遍历每个三角形
    	Triangle & t = m_vTriangles[nTriangle];
    
    	
    	t.mF =Eigen::MatrixXd(4,4);
    	t.mC = Eigen::MatrixXd(4,6);
    
    	
    	double x01 = t.vTriCoords[0](0);
    	double y01 = t.vTriCoords[0](1);
    	double x12 = t.vTriCoords[1](0);
    	double y12 = t.vTriCoords[1](1);
    	double x20 = t.vTriCoords[2](0);
    	double y20 = t.vTriCoords[2](1);
    
    	double k1 = x12*y01 + (-1 + x01)*y12;
    	double k2 = -x12 + x01*x12 - y01*y12;
    	double k3 = -y01 + x20*y01 + x01*y20;
    	double k4 = -y01 + x01*y01 + x01*y20;
    	double k5 = -x01 + x01*x20 - y01*y20 ;
    
    	double a = -1 + x01;
    	double a1 = pow(-1 + x01,2) + pow(y01,2);
    	double a2 = pow(x01,2) + pow(y01,2);
    	double b =  -1 + x20;
    	double b1 = pow(-1 + x20,2) + pow(y20,2);
    	double c2 = pow(x12,2) + pow(y12,2);
    
    	double r1 = 1 + 2*a*x12 + a1*pow(x12,2) - 2*y01*y12 + a1*pow(y12,2);
    	double r2 = -(b*x01) - b1*pow(x01,2) + y01*(-(b1*y01) + y20);
    	double r3 = -(a*x12) - a1*pow(x12,2) + y12*(y01 - a1*y12);
    	double r5 = a*x01 + pow(y01,2);
    	double r6 = -(b*y01) - x01*y20;
    	double r7 = 1 + 2*b*x01 + b1*pow(x01,2) + b1*pow(y01,2) - 2*y01*y20;
    
    	//计算F矩阵
    
    	// F矩阵的第一行
    	t.mF(0,0)= 2*a1 + 2*a1*c2 + 2*r7;
    	t.mF(0,1)= 0;
    	t.mF(0,2)= 2*r2 + 2*r3 - 2*r5;
    	t.mF(0,3)= 2*k1 + 2*r6 + 2*y01;
    
    	// F矩阵的第二行
    	t.mF(1,0)= 0;
    	t.mF(1,1)= 2*a1 + 2*a1*c2 + 2*r7;
    	t.mF(1,2)= -2*k1 + 2*k3 - 2*y01;
    	t.mF(1,3)= 2*r2 + 2*r3 - 2*r5;
    
    	// F矩阵的第三行
    	t.mF(2,0)= 2*r2 + 2*r3 - 2*r5;
    	t.mF(2,1)= -2*k1 + 2*k3 - 2*y01;
    	t.mF(2,2)= 2*a2 + 2*a2*b1 + 2*r1;
    	t.mF(2,3)= 0;
    
    	//F矩阵的第四行
    	t.mF(3,0)= 2*k1 - 2*k3 + 2*y01;
    	t.mF(3,1)= 2*r2 + 2*r3 - 2*r5;
    	t.mF(3,2)= 0;
    	t.mF(3,3)= 2*a2 + 2*a2*b1 + 2*r1;
    
    	// 求逆
    	Eigen::MatrixXd mFInverse=t.mF.inverse();
    	mFInverse *= -1.0;
    	t.mF =  mFInverse;
    
    	//计算C矩阵
    
    	// C矩阵的第一行
    	t.mC(0,0)= 2*k2;
    	t.mC(0,1)= -2*k1;
    	t.mC(0,2)= 2*(-1-k5);
    	t.mC(0,3)= 2*k3;
    	t.mC(0,4)= 2*a;
    	t.mC(0,5)= -2*y01;
    
    	// C矩阵的第二行
    	t.mC(1,0)= 2*k1;
    	t.mC(1,1)= 2*k2;
    	t.mC(1,2) = -2*k3;
    	t.mC(1,3)= 2*(-1-k5);
    	t.mC(1,4)= 2*y01;
    	t.mC(1,5)= 2*a;
    
    	// C矩阵的第三行
    	t.mC(2,0)= 2*(-1-k2);
    	t.mC(2,1)= 2*k1;
    	t.mC(2,2)= 2*k5;
    	t.mC(2,3)= 2*r6;
    	t.mC(2,4)= -2*x01;
    	t.mC(2,5)= 2*y01;
    
    	//C矩阵的第四行
    	t.mC(3,0)= 2*k1;
    	t.mC(3,1)= 2*(-1-k2);
    	t.mC(3,2)= -2*k3;
    	t.mC(3,3)= 2*k5;
    	t.mC(3,4)= -2*y01;
    	t.mC(3,5)= -2*x01;
    
    
    }

    并求解公式11,得每个三角面片新顶点的位置

    3、全局连接拟合。

    构造公式(16)的相关矩阵:

    void RigidMeshDeformer2D::PrecomputeFittingMatrices()
    {
    
    	std::vector<Constraint,Eigen::aligned_allocator<Constraint> > vConstraintsVec;
    	std::set<Constraint>::iterator cur(m_vConstraints.begin()), end(m_vConstraints.end());
    	while ( cur != end )
    		vConstraintsVec.push_back( *cur++ );
    
    	
    	unsigned int nVerts = (unsigned int)m_vDeformedVerts.size();
    	size_t nConstraints = vConstraintsVec.size();
    	unsigned int nFreeVerts = nVerts - nConstraints;
    
    	
    	unsigned int nRow = 0;
    	m_vVertexMap.resize(nVerts);
    	for ( unsigned int i = 0; i < nVerts; ++i ) 
    	{
    		Constraint c(i,vec2(0,0));
    		if ( m_vConstraints.find(c) != m_vConstraints.end() )
    			continue;
    		m_vVertexMap[i] = nRow++;
    	}
    	for ( unsigned int i = 0 ; i < nConstraints; ++i )
    		m_vVertexMap[vConstraintsVec[i].nVertex ] = nRow++;
    	
    
    
    	Eigen::VectorXd gUTestX( nVerts ), gUTestY(nVerts);
    	for ( unsigned int i = 0; i < nVerts; ++i ) 
    	{
    		Constraint c(i,vec2(0,0));
    		if ( m_vConstraints.find(c) != m_vConstraints.end() )
    			continue;
    		int nRow = m_vVertexMap[i];
    		gUTestX[nRow] = m_vInitialVerts[i].vPosition(0);
    		gUTestY[nRow] = m_vInitialVerts[i].vPosition(1);
    	}
    	for ( unsigned int i = 0; i < nConstraints; ++i ) {
    		int nRow = m_vVertexMap[ vConstraintsVec[i].nVertex ];
    		gUTestX[nRow] = vConstraintsVec[i].vConstrainedPos[0];
    		gUTestY[nRow] = vConstraintsVec[i].vConstrainedPos[1];
    	}
    
    
    
    	Eigen::MatrixXd mHX( nVerts, nVerts );
    	Eigen::MatrixXd mHY( nVerts, nVerts );
    	for ( unsigned int i = 0; i < nVerts; ++i )
    		for ( unsigned int j = 0; j < nVerts; ++j )
    			mHX(i,j) = mHY(i,j) = 0.0;
    
    	
    	size_t nTriangles = m_vTriangles.size();
    	for ( unsigned int i = 0; i < nTriangles; ++i ) {
    		Triangle & t = m_vTriangles[i];
    		double fTriSumErr = 0;
    		for ( int j = 0; j < 3; ++j ) {
    			double fTriErr = 0;
    
    			int nA = m_vVertexMap[ t.nVerts[j] ];
    			int nB = m_vVertexMap[ t.nVerts[(j+1)%3] ];
    
    	
    			mHX(nA,nA)+= 2;
    			mHX(nA,nB)+= -2;
    			mHX(nB,nA)+= -2;
    			mHX(nB,nB)+= 2;
    
    	
    			mHY(nA,nA)+= 2;
    			mHY(nA,nB)+= -2;
    			mHY(nB,nA)+= -2;
    			mHY(nB,nB)+= 2;			
    		}
    	}
    
    
    	Eigen::MatrixXd mHX00( (int)nFreeVerts, (int)nFreeVerts );
    	Eigen::MatrixXd mHY00( (int)nFreeVerts, (int)nFreeVerts );
    	ExtractSubMatrix( mHX, 0, 0, mHX00 );
    	ExtractSubMatrix( mHY, 0, 0, mHY00 );
    
    
    	Eigen::MatrixXd mHX01( (int)nFreeVerts, (int)nConstraints );
    	Eigen::MatrixXd mHX10( (int)nConstraints, (int)nFreeVerts );
    	ExtractSubMatrix( mHX, 0, nFreeVerts, mHX01 );
    	ExtractSubMatrix( mHX, nFreeVerts, 0, mHX10 );
    
    	
    	Eigen::MatrixXd mHY01( (int)nFreeVerts, (int)nConstraints );
    	Eigen::MatrixXd mHY10( (int)nConstraints, (int)nFreeVerts );
    	ExtractSubMatrix( mHY, 0, nFreeVerts, mHY01 );
    	ExtractSubMatrix( mHY, nFreeVerts, 0, mHY10 );
    
    
    	m_mHXPrime = mHX00;
    	m_mHYPrime = mHY00;
    
    	m_mDX = mHX01;
    	m_mDY = mHY01;
    
    
    	m_mLUDecompX=Eigen::FullPivLU<Eigen::MatrixXd>(m_mHXPrime);
    	m_mLUDecompY=Eigen::FullPivLU<Eigen::MatrixXd>(m_mHYPrime);
    }

    这篇paper的总思路就是分成三步,因为如果控制顶点、和自由顶点的没有发生变化,相关的矩阵只要经过第一次求解就可以了,因此可以实现实时拖拽更新,这个我在三维图形学网格曲面变形的时候,用到的拉普拉斯网格变形的方法思路大体相同,需要对原网格模型做预处理操作,然后才能实现实时变形。具体这个算法要和图像结合起来,就要对图像进行三角剖分,然后计算每个三角形的放射变换矩阵,根据仿射变换矩阵计算每个像素点值的变化,才能对图像进行变形,具体就不贴代码了,因为这一些代码都是比较简单的,没有什么技术含量在里面。

    参考文献

    1、http://www-ui.is.s.u-tokyo.ac.jp/~takeo/research/rigid/

    2、《As-Rigid-As-Possible Shape Manipulation》

    ************* 作者:hjimce     联系qq:1393852684   更多资源请关注我的博客:http://blog.csdn.net/hjimce                  原创文章,转载请保留本行信息*****************

    展开全文
  • 花了点时间整理了一下数字图像处理知识体系,从宏观上把握图像处理,使自己的学习思路就更加清晰。 1.本文大部分内容来自:http://blog.csdn.net/byxdaz/article/details/4375228 2.有些内容待添加,特别是opencv...

    站得高,才能看得远!

    花了点时间整理了一下数字图像处理知识体系,从宏观上把握图像处理,使自己的学习思路就更加清晰。

    1.本文大部分内容来自:http://blog.csdn.net/byxdaz/article/details/4375228

    2.有些内容待添加,特别是opencv相关的算法实现。

    目录

    一、数字图像基础... 3

    二、数字图像存储与显示... 3

    三、图像变换... 4

    1.卷积... 4

    2.梯度和Sobel导数... 5

    3.拉普拉斯变换... 5

    4.Canny算子... 5

    5.霍夫变换... 5

    6.重映射... 5

    7.几何操作:拉伸、收缩、扭曲和旋转... 5

    8.离散傅里叶变换(DFT)... 5

    9.离散余弦变换(DCT)... 5

    四、形态学图像处理... 5

    1.平滑处理... 5

    2.膨胀与腐蚀... 5

    3.开操作与闭操作... 5

    4.漫水填充算法... 5

    5.尺寸调整... 5

    6.图像金字塔... 6

    7.阈值化... 6

    五、图像边缘检测... 6

    六、图像增强和复原... 8

    1.图像增强... 8

    (1)空间域增强处理... 8

    (2)频率域增强处理... 9

    2.图像复原... 11

    七、图像压缩... 11

    八、图像分割... 12

    九、图像特征提取与匹配... 13

    十、图像分类(识别)... 15

     

    数字图像处理[wq1] 是对图像进行分析、加工、和处理,使其满足视觉、心理以及其他要求的技术。图像处理是信号处理在图像域上的一个应用。目前大多数的图像是以数字形式存储,因而图像处理很多情况下指数字图像处理。此外,基于光学理论的处理方法依然占有重要的地位。 数字图像处理是信号处理的子类, 另外与计算机科学、人工智能等领域也有密切的关系。 传统的一维信号处理的方法和概念很多仍然可以直接应用在图像处理上,比如降噪、量化等。然而,图像属于二维信号,和一维信号相比,它有自己特殊的一面,处理的方式和角度也有所不同。大多数用于一维信号处理的概念都有其在二维图像信号领域的延伸,它们中的一部分在二维情形下变得十分复杂。同时图像处理也具有自身一些新的概念,例如,连通性、旋转不变性,等等。这些概念仅对二维或更高维的情况下才有非平凡的意义。图像处理中常用到快速傅立叶变换,因为它可以减小数据处理量和处理时间。

    数字图像处理应用在以下方面 :

    摄影及印刷 (Photography and printing)

    卫星图像处理 (Satellite imageprocessing)

    医学图像处理 (Medical image processing)

    面孔识别, 特征识别 (Face detection,feature detection, face identification)

    显微图像处理 (Microscope imageprocessing)

    汽车障碍识别 (Car barrier detection)

    一、数字图像基础

    图像的基本概念、图像取样和量化、数字图像表示、空间和灰度级分辨率、图像纹理、像素间的一些基本关系(相邻像素、邻接性、连通性、区域和边界、距离度量)[wq2] 、线性和非线性变换操作。[wq3] 

        常用色彩空间分类:

    二、数字图像存储与显示

    在计算机中,有两种类型的图:矢量图(vector graphics)和位映象图(bitmappedgraphics)。矢量图是用数学方法描述的一系列点、线、弧和其他几何形状,如图(a)所示。因此存放这种图使用的格式称为矢量图格式,存储的数据主要是绘制图形的数学描述;位映象图(bitmappedgraphics)也称光栅图(raster graphics),这种图就像电视图像一样,由象点组成的,如图(b),因此存放这种图使用的格式称为位映象图格式,经常简称为位图格式,存储的数据是描述像素的数值。

        图像格式目前包括bmp格式、gif格式、jpeg格式、jpeg2000格式、tiff格式、psd格式、Png格式、swf格式、svg格式、pcx格式、dxf格式、wmf格式、emf格式、LIC格式、eps格式、TGA格式等。

    目前比较出名的图像处理库有很多,比如LEADTOOLS、OPENCV,LEADTOOLS这个是功能非常强大的图像多媒体库,但是这个是收费注册的。OpenCV 是一个跨平台的中、高层 API 构成,目前包括 300 多个 C 函数。它不依赖与其它的外部库,尽管也可以使用某些外部库。OpenCV 对非商业用途和商业用途都是免费(FREE)的。开源的图像库也有不少,比如:ImageStone、GIMP、CxImage等,虽然它们的功能没有LEADTOOLS强大[wq4] ,但是一般的图像处理是可以应付的。

    三、图像变换

    由于图像阵列很大,直接在空间域[wq5] 中进行处理,涉及计算量很大。因此,往往采用各种图像变换的方法,如傅立叶变换、沃尔什变换、离散余弦变换等间接处理技术,将空间域的处理转换为变换域处理,不仅可减少计算量,而且可获得更有效的处理(如傅立叶变换可在频域中进行数字滤波处理)。目前新兴研究的小波变换在时域和频域中都具有良好的局部化特性,它在图像处理中也有着广泛而有效的应用。

    图像变换,也认为是将一副图像转变成图像数据。

    1.    卷积

     

    2.    梯度和Sobel导数[wq6] 

     

    3.    拉普拉斯变换[wq7] 

     

    4.    Canny算子

     

    5.    霍夫变换

     

    6.    重映射

     

    7.    几何操作:拉伸、收缩、扭曲和旋转[wq8] 

     

    8.    离散傅里叶变换(DFT)

     

    9.    离散余弦变换(DCT)

     

    四、形态学图像处理

    1.    平滑处理

     

    2.    膨胀与腐蚀

     

    3.    开操作与闭操作

     

    4.    漫水填充算法

     

    5.    尺寸调整

     

    6.    图像金字塔

     

    7.    阈值化

     

    五、图像边缘检测

    数字图像的边缘检测是图像分割、目标区域的识别、区域形状提取等图像分析领域十分重要的基础,图像理解和分析的第一步往往就是边缘检测,目前它以成为机器视觉研究领域最活跃的课题之一,在工程应用中占有十分重要的地位。所谓边缘就是指图像局部亮度变化最显著的部分,它是检测图像局部变化显著变化的最基本的运算。边缘的记录有链码表和线段表2种,链码表适合计算周长,线段表容易计算面积以及相关的,他们之间可以相互的转换。

    迄今为止,已经出现了许多成熟的算法。例如微分算法,掩模算法等。在微分算法中,常使用N*N的像素块,例如3*3或者4*4。3*3的像素块如下,

    f(i-1,j-1)  f(i-1,j)  f(i-1,j+1)

    f(i,j-1)     f(i,j)    f(i,j+1)

    f(i+1,j-1)  f(i+1,j)   f(i+1,j+1)

    我们不妨设f(i,j)为待处理的像素,而g(i, j)为处理后的像素。

    常见的边缘检测算法:

    A. Roberts边缘算子

    g(i, j) = sqrt( (f(i, j) - f(i + 1, j))^2 + (f(i + 1, j) - f(i, j +1))^2 )

    或者

    g(i, j) = |f(i,j) - f(i + 1,j)| + |f(i+1,j) - f(i,j+1)|

    B. Sobel边缘算子

    对数字图像的每一个像素f(i,j),考察它的上、下、左、右邻域灰度的加权值,把各方向上(0度、45度、90度、135度)的灰度值加权之和作为输出,可以达到提取图像边缘的效果。

    即 g(i,j) = fxr + fyr, 其中

    fxr = f(i-1,j-1)+2*f(i-1,j)+f(i-1,j+1)-f(i+1,j-1)-2*f(i+1,j)-f(i+1,j+1)

    fyr = f(i-1,j-1)+2*f(i,j-1)+f(i+1,j-1)-f(i-1,j+1)-2*f(i,j+1)-f(i+1,j+1)

    C. Laplace算子

    Laplace算子是一种二阶微分算子。它有两种形式:4邻域微分算子和8邻域微分算子。

     ⊙   4邻域微分

    g(i,j)=|4*f(i,j)-f(i,j-1)-f(i-1,j)-f(i+1,j)-f(i,j+1)|

     ⊙   8邻域微分

    g(i,j)=|8*f(i,j)-f(i,j-1)-f(i-1,j)-f(i+1,j)-f(i,j+1)-f(i-1,j-1)-f(i-1,j+1)-f(i+1,j-1)-f(i+1,j+1)|

    D. Prewitt边缘算子

    prewitt算子是一个边缘模板算子,由八个方向的样板组成,能够在0度,45度,90度,135度,180度,225度角

    等八个方向检测边缘。8个3*3边缘模板及方向如下:

    90度角:            45度角:

    1   1   1          -1  -1  -1

    1  -2   1           1  -2   1

    -1 -1 -1            1   1   1

    0度角:             315度角:

    -1   1   1         1   1   -1

    -1  -2   1        1  -2   -1

    -1   1   1        1   1   -1

    270度角:       225度角:

    1   1   1         -1   -1  1

    -1  -2 1         -1  -2   1

    -1 -1  1           1   1   1

    180度角:      135度角:

    1   1   1          1   -1   -1

    1  -2  -1         1   -2   -1

    1  -1  -1         1    1     1

    3*3时表达式如下:

    A1*f(i-1,j-1)    A8*f(i,j-1)      A7*f(i+1,j-1)

    A2*f(i-1,j)        -2*f(i,j)         A6*f(i+1, j)

    A3*f(i-1,j+1)     A4*f(i,j+1)     A5*f(i+1,j+1)

    g(i,j)=|-2*f(i,j)+A8*f(i,j-1)+A1*f(i-1,j-1)+A2*f(i-1,j)+A3*f(i-1,j+1)+A4*f(i,j+1)+A5*f(i+1,j+1)+A6*f(i+1,j)+A7*f(i+1,j-1)|

    在程序设计中,依次用样板去检测图像,与被检测区域最为相似的样板给出最大值,用该最大值作为算子的输出值。

    E.Kirsch边缘算子

    Kirsch算子是一个模板算子,由八个方向的边缘样板组成,能够在0度,45度,90度,135度,180度,225度角

    等八个方向检测边缘。8个3*3边缘模板及方向如下:

    90度角:            45度角:

    5   5   5          -3   5    5

    -3  0   -3         -3    0   5

    -3 -3 -3          -3   -3  -3

    0度角:             315度角:

    -3  -3   5        -3 -3   -3

    -3  0   5        -3  0   5

    -3   -3   5       -3  5   5

    270度角:       225度角:

    5   5  -3         -3   -3  -3

    5    0  -3        5   0   -3

    -3  -3   -3       5  5   -3

    180度角:      135度角:

    5   -3   -3       5   5   -3

    5   0  -3         5   0  -3

    5  -3  -3         -3  -3  3

    使用方法与prewitt算子一样。

    F.CANNY边缘检测

    六、图像增强和复原

    图像增强和复原的目的是为了提高图像的质量,如去除噪声,提高图像的清晰度等。图像增强不考虑图像降质的原因,突出图像中所感兴趣的部分。如强化图像高频分量,可使图像中物体轮廓清晰,细节明显;如强化低频分量可减少图像中噪声影响。图像复原要求对图像降质的原因有一定的了解,一般讲应根据降质过程建立“降质模型”,再采用某种滤波方法,恢复或重建原来的图像。

    1.     图像增强

    图像增强的目的在于改善图像的显示质量,以利于信息的提取和识别。从方法上说,则是设法摒弃一些认为不必要或干扰的信息,而将所需要的信息得以突出出来,以利于分析判读或作进一步的处理。

    (1)  空间域增强处理

    空间域是指图像平面所在的二维空间,空间域图像增强是指在图像平面上应用某种数学模型,通过改变图像像元灰度值达到增强效果,这种增强并不改变像元的位置。空域增强包括空域变换增强与空域滤波增强两种。空域变换增强是基于点处理的增强方法、空域滤波增强是基于邻域处理的增强方法。

    1)  空域变换增强

    常用的空域变换增强方法包括:对比度增强、直方图增强和图像算术运算等。

    A.对比度增强

    对比度增强是一种通过改变图像像元的亮度分布态势,扩展灰度分布区间来改变图像像元对比度,从而改善图像质量的图像处理方法。因为亮度值是辐射强度的反映,所以也称为辐射增强。常用的方法有对比度线性变换和非线性变换。其关键是寻找到一个函数,以此函数对图像中每一个像元进行变换,使像元得到统一的重新分配,构成得到反差增强的图像。

    B.直方图增强

    直方图均衡化:

        直方图均衡化基本做法是将每个灰度区间等概率分布代替了原来的随机分布,即增强后的图象中每一灰度级的像元数目大致相同。直方图均衡化可使得面积最大的地物细节得以增强,而面积小的地物与其灰度接近的地物进行合并,形成综合地物。减少灰度等级换取对比度的增大。

    直方图归一化:

        直方图归一化是把原图像的直方图变换为某种指定形态的直方图或某一参考图像的直方图,然后按着已知的指定形态的直方图调整原图像各像元的灰级,最后得到一个直方图匹配的图像。这种方法主要应用在有一幅很好的图像作为标准的情况下,对另一幅不满意的图像用标准图像的直方图进行匹配处理,以改善被处理图像的质量。如在数字镶嵌时,重叠区影像色调由于时相等原因差异往往很大,利用直方图匹配这一方法后可以改善重叠区影像色调过度,如果镶嵌图像时相相差不大,完全可以作到无缝镶嵌。

    C.数字图像的算术运算

    两幅或多幅单波段影像,完成空间配准后,通过一系列运算,可以实现图像增强,达到提取某些信息或去掉某些不必要信息的目的。

    2)  空域滤波增强

    空域变换增强是按像元逐点运算的,从整体上改善图像的质量,并不考虑周围像元影响。空间滤波增强则是以重点突出图像上的某些特征为目的的(如突出边缘或纹理等),通过像元与周围相邻像元的关系,采取空间域中的邻域处理方法进行图像增强。邻域法处理用于去噪声、图像平滑、锐化和相关运算。

    图像卷积运算是在空间域上对图像作局部检测的运算,以实现平滑和锐化的目的。具体作法是选定一卷积函数,又称为“M×N窗口”或“模板”,如3×3或5×5等。然后从图像左上角开始开一与模板同样大小的活动窗口,图像窗口与模板像元的亮度值对应相乘再相加。将计算结果赋予中心像元作为其灰度值,然后待移动后重新计算,将计算结果赋予另一个中心像元,以此类推直到全幅图像扫描一遍结束生成新的图像。

    平滑是指图像中出现某些亮度变化过大的区域,或出现不该有的亮点(“噪声”)时,采用平滑方法可以减小变化,使亮度平缓或去掉不必要“噪声”点。它实际上是使图像中高频成分消退,即平滑图像的细节,降低其反差,保存低频成分,在频域中称为低通滤波。具体方法有:均值平滑、中值滤波、锐化。

    锐化的作用在于提高边缘灰度值的变化率,使界线更加清晰。它是增强图像中的高频成分,在频域处理中称为高通滤波,也就是使图像细节的反差提高,也称边缘增强。要突出图像的边缘、线状目标或亮度变化率大的部分常采用锐化方法。一般有三种实现方法:

    A.梯度法

    梯度反映了相邻像元的亮度变化率,即图像中如果存在边缘,如湖泊、河流的边界,山脉和道路等,则边缘处有较大的梯度值。对于亮度值较平滑的部分,亮度梯度值较小。因此,找到梯度较大的位置,也就找到边缘,然后再用不同的梯度计算值代替边缘处像元的值,也就突出了边缘,实现了图像的锐化。通常有罗伯特梯度和索伯尔梯度方法。

    B.拉普拉斯算法

    拉普拉斯算法的意义与梯度法不同,它不检测均匀的亮度变化,而是检测变化率的变化率,相当于二阶微分。计算出的图像更加突出亮度值突变的位置。

    C.定向检测

    当有目的地检测某一方向的边、线或纹理特征时,可选择特定的模板卷积运算作定向检测。可以检测垂直边界、水平边界和对角线边界等,各使用的模板不同。

    (2)  频率域增强处理

    频域增强指在图像的频率域内,对图像的变换系数(频率成分)直接进行运算,然后通过Fourier逆变换以获得图像的增强效果。一般来说,图像的边缘和噪声对应Fourier变换中的高频部分,所以低通滤波能够平滑图像、去除噪声。图像灰度发生聚变的部分与频谱的高频分量对应,所以采用高频滤波器衰减或抑制低频分量,能够对图像进行锐化处理。频域,就是由图像f(x,y)的二维傅立叶变换和相应的频率变量(u,v)的值所组成的空间。在空间域图像强度的变化模式(或规律)可以直接在该空间得到反应。F(0,0)是频域中的原点,反应图像的平均灰度级,即图像中的直流成分;低频反映图像灰度发生缓慢变化的部分;而高频对应图像中灰度发生更快速变化的部分,如边缘、噪声等。但频域不能反应图像的空间信息。

    空域和频域滤波间的对应关系,卷积定理是空域和频域滤波的最基本联系纽带。二维卷积定理:

    基本计算过程:

    取函数h(m,n)关于原点的镜像,得到h(-m,-n)

    对某个(x,y),使h(-m,-n)移动相应的距离,得到h(x-m,y-n)

    对积函数f(m,n)h(x-m,y-n)在(m,n)的取值范围内求和

    位移是整数增量,对所有的(x,y)重复上面的过程,直到两个函数:f(m,n)和h(x-m,y-n)不再有重叠的部分。

    傅立叶变换是空域和频域的桥梁,关于两个域滤波的傅立叶变换对:

    频域与空域滤波的比较:

    1. 对具有同样大小的空域和频率滤波器:h(x,y), H(u,v),频域计算(由于FFT)往往更有效(尤其是图像尺寸比较大时)。但对在空域中用尺寸较小的模板就能解决的问题,则往往在空域中直接操作。

    2. 频域滤波虽然更直接,但如果可以使用较小的滤波器,还是在空域计算为好。    因为省去了计算傅立叶变换及反变换等步骤。

    3. 由于更多的直观性,频率滤波器设计往往作为空域滤波器设计的向导。

    平滑的频率域滤波器类型:

    1 、理想低通滤波器

    2 、巴特沃思低通滤波器

    3 、高斯低通滤波器

    频率域锐化滤波器类型:

    1 理想高通滤波器

    2 巴特沃思高通滤波器

    3 高斯型高通滤波器

    4 频率域的拉普拉斯算子

    5 钝化模板、高频提升滤波和高频加强滤波

    频率域图像增强处理的过程:

    2.     图像复原

    试图利用退化过程的先验知识,去恢复已被退化图像的本来面目。图像复原[wq9] 的基本思路:先建立退化的数学模型,然后根据该模型对退化图像进行拟合。

    图像复原模型可以用连续数学和离散数学处理,处理项的实现可在空间域卷积,或在频域相乘。

    七、图像压缩

    图像压缩是数据压缩技术在数字图像上的应用,它的目的是减少图像数据中的冗余信息从而用更加高效的格式存储和传输数据。图像压缩可以是有损数据压缩也可以是无损数据压缩。对于如绘制的技术图、图表或者漫画优先使用无损压缩,这是因为有损压缩方法,尤其是在低的位速条件下将会带来压缩失真。如医疗图像或者用于存档的扫描图像等这些有价值的内容的压缩也尽量选择无损压缩方法。有损方法非常适合于自然的图像,例如一些应用中图像的微小损失是可以接受的(有时是无法感知的),这样就可以大幅度地减小位速。编码是压缩技术中最重要的方法,它在图像处理技术中是发展最早且比较成熟的技术。

    1.     无损图像压缩方法

    A.行程长度编码

    B.熵编码法

    C.LZW算法

    2.     有损压缩方法

    A.将色彩空间化减到图像中常用的颜色。所选择的颜色定义在压缩图像头的调色板中,图像中的每个像素都用调色板中颜色索引表示。这种方法可以与 抖动(en:dithering)一起使用以模糊颜色边界。

    B.色度抽样,这利用了人眼对于亮度变化的敏感性远大于颜色变化,这样就可以将图像中的颜色信息减少一半甚至更多。

    C.变换编码,这是最常用的方法。首先使用如离散余弦变换(DCT)或者小波变换这样的傅立叶相关变换,然后进行量化和用熵编码法压缩。

    D.分形压缩(en:Fractal compression)。

    八、图像分割

    图像分割是数字图像处理中的关键技术之一。图像分割是将图像中有意义的特征部分提取出来,其有意义的特征有图像中的边缘、区域等,这是进一步进行图像识别、分析和理解的基础。虽然目前已研究出不少边缘提取、区域分割的方法,但还没有一种普遍适用于各种图像的有效方法。因此,对图像分割的研究还在不断深入之中,是目前图像处理中研究的热点之一。

    通常图像分割的实现方法是,将图像分为“黑”、“白”两类,这两类分别代表了两个不同的对象。

    图像分割方法:阈值分割、区域分割、数学形态学、模式识别方法

    A.阈值分割包括以下几种:

    (1)由直方图灰度分布选择阈值

    (2)双峰法选择阈值

    (3)迭代法选取阈值

    原理如下,很好理解。

        迭代法是基于逼近的思想,其步骤如下:

        1.求出图像的最大灰度值和最小灰度值,分别记为ZMAX和ZMIN,令初始阈值T0=(ZMAX+ZMIN)/2;

        2.根据阈值TK将图象分割为前景和背景,分别求出两者的平均灰度值ZO和ZB;

        3.求出新阈值TK+1=(ZO+ZB)/2;

        4.若TK=TK+1,则所得即为阈值;否则转2,迭代计算。

    4)大津法选择阈值[wq10] 

    大津法是属于最大类间方差法,它是自适应计算单阈值的简单高效方法,或者叫(Otsu)。大津法由大津于1979年提出,对图像Image,记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1。图像的总平均灰度为:u=w0*u0+w1*u1。从最小灰度值到最大灰度值遍历t,当t使得值g=w0*(u0-u)2+w1*(u1-u)2最大时t即为分割的最佳阈值。对大津法可作如下理解:该式实际上就是类间方差值,阈值t分割出的前景和背景两部分构成了整幅图像,而前景取值u0,概率为 w0,背景取值u1,概率为w1,总均值为u,根据方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说明构成图像的两部分差别越大, 当部分目标错分为背景或部分背景错分为目标都会导致两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。直接应用大津法计算量较大,因此一般采用了等价的公式g=w0*w1*(u0-u1)2。

    (5)由灰度拉伸选择阈值

    大津法是较通用的方法,但是它对两群物体在灰度不明显的情况下会丢失一些整体信息。因此为了解决这种现象采用灰度拉伸的增强大津法。在大津法的思想上增加灰度的级数来增强前两群物体的灰度差。对于原来的灰度级乘上同一个系数,从而扩大了图像灰度的级数。试验结果表明不同的拉伸系数,分割效果差别比较大。

    B.区域的分割

    区域生长、区域分离与合并

    区域生长算法

    C.基于形态学分水岭的分割

    分水岭分割算法

    九、图像特征提取与匹配[wq11] 

    常用的图像特征有颜色特征、纹理特征、形状特征、空间关系特征。

    A.颜色特征

    特点:颜色特征是一种全局特征,描述了图像或图像区域所对应的景物的表面性质。一般颜色特征是基于像素点的特征,此时所有属于图像或图像区域的像素都有各自的贡献。由于颜色对图像或图像区域的方向、大小等变化不敏感,所以颜色特征不能很好地捕捉图像中对象的局部特征。

    常用的特征提取与匹配方法:

    颜色直方图

    其优点在于:它能简单描述一幅图像中颜色的全局分布,即不同色彩在整幅图像中所占的比例,特别适用于描述那些难以自动分割的图像和不需要考虑物体空间位置的图像。其缺点在于:它无法描述图像中颜色的局部分布及每种色彩所处的空间位置,即无法描述图像中的某一具体的对象或物体。

    颜色直方图特征匹配方法:直方图相交法、距离法、中心距法、参考颜色表法、累加颜色直方图法。

    B.纹理特征

    纹理特征的提取方法比较简单,它是用一个活动的窗口在图像上连续滑动,分别计算出窗口中的方差、均值、最大值、最小值及二者之差和信息熵等,形成相应的纹理图像,当目标的光谱特性比较接近时,纹理特征对于区分目标可以起到积极的作用。选取适当的数据动态变化范围,进行纹理特征提取后,使影像的纹理特征得到突出,有利于提取构造信息。

    特点:纹理特征也是一种全局特征,它也描述了图像或图像区域所对应景物的表面性质。但由于纹理只是一种物体表面的特性,并不能完全反映出物体的本质属性,所以仅仅利用纹理特征是无法获得高层次图像内容的。与颜色特征不同,纹理特征不是基于像素点的特征,它需要在包含多个像素点的区域中进行统计计算。在模式匹配中,这种区域性的特征具有较大的优越性,不会由于局部的偏差而无法匹配成功。作为一种统计特征,纹理特征常具有旋转不变性,并且对于噪声有较强的抵抗能力。但是,纹理特征也有其缺点,一个很明显的缺点是当图像的分辨率变化的时候,所计算出来的纹理可能会有较大偏差。另外,由于有可能受到光照、反射情况的影响,从2-D图像中反映出来的纹理不一定是3-D物体表面真实的纹理。

    常用的特征提取与匹配方法:

    纹理特征描述方法分类

    (1)统计方法统计方法的典型代表是一种称为灰度共生矩阵的纹理特征分析方法Gotlieb 和 Kreyszig 等人在研究共生矩阵中各种统计特征基础上,通过实验,得出灰度共生矩阵的四个关键特征:能量、惯量、熵和相关性。统计方法中另一种典型方法,则是从图像的自相关函数(即图像的能量谱函数)提取纹理特征,即通过对图像的能量谱函数的计算,提取纹理的粗细度及方向性等特征参数

    (2)几何法

    所谓几何法,是建立在纹理基元(基本的纹理元素)理论基础上的一种纹理特征分析方法。纹理基元理论认为,复杂的纹理可以由若干简单的纹理基元以一定的有规律的形式重复排列构成。在几何法中,比较有影响的算法有两种:Voronio 棋盘格特征法和结构法。

    (3)模型法

    模型法以图像的构造模型为基础,采用模型的参数作为纹理特征。典型的方法是随机场模型法,如马尔可夫(Markov)随机场(MRF)模型法和 Gibbs 随机场模型法

    (4)信号处理法

    纹理特征的提取与匹配主要有:灰度共生矩阵、Tamura 纹理特征、自回归纹理模型、小波变换等。灰度共生矩阵特征提取与匹配主要依赖于能量、惯量、熵和相关性四个参数。Tamura 纹理特征基于人类对纹理的视觉感知心理学研究,提出6种属性,即:粗糙度、对比度、方向度、线像度、规整度和粗略度。自回归纹理模型(simultaneousauto-regressive, SAR)是马尔可夫随机场(MRF)模型的一种应用实例。

    C.形状特征

    特点:各种基于形状特征的检索方法都可以比较有效地利用图像中感兴趣的目标来进行检索,但它们也有一些共同的问题。

    常用的特征提取与匹配方法:

    通常情况下,形状特征有两类表示方法,一类是轮廓特征,另一类是区域特征。图像的轮廓特征主要针对物体的外边界,而图像的区域特征则关系到整个形状区域。

    几种典型的形状特征描述方法:

    (1)    边界特征法

    该方法通过对边界特征的描述来获取图像的形状参数。其中Hough 变换检测平行直线方法和边界方向直方图方法是经典方法。Hough 变换是利用图像全局特性而将边缘像素连接起来组成区域封闭边界的一种方法,其基本思想是点—线的对偶性;边界方向直方图法首先微分图像求得图像边缘,然后,做出关于边缘大小和方向的直方图,通常的方法是构造图像灰度梯度方向矩阵。

    (2)傅里叶形状描述符法

    傅里叶形状描述符(Fourier shapedescriptors)基本思想是用物体边界的傅里叶变换作为形状描述,利用区域边界的封闭性和周期性,将二维问题转化为一维问题。由边界点导出三种形状表达,分别是曲率函数、质心距离、复坐标函数。

    (3)几何参数法

    形状的表达和匹配采用更为简单的区域特征描述方法,例如采用有关形状定量测度(如矩、面积、周长等)的形状参数法(shape factor)。在 QBIC 系统中,便是利用圆度、偏心率、主轴方向和代数不变矩等几何参数,进行基于形状特征的图像检索。

    D.空间关系特征

    特点:所谓空间关系,是指图像中分割出来的多个目标之间的相互的空间位置或相对方向关系,这些关系也可分为连接/邻接关系、交叠/重叠关系和包含/包容关系等。通常空间位置信息可以分为两类:相对空间位置信息和绝对空间位置信息。前一种关系强调的是目标之间的相对情况,如上下左右关系等,后一种关系强调的是目标之间的距离大小以及方位。显而易见,由绝对空间位置可推出相对空间位置,但表达相对空间位置信息常比较简单。

    空间关系特征的使用可加强对图像内容的描述区分能力,但空间关系特征常对图像或目标的旋转、反转、尺度变化等比较敏感。另外,实际应用中,仅仅利用空间信息往往是不够的,不能有效准确地表达场景信息。为了检索,除使用空间关系特征外,还需要其它特征来配合。

    常用的特征提取与匹配方法:

    提取图像空间关系特征可以有两种方法:一种方法是首先对图像进行自动分割,划分出图像中所包含的对象或颜色区域,然后根据这些区域提取图像特征,并建立索引;另一种方法则简单地将图像均匀地划分为若干规则子块,然后对每个图像子块提取特征,并建立索引。

    十、图像分类(识别)

    图像分类(识别)属于模式识别的范畴,其主要内容是图像经过某些预处理(增强、复原、压缩)后,进行图像分割和特征提取,从而进行判决分类。图像分类常采用经典的模式识别方法,有统计模式分类和句法(结构)模式分类,近年来新发展起来的模糊模式识别和人工神经网络模式分类在图像识别中也越来越受到重视。

    模式识别是一种从大量信息和数据出发,在专家经验和已有认识的基础上,利用计算机和数学推理的方法对形状、模式、曲线、数字、字符格式和图形自动完成识别的过程。模式识别包括相互关联的两个阶段,即学习阶段和实现阶段,前者是对样本进行特征选择,寻找分类的规律,后者是根据分类规律对未知样本集进行分类和识别。广义的模式识别属计算机科学中智能模拟的研究范畴,内容非常广泛,包括声音和语言识别、文字识别、指纹识别、声纳信号和地震信号分析、照片图片分析、化学模式识别等等。计算机模式识别实现了部分脑力劳动自动化。

    模式识别--对表征事物或现象的各种形式的(数值的,文字的和逻辑关系的)信息进行处理和分析,以对事物或现象进行描述、辨认、分类和解释的过程,是信息科学和人工智能的重要组成部分。

    模式还可分成抽象的和具体的两种形式。前者如意识、思想、议论等,属于概念识别研究的范畴,是人工智能的另一研究分支。我们所指的模式识别主要是对语音波形、地震波、心电图、脑电图、图片、文字、符号、三位物体和景物以及各种可以用物理的、化学的、生物的传感器对对象进行测量的具体模式进行分类和辨识。

    模式识别问题指的是对一系列过程或事件的分类与描述,具有某些相类似的性质的过程或事件就分为一类。模式识别问题一般可以应用以下4种方法进行分析处理。

    模版比对:

    统计模式识别方法:统计模式识别方法是受数学中的决策理论的启发而产生的一种识别方法,它一般假定被识别的对象或经过特征提取向量是符合一定分布规律的随机变量。其基本思想是将特征提取阶段得到的特征向量定义在一个特征空间中,这个空间包含了所有的特征向量,不同的特征向量,或者说不同类别的对象都对应于空间中的一点。在分类阶段,则利用统计决策的原理对特征空间进行划分,从而达到识别不同特征的对象的目的。统计模式识别中个应用的统计决策分类理论相对比较成熟,研究的重点是特征提取。统计模式识别的基本原理是:有相似性的样本在模式空间中互相接近,并形成“集团”,即“物以类聚”。其分析方法是根据模式所测得的特征向量Xi=(xi1,xi2,…,xid)T(i=1,2,…,N),将一个给定的模式归入C个类ω1,ω2,…,ωc中,然后根据模式之间的距离函数来判别分类。其中,T表示转置;N为样本点数;d为样本特征数。

    统计模式识别的主要方法有:判别函数法,k近邻分类法,非线性映射法,特征分析法,主因子分析法等。

    在统计模式识别中,贝叶斯决策规则从理论上解决了最优分类器的设计问题,但其实施却必须首先解决更困难的概率密度估计问题。BP神经网络直接从观测数据(训练样本)学习,是更简便有效的方法,因而获得了广泛的应用,但它是一种启发式技术,缺乏指定工程实践的坚实理论基础。统计推断理论研究所取得的突破性成果导致现代统计学习理论——VC理论的建立,该理论不仅在严格的数学基础上圆满地回答了人工神经网络中出现的理论问题,而且导出了一种新的学习方法——支撑向量机。

    人工神经网络模式识别:人工神经网络的研究起源于对生物神经系统的研究。人工神经网络区别于其他识别方法的最大特点是它对待识别的对象不要求有太多的分析与了解,具有一定的智能化处理的特点。

    句法结构模式识别:又称结构方法或语言学方法。其基本思想是把一个模式描述为较简单的子模式的组合,子模式又可描述为更简单的子模式的组合,最终得到一个树形的结构描述,在底层的最简单的子模式称为模式基元。在句法方法中选取基元的问题相当于在决策理论方法中选取特征的问题。通常要求所选的基元能对模式提供一个紧凑的反映其结构关系的描述,又要易于用非句法方法加以抽取。显然,基元本身不应该含有重要的结构信息。模式以一组基元和它们的组合关系来描述,称为模式描述语句,这相当于在语言中,句子和短语用词组合,词用字符组合一样。基元组合成模式的规则,由所谓语法来指定。一旦基元被鉴别,识别过程可通过句法分析进行,即分析给定的模式语句是否符合指定的语法,满足某类语法的即被分入该类。

    在几种算法中,统计模式识别是最经典的分类识别方法,在图像模式识别中有着非常广泛的应用。


     [wq1]

    本文参考《数字图像处理》(第二版)

    作者:冈萨雷斯

     [wq2]

    参考第二章,掌握概念?

     [wq3]

    线性变换:如果变换函数是线性的或是分段线性,这种变换就是线性变换。以线性函数加大图像的对比度的效果是使整幅图像的质量改善。以分段线性函数加大图像中某个(或某几个)亮度区间的对比度的效果是使局部亮度区间的质量得到改善。

    非线性变换:当变换函数是非线性时,即为非线性变换。常用的有指数变换和对数变换。

     

     [wq4]

    参考《几种图像处理库的研究》:http://blog.csdn.net/byxdaz/article/details/3972293

     [wq5]

    以时间作为变量所进行的研究就是时域

    以频率作为变量所进行的研究就是频域

    以空间坐标作为变量进行的研究就是空间域

    以波数作为变量所进行的研究称为波数域

     [wq6]

    一阶微分

     [wq7]

    二次导数,其离散实现类似于二阶Sobel导数

     [wq8]

    1)  仿射变换

    2)  透视变换

     [wq10]

    OTSU

     [wq11]

    SIFT特征怎么用?




    展开全文
  • #include #include using namespace std; int main(void){ CvPoint2D32f srcTri[3], dstTri[3]; //量化矩阵的创建 ... CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1)... //扭曲 CvMat* warp_mat = cvCreateMat(2, 3,
    #include<cv.h>
    #include<highgui.h>
    
    using namespace std;
    
    int main(void){
    	CvPoint2D32f srcTri[3], dstTri[3];
    	//量化矩阵的创建
    	//旋转
    	CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1);
    	//扭曲
    	CvMat* warp_mat = cvCreateMat(2, 3, CV_32FC1);
    	IplImage *src, *dst;
    	src = cvLoadImage("d:\\testPic\\1.jpeg");
    	if(src != 0){
    		//为dst申请空间,类似使用cvCreateImage();
    		dst = cvCloneImage(src);
    		dst->origin = src->origin;
    		cvZero(dst);
    
    		//compute warp matrix
    		//在原图上确定一个三角形,再确定映射到目标图像上的三角形
    		srcTri[0].x = 0;
    		srcTri[0].y = 0;
    		srcTri[1].x = src->width - 1;
    		srcTri[1].y = 0;
    		srcTri[2].x = 0;
    		srcTri[2].y = src->height - 1;
    		dstTri[0].x = src->width * 0.0;
    		dstTri[0].y = src->height * 0.33;
    		dstTri[1].x = src->width * 0.85;
    		dstTri[1].y = src->height * 0.25;
    		dstTri[2].x = src->width * 0.15;
    		dstTri[2].y = src->height * 0.7;
    
    		//获取量化矩阵
    		cvGetAffineTransform(srcTri, dstTri, warp_mat);
    		//仿射变换
    		cvWarpAffine(src, dst, warp_mat);
    		cvNamedWindow("Affine_Transform", 1);
    		cvShowImage("Affine_Transform", dst);
    		cvWaitKey();
    		cvCopy(dst, src);
    
    		//compute rotation matrix
    		//获取旋转中心
    		CvPoint2D32f center = cvPoint2D32f(src->width / 2, src->height / 2);
    		//旋转角度
    		double angle = 90.0;
    		//扩展比例
    		double scale = 1;
    		//获取量化矩阵
    		cv2DRotationMatrix(center, angle, scale, rot_mat);
    		//仿射变换
    		cvWarpAffine(src, dst, rot_mat);
    		cvShowImage("Affine_Transform", dst);
    		cvWaitKey();
    	}
    	cvReleaseImage(&dst);
    	cvReleaseMat(&rot_mat);
    	cvReleaseMat(&warp_mat);
    	return 0;
    }
    

    展开全文
  • 即使没有计算机图形学基础知识的读者也完全不用担心您是否适合阅读此文,本文的性质属于科普文章,将为您揭开诸如Photoshop、Fireworks、GIMP等软件的图像处理操作的神秘面纱。之前您也许对这些处理技术感到惊奇和...
  • 关于图像处理的书籍

    2019-03-28 21:18:47
    2.《MATLAB图像处理实例详解》 3.网址:图像处理入门必看 - CSDN博客 https://blog.csdn.net/chensanwa/article/details/78650073 目录 笔记:深度学习—卷积神经网络从入门到精通 1.1 概念 ...
  • 在浏览博客是看到一篇文章,对图像处理领域的算法和理论总结的很到位,便转载了过来。 本文转自 http://blog.csdn.net/hitwengqi/article/details/8292675  狂奔的蜗牛 站得高,才能看得远! 花了点时间...
  • 图像处理知识框架

    2018-08-05 14:00:02
    花了点时间整理了一下数字图像处理知识体系,从宏观上把握图像处理,使自己的学习思路就更加清晰。 1.本文大部分内容来自:http://blog.csdn.net/byxdaz/article/details/4375228 2.有些内容待添加,特别是opencv...
  • void ES::ImageProcessing::imageWarpOper(cv::Mat* dst) { Mat src = imread("lena.jpg", IMREAD_COLOR); cv::resize(src, src, Size(src.rows / 4 * 3, src.cols / 4 * 3)); Mat mat; const int rows = src.r....
  • 图像处理常用公式-不错
  • 数字图像处理技术与人脸识别 电子科技大学 格拉斯哥学院 2017/2018级 耿逸飞 2017200602025 序言 如今,随着科技的迅速发展,各大手机厂商对智能手机的研发也愈发深入。传统的手机解锁方式已经不足以满足各大手机...
  • 数字图像处理技术 第一章 图像处理主要内容:广义上:图像采集、图像编码与传输、图像信息处理、图像显示,狭义上:图像增强、图像恢复、图像分割、图像表示 DI:将一幅画面在空间上分割称离散的像素,各像素点的...
  • 这里讨论利用输入图像中像素的小邻域来产生输出图像的方法,在信号处理中这种方法称为滤波(filtering)。其中,最常用的是线性滤波:输出像素是输入邻域像素的加权和。 1.相关算子(Correlation Operator) 定义:...
  • 一:将图像分割为上面正常、下面扭曲的两部分,大致即可 二:将下面扭曲部分的畸变校正 有偿,最好是m文件 ![图片说明](https://img-ask.csdn.net/upload/201711/07/1510066496_763115.jpg)
  • 》点击原文即可阅读,本文是上篇文章的延续,将继续为大家介绍基本图像处理技术,本文作者主要使用SciKit-Image - numpy执行大多数操作,而不是常用的OpenCV工具,当然,其中偶尔也会穿插使用其他库。图片亮度转换 ...
  • 最近发现,看过的文章,没几天就忘了,于是开始写点东西记录一下,...1、第一步需要通过计算图像最小能量线,对图像进行预变性。 看懂这篇文章首先要看懂Seam Carving,这个算法作者有源码,可以下载下来好好解读一下算
1 2 3 4 5 ... 20
收藏数 3,300
精华内容 1,320
关键字:

图像处理 局部扭曲