用C++实现图像旋转变换
用C++实现图像旋转变换
这里主要讨论以图象的中心为圆心旋转。
旋转之后若要保持目标区域大小不变,则整幅图像变大;若要保持整幅图像的大小不变,则旋转出去的部分需要裁剪掉。
旋转前的图旋转后的图旋转后保持原图大小,转出的部分被裁掉以顺时针旋转为例来堆到旋转变换公式。
如下图所示。
旋转前:x0=rcosb;y0=rsinb旋转a角度后:x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sinay 1=rsin(b-a)=rsinbcosa-rcosbsina=-xsina+ycosa矩阵形式为逆变换为上面的公式是以图像的左下角为原点旋转的。
现我们要以图像的中心为原点旋转。
因此需要先将坐标平移到图像中心,如下所示设图象的宽为w,高为h,容易得到:逆变换为现在可以分三步来完成旋转变换:1. 将坐标系x'o'y'平移到xoy ;2. 在xoy坐标系下作旋转变换;3.变换后将坐标系平移回原来位置。
用矩阵表示就是其中R表示旋转变换矩阵。
当旋转不改变图像大小时,T 与T' 互为逆矩阵;当旋转后图像变大时,T 与T'不是逆矩阵关系,因为图像变大了,第一次平移和第二次平移坐标系的距离不一样。
因此当图像变大时,公式应该如下:由于算法实现过程中我们需要的是逆变换的公式,因此我们只写出逆变换的表达式,如下:其中wn ,hn 表示新图像的宽和高,wo, ho 表示原图像的宽和高。
这样,对于新图中的每一点,我们就可以根据上面逆变换公式求出对应原图中的点,得到它的灰度。
如果超出原图范围,则设置为背景色。
要注意的是,由于有浮点运算,计算出来点的坐标可能不是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。
更精确的方法是采用插值,这里暂不讨论。
C++代码如下:/** rotate.cpp* 图像旋转变换(顺时针)* Created on: 2011-10-10* Author: LiChanghai*/// 以图像中心为坐标原点,旋转后不改变图像大小// 函数返回值为指针,指向新申请的内存区域// 因为新图像大小改变了,需要返回新图像的尺寸// 因此形参的高度和宽度都采用指针变量#include<string.h>#include<stdlib.h>#include<cmath>#define pi 3.1415926535unsigned char* rotate(unsigned char*pImage, int*width, int*height, int biBitCount, float angle){//定义以图像中心为原点的坐标系下原图像和新图像的四个角点坐标float src_x1, src_y1, src_x2, src_y2, src_x3, src_y3, src_x4, src_y4;float dst_x1, dst_y1, dst_x2, dst_y2, dst_x3, dst_y3, dst_x4, dst_y4;//定义新图像的高度和宽度int wnew, hnew;//定义计算过程中需要的相关变量float sina, cosa, temp1, temp2, alpha;//角度转化为弧度alpha=pi*angle/180;cosa = float(cos(double(alpha)));sina = float(sin(double(alpha)));//原图像的四个角点的坐标src_x1 = float(-0.5*(*width)); src_y1 = float(0.5*(*height));src_x2 = float(0.5*(*width)); src_y2 = src_y1;src_x3 = src_x1; src_y3 = float(-0.5*(*height));src_x4 = src_x2; src_y4 = src_y3;//计算新图像的四个角点坐标dst_x1 = cosa*src_x1+sina*src_y1;dst_y1 = -sina*src_x1+cosa*src_y1;dst_x2 = cosa*src_x2+sina*src_y2;dst_y2 = -sina*src_x2+cosa*src_y2;dst_x3 = cosa*src_x3+sina*src_y3;dst_y3 = -sina*src_x3+cosa*src_y3;dst_x4 = cosa*src_x4+sina*src_y4;dst_y4 = -sina*src_x4+cosa*src_y4;//计算新图像的高度和宽度float t1 = fabs(dst_x4-dst_x1), t2 = fabs(dst_x3-dst_x2);wnew = int(t1>t2 ? t1:t2);t1 = fabs(dst_y4-dst_y1), t2 = fabs(dst_y3-dst_y2);hnew = int(t1>t2 ? t1:t2);// 计算旋转变换中的两个中间变量,便于以后计算temp1=float( -0.5*wnew*cosa+0.5*hnew*sina+0.5*(*width));temp2=float(-0.5*wnew*sina-0.5*hnew*cosa+0.5*(*height));//计算原图像和新图像每行像素所占的字节数(必须是4的倍数)int lineByte = ((*width) * biBitCount/8+3)/4*4;int lineByte2=(wnew * biBitCount/8+3)/4*4;//申请新的位图数据存储空间unsigned char*pImage2;pImage2=new unsigned char[lineByte2*hnew];//将新图像设置为背景色memset(pImage2, 0, lineByte2*hnew);//遍历新图像的每一个像素进行判断int x, y, x0, y0; // x0, y0为原图像中对应坐标for(y=0; y<hnew; y++)for(x=0; x<wnew; x++){x0= int(x*cosa-y*sina+temp1);y0= int(x*sina+y*cosa+temp2);//如果在原图像范围内则复制像素值if( (x0>=0) && (x0<(*width)) && (y0>=0) && (y0<(*height))){*(pImage2+lineByte2*y+x) = *(pImage+lineByte*y0+x0);}}//修改原图像的高度和宽度*width = wnew;*height = hnew;delete [ ] pImage; //释放原内存空间return pImage2;}该程序在Eclipse上调试通过,结果正确。
opencv 图像翻转旋转
opencv 图像翻转、旋转转自:/watkinsong/article/details/91896491.图像左右翻转、翻转90度opencv中并没有直接封装图像旋转任意角度的函数,一般我们可以使用仿射变换获得旋转后的图像,这时候可以进行任意角度的旋转,但是如果我们需要将图像旋转90度,例如只是对图像进行左右翻转,或者旋转90度将图像放倒,那么如果还使用仿射变换,显得有些不是很简单,有点过于复杂。
实际上可以使用求转置矩阵的方式将图像旋转90度,然后可以沿着指定的坐标轴对旋转后的图像进行翻转变化。
使用transpose(src, dst);对目标图像进行转置变换,可以将垂直的图像变为水平放置。
然后使用flip()函数对图像进行翻转。
整个过程非常简单,可以看下下面的代码就非常清晰的了解了。
// ImageFlip.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "opencv/cv.h"#include "opencv/highgui.h"#include "stdio.h"#include "iostream"using namespace cv;using namespace std;int _tmain(int argc, _TCHAR* argv[]) {Mat src = imread("lena.jpg");Mat dst;transpose(src, dst);Mat dst2;flip(dst, dst2, 1); // flip by y axis Mat dst3;flip(dst, dst3, 0); // flip by x axis Mat dst4;flip(dst, dst4, -1); // flip by both axises imshow("src", src);imshow("dst", dst);imshow("dst2", dst2);imshow("dst3", dst3);imshow("dst4", dst4); cvWaitKey();return 0;}实验结果:原始图像:转置以后:flip(dst, dst2, 1); // flip by y axis2、任意角度旋转、同时缩放(输出图像大小与输入图像大小相同,容易造成图像不全)下面这份代码用于实现对图像的缩放与旋转。
编程实现一幅图像的平移、镜像、旋转、缩小和放大
课程设计任务书学生姓名:专业班级:通信1003班指导教师:郭志强工作单位:信息工程学院题目: 通信工程应用技术初始条件:(1)使用matlab软件进行操作(2)选择一个图像进行处理要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)(1)编程实现一幅图像的平移、镜像、旋转、缩小和放大。
(2)给出所用算法的理论依据和必要的推导过程,给出原始图像和处理后的图像。
时间安排:第15周:安排任务,布置题目;第15—18周:设计仿真,撰写报告第19周:完成设计,提交报告,答辩指导教师签名:年月日系主任(或责任教师)签名:年月日目录摘要 (I)Abstract ........................................................................................................................................................... I I 1 MA TLAB简介 .. (1)1.1 MA TLAB用途 (1)2图像选择及变换 (4)2.1 原始图像选择读取 (4)2.2 图像放大和缩小 (6)2.2.1 图像放大缩小的知识 (6)2.2.2 函数说明及参数选择 (8)2.2.3 源程序及运行结果 (8)2.3 图像任意角度的旋转 (10)2.3.1 函数说明及参数选择 (10)2.3.2 源程序及运行结果 (10)2.4 图像的平移 (12)2.4.1 函数说明及参数选择 (12)2.4.2 源程序及运行结果 (13)2.5 图像经过镜像 (13)3.5.1 函数说明及参数选择 (13)2.5.2 源程序及运行结果 (14)4 感悟体会小结 (17)5 参考文献 (18)附录 (19)全部源程序代码: (19)摘要MATLAB是—套高性能的数值计算和可视化软件,它集数值分析、矩阵运算、信号处理和图形显示于一体,构成—个方便的、界面友好的用户环境。
数字图像处理学
数字图像处理学数字图像处理(digital image processing)是通过计算机对图像进行去除噪声、增强、复原、分割、提取特征等处理的方法和技术。
数字图像处理的产生和迅速发展主要受三个因素的影响:一是计算机的发展;二就是数学的发展(特别就是离散数学理论的创办和健全);三是广泛的农牧业、林业、环境、军事、工业和医学等方面的应用需求的增长。
一、实验内容:主要是图像的几何变换的编程实现,具体包括图像的读取、改写,图像平移,图像的镜像,图像的转置,比例缩放,旋转变换等,具体要求如下:1、编程同时实现图像位移,建议位移后的图像大小维持不变;2、编程实现图像的镜像;3、编程同时实现图像的单位矩阵;4、编程实现图像的比例缩放,要求分别用双线性插值和最近邻插值两种方法来实现,并比较两种方法的缩放效果;5、编程同时实现以任一角度对图像展开旋转变换,建议分别用双线性插值和最近邻插值两种方法去同时实现,并比较两种方法的转动效果。
二、实验目的和意义:本实验的目的就是并使学生熟识并掌控图像处理编程环境,掌控图像位移、镜像、单位矩阵和转动等几何变换的方法,并能够通过程序设计同时实现图像文件的读、写下操作方式,及图像位移、镜像、单位矩阵和转动等几何变换的程序实现。
三、实验原理与主要框架:3.1实验所用编程环境:visualc++(简称vc)是微软公司提供的基于c/c++的应用程序集成开发工具、vc拥有丰富的功能和大量的扩展库,使用它能有效的创建高性能的windows应用程序和web应用程序。
vc除了提供更多高效率的c/c++编译器外,还提供更多了大量的可以器重类和组件,包含知名的谷歌基础类库(mfc)和活动模板类库(atl),因此它就是软件开发人员不可多得的开发工具。
vc丰富的功能和大量的扩展库,类的重用特性以及它对函数库、dll库的支持能使程序更好的模块化,并且通过向导程序大大简化了库资源的使用和应用程序的开发,正由于vc具有明显的优势,因而我选择了它来作为数字图像几何变换的开发工具。
C#图片处理之:旋转图片任意角度.
C#图⽚处理之:旋转图⽚任意⾓度.拍摄的数码相⽚偶尔也有拍歪的时候。
没关系,我们还是可以⽤C#来处理图⽚。
/// <summary>/// 任意⾓度旋转/// </summary>/// <param name="bmp">原始图Bitmap</param>/// <param name="angle">旋转⾓度</param>/// <param name="bkColor">背景⾊</param>/// <returns>输出Bitmap</returns>public static Bitmap KiRotate(Bitmap bmp, float angle, Color bkColor)...{int w = bmp.Width + 2;int h = bmp.Height + 2;PixelFormat pf;if (bkColor == Color.Transparent)...{pf = PixelFormat.Format32bppArgb;}else...{pf = bmp.PixelFormat;}Bitmap tmp = new Bitmap(w, h, pf);Graphics g = Graphics.FromImage(tmp);g.Clear(bkColor);g.DrawImageUnscaled(bmp, 1, 1);g.Dispose();GraphicsPath path = new GraphicsPath();path.AddRectangle(new RectangleF(0f, 0f, w, h));Matrix mtrx = new Matrix();mtrx.Rotate(angle);RectangleF rct = path.GetBounds(mtrx);Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);g = Graphics.FromImage(dst);g.Clear(bkColor);g.TranslateTransform(-rct.X, -rct.Y);g.RotateTransform(angle);g.InterpolationMode = InterpolationMode.HighQualityBilinear;g.DrawImageUnscaled(tmp, 0, 0);g.Dispose();tmp.Dispose();return dst;}最近论坛⾥好像有观点认为C#不适合做图⽚处理。
一种基于FPGA的图像旋转实现技术
一种基于FPGA的图像旋转实现技术曹厚德;刘剑波【摘要】图像旋转是一种常用的数字图像处理技术,目前已广泛应用于各领域.绝大多数数字图像显示系统采取从左向右,从上到下的扫描刷新方式.图像数据也是以同样的方式进行存储.旋转功能的实现能够使图像旋转90°、180°和270°后显示在LCD屏幕上.图像旋转技术的研究与应用通常都集中在软件实现技术领域,提出一种基于硬件的通用技术平台,具有极强适应性的解决方案.【期刊名称】《计算机应用与软件》【年(卷),期】2011(028)007【总页数】3页(P89-91)【关键词】图像旋转;FPGA;扫描刷新;Altera【作者】曹厚德;刘剑波【作者单位】上海广电计算机有限公司上海200233;上海广电计算机有限公司上海200233【正文语种】中文0 引言视频应用是当前消费类电子领域的热点,在视频应用中需要用到大量的数字图像处理算法和模块。
专用的ASIC芯片往往无法同时满足各种特定应用的多媒体视频处理需求;而采用软件实现则运算时间过长、实时性较差。
本文提出一种采用FDP250K-II FPGA芯片实现图像旋转技术的应用解决方案。
该方案采用FDP250K-II FPGA芯片作为液晶数字媒体播放机中的后级图像处理模块,实现视场中心的校正、旋转、精度的计算、实时图像插值等数字视频信号的流水处理,再由Altera公司的EP2S30F484C5N芯片自带的LVDS收发模块实现和上海广电计算机有限公司的液晶数字媒体播放机的控制电路、TFT LCD面板之间的视频传输。
1 采用FDP250K-II的图像旋转技术应用解决方案基于FPGA的图像可旋转液晶数字媒体播放机是传统的多媒体电子媒体播放机替代产品。
系统由控制电路板和TFT LCD面板通过若干LVDS信号对连接组成。
采用FDP250K-II的图像旋转技术应用解决方案如图1所示,在系统控制电路板和TFT LCD面板之间插入一块FDP250K-II应用电路板。
c语言实现图像的旋转与平移
实验二图象的几何变换参考资料1 平移平移(translation)变换是几何变换中最简单的一种。
初始坐标为(x0,y0)的点经过平移(t x,t y)(以向右,向下为正方向)后,坐标变为(x1,y1)。
这两点之间的关系是x1=x0+t x ,y1=y0+t y。
下面给出Translation的源代码。
算法的思想是先将所有区域填成白色,然后找平移后显示区域的左上角点(x0,y0) 和右下角点(x1,y1) ,分几种情况进行处理。
先看x方向(width指图象的宽度)(1)t x≤-width:很显然,图象完全移出了屏幕,不用做任何处理;(2)-width<tx≤0:图象区域的x范围从0到width-|tx|,对应原图的范围从|tx|到width;(3)0< t x <width:图象区域的x范围从t x到width,对应原图的范围从0到width - t x ;(4)t x≥width:图象完全移出了屏幕,不用做任何处理。
y方向是对应的(height表示图象的高度):(1)t y≤-height,图象完全移出了屏幕,不用做任何处理;(2)-height<t y≤0,图象区域的y范围从0到height-|t y|,对应原图的范围从|t y|到height;(3)0<t y<height ,图象区域的y范围从t y到height,对应原图的范围从0到height-t y;(4)t y≥height,图象完全移出了屏幕,不用做任何处理。
这种做法利用了位图存储的连续性,即同一行的象素在内存中是相邻的。
利用memcpy函数,从(x0,y0)点开始,一次可以拷贝一整行(宽度为x1-x0),然后将内存指针移到(x0,y0+1)处,拷贝下一行。
这样拷贝(y1-y0)行就完成了全部操作,避免了一个一个象素的计算,提高了效率。
Translation的源代码如下:int xOffset=0,yOffset=0;BOOL Translation(HWND hWnd){DLGPROC dlgInputBox = NULL;DWORD OffBits,BufSize; LPBITMAPINFOHEADER lpImgData;LPSTR lpPtr;HLOCAL hTempImgData; LPBITMAPINFOHEADER lpTempImgData;LPSTR lpTempPtr;int SrcX0,SrcY0,SrcX1,SrcY1;int DstX0,DstY0,DstX1,DstY1;int RectWidth,RectHeight;BOOL xVisible,yVisible;HDC hDc;HFILE hf;int i;//出现对话框,输入x偏移量xOffset,和y偏移量yOffsetdlgInputBox = (DLGPROC) MakeProcInstance ( (FARPROC)InputBox,ghInst ); DialogBox (ghInst, "INPUTBOX", hWnd, dlgInputBox);FreeProcInstance ( (FARPROC) dlgInputBox );//OffBits为BITMAPINFOHEADER结构长度加调色板的大小OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);BufSize=OffBits+bi.biHeight*LineBytes;//要开的缓冲区的大小//为新产生的位图分配缓冲区内存if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL){MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|MB_ICONEXCLAMATION);return FALSE; //失败,返回}//lpImgData为指向原来位图数据的指针lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);//lpTempImgData为指向新产生位图数据的指针lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); lpPtr=(char *)lpImgData;lpTempPtr=(char *)lpTempImgData;//将新的缓冲区中的每个字节都填成255,这样以后未处理的象素就是白色memset(lpTempPtr,(BYTE)255,BufSize);//两幅图之间的头信息,包括调色板都是相同的,所以直接拷贝头和调色板memcpy(lpTempPtr,lpPtr,OffBits);//xVisible为FALSE时,表示x方向已经移出了可显示的范围xVisible=TRUE;if( xOffset<= -bi.biWidth )xVisible=FALSE;else if( xOffset<=0){DstX0=0; //表示移动后,有图区域的左上角点的x坐标DstX1=bi.biWidth+xOffset; //表示移动后,有图区域的右下角点的x坐标}else if ( xOffset<bi.biWidth){DstX0=xOffset;DstX1=bi.biWidth;}elsexVisible=FALSE;SrcX0=DstX0-xOffset; //对应DstX0在原图中的x坐标SrcX1=DstX1-xOffset; //对应DstX1在原图中的x坐标RectWidth=DstX1-DstX0; //有图区域的宽度//yVisible为FALSE时,表示y方向已经移出了可显示的范围yVisible=TRUE;if( yOffset<= -bi.biHeight )yVisible=FALSE;else if( yOffset<=0){DstY0=0; //表示移动后,有图区域的左上角点的y坐标DstY1=bi.biHeight+yOffset; //表示移动后,有图区域的右下角点的y坐标}else if ( yOffset<bi.biHeight){DstY0=yOffset;DstY1=bi.biHeight;}elseyVisible=FALSE;SrcY0=DstY0-yOffset; //对应DstY0在原图中的y坐标SrcY1=DstY1-yOffset; //对应DstY1在原图中的y坐标RectHeight=DstY1-DstY0; //有图区域的高度if( xVisible && yVisible){ //x,y方向都没有完全移出可显示的范围for(i=0;i<RectHeight;i++){ //拷贝每一行//lpPtr指向要拷贝的那一行的最左边的象素对应在原图中的位//置。
opencv中缩放旋转模板匹配原理
Opencv是一个开源计算机视觉库,可用于处理图像和视频。
在Opencv中,缩放、旋转和模板匹配是常见的图像处理操作,了解这些操作的原理对于深入理解Opencv的工作原理非常重要。
本文将对Opencv中缩放、旋转和模板匹配的原理进行详细介绍,希望能帮助读者更好地掌握图像处理的相关知识。
一、缩放原理1.1 缩放的概念在图像处理中,缩放是指改变图像的尺寸大小。
通常情况下,我们会将图像缩小或放大到需要的大小。
Opencv中提供了resize函数来实现图像的缩放操作。
1.2 缩放的原理Opencv中的resize函数使用了插值算法来实现图像的缩放。
常见的插值算法包括最近邻插值、双线性插值和立方插值。
在进行图像缩放时,resize函数会根据目标图像的大小和原始图像的大小,使用插值算法来计算新图像中每个像素的数值。
这样就可以实现图像的缩放操作。
二、旋转原理2.1 旋转的概念旋转是指改变图像的旋转角度,使得图像产生旋转的效果。
Opencv 中提供了getRotationMatrix2D和warpAffine函数来实现图像的旋转操作。
2.2 旋转的原理Opencv中的旋转操作是通过仿射变换来实现的。
使用getRotationMatrix2D函数来计算出旋转的变换矩阵。
使用warpAffine函数来对图像进行仿射变换,从而实现图像的旋转效果。
在进行仿射变换时,Opencv会对图像进行插值计算,以确保图像旋转后的质量和清晰度。
三、模板匹配原理3.1 模板匹配的概念模板匹配是一种在图像中寻找指定模式的方法。
在Opencv中,模板匹配可以用来在一幅图像中搜索和识别特定的模式。
Opencv中提供了matchTemplate和minMaxLoc函数来实现模板匹配操作。
3.2 模板匹配的原理Opencv中的模板匹配是通过将一个模板图像与另一幅目标图像进行比较来实现的。
将模板图像和目标图像转换为灰度图像。
使用matchTemplate函数对目标图像进行模板匹配计算,得到一个结果图像。
C语言图像旋转 放大 移动程序代码
pImg = cvLoadImage(filename, 1);//载入图像
pImg_xz = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U,3); //创建图像
cvNamedWindow( "原图", 1 );//创建窗口
+q*((1.0-p)*data[(m+height_xz+1)*step+channels*(n+width_xz)]+p*data[(m+height_xz+1)*step+channels*(n+1+width_xz)]));
G=(int)((1.0-q)*((1.0-p)*data[(m+height_xz)*step+channels*(n+width_xz)+1]+p*data[(m+height_xz)*step+channels*(n+1+width_xz)+1])
G=(int)((1.0-q)*((1.0-p)*data[(m+height_xz)*step+channels*(n+width_xz)+1]+p*data[(m+height_xz)*step+channels*(n+1+width_xz)+1])
+q*((1.0-p)*data[(m+height_xz+1)*step+channels*(n+width_xz)+1]+p*data[(m+height_xz+1)*step+channels*(n+1+width_xz)+1]));
C语言图像处理函数大全
C语言图像处理函数大全,完整版∙∙1.图像平移图像平移只是改变图像在屏幕上的位置,图像本身并不发生变化。
假设原图像区域左上角坐标为(x0, y0),右下角坐标为(x1, y1),将图像分别沿x和y轴平移dx和dy,则新图像的左上角坐标为(x0 +dx, y0+dy),右下角坐标为(x1+dx, y1+dy)。
坐标平移变换公式为:x′ = x +dxy′ = y +dy在屏幕上实现图像的移动分为四个步骤:⑴保存原图像到缓冲区。
⑵擦除原图像。
⑶计算平移后的新坐标。
⑷在新的坐标位置重新显示原图像。
其中,擦除原图像的方法与图形变换中擦除原图形的方法一致,在实现中仍采用XOR异或方式画图擦除原图像。
对于新坐标值的计算还需要考虑边界情况,不要在图像平移后超出允许的屏幕范围。
此外,如果采用C函数getimage()和putimage()来保存和恢复图像,则图像的大小不能超过64K。
2.图像颠倒图像颠倒是指把定义好的图像区域上下翻转地显示在屏幕上。
分析图像颠倒的过程,可发现每行的图像信息都保持不变,而只是改变了行的顺序,将第一行与最后的第n行相互交换,第二行与第n-1行交换……,依此类推,从而实现了图像的颠倒。
只需采用按行交换的方式,即可方便地修改缓冲区内容,实现图像的颠倒。
基本步骤如下:(1) 用getimage()保存原图像,并擦除原图像。
(2) 计算图像的高度,即行数height;计算图像宽度width;计算保存一行图像信息height = bottom -top +1;width = right -left +1;linebytes = (width +7) /8 *4;(3)利用行交换缓冲区linebuf在图像内存缓冲区中进行信息交换,即把第一行与最末行交换,第2行与第n-1行交换……,依此类推,直至全部交换完毕。
(4)把交换后的图像缓冲区内容重新显示在屏幕上。
3.图像镜像变换镜像变换是指将指定区域的图像左右翻转地显示在屏幕。
c#数字图像处理(十一)图像旋转
c#数字图像处理(⼗⼀)图像旋转如果平⾯上的点绕原点逆时针旋转θº,则其坐标变换公式为:x'=xcosθ+ysinθ y=-xsinθ+ycosθ其中,(x, y)为原图坐标,(x’, y’)为旋转后的坐标。
它的逆变换公式为:x=x'cosθ-y'sinθ y=x'sinθ+y'cosθ矩阵形式为:和缩放类似,旋转后的图像的像素点也需要经过坐标转换为原始图像上的坐标来确定像素值,同样也可能找不到对应点,因此旋转也⽤到插值法。
在此选⽤性能较好的双线性插值法。
为提⾼速度,在处理旋转90º、-90º、±180º时使⽤了镜像来处理。
///<summary>///图像旋转///</summary>///<param name="srcBmp">原始图像</param>///<param name="degree">旋转⾓度</param>///<param name="dstBmp">⽬标图像</param>///<returns>处理成功 true 失败 false</returns>public static bool Rotation(Bitmap srcBmp, double degree, out Bitmap dstBmp){if (srcBmp == null){dstBmp = null;return false;}dstBmp = null;BitmapData srcBmpData = null;BitmapData dstBmpData = null;switch ((int)degree){case0:dstBmp = new Bitmap(srcBmp);break;case -90:dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);unsafe{byte* ptrSrc = (byte*)srcBmpData.Scan0;byte* ptrDst = (byte*)dstBmpData.Scan0;for (int i = 0; i < srcBmp.Height; i++){for (int j = 0; j < srcBmp.Width; j++){ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];ptrDst[j * dstBmpData.Stride + (dstBmp.Height - i - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];}}}srcBmp.UnlockBits(srcBmpData);dstBmp.UnlockBits(dstBmpData);break;case90:dstBmp = new Bitmap(srcBmp.Height, srcBmp.Width);srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);unsafe{byte* ptrSrc = (byte*)srcBmpData.Scan0;byte* ptrDst = (byte*)dstBmpData.Scan0;for (int i = 0; i < srcBmp.Height; i++){for (int j = 0; j < srcBmp.Width; j++){ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];ptrDst[(srcBmp.Width - j - 1) * dstBmpData.Stride + i * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];}}}srcBmp.UnlockBits(srcBmpData);dstBmp.UnlockBits(dstBmpData);break;case180:case -180:dstBmp = new Bitmap(srcBmp.Width, srcBmp.Height);srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);unsafe{byte* ptrSrc = (byte*)srcBmpData.Scan0;byte* ptrDst = (byte*)dstBmpData.Scan0;for (int i = 0; i < srcBmp.Height; i++){for (int j = 0; j < srcBmp.Width; j++){ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3] = ptrSrc[i * srcBmpData.Stride + j * 3];ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 1] = ptrSrc[i * srcBmpData.Stride + j * 3 + 1];ptrDst[(srcBmp.Width - i - 1) * dstBmpData.Stride + (dstBmp.Height - j - 1) * 3 + 2] = ptrSrc[i * srcBmpData.Stride + j * 3 + 2];}}}srcBmp.UnlockBits(srcBmpData);dstBmp.UnlockBits(dstBmpData);break;default://任意⾓度double radian = degree * Math.PI / 180.0;//将⾓度转换为弧度//计算正弦和余弦double sin = Math.Sin(radian);double cos = Math.Cos(radian);//计算旋转后的图像⼤⼩int widthDst = (int)(srcBmp.Height * Math.Abs(sin) + srcBmp.Width * Math.Abs(cos));int heightDst = (int)(srcBmp.Width * Math.Abs(sin) + srcBmp.Height * Math.Abs(cos));dstBmp = new Bitmap(widthDst, heightDst);//确定旋转点int dx = (int)(srcBmp.Width / 2 * (1 - cos) + srcBmp.Height / 2 * sin);int dy = (int)(srcBmp.Width / 2 * (0 - sin) + srcBmp.Height / 2 * (1 - cos));int insertBeginX = srcBmp.Width / 2 - widthDst / 2;int insertBeginY = srcBmp.Height / 2 - heightDst / 2;//插值公式所需参数double ku = insertBeginX * cos - insertBeginY * sin + dx;double kv = insertBeginX * sin + insertBeginY * cos + dy;double cu1 = cos, cu2 = sin;double cv1 = sin, cv2 = cos;double fu, fv, a, b, F1, F2;int Iu, Iv;srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);unsafe{byte* ptrSrc = (byte*)srcBmpData.Scan0;byte* ptrDst = (byte*)dstBmpData.Scan0;for (int i = 0; i < heightDst; i++){for (int j = 0; j < widthDst; j++){fu = j * cu1 - i * cu2 + ku;fv = j * cv1 + i * cv2 + kv;if ((fv < 1) || (fv > srcBmp.Height - 1) || (fu < 1) || (fu > srcBmp.Width - 1)){ptrDst[i * dstBmpData.Stride + j * 3] = 150;ptrDst[i * dstBmpData.Stride + j * 3 + 1] = 150;ptrDst[i * dstBmpData.Stride + j * 3 + 2] = 150;}else{//双线性插值Iu = (int)fu;Iv = (int)fv;a = fu - Iu;b = fv - Iv;for (int k = 0; k < 3; k++){F1 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + Iu * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + Iu * 3 + k);F2 = (1 - b) * *(ptrSrc + Iv * srcBmpData.Stride + (Iu + 1) * 3 + k) + b * *(ptrSrc + (Iv + 1) * srcBmpData.Stride + (Iu + 1) * 3 + k); *(ptrDst + i * dstBmpData.Stride + j * 3 + k) = (byte)((1 - a) * F1 + a * F2);}}}}}srcBmp.UnlockBits(srcBmpData);dstBmp.UnlockBits(dstBmpData);break;}return true;}。
C++3D图形变换(含源码,下载后可复制黏贴使用)
实验三 3D图形变换一.实验目的:掌握3D图像的变换,了解多数的3D变换,平移,旋转等几何变换,还有投影变换等知识。
二.实验原理:3D图像的移动,比例变化,旋转等几何变换算法原理及各种投影变换算法原理。
三.实验步骤:一.建立MFC单文档程序,用来编写3D变换。
二.建立Mainframe,并设计,添加相应的ID及映射函数。
三.实验的主要代码:1、设计3维图形平移变换算法的实现程序;void CMyView::OnTranslation(){m_Select=SEL_TS;m_str="平移";CBaseClass my1; //构造新的CBaseClass对象int i,j;for ( i=1;i<=4;++i){for ( j=1;j<=4;++j)my1.A[i][j]=0;}my1.A[1][1]=1;my1.A[2][2]=1;my1.A[4][4]=1;my1.A[3][3]=1;my1.A[4][1]=20; //x轴方向上平移my1.A[4][2]=28; //y轴方向上平移my1.A[4][3]=28; //z轴方向上平移my1.Draw();}2、设计3维图形缩放变换算法的实现程序;void CMyView::OnScalingS(){m_Select=SEL_MO;m_str="整体变比";CBaseClass my1; //构造新的CBaseClass对象int i,j;for ( i=1;i<=4;++i){for ( j=1;j<=4;++j)my1.A[i][j]=0;}my1.A[1][1]=1;my1.A[2][2]=1;my1.A[3][3]=1;my1.A[4][4]=0.5;my1.Draw();}void CMyView::OnScalingXyz(){m_Select=SEL_MO;m_str="XYZ变比";CBaseClass my1; //构造新的CBaseClass对象int i,j;for ( i=1;i<=4;++i){for ( j=1;j<=4;++j)my1.A[i][j]=0;}my1.A[1][1]=2; //x轴方向上比例my1.A[2][2]=1; //y轴方向上比例my1.A[3][3]=2; //z轴方向上比例my1.A[4][4]=1;my1.Draw();}3、设计3维图形旋转变换算法的实现程序。
opencv练习题
OpenCV 练习题一、基础操作题1. 创建一个空白的黑色图像,尺寸为 300x200。
2. 在图像上绘制一个红色的正方形,边长为 100。
3. 在图像上绘制一个蓝色的圆形,半径为 50。
4. 在图像上绘制一条从左上角到右下角的绿色直线。
5. 在图像上绘制一个黄色的三角形,边长分别为 50、60、70。
二、图像处理题6. 读取当前目录下的 "example.jpg" 图像。
7. 将图像转换为灰度图。
8. 对灰度图进行高斯模糊处理,模糊半径为 5。
9. 对图像进行边缘检测,使用 Canny 算法。
10. 对图像进行二值化处理,阈值设置为 128。
三、特征检测与匹配题11. 在当前目录下找到 "image1.jpg" 和 "image2.jpg",使用SIFT 算法检测特征点。
12. 使用 FLANNKDTREE 算法进行特征点匹配。
13. 根据匹配结果,绘制特征点匹配图。
14. 使用 BRUTEFORCE 算法进行特征点匹配。
15. 使用 BFMatcher 创建一个匹配器,并使用它进行特征点匹配。
四、图像变换题16. 对图像进行平移变换,向右平移 50 像素,向下平移 30 像素。
17. 对图像进行旋转变换,旋转角度为 45 度。
18. 对图像进行缩放变换,缩放比例为 0.5。
19. 对图像进行翻转变换,水平翻转。
20. 对图像进行剪切变换,剪切区域为左上角 (50, 50) 到右下角 (200, 150)。
五、视频处理题21. 打开当前目录下的 "video.mp4" 视频文件。
22. 读取视频的第一帧图像。
23. 对视频帧进行颜色空间转换,从 BGR 转换到 HSV。
24. 在视频帧上添加文字 "Hello, OpenCV!",字体为 Arial,字号为 24。
25. 显示视频帧,并等待用户按键后继续显示下一帧。
getrotationmatrix2d 新坐标计算
题目:getRotationMatrix2D新坐标计算概述:在计算机视觉和图像处理中,经常需要对图像进行旋转操作。
使用OpenCV库可以方便地进行图像旋转,其中getRotationMatrix2D函数可以帮助我们计算旋转矩阵,从而实现图像的旋转操作。
本文将对getRotationMatrix2D函数的用法和新坐标计算进行详细介绍。
一、getRotationMatrix2D函数介绍getRotationMatrix2D是OpenCV中的函数,它用于计算2D旋转的变换矩阵。
该函数的原型如下:```cppMat getRotationMatrix2D(Point2f center, double angle, double scale)```其中,center表示旋转的中心点坐标,angle表示旋转的角度,scale 表示旋转后的缩放比例。
该函数返回一个2x3的变换矩阵,可以用于对图像进行旋转操作。
二、getRotationMatrix2D函数的用法以下是一个getRotationMatrix2D函数的示例代码:```cppPoint2f center(img.cols / 2.0, img.rows / 2.0);double angle = 45;double scale = 1.0;Mat rot_mat = getRotationMatrix2D(center, angle, scale);```在这个示例中,我们首先定义了旋转的中心点坐标,然后指定了旋转的角度和缩放比例,最后调用getRotationMatrix2D函数计算出变换矩阵。
三、新坐标的计算得到变换矩阵之后,我们可以利用它来计算旋转后的新坐标。
假设我们有一个点(x, y),我们可以通过以下公式计算它在旋转后的新坐标(x', y'):```cppx' = rot_mat.at<double>(0, 0) * x + rot_mat.at<double>(0, 1) * y + rot_mat.at<double>(0, 2);y' = rot_mat.at<double>(1, 0) * x + rot_mat.at<double>(1, 1) * y + rot_mat.at<double>(1, 2);```使用这些公式,我们可以方便地计算出旋转后的新坐标。
矩阵逆时针旋转90度c语言代码
矩阵逆时针旋转90度C语言代码1. 前言在编程领域,矩阵是一个非常常见且重要的数据结构,而旋转矩阵则是矩阵操作中的一个常见问题。
在本文中,我将深入探讨矩阵逆时针旋转90度的C语言代码实现,并尽可能详细地解释其中的原理和逻辑。
2. 理解矩阵逆时针旋转让我们深入理解矩阵逆时针旋转的概念。
矩阵逆时针旋转90度意味着矩阵中的每一个元素都按照逆时针的方向进行旋转,最终得到一个新的矩阵。
这种操作在图像处理、游戏开发等领域经常会遇到,因此对于程序员来说,掌握矩阵旋转的代码实现是非常重要的。
3. 矩阵逆时针旋转的基本思路想要编写矩阵逆时针旋转90度的C语言代码,首先我们需要明确旋转后的矩阵大小和元素的变化规律。
以一个n x n的矩阵为例,逆时针旋转后的矩阵同样是n x n的大小。
对于原矩阵中的每一个元素matrix[i][j],在逆时针旋转后,它会被放置在新矩阵的第j行第n-i-1列的位置上。
4. 实现矩阵逆时针旋转的C语言代码接下来,我将介绍实现矩阵逆时针旋转的C语言代码。
在实际编码中,我们可以采取原地旋转的方式,即在不使用额外空间的情况下完成矩阵的旋转操作。
```c#include <stdio.h>#define N 3void rotate(int matrix[N][N]) {for (int i = 0; i < N / 2; i++) {for (int j = i; j < N - 1 - i; j++) {int temp = matrix[i][j];matrix[i][j] = matrix[j][N - 1 - i];matrix[j][N - 1 - i] = matrix[N - 1 - i][N - 1 - j]; matrix[N - 1 - i][N - 1 - j] = matrix[N - 1 - j][i]; matrix[N - 1 - j][i] = temp;}}}int main() {int matrix[N][N] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};rotate(matrix);for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {printf("%d ", matrix[i][j]);}printf("\n");}return 0;}```在这段代码中,我们使用了两层循环来遍历矩阵中的每一个元素,并按照逆时针旋转的逻辑进行位置交换。
C++Builder_图像的几何放大_缩小_任意角度旋转
C++Builder实现图像的放大、缩小、任意角度旋转功能学号:090081001023学生所在学院:信息工程学院学生姓名:吴静任课教师:熊邦书教师所在学院:信息工程学院2010年1月09级研8班实现图像的放大、缩小、任意角度旋转功能吴静信息工程学院摘要:本文介绍了C++程序设计在数字图像处理应用领域的简单运用及其重要意义,详细阐述了利用C++Builder设计简单的图像处理软件的方法和步骤,实现了图像的任意倍数的放大、缩小、任意角度旋转功能。
在此基础上,对数字图像处理的研究有了初步的了解,并且进一步熟悉了C++程序设计在实际应用中的一般方法和思想,为以后进一步的编程和对图像处理的研究打下了基础。
关键词:C++Builedr 放大缩小任意角度旋转Abstract:This article describes the C++ programming in digital image processing applicationsthe use and significance of a simple detailede the use of C++ Builderdesigned to be simple image processing software methods and steps to achievean arbitrary multiple of the image to enlarge,reduceany angle rotation.On thisbasis,the study of digital image processing an initial understanding ofandfurther familiar wite C++ programmers in practical appliacation of the generalmethods and ideas for future programming and further image processing to laythe foundation for the study.Keywords:C++ Builder enlarge reduce rotation at any angle1 组件介绍1.1 窗体(Form)窗体是人机交互的主要界面,窗体的界面设计是十分重要的,一个好的软件需要一个漂亮的窗体来衬托。
图像的几何变换的两种实现(旋转、平移、放大、缩小)
面向对象程序设计学号:2学生所在学院:信息工程学院学生姓名:邵丽群任课教师:熊邦书教师所在学院:信息工程学院2013级实现图像的几何变换电子信息工程信息工程学院摘要:几何变换是最常见的图像处理手段,通过对变形的图像进行几何校正,可以得出准确的图像。
常用的几何变换功能包括图像的平移、图像的镜像变换、图像的转置、图像的缩放、图像的旋转等等。
目前数字图像处理的应用越来越广泛,已经渗透到工业、航空航天、军事等各个领域,在国民经济中发挥越来越大的作用。
作为数字图像处理的一个重要部分,本文接受的工作是如何Visual C++编程工具设计一个完整的应用程序,实现经典的图像几何变换功能。
程序大概分为两大部分:读写BMP图像,和数字图像的几何变换。
即首先用Visual C++创建一个单文档应用程序框架,在实现任意BMP图像的读写,打印,以及剪贴板操作的基础上,完成经典的图像几何变换功能。
图像几何变换的Visual C++编程实现,为校课题的实现提供了一个实例。
关键字:图像处理;几何变换(图像的平移、缩放、转置、旋转和镜像变换);BMP图像;Visual C++一、引言图像几何变换是指用数学建模的方法来描述图像位置、大小、形状等变化的方法。
在实际场景拍摄到的一幅图像,如果画面过大或过小,都需要进行缩小或放大。
如果拍摄时景物与摄像头不成相互平行关系的时候,会发生一些几何畸变,例如会把一个正方形拍摄成一个梯形等。
这就需要进行一定的畸变校正。
在进行目标物的匹配时,需要对图像进行旋转、平移等处理。
在进行三维景物显示时,需要进行三维到二维平面的投影建模。
因此,图像几何变换是图像处理及分析的基础。
图像几何变换是计算机图像处理领域中的一个重要组成部分,也是值得深讨的一个重要课题。
在图像几何变换中主要包括图像的放缩、图像的旋转、图像的移动、图像的镜像、图像的块操作等容,几何变换不改变图像的像素值,只改变像素所在的几何位置。
从广义上说,图像是自然界景物的客观反映,是人类认识世界和人类本身的重要源泉。
基于OpenCV和C++实现图片旋转
基于OpenCV和C++实现图⽚旋转图⽚旋转,本质上是对旋转后的图⽚中每个像素点计算在原图的位置。
然后照搬过来就好。
(多说⼀句,如果计算出来在原图中的位置不是整数⽽是⼩数,因为像素点个数都是整数,就需要⼩数到整数的转换。
这个转换过程是有讲究的,需要⽤到插值:最近邻插值、双线性插值等等。
这⾥我使⽤的是最简单的最近邻插值,即对⼩数四舍五⼊成整数,C/C++ 实现四舍五⼊见这⾥)图形图像课上⼀般会介绍旋转变换矩阵,其中 t 为需要旋转的⾓度,[x'; y']是变换后坐标(其中分号表⽰上下关系):即表⽰为:[x'; y'] = [cos(t) sin(t); -sin(t) cos(t)][x; y]因为我个⼈兴趣爱好(放P就是⽼师逼的。
),不允许使⽤ OpenCV 封装好的旋转函数。
只能⾃⼰实现,我开始的想法是:先求变换矩阵逆矩阵,然后将⼀张全⿊图中每个点⼀⼀对应插值到原图中。
结果发现转换后图⽚全⿊了……后来发现原点设置不对。
⽤OpenCV中的 Mat格式存储(或⼆维数组)的图⽚,原点在左上⾓。
但是想要实现的旋转原点在图⽚中⼼。
同时, Mat格式存储(或⼆维数组)的坐标系中 y轴正⽅向向下。
这样⼈类视觉上的顺时针旋转,在⼆维数组的坐标系中是逆时针旋转。
最重要的⼀点,也是⼆维数组操作中极易忽略的⼀点:数组操作的是数组下标,不是坐标系(数组的⾏数 rows 是矩形的宽width ,列数 cols 是矩形的长 length )。
⽐如坐标系(此时为了更贴近数组布局,我们假设 y 轴坐标系是向下的)中,矩形顶点是:但是在数组中,因为是⾏优先,所以四个点的下标取值为:有没有发现,两种坐标是相反的!总结下来,我们的图⽚旋转需要注意以下⼏点:1. 变换后图⽚中的每个像素点(i; j),需要平移到相对旋转中⼼的新坐标,即(i - Mat.rows/2; j - Mat.cols/2)。
计算完成之后,需要再次还原到相对左上⾓原点的旧坐标;2. 本来需要变换后图⽚乘以原图变换矩阵的逆矩阵对应到原图中坐标。
opencv remap 实现原理
一、概述opencv是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉功能。
其中,remap是opencv中的一种图像处理函数,可以实现图像的几何变换,如放缩、旋转、平移等。
本文将介绍remap 函数的实现原理。
二、remap函数的功能remap函数的功能是将输入图像中的每个像素根据一个变换关系映射到输出图像中的一个新位置。
这个变换关系由用户提供的两个映射矩阵xmap和ymap来描述,其中xmap和ymap分别指定了输入图像中每个像素的x和y坐标在输出图像中的映射位置。
通过remap函数,用户可以实现各种复杂的几何变换,例如透视变换、极坐标转换等。
remap函数还可以进行插值操作,确保输出图像中像素值的连续性和平滑性。
三、remap函数的实现原理remap函数的实现原理主要涉及两个关键步骤:映射计算和插值计算。
1. 映射计算在映射计算阶段,remap函数首先需要计算输入图像中每个像素的映射位置。
这个映射过程实质上就是对输入图像中的每个像素进行坐标变换,得到其在输出图像中的新位置。
这个坐标变换由用户提供的xmap和ymap矩阵进行描述,remap函数通过这两个矩阵来计算输入图像中每个像素的映射位置。
2. 插值计算映射计算得到的映射位置是浮点型坐标值。
为了得到输出图像中的像素值,remap函数需要进行插值计算。
这个插值过程是为了根据输入图像中的像素值,推断其在输出图像中的值。
opencv中提供了多种插值算法,如最近邻插值、双线性插值、双三次插值等,用户可以根据实际需求选择合适的插值算法进行计算。
四、remap函数的使用示例下面是一个使用remap函数实现图像放缩的示例代码:```c++#include "opencv2/opencv.hpp"using namespace cv;int main(){Mat img = imread("input.jpg");Mat xmap, ymap;// 生成xmap和ymap矩阵,实现图像的放缩变换// ...Mat remap_img;// 使用remap函数进行图像放缩remap(img, remap_img, xmap, ymap, INTER_LINEAR);imshow("remap_img", remap_img);waitKey();return 0;}```在上面的示例代码中,首先读入输入图像,然后根据需求生成xmap和ymap矩阵,最后调用remap函数实现图像的放缩变换,并展示输出图像。
C#实现图片自由变换任意扭曲的算法
C#实现图⽚⾃由变换任意扭曲的算法 先看看效果 界⾯是仿照某个⼈(⽹上版本太多,找不到原作者)的弄出来的,界⾯不是重点,重点是算法。
下⾯就直接贴⽼外的那幅图⼤致讲讲思想。
⾸先是从原本图⽚转化成⼀幅理想化的⽬标图⽚,那幅图⽚只是理想化的,最终的图⽚是最右边的那幅。
转换的过程就是根据转换后图⽚的四个⾓计算出⽬标图⽚的size,⽣成⼀个矩阵,就是那个Destination Image,然后把理想化的⽬标图⽚覆盖过去,把理想化图⽚的每个“像素格”(已经不是真正的像素格了,因为经过了扭曲变形)跟那个矩阵对⽐,看看覆盖了哪些格⼦,覆盖的⾯积有多少,按百分⽐地把颜⾊累加到对应的格⼦上。
实际上那个格⼦就相当于新图⽚的像素点了。
按照矩阵⽣成最终的⽬标图。
接着就介绍算法⾥⾯调⽤的⽅法层次 把已经弄懂(并不代表完全懂的)的代码贴出来,⾸先是最外层的⽅法1public void CreateTransform(Bitmap src,ref Bitmap dst, List<double> xcorner, List<double> ycorner, Aaf_callback callbackfunc)2 {3int right = 0, bottom = 0;45//主要是根据新图⽚的坐标,计算出图⽚的宽和⾼,构造⽬标图⽚的Bitmap的6double offx = xcorner[0];7double offy = ycorner[0];8for (int i = 1; i < 4; i++)9 {10if (xcorner[i] < offx) offx = xcorner[i];11if (ycorner[i] < offy) offy = ycorner[i];12 }1314for (int i = 0; i < 4; i++)15 {16 xcorner[i] -= offx;17 ycorner[i] -= offy;18if (roundup(xcorner[i]) > right) right = roundup(xcorner[i]);19if (roundup(ycorner[i]) > bottom) bottom = roundup(ycorner[i]);20 }21 dst = new Bitmap(right, bottom);22 Transform(src, dst, xcorner, ycorner, null);23 } 上⾯这个⽅法只是定了⽬标图⽚的尺⼨,其余什么都没做。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用C++实现图像旋转变换
(代码较长,
本人使用C++实现了一个类似GDI+ Matrix的C++几何变换类TransformMatrix。
略,参见我的BLOG文章《实现完整的图像平面几何变换》)。
我所说的“实现完整的图像平面几何变换”,是指可以通过TransformMatrix::Multiply函数或者更直接的变换矩阵成员设置去实现“完整的”图像
几何变换,除非其不能使用平面几何变换矩阵进行描述(如梯形变换我就没想到怎么实现,
也许其超出了平面几何变换矩阵范畴?),或者不能进行实际的几何变换(不可逆);“实现
完整的图像几何变换”的另一层含义是下面的图像变换执行函数可实现TransformMatrix
所能表示的任意图像几何变换,而不必去写一个个具体的,如缩放、旋转变换函数等。
C/C++ code
// 获取子图数据
BOOL GetSubBitmapData(CONST BitmapData *data, INT x, INT y, INT width, INT height, BitmapDa {
if (x < 0)
{
width += x;
x = 0;
}
if (x + width > (INT)data->Width)
width = (INT)data->Width - x;
if (width <= 0) return FALSE;
if (y < 0)
{
height += y;
y = 0;
}
if (y + height > (INT)data->Height)
height = (INT)data->Height - y;
if (height <= 0) return FALSE;
sub->Width = width;
sub->Height = height;
sub->Stride = data->Stride;
sub->Scan0 = (CHAR*)data->Scan0 + y * data->Stride + (x << 2);
return TRUE;
}
// 执行图像数据几何变换
VOID Transform(BitmapData *dest, INT x, INT y, CONST BitmapData *source, TransformMatrix *m {
// 复制几何变换矩阵对象
TransformMatrix m(matrix);
// 几何变换矩阵绝对增加平移量x, y
m.GetElements().dx += x;
m.GetElements().dy += y;
// 按几何变换矩阵计算并获取目标图像数据子数据
float fx, fy, fwidth, fheight;
m.GetTransformSize(source->Width, source->Height, fx, fy, fwidth, fheight);
BitmapData dst;
if (!GetSubBitmapData(dest, (INT)fx, (INT)fy,
(INT)(fwidth + 0.999999f), (INT)(fheight + 0.999999f), &dst))
return;
// 获取几何变换逆矩阵
if (!m.Invert()) return;
// 如果子图数据与目标图像原点不一致,几何变换矩阵相对增加平移量fx, fy
if (fx > 0.0f || fy > 0.0f)
{
if (fx < 0.0f) fx = 0.0f;
else if (fy < 0.0f) fy = 0.0f;
m.Translate(fx, fy);
}
// 设置子图扫描线指针及行偏移宽度
UINT *pix = (UINT*)dst.Scan0;
INT dstOffset = (dst.Stride >> 2) - dst.Width;
// 几何变换逆矩阵的平移量为与子图原点对应的源图起始坐标点
MatrixElements e = m.GetElements();
float xs = e.dx;
float ys = e.dy;
// 逐点计算并复制源图几何变换后的数据到目标子图
for (y = 0; y < (INT)dst.Height; y ++, pix += dstOffset, xs += e.m21, ys += e.m22)
{
float xs0 = xs;
float ys0 = ys;
for (x = 0; x < (INT)dst.Width; x ++, pix ++, xs0 += e.m11, ys0 += e.m12)
{
INT x0 = xs0 < 0.0f? (INT)(xs0 - 0.5f) : (INT)(xs0 + 0.5f);
INT y0 = ys0 < 0.0f? (INT)(ys0 - 0.5f) : (INT)(ys0 + 0.5f);
if (y0 >= 0 && y0 < (INT)source->Height && x0 >= 0 && x0 < (INT)source->Width) *pix = *(UINT*)((CHAR*)source->Scan0 + y0 * source->Stride + (x0 << 2));
}
}
}
函数特点:
1、可以实现任意的图像几何变换(只要TransformMatrix能正确表达的,即变换矩阵
可逆);
2、采用了GDI+ 的BitmapData结构(转换为32位ARGB像素格式),而并非任何具体
的图像格式,保证了其通用性;
3、函数使用浮点数运算,但在计算像素点位置时避免了通常的浮点数乘除运算,既提高了一定的运算速度,也为以后修改为定点数运算奠定了基础;
4、函数采用临近像素插值,且没有边界像素处理代码,像素复制质量较差。
可以看出,Transform函数的着重点在于特点(1),在实际的实现代码中,可以把它作为一个框架进行扩充和修改。
下面是例子运行截图:
GDI+位图旋转45度
VCL位图缩放与剪切组合变换。