百问FB显示开发图像处理 - 图像调整

2.4 图像调整

2.4.1 图像的缩放

2.4.1.1 图像缩放算法浅析

图像缩放算法有很多种,这里参考网友"lantianyu520"所著的"图像缩放算法"。

原理浅析

​ 要理解这个图像缩放算法的原理,最重要的是需要理解:对于图像上的每一个像素点,它缩放前后,相对于整个图像的比例应该是一样的。

比如:

​ 以一个长度和宽度分别为200,100的长方形为例,将其放大两倍,那么缩放后的长度和宽度为400,200。

为方便理解,我们建立一个笛卡尔坐标系,把这个长方形左下角的顶点放到坐标(0,0)位置,四个点的坐标分别为:(0,0),(0,100),(200,0),(200,100)。

​ 假设此时对长方形中的坐标点(40,50),它的x坐标相对于长的比值是40/200=0.2,y坐标相对于宽的比值是50/100=0.5,那么该点的变换后的坐标Dx,Dy则应满足:Dx/400 = 5;Dy/200 = 0.5,这样,缩放后的坐标就可以算出来了。

​ 根据上面的分析,设缩放前的像素点坐标为(Sx,Sy),对应的缩放后的像素点坐标为(Dx,Dy),缩放前的图像长宽分别为Sw,Sh,缩放后的图像长宽分别为Dw,Dh,则有:

Sx/Dx = Sw/Dw,Sy/Dy = Sh/Dh

故有Sx = Dx * Sw/Dw,Sy = Dy * Sh/Dh,

2.4.1.2源码编写:图像缩放算法

有了这个上面两条等式后,图像缩放算法的代码就好理解了。

下面的函数实现了基于上述原理实现的图像缩放算法:

代码清单2.4
1.	/********************************************************************** 
2.	 * 函数名称: PicZoom 
3.	 * 功能描述: 近邻取样插值方法缩放图片 
4.	 *            注意该函数会分配内存来存放缩放后的图片,用完后要用free函数释放掉 
5.	 *            "近邻取样插值"的原理请参考网友"lantianyu520"所著的"图像缩放算法" 
6.	 * 输入参数: ptPicData - 内含缩放前后的图像数据 
7.	 *            fSize    - 缩放倍数 
8.	 * 输出参数: ptPicData->pucZoomData,内含缩放后的数据 
9.	 * 返 回 值: 0 - 成功, 其他值 - 失败 
10.	 ***********************************************************************/  
11.	int PicZoom(PT_PictureData ptPicData,float fSize)  
12.	{  
13.	    ptPicData->iZoomWidth = ptPicData->iWidth * fSize;  
14.	    ptPicData->iZoomHeight= ptPicData->iHeight* fSize;  
15.	    unsigned long* pdwSrcXTable;  
16.	    unsigned long x;  
17.	    unsigned long y;  
18.	    unsigned long dwSrcY;  
19.	    unsigned char *pucDest;  
20.	    unsigned char *pucSrc;  
21.	    unsigned long dwPixelBytes = ptPicData->iBpp/8;  
22.	    ptPicData->pucZoomData= malloc(sizeof(unsigned char) * ptPicData->iZoomWidth*ptPicData->iZoomHeight*ptPicData->iBpp/8);  
23.	    pdwSrcXTable = malloc(sizeof(unsigned long) * ptPicData->iZoomWidth);  
24.	    if (NULL == pdwSrcXTable){  
25.	        printf("malloc error!\n");  
26.	        return -1;  
27.	    }  
28.	  
29.	    /* 这几个for循环的本质是Sx = Dx * Sw/Dw,Sy = Dy * Sh/Dh*/  
30.	    for (x = 0; x < ptPicData->iZoomWidth; x++){//生成表 pdwSrcXTable  
31.	        /* 第一个for循环对应x方向的坐标 
32.	     * pdwSrcXTable[x] 对应Sx, 
33.	     * x 对应Dx, 
34.	     * ptPicData->iWidth 对应Sw 
35.	     * ptPicData->iZoomWidth 对应 Dw*/   
36.	        pdwSrcXTable[x]=(x*ptPicData->iWidth/ptPicData->iZoomWidth);  
37.	    }  
38.	  
39.	    for (y = 0; y < ptPicData->iZoomHeight; y++){  
40.	    /* 第2个循环对应y方向的坐标 
41.	     * dwSrcY 对应Sy, 
42.	     * y 对应Dy, 
43.	     * ptPicData->iHeight 对应Sh 
44.	     * ptPicData->iZoomHeight 对应 Dh*/      
45.	        dwSrcY = (y * ptPicData->iHeight / ptPicData->iZoomHeight);  
46.	    /* 根据这些可算得各像素点的RGB数据存放的地址 */  
47.	        pucDest = ptPicData->pucZoomData + y*ptPicData->iZoomWidth*3;  
48.	        pucSrc  = ptPicData->pucRgbData + dwSrcY*ptPicData->iWidth*3;  
49.	  
50.	    /* 最后拷贝数据 */          
51.	        for (x = 0; x <ptPicData->iZoomWidth; x++){  
52.	             memcpy(pucDest+x*dwPixelBytes, pucSrc+pdwSrcXTable[x]*dwPixelBytes, dwPixelBytes);  
53.	        }  
54.	    }  
55.	  
56.	    free(pdwSrcXTable);  
57.	    return 0;  
58.	}  

2.4.2 图像的旋转

2.4.2.1 图像旋转算法浅析

这里的图像旋转算法原理参考网友"落叶的思维"所著的"图像旋转算法与实现"

原理浅析

这个旋转算法的原理的关键点有两个:

  1. 原图像是以图像的左下角为原点建立笛卡尔坐标系的,而旋转一般是以图像的中心作为旋转点旋转的。

因此为了便于转换,我们先约定两个坐标系,一个是以图像左下角为原点建立的坐标系,称为坐标系A,这也是原图像的坐标系。一个是以图像中心为原点建立的坐标系,称为坐标系B。

由此,可以知道这个旋转算法的步骤:先将坐标系A下的坐标转换为坐标系B下的坐标,然后在坐标系B下进行图像的旋转。

在坐标系B下,我们假设点(x0,y0)距离原点的距离为r,点与原点之间的连线与x轴的夹角为b,旋转的角度为a,旋转后的点为(x1,y1), 如下图所示。

ImageProcess_Image005

那么有以下结论:

x0=rcosb;y0=rsinb

x1 = rcos(b-a) = rcosbcosa+rsinbsina=x0cosa+y0sina;

y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa;

最后,由于我们显示图像的RGB数据还是要在坐标系A下获取的,我们最后只需要将坐标系B下的x1,y1转换回坐标系A下的坐标就可以了。

旋转后的图像的长和宽会发生变化,因此要计算新图像的长和宽。

由几何关系可知,新图像的长和宽分别是旋转后,对角坐标相见后的最大值

2.4.2.2 源码编写:图像旋转算法
代码清单2.5
1.	 #define PI 3.1415926535  
2.	//角度到弧度转化  
3.	#define RADIAN(angle) ((angle)*PI/180.0)  
4.	  
5.	  
6.	  
7.	  
8.	  
9.	typedef struct ConcernCoor {  
10.	    int iLTx;// left top x  
11.	    int iLTy;//left top y  
12.	    int iLBx;//left bottom x  
13.	    int iLBy;//left bottom y  
14.	    int iRTx;//right top x  
15.	    int iRTy;//right top y  
16.	    int iRBx;// right bottom x  
17.	    int iRBy;// right bottom y  
18.	}T_ConcernCoor, *PT_ConcernCoor;  
19.	  
20.	  
21.	/********************************************************************** 
22.	 * 函数名称: max 
23.	 * 功能描述:比较两个参数,返回较大值 
24.	 * 输入参数:x,y均为int型 
25.	 * 输出参数: 无 
26.	 * 返 回 值: x,y中的较大值 
27.	 ***********************************************************************/  
28.	static int max(int x,int y){  
29.	    return x>y?x:y;  
30.	}  
31.	/********************************************************************** 
32.	 * 函数名称: PicRotate 
33.	 * 功能描述: 旋转图片 
34.	 *            注意该函数会分配内存来存放缩放后的图片,用完后要用free函数释放掉 
35.	 *              参考网友"落叶的思维"所著的"图像旋转算法与实现" 
36.	 * 输入参数: ptPicData - 内含图片的象素数据 
37.	 *            fAngle    - 旋转角度,0<=angle<=360 
38.	 * 输出参数: ptPicData->pucRotateData,内含旋转后的rgb数据 
39.	 * 返 回 值: 0 - 成功, 其他值 - 失败 
40.	 ***********************************************************************/  
41.	int PicRotate(PT_PictureData ptPicData,float fAngle)  
42.	{  
43.	    int i ,j;  
44.	    T_ConcernCoor tConCor,tRonCor;  
45.	    //原图像每一行去除偏移量的字节数  
46.	    //int iSrcLineSize = bitCount * srcW / 8;  
47.	    int iSrcLineSize = ptPicData->iBpp* ptPicData->iZoomWidth / 8;  
48.	    int iDesLineSize;  
49.	    int iX;//旋转后的x坐标  
50.	    int iY; //旋转后的y坐标  
51.	  
52.	       /* 将坐标系A下的坐标转换为坐标系B下的坐标, 
53.	        * 用于计算旋转后的图像的宽和高  
54.	        * tConCor用于存放坐标系B下旋转前的坐标 
55.	        * tRonCor用于存放坐标系B下旋转后的坐标*/  
56.	       tConCor.iLTx = -ptPicData->iZoomWidth/2; tConCor.iLTy = ptPicData->iZoomHeight/2;  
57.	    tConCor.iRTx = ptPicData->iZoomWidth/2; tConCor.iRTy = ptPicData->iZoomHeight/2;  
58.	    tConCor.iLBx = -ptPicData->iZoomWidth/2;tConCor.iLBy = -ptPicData->iZoomHeight/2;  
59.	    tConCor.iRBx = ptPicData->iZoomWidth/2;tConCor.iRBy = -ptPicData->iZoomHeight/2;  
60.	  
61.	  
62.	    /* 计算坐标系B下旋转后的坐标 */  
63.	    double sina = sin(RADIAN(fAngle));  
64.	    double cosa = cos(RADIAN(fAngle));  
65.	    tRonCor.iLTx =tConCor.iLTx * cosa + tConCor.iLTy * sina;  
66.	    tRonCor.iLTy = -tConCor.iLTx * sina + tConCor.iLTy * cosa;  
67.	    tRonCor.iRTx =tConCor.iRTx * cosa + tConCor.iRTy * sina;  
68.	    tRonCor.iRTy = -tConCor.iRTx * sina + tConCor.iRTy * cosa;  
69.	    tRonCor.iLBx = tConCor.iLBx * cosa + tConCor.iLBy * sina;  
70.	    tRonCor.iLBy = -tConCor.iLBx * sina + tConCor.iLBy * cosa;  
71.	    tRonCor.iRBx = tConCor.iRBx * cosa + tConCor.iRBy * sina;  
72.	    tRonCor.iRBy = -tConCor.iRBx * sina + tConCor.iRBy * cosa;  
73.	  
74.	      
75.	    /* 计算旋转后图像宽和高 */  
76.	    ptPicData->iRotateWidth = max(abs(tRonCor.iRBx - tRonCor.iLTx),abs(tRonCor.iRTx - tRonCor.iLBx));  
77.	    ptPicData->iRotateHeight = max(abs(tRonCor.iRBy - tRonCor.iLTy),abs(tRonCor.iRTy - tRonCor.iLBy));  
78.	  
79.	    /* 像素信息要保证3字节对齐,否则数据有可能出错*/  
80.	    iDesLineSize = ((ptPicData->iRotateWidth* ptPicData->iBpp+ 23) / 24) * 3 ;  
81.	    /* 分配旋转后的空间,注意这里要用旋转后的宽和高 */  
82.	    ptPicData->pucRotateData = malloc(iDesLineSize * ptPicData->iRotateHeight);  
83.	    if(NULL == ptPicData->pucRotateData){  
84.	        printf("malloc error\n");  
85.	        return -1;  
86.	    }  
87.	  
88.	    /* 通过新图像的坐标,计算对应的原图像的坐标* 
89.	      * i,j坐标就是对应的坐标系B下的x1,y1*/  
90.	    for (i = 0; i < ptPicData->iRotateHeight; i++){          
91.	        for (j = 0; j < ptPicData->iRotateWidth; j++){  
92.	            /* 坐标系B下的x,y1坐标,经过逆运算转换得到iX,iY,这两个值对应x0,y0 */  
93.	            iX = (j - ptPicData->iRotateWidth / 2)*cos(RADIAN(360 - fAngle)) + (-i + ptPicData->iRotateHeight / 2)*sin(RADIAN(360 - fAngle));  
94.	            iY = -(j - ptPicData->iRotateWidth / 2)*sin(RADIAN(360 - fAngle)) + (-i + ptPicData->iRotateHeight / 2)*cos(RADIAN(360 - fAngle));  
95.	            /*如果这个坐标不在原图像内,则不赋值*/  
96.	            if (iX > ptPicData->iZoomWidth / 2 || iX < -ptPicData->iZoomWidth / 2 || iY > ptPicData->iZoomHeight / 2 || iY < -ptPicData->iZoomHeight / 2){  
97.	                continue;  
98.	            }  
99.	            /* 再将坐标系B下的x0,y0坐标,转换为坐标系A下的坐标 */  
100.	            int iXN = iX + ptPicData->iZoomWidth / 2;   
101.	         int iYN = abs(iY - ptPicData->iZoomHeight  / 2);  
102.	            /* 值拷贝*/  
103.	            memcpy(&ptPicData->pucRotateData[i * iDesLineSize + j * 3],&ptPicData->pucZoomData[iYN * iSrcLineSize + iXN * 3],3);    
104.	        }  
105.	    }  
106.	  return 0;  
107.	}  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/929663.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式驱动开发详解5(ioctl的使用)

文章目录 ioctl介绍应用层详解驱动层详解ioctl的cmd实验例程 ioctl介绍 linux内核给用户提供了两类系统调用函数&#xff1a;一类是数据操作函数&#xff0c;比如read、write…。 另外一类函数是非数据操作函数&#xff0c;比如ioctl…&#xff0c;用户程序可以用ioctl给底层设…

从零开始使用GOT-OCR2.0——多模态OCR项目:微调数据集构建 + 训练(解决训练报错,成功实验微调训练)

在上一篇文章记录了GOT-OCR项目的环境配置和基于官方模型参数的基础使用。环境安装的博文快速链接&#xff1a; 从零开始使用GOT-OCR2.0——多模态通用型OCR&#xff08;非常具有潜力的开源OCR项目&#xff09;&#xff1a;项目环境安装配置 测试使用-CSDN博客 本章在环境配置…

Facebook:筑牢隐私安全堡垒,守护社交净土

在全球社交媒体平台中&#xff0c;Facebook一直是风靡全球的佼佼者。然而&#xff0c;随着数字化信息的迅速膨胀&#xff0c;用户隐私保护的重要性日益凸显。面对用户对数据安全性的高度重视&#xff0c;Facebook致力于通过一系列措施来确保隐私保护&#xff0c;守护每位用户的…

VBA信息获取与处理第四个专题第二节:将工作表数据写入VBA数组

《VBA信息获取与处理》教程(版权10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互…

python通过ODBC连接神通数据库

1、安装神通数据库 2、安装python 3、安装pyodbc pip3 install pyodbc-5.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 注&#xff1a;pyodbc要和python版本相对应 4、安装unixodbc 5、配置神通数据库ODBC数据源 6、示例代码如下 #!/usr/bin/python…

Vue Web开发(一)

1. 环境配置 1.1. 开发工具下载 1.1.1. HbuilderX 官网地址&#xff1a;https://uniapp.dcloud.net.cn/ 1.1.2. Visual Studio Code 官网地址&#xff1a;https://code.visualstudio.com/Download 1.1.3. Node环境 官网地址&#xff1a;https://nodejs.cn/   正常软件安装…

Tomcat新手成长之路:安装部署优化全解析(下)

接上篇《Tomcat新手成长之路&#xff1a;安装部署优化全解析&#xff08;上&#xff09;》: link 文章目录 7.应用部署7.1.上下文7.2.启动时进行部署7.3.动态应用部署 8.Tomcat 类加载机制8.1.简介8.2.类加载器定义8.3.XML解析器和 Java 9.JMS监控9.1.简介9.2.启用 JMX 远程监…

模拟实现vector(非常详细)

模拟实现vector 1.vector基本概念2.vector()默认构造函数3.size()成员函数迭代器4.capacity()成员函数5.empty()成员函数6.reverse()成员函数7.push_back()成员函数8.pop_back()成员函数9.operator[ ]成员函数10.resize()成员函数11.insert()成员函数12.erase()成员函数13.swap…

Elastic Cloud Serverless:深入探讨大规模自动扩展和性能压力测试

作者&#xff1a;来自 Elastic David Brimley, Jason Bryan, Gareth Ellis 及 Stewart Miles 深入了解 Elasticsearch Cloud Serverless 如何动态扩展以处理海量数据和复杂查询。我们探索其在实际条件下的性能&#xff0c;深入了解其可靠性、效率和可扩展性。 简介 Elastic Cl…

微信小程序之手机归属地查询

微信小程序之手机归属地查询 需求描述 API申请和小程序设置 API申请 第一步&#xff1a;完整账号注册 我们需要来到如下网站&#xff0c;注册账号&#xff1a;万维易源 第二步&#xff1a;账号注册完成以后&#xff0c;点击右上角的控制台信息。 第三步&#xff1a;在控制…

Agent AI: Surveying the Horizons of Multimodal Interaction---摘要、引言、代理 AI 集成

题目 智能体AI:多模态交互视野的考察 论文地址&#xff1a;https://arxiv.org/abs/2401.03568 图1&#xff1a;可以在不同领域和应用程序中感知和行动的Agent AI系统概述。Agent AI是正在成为通用人工智能&#xff08;AGI&#xff09;的一个有前途的途径。Agent AI培训已经证…

分布式光伏电站如何实现监控及集中运维管理?

安科瑞戴婷 Acrel-Fanny 前言 今年以来&#xff0c;在政策利好推动下光伏、风力发电、电化学储能及抽水蓄能等新能源行业发展迅速&#xff0c;装机容量均大幅度增长&#xff0c;新能源发电已经成为新型电力系统重要的组成部分&#xff0c;同时这也导致新型电力系统比传统的电…

SpringMVC其他扩展

一、全局异常处理机制: 1.异常处理两种方式: 开发过程中是不可避免地会出现各种异常情况的&#xff0c;例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题&#xff0c;甚至直接导致程序崩溃。因此&#xff0c;在开发过程中&#xff0c;…

Cesium 6 ,Cesium 全局注册,Cesium 常用事件解析与应用,全局注册Cesium事件

目录 前言 一. 全局注册事件 1.1 事件机制介绍 1.2 this.Cesium 和 this.viewer 1.3 全局注册 二. 常见事件分类 2.1 鼠标事件 2.1.1 点击事件 (click) 2.1.2 双击事件 (doubleClick) 2.1.3 鼠标移动事件 (mouseMove) 2.1.4 鼠标滚轮事件 (mouseWheel) 2.2 视图与摄…

matlab2024a安装

1.开始安装 2.点击安装 3.选择安装密钥 4.接受条款 5.安装密钥 21471-07182-41807-00726-32378-34241-61866-60308-44209-03650-51035-48216-24734-36781-57695-35731-64525-44540-57877-31100-06573-50736-60034-42697-39512-63953 6 7.选择许可证文件 8.找许可证文件 9.选…

在玩“吃鸡”的时候游戏崩溃要如何解决?游戏运行时崩溃是什么原因?

“吃鸡”游戏崩溃问题深度解析与解决方案&#xff1a;原因、修复与预防 在紧张刺激的“吃鸡”&#xff08;即《绝地求生》&#xff09;游戏中&#xff0c;突然遭遇游戏崩溃无疑会让玩家倍感沮丧。作为一名经验丰富的软件开发从业者&#xff0c;我深知游戏崩溃可能由多种因素引…

学习threejs,通过设置纹理属性来修改纹理贴图的位置和大小

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 贴图 二、&#x1…

【开源安全保护】如何安装JumpServer堡垒机

【开源安全保护】如何安装JumpServer堡垒机 什么是堡垒机 大家好&#xff0c;我是星哥&#xff0c;今天我以前来认识堡垒机 堡垒机&#xff08;Bastion Host&#xff09;&#xff0c;也称为跳板机&#xff08;Jump Server&#xff09;&#xff0c;是指在计算机网络中&#x…

JSP知识点总结

jsp九大对象 在jsp中内置了9个对象&#xff0c;无需创建该对象即可使用。其名称为固定名称。 1.out输出对象 - 属于JspWriter print(): 输出 flush(): 刷新 close(): 关闭 2.request请求对象 - 属于HttpServletRequest getParameter(): 获取请求的参数 setCharacterEncodin…

微信小程序全屏显示地图

微信小程序在界面上显示地图&#xff0c;只需要用map标签 <map longitude"经度度数" latitude"纬度度数"></map>例如北京的经纬度为&#xff1a;116.407004,39.904595 <map class"bgMap" longitude"116.407004" lati…