设x0处的函数值为f(x0), x1处的函数值为f(x1), 设x0 < x < x1,对f(x)进行线性插值可得:
f(x) = f(x0)*(x1-x)/(x1-x0) + f(x1)*(x-x0)/(x1-x0)
实现代码:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <cmath>
using namespace cv;
using namespace std;
#define PI 3.14159265
void MyScale(Mat& src, Mat& dst, float TransMat[3][3]);
/**
* @function main
*/
int main( int argc, char** argv )
{
// load image
char* imageName = "images/Lenna_256.png";
Mat image;
image = imread(imageName,1);
if(!image.data)
{
cout << "No image data" << endl;
return -1;
}
// show image
namedWindow("image", CV_WINDOW_AUTOSIZE);
imshow("image", image);
Mat dst;
float transMat[3][3] = { {2.0, 0, 0}, {0, 2.0, 0}, {0, 0, 1} };
MyScale(image, dst, transMat);
namedWindow("out_image", CV_WINDOW_AUTOSIZE);
imshow("out_image", dst);
//imwrite("Lenna_scale_bilinear.jpg", dst);
waitKey(0);
return 0;
}
void MyScale(Mat& src, Mat& dst, float TransMat[3][3])
{
CV_Assert(src.data);
CV_Assert(src.depth() != sizeof(uchar));
// calculate margin point of dst image
float left = 0;
float right = 0;
float top = 0;
float down = 0;
float x = src.cols * 1.0f;
float y = 0.0f;
float u1 = x * TransMat[0][0] + y * TransMat[0][1];
float v1 = x * TransMat[1][0] + y * TransMat[1][1];
x = src.cols * 1.0f;
y = src.rows * 1.0f;
float u2 = x * TransMat[0][0] + y * TransMat[0][1];
float v2 = x * TransMat[1][0] + y * TransMat[1][1];
x = 0.0f;
y = src.rows * 1.0f;
float u3 = x * TransMat[0][0] + y * TransMat[0][1];
float v3 = x * TransMat[1][0] + y * TransMat[1][1];
left = min( min( min(0.0f,u1), u2 ), u3);
right = max( max( max(0.0f,u1), u2 ), u3);
top = min( min( min(0.0f,v1), v2 ), v3);
down = max( max( max(0.0f,v1), v2 ), v3);
// create dst image
dst.create(int(abs(right-left)), int(abs(down-top)), src.type());
CV_Assert( dst.channels() == src.channels() );
int channels = dst.channels();
int i,j;
uchar* p;
uchar* q0;
uchar* q1;
for( i = 0; i < dst.rows; ++i)
{
p = dst.ptr<uchar>(i);
for ( j = 0; j < dst.cols; ++j)
{
//
x = (j+left)/TransMat[0][0] ; // NOTE: adverse rotation here!!!
y = (i+top)/TransMat[1][1] ;
int x0 = int(x);
int y0 = int(y);
int x1 = int(x) + 1;
int y1 = int(y) + 1;
if( (x0 >= 0) && (x0 < src.cols) && (y0 >= 0) && (y0 < src.rows) &&
(x1 >= 0) && (x1 < src.cols) && (y1 >= 0) && (y1 < src.rows) )
{
q0 = src.ptr<uchar>(y0);
q1 = src.ptr<uchar>(y1);
switch(channels)
{
case 1:
{
//p[j] = q[x];
break;
}
case 3:
{
float b0 = q0[3*x0] ;
float g0 = q0[3*x0+1];
float r0 = q0[3*x0+2];
float b1 = q0[3*x1] ;
float g1 = q0[3*x1+1];
float r1 = q0[3*x1+2];
float b2 = q1[3*x0] ;
float g2 = q1[3*x0+1];
float r2 = q1[3*x0+2];
float b3 = q1[3*x1] ;
float g3 = q1[3*x1+1];
float r3 = q1[3*x1+2];
float b4 = b0 * (x1-x) / (x1-x0) + b1 * (x-x0) / (x1-x0);
float g4 = g0 * (x1-x) / (x1-x0) + g1 * (x-x0) / (x1-x0);
float r4 = r0 * (x1-x) / (x1-x0) + r1 * (x-x0) / (x1-x0);
float b5 = b2 * (x1-x) / (x1-x0) + b3 * (x-x0) / (x1-x0);
float g5 = g2 * (x1-x) / (x1-x0) + g3 * (x-x0) / (x1-x0);
float r5 = r2 * (x1-x) / (x1-x0) + r3 * (x-x0) / (x1-x0);
p[3*j] = b4 * (y1-y) / (y1-y0) + b5 * (y-y0) / (y1-y0);
p[3*j+1] = g4 * (y1-y) / (y1-y0) + g5 * (y-y0) / (y1-y0);
p[3*j+2] = r4 * (y1-y) / (y1-y0) + r5 * (y-y0) / (y1-y0);
break;
}
}
}
}
}
}
图1为原图,图2为放大2倍的图像,直接对计算坐标取整;图3为放大二倍的图像,对坐标进行双线性插值。



本文介绍了图像放大的基本原理,并通过线性插值公式展示了如何在x0和x1之间进行插值计算。同时,给出了两种放大图像的方法:一种是对坐标直接取整,另一种则是采用双线性插值技术,对比了两者的差异,结果显示双线性插值能提供更平滑的放大效果。

1万+

被折叠的 条评论
为什么被折叠?



