上述图片中像素点的说明:
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;
}
示例图像及结果展示