双线性插值原理分析及c++实现

双线性插值原理分析及C++实现


双线性插值(又称为双线性内插 ) : 其核心思想利用虚拟点四周真实存在的四个像素点分别在两个方向上进行线性插值操作

公式推导过程 双线性插值原理分析及c++实现_第1张图片

上述图片中像素点的说明:
Q11,Q21,Q12,Q22 分别为虚拟点周围四个真实存在的像素点
R1,R2 分别为X方向上线性插值后的值点
P 为双线性待插值点

1). x方向上插值:
R1(i , y)= ( x + 1 - i ) * Q11 + ( i - x ) * Q21
R2(i , y)= ( x + 1 - i ) * Q12 + ( i - x ) * Q22

2). y方向上插值:
P(i , j)= ( y + 1 - j ) * R1 + ( j - y ) * R2

3). 双线性插值的具体推导过程:
P(i , j)= ( y + 1 - j ) * [ ( x + 1 - i ) * Q11 + ( i - x ) * Q21 ] + ( j - y ) * [ ( y + 1 - j ) * R1 + ( j - y ) * R2 ]

令 i = x + u , j = y + v
P(i , j)= (1 - u) * ( 1 - v ) * Q11 + u * ( 1 - v ) * Q21 + (1 - u) * v * Q12 + u * v * Q22

示例代码

#include "stdafx.h"
#include "iostream"
#include "opencv2/opencv.hpp"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"

using namespace std;
using namespace cv;    

#pragma comment(lib,"./opencv_world300d.lib")

void Bilinera(cv::Mat& src, cv::Mat& dst, double sx, double sy)
{
	int dst_rows = round(src.rows * sy);//把一个小数四舍五入 height
	int dst_cols = round(src.cols * sx); //width

	dst = cv::Mat(dst_rows, dst_cols, src.type());
	for (int i = 0; i < dst.rows; i++)
	{
		//几何中心对齐
		double index_i = (i + 0.5) / sy - 0.5;
		//防止越界
		if (index_i < 0) index_i = 0;
		if (index_i >= src.rows - 1) index_i = src.rows - 2;
		//相邻2*2像素的行(坐标)
		int i1 = floor(index_i);//把一个小数向下取整 2.2==2
		int i2 = ceil(index_i);//把一个小数向上取整  2.2==3
		//u为得到浮点型坐标行的小数部分
		double u = index_i - i1;
		for (int j = 0; j < dst.cols; j++)
		{
			//几何中心对齐
			double index_j = (j + 0.5) / sx - 0.5;
			//防止越界
			if (index_j < 0) index_j = 0;
			if (index_j >= src.cols - 1) index_j = src.cols - 2;
			//相邻2*2像素的列(坐标)
			int j1 = floor(index_j);
			int j2 = ceil(index_j);
			//v为得到浮点型坐标列的小数部分
			double v = index_j - j1;
			if (src.channels() == 1)
			{
				//灰度图像
				dst.at<uchar>(i, j) = (1 - u)*(1 - v)*src.at<uchar>(i1, j1) + (1 - u)*v*src.at<uchar>(i1, j2) + u*(1 - v)*src.at<uchar>(i2, j1) + u*v*src.at<uchar>(i2, j2);
			}
			else
			{
				//彩色图像
				dst.at<cv::Vec3b>(i, j)[0] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[0] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[0] + u*(1 - v)*src.at<cv::Vec3b>(i2, j1)[0] + u*v*src.at<cv::Vec3b>(i2, j2)[0];
				dst.at<cv::Vec3b>(i, j)[1] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[1] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[1] + u*(1 - v)*src.at<cv::Vec3b>(i2, j1)[1] + u*v*src.at<cv::Vec3b>(i2, j2)[1];
				dst.at<cv::Vec3b>(i, j)[2] = (1 - u)*(1 - v)*src.at<cv::Vec3b>(i1, j1)[2] + (1 - u)*v*src.at<cv::Vec3b>(i1, j2)[2] + u*(1 - v)*src.at<cv::Vec3b>(i2, j1)[2] + u*v*src.at<cv::Vec3b>(i2, j2)[2];
			}
		}
	}
}

int main()
{
	const char* imageName = "C:\\Users\\Public\\Pictures\\Sample Pictures\\flower.jpg";
	Mat srcImage = imread(imageName);
	if (srcImage.empty())
	{
		fprintf(stderr, "Can not load image %s\n", srcImage);
		return -1;
	}
	int iSrcWidth = 1024, iSrcHeight = 768;
	int iDstWidth = 4000, iDstHeight = 3000;
	Mat dstImage;
	double sx = static_cast<double>(1.0 / (1.0*iSrcWidth / iDstWidth));
	double sy = static_cast<double>(1.0 / (1.0*iSrcHeight / iDstHeight));
	Bilinera(srcImage, dstImage, sx, sy);
	imwrite("D:\\123.jpg", dstImage);
	return 0;
}

示例图像及结果展示

示例图像
双线性插值原理分析及c++实现_第2张图片

结果图像
双线性插值原理分析及c++实现_第3张图片

你可能感兴趣的:(图像插值,c++)