C++模拟OpenGL库——图片处理及纹理系统(三):图片缩放操作:简单插值二次线性插值

news2024/10/6 12:31:05

目录

简单插值

二次线性插值


简单插值

如图,我们想把一张小图缩放成一张大图,自然的想法就是按照它们的长宽比例进行缩放(zoomX)。

但是问题也显而易见,在缩放的过程中,小图的像素并不能一一映射到大图的每一个像素中,会导致失真,也就是说大图中的像素与像素之间并不是原图像素的连续。

开始动手,我们在Image.h中添加方法:

 实现如下:

通过简单的设置缩放比例来实现对像素的操作

	Image* Image::zoomImage(const Image* _image, float _zoomX, float _zoomY)
	{
		int _width = _image->getWidth() * _zoomX;
		int _height = _image->getHeight() * _zoomY;
		byte* _data = new byte[_width * _height * sizeof(RGBA)];
		Image* _resultImage = nullptr;

		for (int i = 0; i < _width; ++i) {
			for (int j = 0; j < _height; ++j) {
				int _imageX = (float)i / _zoomX;
				int _imageY = (float)j / _zoomY;

				_imageX = _imageX < _image->getWidth() ? _imageX : (_image->getWidth() - 1);
				_imageY = _imageY < _image->getHeight() ? _imageY : (_image->getHeight() - 1);
				
				RGBA _color = _image->getColor(_imageX, _imageY);
				memcpy(_data + (j * _width + i) * sizeof(RGBA), &_color, sizeof(RGBA));
			}
		}
		_resultImage = new Image(_width, _height, _data);
		
		delete[]_data;
		return _resultImage;
	}

我们把它放大三倍 

效果如下,非常粗糙。 

5倍:

 

二次线性插值

刚才简单插值的效果我们也看到了,非常的糊。

原因在于我们直接进行了整数上的乘除操作,也就意味着要截断浮点数的值。

那如果我们要考虑这些浮点数具体是多少呢?

先上图

总体的原理就是:我们考虑一个点的颜色值时,需要考虑周围四个像素的颜色值,进行一个判断来决定最后的颜色值。

在图中,我们可以根据分割出来的区域来确定周围四个像素对其目标点的贡献权重值。

对于(x1,y1)对其目标点的贡献为:disX2 * disY2;

对于(x2,y1)对其目标点的贡献为:disX1 * disY2;

对于(x1,y2)对其目标点的贡献为:disX2 * disY1;

对于(x2,y2)对其目标点的贡献为:disX1 * disY1;

其实可以看出规律,就是想对应的面积区域所占整体面积(为1)的比值,因为是负相关的。

同样的,在Image中实现:

	Image* Image::zoomImageBilinear(const Image* _image, float _zoomX, float _zoomY)
	{
		int _width = _image->getWidth() * _zoomX;
		int _height = _image->getHeight() * _zoomY;
		byte* _data = new byte[_width * _height * sizeof(RGBA)];
		Image* _resultImage = nullptr;

		float coordX = 0.0, coordY = 0.0;
		int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
		float disX1 = 0.0, disY1 = 0.0, disX2 = 0.0, disY2 = 0.0;

		for (int i = 0; i < _width; ++i) {
			//disX1 disX2的计算
			coordX = i / _zoomX;
			x1 = (int)coordX;
			if (x1 >= _image->getWidth() - 1) {
				x1 = _image->getWidth() - 1;
				x2 = x1;
			}
			else {
				x2 = x1 + 1;
			}
			disX1 = coordX - x1;
			disX2 = 1.0 - disX1;

			for (int j = 0; j < _height; ++j) {
				//disY1 disY2的计算
				coordY = j / _zoomY;
				y1 = (int)coordY;
				if (y1 >= _image->getHeight() - 1) {
					y1 = _image->getHeight() - 1;
					y2 = y1;
				}
				else {
					y2 = y1 + 1;
				}
				disY1 = coordY - y1;
				disY2 = 1.0 - disY1;

				//取周围四个像素的颜色值
				RGBA _color11 = _image->getColor(x1, y1);
				RGBA _color21 = _image->getColor(x1, y2);
				RGBA _color12 = _image->getColor(x2, y1);
				RGBA _color22 = _image->getColor(x2, y2);

				RGBA _targetColor;
				_targetColor.m_r =
					(float)_color11.m_r * disX2 * disY2 +
					(float)_color12.m_r * disX2 * disY1 +
					(float)_color21.m_r * disX1 * disY2 +
					(float)_color22.m_r * disX1 * disX2;
				_targetColor.m_g =
					(float)_color11.m_g * disX2 * disY2 +
					(float)_color12.m_g * disX2 * disY1 +
					(float)_color21.m_g * disX1 * disY2 +
					(float)_color22.m_g * disX1 * disX2;
				_targetColor.m_b =
					(float)_color11.m_b * disX2 * disY2 +
					(float)_color12.m_b * disX2 * disY1 +
					(float)_color21.m_b * disX1 * disY2 +
					(float)_color22.m_b * disX1 * disX2;
				_targetColor.m_a =
					(float)_color11.m_a * disX2 * disY2 +
					(float)_color12.m_a * disX2 * disY1 +
					(float)_color21.m_a * disX1 * disY2 +
					(float)_color22.m_a * disX1 * disX2;

				memcpy(_data + (j * _width + i) * sizeof(RGBA), &_targetColor, sizeof(RGBA));
			}
		}

		_resultImage = new Image(_width, _height, _data);

		delete[]_data;
		return _resultImage;
	}

我们来对比一下两种方法:

 

下面是简单插值,上面是二次线性插值,明显二次线性插值会更清晰一些,这里由于图片颜色比较特殊,所以看起来有些瑕疵,但原理大致是正确的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蜂巢能源冲刺科创板上市:拟募资150亿元,上半年收入37亿元

11月18日&#xff0c;蜂巢能源科技股份有限公司&#xff08;下称“蜂巢能源”&#xff09;在上海证券交易所递交招股书&#xff0c;准备在科创板上市。本次冲刺科创板上市&#xff0c;蜂巢能源计划募资150亿元&#xff0c;主要用于动力锂离子电池项目、研发中心建设项目等。 据…

Unity游戏Mod/插件制作教程02 - 开发环境准备

前言 虽然本教程的目标读者是有C#基础的玩家&#xff0c;但是作为流程&#xff0c;基础的开发软件部分我还是要记录一下。 安装VisualStudio VisualStudio是我们开发插件最重要的工具&#xff0c;也许你习惯其他开发.net的工具&#xff0c;但是免费的VisualStudio已经足够好用…

王道OS 1.1_1 操作系统的概念、功能和目标

王道OS 1.1_1 操作系统的概念、功能和目标 chap1 计算机系统概述 参考资料 B站王道考研操作系统概念 第9版 &#xff08;原书、译本&#xff09; 好久没有写博客总结整理和输出了&#xff0c;学习的惰性在一次次的考试周从零开始的经历中达到了巅峰&#xff0c;现在想重振旗鼓…

换工作有感

最近很长一段时间没有更新博客&#xff0c;更新关于vim相关的操作&#xff0c;主要是最近在忙于换工作的事情。其实本来我也没打算换工作的&#xff0c;主要是最近公司的一些骚操作让我觉得心里很不爽&#xff0c;所以一怒之下提出离职。 背景 先来说说这个事情的背景吧&#…

2022年 SecXOps 安全智能分析技术白皮书 附下载地址

近年来&#xff0c;互联网、大数据和人工智能 等技术都得到了飞速的发展&#xff0c;网络攻击的方法也越来越复杂&#xff0c;过去广泛、漫无目的的攻击威胁&#xff0c;在数年内迅速地转化为有目标、有组织、长期 潜伏的多阶段组合式高级可持续威胁&#xff08;Advanced Persi…

计算机网络——第五章网络层笔记(5)

网络地址翻译&#xff08;NAT&#xff09; Private IP address:不可路由的地址、也可用于广域网链路上 NAT&#xff1a;net address translate 私有IP地址和公有IP地址之间的转换。 PAT&#xff1a;port address translate 将多个私有IP地址影射到同一个公有IP地址的不同…

跑步时戴什么耳机好、分享五款最适合跑步的运动耳机排名清单

在进行户外跑步、骑行等运动&#xff0c;往往会感到枯燥乏味&#xff0c;很难坚持下去&#xff0c;就像我经常跑一圈就觉得没了动力&#xff0c;但是当我戴上耳机听音乐跑步时&#xff0c;不知不觉就结束了&#xff0c;就感觉时间过得很快。不过话有说回来&#xff0c;适合跑步…

【JVM】jvm的体系结构

JVM体系结构如下图所示&#xff1a; JVM大致可以分为五大模块&#xff1a; 类加载子系统&#xff08;Class Loader SubSystem&#xff09;运行时数据区&#xff08;Runtime Data Area&#xff09;执行引擎&#xff08;Execution Engine&#xff09;Java本地接口&#xff08;Ja…

Java native关键字 实现

需要用到gcc mingw64: 下载安装MinGW-w64详细步骤&#xff08;c/c的编译器gcc的windows版&#xff0c;win10真实可用&#xff09;_jjxcsdn的博客-CSDN博客_mingw-w64 我也是根据上面地址安装的 在d盘创建一个.java文件 编写内容 testInt方法用 native关键字修饰 静态块里需要…

Tauri 打包

1、第一次打包运行命令 npm run tauri build 2、可能会出现下面问题 我们需要在tauri.conf.json里面查找identifier这个名称 原来是com.tauri.dev 随便改下名字&#xff0c;我这里改成build了 3、修改配置后&#xff0c;继续打包又出现问题&#xff0c;如下图 我们就单独去下…

Google Earth Engine(GEE)——join连接在GEE中的应用(同一sentinel-2影像集合)含滑动窗口平滑影像过程

JOIN联接允许您根据一个或多个条件组合不同的集合。 ImageCollection 到 ImageCollection 在数据融合中很有用(从不同的数据集中找到匹配的图像) FeatureCollection 到 ImageCollection 用于数据提取(在多个位置提取图像) FeatureCollection 到 FeatureCollection 在地理处…

公式编辑器Axmath+公式识别器SimpleTex+Markdown编辑器Typora

Ⅰ.公式编辑器Axmath 下载方式&#xff1a; ①百度网盘&#xff1a;https://pan.baidu.com/share/init?surlUWHIHWJHm-mC5q5LUCyEuA 提取码&#xff1a;1r2a ②城通网盘&#xff1a;https://url86.ctfile.com/f/32005086-727935308-6024d8?p5422 访问码&#xff1a;5422 软件…

Cellular/Wifi/Bluetooth频率

Cellular NR频率 3GPP R17定义的NR FR1频段如下表&#xff1a; 图片来自于38.101国内常用FDD频段&#xff1a; n1: 2100MHz~2170MHz&#xff0c;共79MHz带宽 n3: 1805MHz~1880MHz&#xff0c;共75MHz带宽 n5: 869MHz~894MHz&#xff0c;共25MHz带宽 n8: 925MHz~960MHz&…

【Redis-03】Redis数据库的实现原理

在之前的文章我们介绍过&#xff0c;Redis服务器在启动之初&#xff0c;会初始化RedisServer的实例&#xff0c;在这个实例中存在很多重要的属性结构&#xff0c;同理本篇博客中介绍的数据库实现原理也会和其中的某些属性相关&#xff0c;我们继续看一下吧。 1.服务器和客户端…

基于改进萤火虫算法的图像分割的应用(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

可执行文件的装载与进程

进程虚拟地址空间 每个程序被运行起来以后&#xff0c;它将拥有自己独立虚拟空间地址&#xff0c;这个虚拟地址空间的大学由计算机的硬件平台决定&#xff0c;具体地说是由CPU的位数决定。硬件决定了地址空间的最大理论上限&#xff0c;即硬件的寻址空间大小&#xff0c;比如32…

欢迎使用Markdown编辑器

欢迎使用Markdown编辑器欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个…

HTML的常用结构标签(详细)

1.文本标题 &#x1f340; <h1> </h1>~~~<h6> </h6>,从h1到h6字体由大到小 2.段落 &#x1f340; <p> </p> 3.加粗 &#x1f340; <b> </b> 和 <strong> </strong> 4.倾斜 &#x1f340; <i></i&…

[MQ] SpringBoot使用扇型(广播)交换机/主题交换机

✨✨个人主页:沫洺的主页 &#x1f4da;&#x1f4da;系列专栏: &#x1f4d6; JavaWeb专栏&#x1f4d6; JavaSE专栏 &#x1f4d6; Java基础专栏&#x1f4d6;vue3专栏 &#x1f4d6;MyBatis专栏&#x1f4d6;Spring专栏&#x1f4d6;SpringMVC专栏&#x1f4d6;SpringBoot专…

刷式过滤器 不锈钢全自动刷式过滤器

原理概述 当水从进水口进入过滤器滤筒内部&#xff0c;杂质被拦截在过滤筒内壁&#xff0c;过滤后的干净水从出水口流出&#xff0c;当滤筒内壁的杂质越积越多时&#xff0c;自清洗过滤器进出口的压差达到预设值、达到清洗时间或手动预制时&#xff0c;过滤器将开始自清洗过程…