无损失放大低分辨率图片

时间: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.部分效果图