图像的放大:双线性插值算法(C++实现)

图像的放大本质上就是增加像素点,目前常用的传统方法是内插法,代表算法有最临近点插值算法、双线性插值算法和双三次插值法,这些算法都是基于相邻像素点的像素值计算所要增加的像素点的像素值,因而在放大时会有失真的现象存在。在深度学习领域,图像的方法也称为超分辨率,一般采用Gan网络对抗生成高分辨率图片,尽管在一些数据集中取得不错的表现,但是算法的鲁棒性还有待加强。因此,了解传统的内插法还是有很大必要的。

最临近点插值算法

这是最简单的一种插值方法,在所求象素的相邻(上下左右)象素中,将距离待求象素最近的邻象素灰度赋给待求象素。设i+u, j+v(i, j为正整数, u, v为大于零小于1的小数,下同)为待求象素坐标,则待求象素灰度的值为f(n(i+u),n( j+v)) ,其中n为最近的一个像素。
在这里插入图片描述
优点:简单、计算量小。
缺点:效果不好,图像放大后失真现象严重。

双线性插值算法

双线性内插法是利用待求像素四个相邻像素的灰度,按照其距内插点的距离赋予不同的权重,进行线性内插,如下图所示:

在这里插入图片描述

从图中看出,f(x,y)为所求的像素值,其相邻点为图中红点所示分别为f(i,j),f(i+1,j),f(i,j+1),f(i+1,j+1),其像素值如图中绿色线条所示,长度代表值的大小。通过f(x,y)与4点的距离比例,再分别乘以4点的像素值,可以得到所求像素点的值,如图中蓝色线条所示。
优点:图像连续性较好,是目前最常用的内插法。
缺点:放大时图像较为模糊,细节损失较严重。
代码如下:
"bmp.h"的头文件代码: bmp图片的类以及读写函数 bmp.h

#include <iostream>
#include <string.h>   
#include <math.h>       
#include <stdlib.h>     
#include <malloc.h>  
#include <cstdio> 
#include "bmp.h"
using namespace std;
#define DRAW_HEIGHT 512  //目标图像高度  
#define DRAW_WIDTH 512  //目标图像宽度  

int main()
{ 
    BMP rbmp;
    BMP wbmp(DRAW_WIDTH,DRAW_HEIGHT);
	char strFile[50] = "./lena24.bmp";//打开图像路径,BMP图像必须为24位真彩色格式  
	char strFilesave[50] = "./test.bmp";//处理后图像存储路径 
    //读取位图的数据 
    imread(strFile,rbmp);
    int width = rbmp.cols();
	int height = rbmp.rows(); 
	int l_width = WIDTHBYTES(width*24);//计算位图的实际宽度并确保它为4byte的倍数  
    //写位图的数据
    int write_width = WIDTHBYTES(DRAW_WIDTH*24);//计算写位图的实际宽度(字节)并确保它为4byte的倍数   
	/*******************图像处理部分******************/
    for (int hnum = 0; hnum < DRAW_HEIGHT; hnum++)
	{

    	for (int wnum = 0; wnum < DRAW_WIDTH; wnum++)
		{
			double d_original_img_hnum = hnum*height / (double)DRAW_HEIGHT;
			double d_original_img_wnum = wnum*width / (double)DRAW_WIDTH;
			int i_original_img_hnum = d_original_img_hnum;
			int i_original_img_wnum = d_original_img_wnum;
			double distance_to_a_x = d_original_img_wnum - i_original_img_wnum;//在原图像中与a点的水平距离  
			double distance_to_a_y = d_original_img_hnum - i_original_img_hnum;//在原图像中与a点的垂直距离  
			int original_point_a = i_original_img_hnum*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点A    
			int original_point_b = i_original_img_hnum*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点B  
			int original_point_c = (i_original_img_hnum + 1)*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点C   
			int original_point_d = (i_original_img_hnum + 1)*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点D   
			if (i_original_img_hnum +1== DRAW_HEIGHT - 1)
			{
				original_point_c = original_point_a;
				original_point_d = original_point_b;
			}
			if (i_original_img_wnum +1== DRAW_WIDTH - 1)
			{
				original_point_b = original_point_a;
				original_point_d = original_point_c;
			}                              
 
			int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量  
			wbmp.pColorData[pixel_point] =
				rbmp.pColorData[original_point_a] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_b] * distance_to_a_x*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_c] * distance_to_a_y*(1 - distance_to_a_x) +
				rbmp.pColorData[original_point_d] * distance_to_a_y*distance_to_a_x;
			wbmp.pColorData[pixel_point + 1] =
				rbmp.pColorData[original_point_a + 1] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_b + 1] * distance_to_a_x*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_c + 1] * distance_to_a_y*(1 - distance_to_a_x) +
				rbmp.pColorData[original_point_d + 1] * distance_to_a_y*distance_to_a_x;
			wbmp.pColorData[pixel_point + 2] =
				rbmp.pColorData[original_point_a + 2] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_b + 2] * distance_to_a_x*(1 - distance_to_a_y) +
				rbmp.pColorData[original_point_c + 2] * distance_to_a_y*(1 - distance_to_a_x) +
				rbmp.pColorData[original_point_d + 2] * distance_to_a_y*distance_to_a_x;
 
		}
    }
	/*******************图像处理部分******************/
    std::cout<<"Done!"<<std::endl;
    imwrite(strFilesave,wbmp); 
    system("pause"); 
    return 0;
}

效果图:
在这里插入图片描述
在这里插入图片描述

双三次插值法

这个算法原理比较复杂,我另开一章记录,连接如下:
图像的放大:双三次插值算法(C++实现)

opencv实现

opencv自带的resize()函数已经实现了以上算法,仅需要一行代码即可完成。

void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR )

前两个参数分别为输入和输出图像,dsize表示输出图像的大小,fx、fy是沿x轴和y轴的缩放系数。

dsize=Size(round(fx∗src.cols),round(fy∗src.rows))
dsize和fx、fy不能同时为0。fx、fy是沿x轴和y轴的缩放系数;默认取0时,计算如下
其中的参数interpolation表示插值方式,有以下几种:
INTER_NEAREST - 最近邻插值
INTER_LINEAR - 线性插值(默认)
INTER_AREA - 区域插值
INTER_CUBIC - 三次样条插值
INTER_LANCZOS4 - Lanczos插值

  • 4
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值