图像放大并用双线性插值

设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为放大二倍的图像,对坐标进行双线性插值。

图像放大并用双线性插值_第1张图片

                                 

 

你可能感兴趣的:(图像放大并用双线性插值)