图像几何变换:旋转,缩放,斜切

几何变换


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

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

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

空间变换

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

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

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

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

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

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

OpenCV中的图像变换函数


基本的放射变换函数:


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

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

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

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

即对应每个点的变换

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

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

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


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


//<strong>旋转</strong><strong>图像</strong>内容不变,尺寸相应变大
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));
//<strong>旋转</strong>数组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);
// <strong>旋转</strong>中心
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);
//对<strong>图像</strong>做仿射<strong>变换</strong>
//CV_WARP_FILL_OUTLIERS - 填充所有输出<strong>图像</strong>的象素。
//如果部分象素落在输入<strong>图像</strong>的边界外,那么它们的值设定为 fillval.
//CV_WARP_INVERSE_MAP - 指定 map_matrix 是输出<strong>图像</strong>到输入<strong>图像</strong>的反<strong>变换</strong>,
cvWarpAffine( img,img_rotate, &map_matrix, CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
return img_rotate;
}

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

试一下用cvGetQuadrangleSubPix函数:


//<strong>旋转</strong><strong>图像</strong>内容不变,尺寸相应变大
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;
//<strong>旋转</strong>后的新图尺寸
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);
//保证原图可以任意角度<strong>旋转</strong>的最小尺寸
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);
//将原图复制到临时<strong>图像</strong>tmp中心
cvSetImageROI(temp, cvRect(tempX, tempY, width, height));
cvCopy(img, temp, NULL);
cvResetImageROI(temp);
//<strong>旋转</strong>数组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];
// 将<strong>旋转</strong>中心移至<strong>图像</strong>中间
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;
//读入<strong>图像</strong>
src = imread( "baboon.jpg", 1 );
warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
// 用3个点确定A仿射<strong>变换</strong>
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() );
/// <strong>旋转</strong>矩阵
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
实验代码下载:http://download.csdn.net/detail/xiaowei_cqu/4339856


图像几何变换:旋转,缩放,斜切,布布扣,bubuko.com

时间: 2024-08-25 23:36:13

图像几何变换:旋转,缩放,斜切的相关文章

Android图片旋转,缩放,位移,倾斜,对称完整示例(二)——Bitmap.createBitmap()和Matrix

MainActivity如下: package cc.c; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.widget.ImageView; /** * Demo描述: * 利用B

[opencv] 图像几何变换:旋转,缩放,斜切

几何变换 几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动. 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标.这时就需要灰度级差值将映射的新坐标匹配到输出像素之间.最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿.这种方法也叫零阶插值,相应比较复杂的还有一阶和高阶插值. 插值算法感觉只要了解就可以了,图像处理中比较需要理解的还是空间变换. 空间变换

opencv 图像平移、缩放、旋转、翻转 图像仿射变换

图像几何变换 图像几何变换从原理上看主要包括两种:基于2x3矩阵的仿射变换(平移.缩放.旋转.翻转).基于3x3矩阵的透视变换. 图像平移 opencv实现图像平移 实现图像平移,我们需要定义下面这样一个矩阵,tx和ty分别是x和y方向上平移的距离: 图像平移利用仿射变换函数 cv.warpAffine() 实现 实验 # 图像平移 import numpy as np import cv2 as cv img = cv.imread('paojie.jpg') rows, cols = img

今日学习总结,2D位移,缩放,旋转,斜切扭曲,过渡,动画

(一)2D 位移,缩放,旋转,斜切扭曲:位移: transform:translate(?px,?px) 不影响其他的布局,只对自己设置的起作用缩放: transform:scale(.5,.5) 括号里代表的是百分比. 参照点默认中心点旋转: transform:rotate(45deg)括号里表示度数45°也可以使用弧度rad 顺序为顺时针顺序斜切扭曲: transform:skew(x,y)分别表示X,Y轴不不同程度,可以用弧度也可以用度数参照点坐标: transform-origin(x

C#图像剪裁、缩放、旋转、转化为鼠标光标

//======================================================= //图像剪裁.缩放,转化为鼠标光标 //======================================================= /// <summary> /// 从图像pic中截取区域Rect构建新的图像 /// </summary> public Bitmap GetRect(Image pic, Rectangle Rect) { //创

在CSS3中,可以利用transform功能来实现文字或图像的旋转、缩放、倾斜、移动这四种类型的变形处理

CSS3中的变形处理(transform)属 transform的功能分类 1.旋转 transform:rotate(45deg); 该语句使div元素顺时针旋转45度.deg是CSS 3的"Values and Units"模块中定义的一个角度单位. 2.缩放 transform:scale(0.8,1); 使用缩放的方法实现文字或图像的缩放效果,在参数中指定缩放倍率.该语句使用scale方法使该元素在水平方向上缩小了20%,垂直方向上不缩放. 3.倾斜 transform:ske

openCV—Python(5)—— 图像几何变换

一.函数简介 1.warpAffine-图像放射变换(平移.旋转.缩放) 函数原型:warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) src:原图像矩阵: M:变换矩阵: dszie:图像尺寸(大小) 其它参数默认即可. 2.flip-图像翻转 函数原型:flip(src, flipCode, dst=None) sre:原图像矩阵: flipCode:翻转方向:1:水平翻转:0:

php基础之gd图像生成、缩放、logo水印和简单验证码实现

php基础之gd图像生成.缩放.logo水印和简单验证码实现 阅读目录 图像生成 缩略图 水印生成 验证码 gd 库是php最常用的图片处理库之一(另外一个是imagemagick),可以生成图片.验证码.水印.缩略图等等.要使用gd库首先需要开启gd库扩 展,windows系统下需要在php.ini中将extension=php_gd2.dll 前边的分号去掉然后重启web服务器,linux系统下一般在编译php时已经开启gd库扩展,要是没有开启gd库扩展则需要先编译安装freetype ,j

C#数字图像处理算法学习笔记(三)--图像几何变换

C#数字图像处理算法学习笔记(三)--图像几何变换 几何图像处理包括 图像的平移变换,镜像变换,旋转变换,伸缩变换,在这里仅以水平镜像为例,通过代码来理解其基本操作方式: 翻转前: 翻转后: //后台代码: public partial class Form1 : Form { private string _curFileName; private Bitmap _srcBitmap; private Bitmap _dstBitmap; public Form1() { Initialize