图像旋转以及C代码实现

    图像旋转就是将图像按一定角度旋转,依据当前点坐标计算出来的旋转后的坐标往不是整数,因此需要进行插值。常用的插值方法有最近邻插值法、线性插值法和样条插值法(这个我也不懂)。最近邻插值速度快,效果差;双向性插值法效果较好,速度还行。这里只讨论使用反向映射和双线性插值的图像旋转。

旋转原理:

反向映射就是依据旋转后图像中的坐标,求出其在原图像中的坐标。

如图,将图像逆时针旋转一个角度

 

    计算旋转后图像时就可以利用(3)式用旋转后的坐标计算其在原图中的坐标,并利用附近的像素插值的到当前的像素值。

    图像的原点一般在左上角,这样计算出来的坐标会有负值,一般将图像原点平移到图像中心。记原图像的宽高为srcW、srcH,旋转后图像宽高为dstW、dstH,那么(3)式就变为:

 

双线性插值

    由旋转后图像坐标计算出来的原图像坐标往往不是整数,为了保证旋转效果,进行双线性插值。双线性插值就是对两个变量的线性插值,分别对每个变量线性插值就得到最终的插值结果。

详细资料参考

http://www.cnblogs.com/linkr/p/3630902.html

 

代码如下,使用opencv加载图像。

调用方法

void main(int argc, char** argv)
{
	IplImage* iplOrg=cvLoadImage(argv[1]);	//加载图像
	unsigned char* pColorImg=NULL;
	int width=iplOrg->width;
	int height=iplOrg->height;
	pColorImg=(unsigned char*)malloc(width*height*3*sizeof(unsigned char));

	cvCvtColor(iplOrg,iplOrg,CV_BGR2RGB);
	IplToUchar(iplOrg,pColorImg);	//用数组表示图像
	cvReleaseImage(&iplOrg);

	double degree=15;	//逆时针旋转角度0~180

	int tempLength=sqrt((double)width * width + (double)height *height) + 10;//保证原图可以任意角度旋转的最小尺寸
	unsigned char* pTemp=(unsigned char*)malloc(tempLength*tempLength*3*sizeof(unsigned char));

		
	//旋转
	myImgRotate(pColorImg,width,height,pTemp,tempLength,tempLength,degree,3);
	DisplayPicture(tempLength,tempLength,pTemp,"rotate.bmp",3);	//保存图像
	
	free(pTemp);
	pTemp=NULL;
	free(pColorImg);
	pColorImg=NULL;
	
}


 

旋转函数

//逆时针旋转到pdst的中心,其它用0填充
//pSrc,srcW,srcH原图及其尺寸
//pDst,dstW,dstH旋转后图像及其尺寸
//旋转角度
//通道数
void myImgRotate(unsigned char* pSrc,int srcW,int srcH,
						   unsigned char* pDst,int dstW,int dstH,
						   double degree,int nchannel)
{

	int k;
	double angle = degree  * 3.1415926 / 180.;	//旋转角度
	double co=cos(angle);	//余弦
	double si=sin(angle);	//正弦
	int rotateW,rotateH;	//旋转后图像的高宽
	int srcWidthStep=srcW*nchannel;//宽度步长
	int dstWisthStep=dstW*nchannel;	
	int x,y;
	int xMin,xMax,yMin,yMax;
	int xOff,yOff;	//偏移
	double xSrc=0.;
	double ySrc=0.;	//变换后图像的坐标在原图中的坐标

	//临时变量
	float valueTemp=0.;
	float a1,a2,a3,a4;

	memset(pDst,0,dstWisthStep*dstH*sizeof(unsigned char));
	//计算旋转后的坐标范围
	rotateH=srcW*fabs(si)+srcH*fabs(co);
	rotateW=srcW*fabs(co)+srcH*fabs(si);

	//计算偏移
	xOff=dstW/2;
	yOff=dstH/2;

	yMin=(dstH-rotateH)/2.;
	yMax=yMin+rotateH+1;	//加1
	xMin=(dstW-rotateW)/2.;
	xMax=xMin+rotateW+1;

	for (y=yMin;y<=yMax;y++)
	{
		for (x=xMin;x<=xMax;x++)
		{
			//求取在原图中的坐标
			ySrc=si*double(x-xOff)+co*double(y-yOff)+double(int(srcH/2));
			xSrc=co*double(x-xOff)-si*double(y-yOff)+double(int(srcW/2));
			
			//如果在原图范围内
			if (ySrc>=0. && ySrc<srcH-0.5 && xSrc>=0. && xSrc<srcW-0.5)
			{
				//插值
				int xSmall=floor(xSrc);
				int xBig=ceil(xSrc);
				int ySmall=floor(ySrc);
				int yBig=ceil(ySrc);

				for (k=0;k<nchannel;k++)
				{
					a1=(xSmall>=0 && ySmall>=0 ? pSrc[ySmall*srcWidthStep+xSmall*nchannel+k]:0);
					a2=(xBig<srcW && ySmall>=0 ? pSrc[ySmall*srcWidthStep+xBig*nchannel+k]:0);
					a3=(xSmall>=0 && yBig<srcH ? pSrc[yBig*srcWidthStep+xSmall*nchannel+k]:0);
					a4=(xBig<srcW && yBig<srcH ? pSrc[yBig*srcWidthStep+xBig*nchannel+k]:0);
					double ux=xSrc-xSmall;
					double uy=ySrc-ySmall;
					//双线性插值
					valueTemp=(1-ux)*(1-uy)*a1+(1-ux)*uy*a3+(1-uy)*ux*a2+ux*uy*a4;
					pDst[y*dstWisthStep+x*nchannel+k]=floor(valueTemp);
				}

			}
		}
	}
}


结果

    

参考资料

http://blog.csdn.net/xiaowei_cqu/article/details/7616044

http://www.cnblogs.com/mlv5/archive/2012/02/02/2336321.html

http://www.cnblogs.com/slysky/archive/2012/03/21/2410743.html

http://blog.csdn.net/jia20003/article/details/8221173

 

 

 

 

 

 

  • 11
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: 可以使用C语言图形库来实现12864屏幕显示图像的旋转缩放,例如SDL库。可以使用SDL_RenderCopyEx函数来设置旋转和缩放参数,然后使用SDL_RenderPresent函数把图像绘制到12864屏幕上。 ### 回答2: 要实现12864屏幕的图像旋转和缩放,可以使用C语言编写以下代码: 首先,我们需要定义一个二维数组来表示屏幕的像素矩阵,假设屏幕的分辨率为128x64。为了实现旋转和缩放,我们需要定义一个新的数组用于保存处理后的图像。 ```c #define WIDTH 128 #define HEIGHT 64 unsigned char screen[WIDTH][HEIGHT]; // 原始屏幕像素矩阵 unsigned char rotated[HEIGHT][WIDTH]; // 旋转后的像素矩阵 unsigned char scaled[WIDTH*2][HEIGHT*2]; // 缩放后的像素矩阵 // 图像旋转函数 void rotateImage() { int i, j; for(i=0; i<HEIGHT; i++) { for(j=0; j<WIDTH; j++) { rotated[HEIGHT-1-i][j] = screen[j][i]; // 将原始图像逆时针旋转90度 } } } // 图像缩放函数 void scaleImage() { int i, j, m, n; for(i=0; i<WIDTH; i++) { for(j=0; j<HEIGHT; j++) { int pixel = screen[i][j]; // 将每个像素扩展为2x2的区块 for(m=0; m<2; m++) { for(n=0; n<2; n++) { scaled[i*2+m][j*2+n] = pixel; } } } } } int main() { // 在此处读取/生成原始图像矩阵screen // 调用图像旋转函数 rotateImage(); // 调用图像缩放函数 scaleImage(); // 在此处将旋转后或缩放后的图像矩阵绘制到12864屏幕上 return 0; } ``` 在上述示例代码中,`rotateImage()`函数实现了将原始图像逆时针旋转90度,并将结果保存到`rotated`数组中。`scaleImage()`函数将原始图像每个像素的区块都扩展为2x2的区块,并将结果保存到`scaled`数组中。 在`main()`函数中,可根据需要在适当的位置读取/生成原始图像矩阵,并在处理后将旋转或缩放后的图像矩阵绘制到12864屏幕上。 请注意,上述代码仅为示例,并未考虑具体的图像处理接口和绘制方法,实际应用中可能需要根据使用的显示屏幕和所用的图像处理库进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值