无损失放大低分辨率图片
时间:2022-07-23
本文章向大家介绍无损失放大低分辨率图片,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
无损失放大低分辨率图片
概述
有时候,从网上下载或者截图的图片的分辨率和大小有时并不能符合需求,这时就需要对图片进行一定的缩放处理。有没有什么办法能实现对低分辨率图片的放大呢?带着这个问题,查阅了部分资料并试验了一部分网站和平台,最终实现了简单的图片无损缩放,有技术实现(C++工程实现)也有软件实现。
1.软件实现
软件或者平台有很多,这里推荐几个。(效果图在最后)
1.
http://waifu2x.udp.jp/
2.
https://bigjpg.com/
3.
BenVista PhotoZoom软件(公众号后台回复BenVista获取)
2.工程实现
图片一般分为两类:栅格图和矢量图,在此处不研究矢量图。所谓栅格图,也就是一个个像素点堆积而成的一个图片,当把一个图片放大到一定程度时就可看到一个个像素点。
本部分采用网上的图像插值技术对图像进行缩放。插值缩放的原理是基于目标分辨率中的点,将其按照缩放关系对应到源图像中,寻找源图像中的点(不一定是整像素点),然后通过源图像中的相关点插值得到目标点。本篇文章,我们介绍Nearest-neighbor和Bilinear插值的原理及C++实现。
本文的代码运行环境是:Win10的VS2013
一共三个文件:main.cpp resize.cpp resize.h
//main.cpp
#pragma warning( disable : 4996)
#include <string.h>
#include <iostream>
#include "resize.h"
int main()
{
const char *input_file = "C:\Users\Jingjie\Desktop\t.jpg"; //absolute path
const char *output_file = "C:\Users\Jingjie\Desktop\t1.jpg"; //absolute path
int src_width = 550;
int src_height = 550;
int dst_width = 1080;
int dst_height = 1080;
int resize_type = 0; //0:nearest, 1:bilinear
resize(input_file, src_width, src_height, output_file, dst_width, dst_height, resize_type);
return 0;
}
//resize.cpp
#pragma warning( disable : 4996)
#include "resize.h"
int clip3(int data, int min, int max)
{
return (data > max) ? max : ((data < min) ? min : data);
if (data > max)
return max;
else if (data > min)
return data;
else
return min;
}
//bilinear takes 4 pixels (2×2) into account
/*
* 函数名:bilinearHorScaler
* 说明:水平方向双线性插值
* 参数:
*/
void bilinearHorScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height)
{
double resizeX = (double)dst_width / src_width;
for (int ver = 0; ver < dst_height; ++ver){
for (int hor = 0; hor < dst_width; ++hor){
double srcCoorX = hor / resizeX;
double weight1 = srcCoorX - (double)((int)srcCoorX);
double weight2 = (double)((int)(srcCoorX + 1)) - srcCoorX;
double dstValue = *(src_image + src_width * ver + clip3((int)srcCoorX, 0, src_width - 1)) * weight2 + *(src_image + src_width * ver + clip3((int)(srcCoorX + 1), 0, src_width - 1)) * weight1;
*(dst_image + dst_width * ver + hor) = clip3((uint8)dstValue, 0, 255);
}
}
}
/*
* 函数名:bilinearVerScaler
* 说明:垂直方向双线性插值
* 参数:
*/
void bilinearVerScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height)
{
double resizeY = (double)dst_height / src_height;
for (int ver = 0; ver < dst_height; ++ver){
for (int hor = 0; hor < dst_width; ++hor){
double srcCoorY = ver / resizeY;
double weight1 = srcCoorY - (double)((int)srcCoorY);
double weight2 = (double)((int)(srcCoorY + 1)) - srcCoorY;
double dstValue = *(src_image + src_width * clip3((int)srcCoorY, 0, src_height - 1) + hor) * weight2 + *(src_image + src_width * clip3((int)(srcCoorY + 1), 0, src_height - 1) + hor) * weight1;
*(dst_image + dst_width * ver + hor) = clip3((uint8)dstValue, 0, 255);
}
}
}
/*
* 函数名:yuv420p_NearestScaler
* 说明:最近邻插值
* 参数:
*/
void nearestScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height)
{
double resizeX = (double)dst_width / src_width; //水平缩放系数
double resizeY = (double)dst_height / src_height; //垂直缩放系数
int srcX = 0;
int srcY = 0;
for (int ver = 0; ver < dst_height; ++ver) {
for (int hor = 0; hor < dst_width; ++hor) {
srcX = clip3(int(hor / resizeX + 0.5), 0, src_width - 1);
srcY = clip3(int(ver / resizeY + 0.5), 0, src_height - 1);
*(dst_image + dst_width * ver + hor) = *(src_image + src_width * srcY + srcX);
}
}
}
void resize(const char *input_file, int src_width, int src_height, const char *output_file, int dst_width, int dst_height, int resize_type)
{
//define and init src buffer
int *src_y = new int[src_width * src_height];
int *src_cb = new int[src_width * src_height / 4];
int *src_cr = new int[src_width * src_height / 4];
memset(src_y, 0, sizeof(int) * src_width * src_height);
memset(src_cb, 0, sizeof(int) * src_width * src_height / 4);
memset(src_cr, 0, sizeof(int) * src_width * src_height / 4);
//define and init dst buffer
int *dst_y = new int[dst_width * dst_height];
int *dst_cb = new int[dst_width * dst_height / 4];
int *dst_cr = new int[dst_width * dst_height / 4];
memset(dst_y, 0, sizeof(int) * dst_width * dst_height);
memset(dst_cb, 0, sizeof(int) * dst_width * dst_height / 4);
memset(dst_cr, 0, sizeof(int) * dst_width * dst_height / 4);
//define and init mid buffer
int *mid_y = new int[dst_width * src_height];
int *mid_cb = new int[dst_width * src_height / 4];
int *mid_cr = new int[dst_width * src_height / 4];
memset(mid_y, 0, sizeof(int) * dst_width * src_height);
memset(mid_cb, 0, sizeof(int) * dst_width * src_height / 4);
memset(mid_cr, 0, sizeof(int) * dst_width * src_height / 4);
uint8 *data_in_8bit = new uint8[src_width * src_height * 3 / 2];
memset(data_in_8bit, 0, sizeof(uint8) * src_width * src_height * 3 / 2);
uint8 *data_out_8bit = new uint8[dst_width * dst_height * 3 / 2];
memset(data_out_8bit, 0, sizeof(uint8) * dst_width * dst_height * 3 / 2);
FILE *fp_in = fopen(input_file, "rb");
if (NULL == fp_in)
{
//exit(0);
printf("open file failure");
}
FILE *fp_out = fopen(output_file, "wb+");
//data read
fread(data_in_8bit, sizeof(uint8), src_width * src_height * 3 / 2, fp_in);
//Y component
for (int ver = 0; ver < src_height; ver++)
{
for (int hor = 0; hor < src_width; hor++)
{
src_y[ver * src_width + hor] = data_in_8bit[ver * src_width + hor];
}
}
//c component YUV420P
for (int ver = 0; ver < src_height / 2; ver++)
{
for (int hor = 0; hor < src_width / 2; hor++)
{
src_cb[ver * (src_width / 2) + hor] = data_in_8bit[src_height * src_width + ver * src_width / 2 + hor];
src_cr[ver * (src_width / 2) + hor] = data_in_8bit[src_height * src_width + src_height * src_width / 4 + ver * src_width / 2 + hor];
}
}
//resize
if (0 == resize_type)
{
nearestScaler(src_y, dst_y, src_width, src_height, dst_width, dst_height);
nearestScaler(src_cb, dst_cb, src_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
nearestScaler(src_cr, dst_cr, src_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
}
else if (1 == resize_type)
{
bilinearHorScaler(src_y, mid_y, src_width, src_height, dst_width, src_height);
bilinearHorScaler(src_cb, mid_cb, src_width / 2, src_height / 2, dst_width / 2, src_height / 2);
bilinearHorScaler(src_cr, mid_cr, src_width / 2, src_height / 2, dst_width / 2, src_height / 2);
bilinearVerScaler(mid_y, dst_y, dst_width, src_height, dst_width, dst_height);
bilinearVerScaler(mid_cb, dst_cb, dst_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
bilinearVerScaler(mid_cr, dst_cr, dst_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
}
else
{
nearestScaler(src_y, dst_y, src_width, src_height, dst_width, dst_height);
nearestScaler(src_cb, dst_cb, src_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
nearestScaler(src_cr, dst_cr, src_width / 2, src_height / 2, dst_width / 2, dst_height / 2);
}
//data write
for (int ver = 0; ver < dst_height; ver++)
{
for (int hor = 0; hor < dst_width; hor++)
{
data_out_8bit[ver * dst_width + hor] = clip3(dst_y[ver * dst_width + hor], 0, 255);
}
}
for (int ver = 0; ver < dst_height / 2; ver++)
{
for (int hor = 0; hor < dst_width / 2; hor++)
{
data_out_8bit[dst_height * dst_width + ver * dst_width / 2 + hor] = clip3(dst_cb[ver * (dst_width / 2) + hor], 0, 255);
data_out_8bit[dst_height * dst_width + dst_height * dst_width / 4 + ver * dst_width / 2 + hor] = clip3(dst_cr[ver * (dst_width / 2) + hor], 0, 255);
}
}
fwrite(data_out_8bit, sizeof(uint8), dst_width * dst_height * 3 / 2, fp_out);
delete[] src_y;
delete[] src_cb;
delete[] src_cr;
delete[] dst_y;
delete[] dst_cb;
delete[] dst_cr;
delete[] mid_y;
delete[] mid_cb;
delete[] mid_cr;
delete[] data_in_8bit;
delete[] data_out_8bit;
fclose(fp_in);
fclose(fp_out);
}
//resize.h
#ifndef RESIZE_H
#define RESIZE_H
#include <stdio.h>
#include <string.h>
typedef unsigned char uint8;
typedef unsigned short uint16;
int clip3(int data, int min, int max);
void bilinearHorScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height);
void bilinearVerScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height);
void nearestScaler(int *src_image, int *dst_image, int src_width, int src_height, int dst_width, int dst_height);
void resize(const char *input_file, int src_width, int src_height, const char *output_file, int dst_width, int dst_height, int resize_type);
#endif
3.部分效果图
- 【线程池】线程池与工作队列
- 一个快速方便的图形化 Python 调试器 —— birdseye | Github 项目推荐
- 关于分区表的在线重定义(r5笔记第98天)
- 10个实用的但偏执的Java编程技术
- 看似诡异的tablespace online问题(r5笔记第95天)
- python2.7进行爬虫POI代码(划分小网格算法)
- 从 Encoder 到 Decoder 实现 Seq2Seq 模型
- python2.7进行爬虫百度POI代码(划分小网格算法)
- 如何通过TTL调试光猫
- 基于树莓派和Tensowflow的物体识别-brain
- SNA中:中心度及中心势诠释(不完整代码)
- 教程 | 基于计算机视觉使用Python和OpenCV计算道路交通
- 干货 | MVP模式在携程酒店的应用和扩展
- memlock过低导致的数据库性能问题(r6笔记第10天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Laravel 前端资源配置教程
- laravel框架语言包拓展实现方法分析
- PHP使用JpGraph绘制折线图操作示例【附源码下载】
- Laravel Eloquent分表方法并使用模型关联的实现
- 关于laravel模板中生成URL的几种模式总结
- Laravel基础-关于引入公共文件的两种方式
- Laravel框架Blade模板简介及模板继承用法分析
- 基于Laravel 多个中间件的执行顺序详解
- 关于laravel 日志写入失败问题汇总
- 确保Laravel网站不会被嵌入到其他站点中的方法
- PHP PDO和消息队列的个人理解与应用实例分析
- tp5 sum某个字段相加得到总数的例子
- laravel框架创建授权策略实例分析
- tp5递归 无限级分类详解
- PHP 进程池与轮询调度算法实现多任务的示例代码