精华内容
下载资源
问答
  • 几何变换

    千次阅读 2020-10-23 08:11:53
    涉及函数cv2.getPerspectiveTransform,cv2.warpAffine和cv2.warpPersperctive 1.扩展缩放 只是改变图像的尺寸大小,cv2.resize()可以实现这个功能。在缩放时推荐cv2.INTER_AREA,在拓展时推荐cv2.INTER_CUBIC(慢...

    涉及函数cv2.getPerspectiveTransform,cv2.warpAffine和cv2.warpPersperctive

    1.扩展缩放
    只是改变图像的尺寸大小,cv2.resize()可以实现这个功能。在缩放时推荐cv2.INTER_AREA,在拓展时推荐cv2.INTER_CUBIC(慢)和cv2.INTER_LINEAR。默认情况下所有改变图像尺寸大小的操作使用的是插值法都是cv2.INTER_LINEAR。

    import cv2
    
    img = cv2.imread('45.jpg')
    #下面的None本应该是输出图像的尺寸,但是因为后面我们设置了缩放因子,所以,这里为None
    res = cv2.resize(img,None,fx=2,fy=2,interpolation=cv2.INTER_CUBIC)
    #or
    #这里直接设置输出图像的尺寸,所以不用设置缩放因子
    height , width =img.shape[:2]
    res = cv2.resize(img,(2*width,2*height),interpolation=cv2.INTER_CUBIC)
    
    while(1):
        cv2.imshow('res',res)
        cv2.imshow('img',img)
    
        if cv2.waitKey(1)&0xFF == 27:
            break
    cv2.destroyAllWindows()
    

    2.平移
    如果想要沿(x,y)方向移动,移动的距离为(tx,ty)可以以下面方式构建移动矩阵。

    可以使用Numpy数组构建矩阵,数据类型是np.float32,然后传给函数cv2.warpAffine()
    函数cv2.warpAffine() 的第三个参数的是输出图像的大小,它的格式
    应该是图像的(宽,高)。应该记住的是图像的宽对应的是列数,高对应的是行数。
    3.旋转
    对一个图像旋转角度θ,需要使用下面的旋转矩阵。

    但OpenCVC允许在任意地方进行旋转,所以矩阵应该为

    其中α = scale · cos θ
    为构建旋转矩阵,OpenCV提供了一个函数cv2.getRotationMatrix2D。

    import cv2
    img = cv2.imread('45.jpg',0)
    rows,cols=img.shape
    #这里的第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
    #可以通过设置旋转中心,缩放因子以及窗口大小来防止旋转后超出边界的问题。
    M=cv2.getRotationMatrix2D((cols/2,rows/2),45,0.6)
    #第三个参数是输出图像的尺寸中心
    dst=cv2.warpAffine(img,M,(2*cols,2*rows))
    while(1):
        cv2.imshow('img',dst)
        if cv2.waitKey(1)==27:
            break
    cv2.destroyAllWindows()
    

    4.仿射变换
    在仿射变换中,原图中所有平行线在结果图像中同样平行。为创建这个矩阵,需要从原图像中找到三个点以及他们在输出图像中的位置,然后cv2.getAffineTransForm()会创建一个2X3的矩阵。最后这个矩阵会被传给函数cv2.warpAffine()

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    img=cv2.imread(''draw.png')
    rows,cols,ch = img.shape
    
    pts1 = np.float32([50,50],[200,50],[50,200])
    pts2 = np.float32([10,100],[200,50],[100,250])
    #行,列,通道数
    M = cv2.getAffineTransform(pts1,pts2)
    
    dst = cv2.warpAffine(img,M,(cols,rows))
    
    plt.subplot(121,plt.imshow(img),plt.title('Input'))
    plt.subplot(121,plt.imshow(img),plt.title('output'))
    plt.show()
    

    5.透视变换
    对于视角变换,我们需要一个3x3变换矩阵。在变换前后直线还是直线。需要在原图上找到4个点,以及他们在输出图上对应的位置,这四个点中任意三个都不能共线,可以有函数cv2.getPerspectiveTransform()构建,然后这个矩阵传给函数cv2.warpPerspective()

    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    img=cv2.imread('sudokusmall.png')
    rows,cols,ch=img.shape
    
    pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
    pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
    
    M=cv2.getPerspectiveTransform(pts1,pts2)
    
    dst=cv2.warpPerspective(img,M,(300,300))
    
    plt.subplot(121,plt.imshow(img),plt.title('Input'))
    plt.subplot(121,plt.imshow(img),plt.title('Output'))
    plt.show()
    展开全文
  • 齐次坐标与几何变换 齐次坐标与几何变换 齐次坐标与几何变换 齐次坐标与几何变换
  • 【OpenCV】图像几何变换:旋转,缩放,斜切

    万次阅读 多人点赞 2012-05-30 14:56:25
    几何变换 几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动。 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定...

    几何变换

    几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动。

    几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标。这时就需要灰度级差值将映射的新坐标匹配到输出像素之间。最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿。这种方法也叫零阶插值,相应比较复杂的还有一阶和高阶插值。

    插值算法感觉只要了解就可以了,图像处理中比较需要理解的还是空间变换。

    空间变换

    空间变换对应矩阵的仿射变换。一个坐标通过函数变换的新的坐标位置:

    所以在程序中我们可以使用一个2*3的数组结构来存储变换矩阵:

    以最简单的平移变换为例,平移(b1,b2)坐标可以表示为:

    因此,平移变换的变换矩阵及逆矩阵记为:

    缩放变换:将图像横坐标放大(或缩小)sx倍,纵坐标放大(或缩小)sy倍,变换矩阵及逆矩阵为:

    选择变换:图像绕原点逆时针旋转a角,其变换矩阵及逆矩阵(顺时针选择)为:

     

    OpenCV中的图像变换函数

    基本的放射变换函数:

     

    void cvWarpAffine( 
        const CvArr* src,//输入图像
        CvArr* dst, //输出图像
        const CvMat* map_matrix,   //2*3的变换矩阵
        int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,   //插值方法的组合
        CvScalar fillval=cvScalarAll(0)   //用来填充边界外的值
    );

    另外一个比较类似的函数是cvGetQuadrangleSubPix:

     

     

    void cvGetQuadrangleSubPix( 
           const CvArr* src,  //输入图像 
           CvArr* dst,   // 提取的四边形
           const CvMat* map_matrix //2*3的变换矩阵
    );

    这个函数用以提取输入图像中的四边形,并通过map_matrix变换存储到dst中,与WarpAffine变换意义相同,

     

    即对应每个点的变换:

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

     

    实践:图像旋转变换(原尺寸)

    首先用cvWarpAffine实验将图像逆时针旋转degree角度。

    //逆时针旋转图像degree角度(原尺寸)
    void rotateImage(IplImage* img, IplImage *img_rotate,int degree)
    {
    	//旋转中心为图像中心
    	CvPoint2D32f center;  
    	center.x=float (img->width/2.0+0.5);
    	center.y=float (img->height/2.0+0.5);
    	//计算二维旋转的仿射变换矩阵
    	float m[6];            
    	CvMat M = cvMat( 2, 3, CV_32F, m );
    	cv2DRotationMatrix( center, degree,1, &M);
    	//变换图像,并用黑色填充其余值
    	cvWarpAffine(img,img_rotate, &M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0) );
    }

    逆时针旋转30度结果:

    这里我们将新的图像还保留原来的图像尺寸。这样的效果显然不太好,我们通过计算相应放大图像尺寸。

     

    实践:图像旋转变换(保留原图内容,放大尺寸)

    需要计算新图的尺寸,示意图如下:

    所以新图size为(width*cos(a)+height*sin(a), height*cos(a)+width*sin(a))

    //旋转图像内容不变,尺寸相应变大
    IplImage* rotateImage1(IplImage* img,int degree){
    	double angle = degree  * CV_PI / 180.; // 弧度  
    	double a = sin(angle), b = cos(angle); 
    	int width = img->width;  
    	int height = img->height;  
    	int width_rotate= int(height * fabs(a) + width * fabs(b));  
    	int height_rotate=int(width * fabs(a) + height * fabs(b));  
    	//旋转数组map
    	// [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]
    	// [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]
    	float map[6];
    	CvMat map_matrix = cvMat(2, 3, CV_32F, map);  
    	// 旋转中心
    	CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);  
    	cv2DRotationMatrix(center, degree, 1.0, &map_matrix);  
    	map[2] += (width_rotate - width) / 2;  
    	map[5] += (height_rotate - height) / 2;  
    	IplImage* img_rotate = cvCreateImage(cvSize(width_rotate, height_rotate), 8, 3); 
    	//对图像做仿射变换
    	//CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。
    	//如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
    	//CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,
    	cvWarpAffine( img,img_rotate, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));  
    	return img_rotate;
    }

     

    实践:图像旋转变换(保留原图内容,放大尺寸)-2

    试一下用cvGetQuadrangleSubPix函数:

    //旋转图像内容不变,尺寸相应变大
    IplImage* rotateImage2(IplImage* img, int degree)  
    {  
    	double angle = degree  * CV_PI / 180.; 
    	double a = sin(angle), b = cos(angle); 
    	int width=img->width, height=img->height;
    	//旋转后的新图尺寸
    	int width_rotate= int(height * fabs(a) + width * fabs(b));  
    	int height_rotate=int(width * fabs(a) + height * fabs(b));  
    	IplImage* img_rotate = cvCreateImage(cvSize(width_rotate, height_rotate), img->depth, img->nChannels);  
    	cvZero(img_rotate);  
    	//保证原图可以任意角度旋转的最小尺寸
    	int tempLength = sqrt((double)width * width + (double)height *height) + 10;  
    	int tempX = (tempLength + 1) / 2 - width / 2;  
    	int tempY = (tempLength + 1) / 2 - height / 2;  
    	IplImage* temp = cvCreateImage(cvSize(tempLength, tempLength), img->depth, img->nChannels);  
    	cvZero(temp);  
    	//将原图复制到临时图像tmp中心
    	cvSetImageROI(temp, cvRect(tempX, tempY, width, height));  
    	cvCopy(img, temp, NULL);  
    	cvResetImageROI(temp);  
    	//旋转数组map
    	// [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]
    	// [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]
    	float m[6];  
    	int w = temp->width;  
    	int h = temp->height;  
    	m[0] = b;  
    	m[1] = a;  
    	m[3] = -m[1];  
    	m[4] = m[0];  
    	// 将旋转中心移至图像中间  
    	m[2] = w * 0.5f;  
    	m[5] = h * 0.5f;  
    	CvMat M = cvMat(2, 3, CV_32F, m);  
    	cvGetQuadrangleSubPix(temp, img_rotate, &M);  
    	cvReleaseImage(&temp);  
    	return img_rotate;
    }  

     

     

    实践:图像放射变换(通过三点确定变换矩阵)

    在OpenCV 2.3的参考手册中《opencv_tutorials》介绍了另一种确定变换矩阵的方法,通过三个点变换的几何关系映射实现变换。

    变换示意图如下:

    即通过三个点就可以确定一个变换矩阵。(矩形变换后一定为平行四边形)

    以下是基于OpenCV 2.3的代码(需至少2.0以上版本的支持)

    int main( )
    {
    	Point2f srcTri[3];
    	Point2f dstTri[3];
    	Mat rot_mat( 2, 3, CV_32FC1 );
    	Mat warp_mat( 2, 3, CV_32FC1 );
    	Mat src, warp_dst, warp_rotate_dst;
    	//读入图像
    	src = imread( "baboon.jpg", 1 );
    	warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    	// 用3个点确定A仿射变换
    	srcTri[0] = Point2f( 0,0 );
    	srcTri[1] = Point2f( src.cols - 1, 0 );
    	srcTri[2] = Point2f( 0, src.rows - 1 );
    	dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
    	dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
    	dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );
    	warp_mat = getAffineTransform( srcTri, dstTri );
    	warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
    	/// 旋转矩阵
    	Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
    	double angle = -50.0;
    	double scale = 0.6;
    	rot_mat = getRotationMatrix2D( center, angle, scale );
    	warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
    	OpenCV 1.0的形式
    	//IplImage * img=cvLoadImage("baboon.jpg");
    	//IplImage *img_rotate=cvCloneImage(img);
    	//CvMat M =warp_mat;
    	//cvWarpAffine(img,img_rotate, &M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0) );
    	//cvShowImage("Wrap2",img_rotate);
    
    	namedWindow( "Source", CV_WINDOW_AUTOSIZE );
    	imshow( "Source", src );
    	namedWindow( "Wrap", CV_WINDOW_AUTOSIZE );
    	imshow( "Wrap", warp_dst );
    	namedWindow("Wrap+Rotate", CV_WINDOW_AUTOSIZE );
    	imshow( "Wrap+Rotate", warp_rotate_dst );
    	waitKey(0);
    	return 0;
    }

    变换结果:

     

    转载请注明出处:http://blog.csdn.net/xiaowei_cqu/article/details/7616044
    实验代码下载:https://github.com/xiaoweicqu/image-rotate/blob/master/main_rotate.cpp

    写在最后的一点点闲话

    之前一直用的2.1的版本,后来装了2.3,只是听说2.3很强大,但我刚开始学,用的也基础,完全没感觉出不同。直到今天忽然看到了2.3的手册,才发现从2.0开始函数和基本结构都有了很大的改变,而我一直还是用的1.0风格的函数(比如cvMat,cvLoadImage)。我的两个学习工具《Learnning OpenCV》和《OpenCV中文参考手册》都是基于1.0的,这也是我到今天才看到Mat,然后直接被惊艳到了。

    别人总结出来的东西能帮助我们在一开始迅速入门,但要学深,学精,终归还是要自己去努力挖的。

     

     

    展开全文
  • HALCON几何变换

    2020-03-07 16:24:35
    深入浅出HALCON几何变换 在机器视觉系统中,镜头是重要成像部件之一,而基于小孔成像原理的工业镜头往往会产生透视畸变现象,如何校正畸变是进行图像分析的前提,这其中就会用到投影变换,也是几何变换的一种。除...

    深入浅出HALCON几何变换

    在机器视觉系统中,镜头是重要成像部件之一,而基于小孔成像原理的工业镜头往往会产生透视畸变现象,如何校正畸变是进行图像分析的前提 ,这其中就会用到投影变换,也是几何变换的一种。除此之外,图像处理中常用到的平移、旋转、缩放等,也属于几何变换。本文将通过实例详细介绍HALCON中的几何变换。

     

    基础知识

     

    齐次坐标(Homogenous Coordinate)

     

    齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示。例如二维点p(x,y)àp(x,y, w)就成了齐次坐标,同理三维点p(x,y,z)àp(x,y,z, w)也成了齐次坐标。显然,齐次坐标的表达并不是唯一的,随w值的不同而不同。在计算机图学中,w 作为通用比例因子,它可取任意正值,但一般在几何变换中,总是取w=1。齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易于进行几何变换。

     

    以点p(x,y)为例,如果想把它平移至p(x+a,y+b),是不可能用矩阵计算完成的,现在换成齐次坐标(x,y,1),通过矩阵相乘(左侧公式) ,很方便得到平移后的坐标(x+a,y+b)。通常把变换矩阵写到左侧,为了保持一致把变换矩阵改成右下角形式,这就是齐次变换矩阵。

     

    http://img.xiumi.us/xmi/ua/T5lQ/i/ea772a8791f2edf46620c793afeba87f-sz_65251.jpg?x-oss-process=style/xmorient

     

    齐次变换矩阵

     

    在同一变换矩阵中既表示姿态(旋转、缩放等)又表示位置(平移),这种形式的矩阵称为齐次变换矩阵。如下:

    http://img.xiumi.us/xmi/ua/T5lQ/i/d437ab9c99824dfd6c1aec02335f05e5-sz_63697.jpg?x-oss-process=style/xmorient

    齐次坐标的使用,使得几何变换更容易计算,尤其对于仿射变换(二维/三维)更加方便,由于图形硬件、视觉算法已经普遍支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它成为图形学中的一个标准,下面提到的几何变换(仿射变换)都以齐次坐标和齐次变换矩阵为基础。

     

    几何变换

     

    几何变换包括:

    相似变换(Similarity Transformation)

    仿射变换(Affine Transformation)

    投影变换(Projective Transformation)

     

    注:线性变换不包含平移,所以没有归入几何变换,总之HALCON中常用几何变换是仿射和投影变换,而相似变换是仿射变换的一种简单情况!相似变换、仿射变换、投影变换既可以发生在二维空间内也可发生在三维空间内。

     

    相似变换

     

    相似变换的定义:由一个平面/立体图形变换到另一个平面/立体图形,在改变的过程中保持形状不变(大小方向和位置可变),任何相似变换都可以分解为等比例缩放、平移、旋转的组合,例如,对于缩放,用齐次变换矩阵可以如下表示(二维和三维),其中a≠0。

     

    http://img.xiumi.us/xmi/ua/T5lQ/i/a2f3d71d102e594fa1d0620fdcfa0296-sz_61319.jpg?x-oss-process=style/xmorient

     

    仿射变换

     

    仿射变换的定义:由一个平面/立体图形变换到另一个平面/立体图形,在改变的过程中保持直线和平行线不变(平行线映射为平行线),任何仿射变换都可以分解为缩放、平移、旋转和切变(Shearing)的组合,对于仿射变换,齐次变换矩阵如下表示(二维和三维):

    http://img.xiumi.us/xmi/ua/T5lQ/i/e2b011e05d3d684dcd732322e3de24ff-sz_65230.jpg?x-oss-process=style/xmorient

     

    对于仿射变换,有两个比较特殊的变换:非等比例缩放和切变(如下图),除了这两个特殊的变换之外,相似变换可以看做是仿射变换的特殊形式,注:线性变换包括旋转、缩放、切变,但不包含平移,因此仿射变换也定义为一个线性变换再加上一个平移变换。

    http://img.xiumi.us/xmi/ua/T5lQ/i/c804551e007d858b9303e3f46169c26e-sz_43987.jpg?x-oss-process=style/xmorient

    投影变换

     

    投影变换的定义:变换过程中,直线映射为直线(但不一定保证平行度),任何二维投影变换都可以用3x3可逆矩阵表示,而任何三维投影变换都可以用4x4可逆矩阵表示。如下:

    http://img.xiumi.us/xmi/ua/T5lQ/i/0ca85cd2393078a9e7f2c9c0d85dce33-sz_72936.jpg?x-oss-process=style/xmorient

    从定义来看,仿射变换可以看做是投影变换的特殊形式。另外,把投影变换矩阵的最后一行变为[0,0,1]或者[0,0,0,1],即可变为仿射变换矩阵,也可以证明仿射变换是投影变换的特殊形式。因此,对于平移、缩放、切变等,仿射变换和投影变换都可以实现。

     

    如下例子,把左图进行旋转操作变成右图,可以用仿射变换和投影变换两种方式实现。

    http://img.xiumi.us/xmi/ua/T5lQ/i/32cd78b5600b1503068ded7663b95b6c-sz_172066.jpg?x-oss-process=style/xmorient

    • 仿射变换实现方法

     

    hom_mat2d_identity (HomMat2DIdentity)

    hom_mat2d_rotate (HomMat2DIdentity, rad(-90), 256, 256, HomMat2DRotate)

    affine_trans_image (Image, ImageAffinTrans, HomMat2DRotate, 'constant', 'false')

     

    • 投影变换实现方法之一

    (直接用给定点生成投影变换矩阵)

     

    hom_vector_to_proj_hom_mat2d([0,0,512,512],[0,512,512,0],[1,1,1,1], [512,512,0,0], [1,1,1,1], ‘dlt', HomMat2D)

    projective_trans_image (Image, TransImage, HomMat2D, 'bilinear', 'false', 'false')

     

    • 投影变换实现方法之二

    (用三维仿射变换矩阵生成投影变换矩阵)

     

    注:对于旋转来说,也可以看做是相机沿Z轴旋转90度后的成像效果,因此也可以用三维仿射变换,先转换相机坐标系,再生成投影变换矩阵!

     

    hom_mat3d_identity (HomMat3DIdentity)

    hom_mat3d_rotate (HomMat3DIdentity, rad(90), 'z', 256, 256, 512, HomMat3DRotate)

    hom_mat3d_project (HomMat3DRotate, 256, 256, 512, HomMat2D)

    projective_trans_image (Image, TransImage, HomMat2D, 'bilinear', 'false', 'false')

     

    旋转示例中的仿射变换矩阵(也是齐次变换矩阵)

    http://img.xiumi.us/xmi/ua/T5lQ/i/6ac5f7d3f12ee3806ea6f93b95b909d6-sz_65572.jpg?x-oss-process=style/xmorient

    旋转示例中的投影变换矩阵(3X3),也是可逆矩阵

    http://img.xiumi.us/xmi/ua/T5lQ/i/fdc4032ac1ea706724b46eb1ebd2bba6-sz_76502.jpg?x-oss-process=style/xmorient

    同理,缩放、切变等,仿射变换和投影变换也都可以实现,但如下变换,只能用二维投影变换矩阵实现,因为变换过程中没有保证线的平行性。

    http://img.xiumi.us/xmi/ua/T5lQ/i/a3d23ec81a0fc85f98cdcda0d92ca234-sz_168731.jpg?x-oss-process=style/xmorient

    S

    总结

     

    HALCON中所用的变换知识只涉及到了二维、三维仿射变换和二维投影变换,二维仿射变换多用于平面图像的平移、旋转、缩放等;三维仿射变换多用于三维坐标系的平移、旋转等(或者用3D位姿表示),而二维投影变换多用于校正透视畸变,也就是三维空间的景象如何投影到相机靶面上的效果,如果相机和被测平面不垂直就会有畸变。

     

    在成像过程中,普通工业镜头(小孔成像原理)都会带来透视畸变,也就是常见的近大远小现象,除非相机和被测平面保持绝对垂直,否则透视畸变是不可避免的。因此,通过三维空间的仿射变换(变换坐标系,使相机不垂直于被摄平面),可以产生透视畸变效果,也就是相当于进行了投影变换,HALCON也提供了算子hom_mat3d_project,能直接把三维仿射变换矩阵转换成二维投影变换矩阵(4x4的矩阵转换成3x3矩阵)。下面我们通过一个例子来说明一下。

    http://img.xiumi.us/xmi/ua/T5lQ/i/e908fb114226888ce9dc9c760dc3b4e4-sz_136465.jpg?x-oss-process=style/xmorient

    首先生成单位矩阵,进行一系列的旋转变换,产生三维仿射变换矩阵,也就是使得相机和被摄平面不垂于!

     

    hom_mat3d_identity (HomMat3D)

    hom_mat3d_rotate (HomMat3D, rad(20.0), 'z', PrincipalRow, PrincipalColumn, Focus, HomMat3D)

    hom_mat3d_rotate (HomMat3D, rad(35.0), 'y', PrincipalRow, PrincipalColumn, Focus, HomMat3D)

    hom_mat3d_rotate (HomMat3D, rad(25.0), 'x', PrincipalRow, PrincipalColumn, Focus, HomMat3D)

     

    把三维仿射变换矩阵再转化成二维投影变换矩阵

     

    hom_mat3d_project (HomMat3D, PrincipalRow, PrincipalColumn, Focus, ProjectionMatrix)

     

    进行投影变换,也就是我们看到的右侧的效果

     

    projective_trans_image (Image, TransImage, ProjectionMatrix, 'bilinear', 'false', 'false')

     

    另外一种方法是,直接使用给定点生成投影变换矩阵,可以得到同样的效果

     

    hom_vector_to_proj_hom_mat2d ([0,0,512,512], [0,512,512,0], [1,1,1,1], [-120,146,555,296], [120,752,368,72], [1,1,1,1], 'normalized_dlt', HomMat2D)

    projective_trans_image (Image, TransImage1, HomMat2D, 'bilinear', 'false', 'false')

     

    上面的这个例子是很好的说明了透视畸变现象如何产生的,左侧图是相机垂直于被摄平面,没有透视变形现象。然后进行了一系列的三维仿射变换,产生的效果就是相机不再垂直于被摄面,所以右图产生了透视畸变现象,那么从左图到右图恰恰是进行了一次二维投影变换。因为投影变换矩阵是可逆的,所以也可以把右图校正为左图,这恰恰是HALCON中投影变换的用处所在!

     

    以下例子也是HALCON中典型的畸变校正示例,使用的正是投影变换。

     

    http://img.xiumi.us/xmi/ua/T5lQ/i/d33a32af69401138980de23e0d270eba-sz_178725.jpg?x-oss-process=style/xmorient

     

    附录

     

    解释一下HALCON中的:

    hom_mat2d_*和hom_mat3d_*算子

     

    hom_mat2d_identity产生2x3矩阵,用于描述二维变换,实际上是3x3齐次变换矩阵(仿射变换);

    hom_mat3d_identity产生3x4矩阵,用于描述三维变换,实际上是4x4齐次变换矩阵(仿射变换);

    hom_mat2d_*既支持2x3矩阵(仿射变换)也支持3x3矩阵(投影变换);

    hom_mat3d_*支持3x4矩阵(仿射变换),也就是4x4齐次变换矩阵

     

    关于如何在HALCON中生成的:

    仿射变换矩阵和投影变换矩阵

     

    仿射变换矩阵

    用hom_mat2d_identity或者hom_mat3d_identity产生单位矩阵,然后经过平移、旋转、缩放等操作后得到仿射变换矩阵。

     

    投影变换矩阵

    hom_mat3d_project能直接把三维仿射变换矩阵转换成投影变换矩阵,如果知道空间坐标系是如何变换的,可以用这种方法;

    hom_vector_to_proj_hom_mat2d用给定点生成投影变换矩阵,输入点的坐标为三维齐次坐标,可以支持无穷远点和有限远点的变换;

    vector_to_proj_hom_mat2d用给定点生成投影变换矩阵,输入点为二维非齐次坐标,支持有限远的点的变换;

     

    注:对于涉及有限远点的变换,以上两个算子都可以!

     

    展开全文
  • 图像的几何变换包括:图像的空间平移、比例缩放、旋转、仿射变换和图像插值。 图像几何变换的实质:改变像素的空间位置,估算新空间位置上的像素值。  图像几何变换的一般表达式:[,][(,),(,)]uvXxyYxy ,其中,...
  • 几何变换详解

    千次阅读 2018-08-22 21:41:59
    在三维图形学中,几何变换大致分为三种,平移变换(Translation),缩放变换(Scaling),旋转变换(Rotation)。以下讨论皆针对DirectX,所以使用左手坐标系。 平移变换 将三维
    原文地址为:几何变换详解

    在三维图形学中,几何变换大致分为三种,平移变换(Translation),缩放变换(Scaling),旋转变换(Rotation)。以下讨论皆针对DirectX,所以使用左手坐标系。

    平移变换

    将三维空间中的一个点[x, y, z, 1]移动到另外一个点[x', y', z', 1],三个坐标轴的移动分量分别为dx=Tx, dy=Ty, dz=Tz, 即

    x' = x + Tx

    y' = y + Ty

    z' = z + Tz

    平移变换的矩阵如下。

    缩放变换

    将模型放大或者缩小,本质也是对模型上每个顶点进行放大和缩小(顶点坐标值变大或变小),假设变换前的点是[x, y, z, 1],变换后的点是[x', y', z', 1],那么

    x' = x * Sx

    y' = y * Sy

    z' = z * Sz

    缩放变换的矩阵如下。

    旋转变换

    这是三种变换中最复杂的变换,这里只讨论最简单的情况,绕坐标轴旋转,关于绕任意轴旋转,在后续的随笔中介绍。

    绕X轴旋转

    绕X轴旋转时,顶点的x坐标不发生变化,y坐标和z坐标绕X轴旋转θ度,旋转的正方向为顺时针方向(沿着旋转轴负方向向原点看)。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

    关于旋转的正方向,OpenGL与多数图形学书籍规定旋转正方向为逆时针方向(沿着坐标轴负方向向原点看),比如Computer Graphics C Version,p409。

    绕Y轴旋转

    绕Y轴旋转时,顶点的y坐标不发生变化,x坐标和z坐标绕Y轴旋转θ度。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

    绕Z轴旋转

    绕Z轴旋转时,顶点的z坐标不发生变化,x坐标和y坐标绕Z轴旋转θ度。[x, y, z, 1]表示变换前的点,[x', y', z', 1]表示变换后的点。变换矩阵如下。

    绕坐标轴旋转的矩阵推导

    上面三个旋转矩阵是如何得来的呢?我们推导一下,首先看一下二维的情况,再扩展到三维即可。实际上上面三种绕坐标轴旋转的情况属于特殊的二维旋转,比如绕Z轴旋转,相当于在与XOY平面上绕原点做二维旋转。

    假设点P(x, y)是平面直角坐标系内一点,其到原点的距离为r,其与X轴的夹角为A,现将点P绕原点旋转θ度,得到点P'(x', y'),P'与X轴的夹角为B,则A = B - θ。(注意,在二维坐标中,逆时针旋转时角度为正,顺时针旋转时角度为负,下图中由P旋转到P',角度为θ,若是由P'转到P,则角度为-θ)。

     

    于是可得下面的转换方程

    (式一)

    写成矩阵的形式就是

    求得旋转矩阵为

    由于这里使用齐次坐标,所以还需加上一维,最终变成如下形式

    绕Z轴旋转矩阵

    和前面给出的绕Z轴旋转矩阵完全吻合。

    对于绕X轴旋转的情况,我们只需将式一中的x用y替换,y用z替换,z用x替换即可。替换后得到

    (式二)

    对应的旋转矩阵为

    绕X轴旋转矩阵

    对于绕Y轴旋转的情况,只需对式二做一次同样的替换即可,的到的变换方程为

    对应的变换矩阵为

    绕Y轴旋转矩阵

    逆矩阵

    平移变换矩阵的逆矩阵与原来的平移量相同,但是方向相反。

    旋转变换矩阵的逆矩阵与原来的旋转轴相同但是角度相反。

    缩放变换的逆矩阵正好和原来的效果相反,如果原来是放大,则逆矩阵是缩小,如果原来是缩小,则逆矩阵是放大。

    == Happy Coding ==


    转载请注明本文地址:几何变换详解
    展开全文
  • 三维图形几何变换是二维图形几何变换的扩展。在三维空间中,用规范化齐次坐标[x y z 1]表示三维点,变换原理是把齐次坐标点(x, y, z, 1)通过变换矩阵变换成新的齐次坐标点(x’ y’, z’, 1)
  • 【多视角立体视觉系列】 几何变换的层次——投影变换,仿射变换,度量变换和欧几里德变换 20200226 FesianXu 前言 几何变换非常常见,在计算机视觉和图形学上更是如此,而这里指的几何一般是由点,线,面等几何...
  • 图像的几何变换

    千次阅读 2016-11-25 15:02:59
    几何变换是图像处理和图像分析的重要内容,按照变换性质可以分为位置变换、形状变换以及复合变换。图像的几何变换方式是使得图像在变换矩阵T的作用下变换为另一幅图像。
  • 没啥别的说的,图像变换中最常用的几个几何变换T矩阵需要的拿走 1 变换矩阵T的基本形式 T = P为新坐标,P0为原坐标。 T中除了左下角是1以外,其余各个变量都有意义 图像的平面变换又叫仿射变换,与之...
  • 三维图形几何变换

    千次阅读 2018-08-05 18:40:26
    三维图形变换分为:几何变换和投影变换。  基本几何变换都是相对于坐标原点、坐标轴和坐标平面,包括:平移、缩放、旋转、对称和错切。  三维空间中点的变换可以表示成点的齐次坐标与四阶的变换矩阵相乘。 1 ...
  • 几何变换及变换矩阵

    千次阅读 2016-04-14 09:33:18
    1、基本几何变换及变换矩阵 基本几何变换都是相对于坐标原点和坐标轴进行的几何变换,有平移、比例、旋转、反射和错切等。 1.1 平移变换 是指将p点沿直线路径从一个坐标位置移到另一个坐标位置的重定位过程。他...
  • iOS 几何变换

    千次阅读 2013-07-25 14:41:19
    iOS 三维几何变换
  • 几何变换包括仿射变换、投影变换、图像变换以及极坐标变换。不同的资料可能会有不同的划分。它们具体的数学表达感性趣的可以自己查找。这里只描述Halcon的仿射变换运用。 Halcon中的放射变换常用的两种方式:旋转...
  • 几何变换 -- 仿射变换

    2017-05-29 09:33:14
    简单来说,在平常的图像处理和机器视觉等应用中,几何变换通常是指不太复杂的线性几何变换,其中主要分仿射变换和投射变换。 许多常见的变换问题都能由仿射变换描述,仿射变换等式如下: 等式右边是变换前的...
  • 几何变换——关于透视变换和仿射变换以及齐次坐标系的讨论 2019/10/26 FesianXu 前言 在本文首先介绍了引入齐次坐标系的必要性,随后介绍了在几何变换中常见的投射变换和仿射变换,这俩种变换在计算机视觉问题中...
  • MATLAB中的几何变换

    2019-03-16 17:56:22
    MATLAB在数字图像处理中有很多几何变换的函数,以下为基本例子 首先读取原图像再一次进行几何变换 P=imread('picture1.png'); 1、图像旋转 imrotate(picture,angle,‘bilinear’or’nearest’); q其中picture是...
  • 几何变换有时也称为建模变换(modeling transformation ),但有些图形系统将两者区分开来。建模变换一般用于构造场景或给出由多个部分组合而成的复杂对象的层次式描述等。例如,一架飞机由机翼、机尾、机身、发动机和...
  • 几何变换 应用于对象几何描述并改变它的位置、方向或大小的操作成为几何变换(geometric transformation)。一个三维位置在齐次坐标中表示为四元列向量。因此,每一次几何变换操作表示成一个从左边去乘坐标向量的4*...
  • 三维空间几何变换矩阵

    千次阅读 2018-11-26 10:02:38
    三维空间几何变换矩阵 标签: 矩阵变换 https://blog.csdn.net/piaoxuezhong/article/details/70171525 继之前的http://blog.csdn.net/piaoxuezhong/article/details/62430051绕轴旋转,这里汇总了一下三维空间中的...
  • matlab invert()函数 逆几何变换

    千次阅读 2019-02-06 11:40:40
    一、语法 invtform = invert(tform);...tform :几何变换,指定为affine3d几何变换对象。 四、输出参数 invtform :几何变换的逆,作为affine3d几何变换对象返回。 五、例子 // 创建一个affine3d对象,该对象...
  • 图像处理之几何变换

    2020-04-23 12:54:16
    几何变换的概念与应用 几何变换是将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置,改变图像的几何位置、几何形状、几何尺寸等几何特征。其实质是改变像素的空间位置,估算新空间位置上的像素值。包括图像的...
  • OpenGL几何变换

    千次阅读 2015-09-29 21:44:09
    OpenGL几何变换  OpenGL中指定了顶点之后,但在屏幕上显示它们之前,会发生三种类型的变换:视图变换、模型变换和投影变换。OpenGL中一些变换术语如下表: 变换 用途 视图(Viewing) 指定观察者或照相机的位置 ...
  • 除了在之前介绍图像复原中滤波的手段以外,图像的几何变换也是图像复原中的一部分。这一期我们就从几何变换的角度来讲图像复原! 那什么是图像的几何变换呢?举几个例子,我们将图像在背景中平移,将一张方方正正...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 64,656
精华内容 25,862
关键字:

几何变换