opencv的双立方插值

写opencv的时候用到了resize函数,

看到一个参数INTER_CUBIC

cv::InterpolationFlags::INTER_CUBIC

这个参数就是表示使用双立方插值的方式对图像进行缩放。

然后就去查了一下双立方插值算法。

然后说一下双立方插值怎么计算的:

1、

先给出一张图像src(原图像),大小假设为(m,n)

输出图像定义为dst

输出图像的大小定义为Size size(M,N)

2、

输出图像的dst(i,j)的值怎么计算呢?

首先我们判断一下缩放后的dst(i,j)在原图src中位置在哪?

可以按照计算方式:

float row = i*m/M;
float col = j*n/N;

这里计算出来的位置为(row,col),也就是dst(i,j)在原图中的位置的值是src(row,col),也就是dst(i,j) = src(row,col);

2、

但是row,col都是浮点数,那怎么计算src(row,col)这个值呢?

好吧,这个图1很多地方都有了,这里借用一下。图中暂且可以把p点认为是点(row,col),那这里就是要计算p点的值,

p点的值怎么计算呢,这里是取p点周围的16个像素,类似于下图1,

然后p点的值(影响因子w_ij乘以a_ij,然后求和):

value = src(row,col) = \sum_{i=0}^{3}\sum_{j=0}^{3}a_i_j*w_i_j

双立方插值说明图 图1

3、

这里上面已经可以计算src(row,col)了,也就可以得到dst(i,j),因为dst(i,j)=src(row,col),

但是上面出现了一个w_i_j,这个是什么呢,怎么计算呢?

这里w_ij就是上面说的影响因子,图一中4*4图像每个像素对应一个影响因子,总共16个,怎么计算这16个影响因子。

这里要引入一个函数,Bicubic函数,影响因子的计算就是基于这个函数:

opencv的双立方插值_第1张图片

通过获取每行(列)像素对应的x就可以获取w_ij了。

4、

所以x(y)的值要怎么计算呢?

这里现获得x_i(行),y_j(列),然后获得w_i,w_j,最后w_ij=w_i*w_j.

//行
x_0 = (1+u);
x_1 = (u);
x_2 = (1-u);
x_3 = (2-u);
//列
y_0 = (1+v);
y_1 = (v);
y_2 = (1-v);
y_3 = (2-v);
//u = row - (int)row
//v = col - (int)col

w_i = w(x_i);//行影响因子
w_j = w(y_j);//列影响因子
w_ij = w_i*w_j;

到这里,就已经获得了所有需要的东西,就可以计算了。

#include 
#include 
#include 
using namespace cv;
//双立方插值函数
float bicubic(float x)
{
	float a = 0.25f;
	float res = 0.f;
	x = fabsf(x);
	if (x <= 1.f)
		res = (a + 2) * x * x * x - (a + 3) * x * x + 1;
	else if (x > 1.f && x <= 2.f)
		res = a * x * x * x - 5 * a * x * x + 8 * a * x - 4 * a;
	return res;
}
void getImpactFactors(float rowU,float colV,vector& rowImFac,vector& colImFac,int starti,int startj)
{
	//取整
	int row = (int)rowU;
	int col = (int)colV;
	//4*4行列影响因子
	rowImFac.resize(4);
	colImFac.resize(4);
	float temp;
	//计算行系数因子
	for (int i = 0; i < 4; i++)
	{
		if (starti + i <= 0)
			temp = rowU - row - (starti + i);
		else
			temp = (starti + i) - (rowU - row);
		rowImFac[i] = bicubic(temp);
	}
	//计算列系数因子
	for (int j = 0; j < 4; j++)
	{
		if (startj + j <= 0)
			temp = colV - col - (startj + j);
		else
			temp = (startj + j) - (colV - col);
		colImFac[j] = bicubic(temp);
	}
}

void myBicubicResize(Mat inputMat, Mat& outputMat, Size size)
{
	outputMat = Mat::zeros(size, CV_32FC3);
	float inputrows = (float)inputMat.rows;
	float inputcols = (float)inputMat.cols;
	float outputrows = (float)size.height;
	float outputcols = (float)size.width;

	Mat tmmat;
	//BORDER_DEFAULT = BORDER_REFLECT_101
	copyMakeBorder(inputMat, tmmat, 2, 2, 2, 2, BORDER_DEFAULT);

	vector rowImFac(4), colImFac(4);
	for (int row = 0; row < outputrows; row++)
	{
		for (int col = 0; col < outputcols; col++)
		{
			//计算outputMat(row,col)在原图中的位置坐标
			float inputrowf = row * (inputrows / outputrows);
			float inputcolf = col * (inputcols / outputcols);
			//取整
			int interow = (int)inputrowf;
			int intecol = (int)inputcolf;
			float row_dy = inputrowf - interow;
			float col_dx = inputcolf - intecol;
			//因为扩展了边界,所以+2
			interow += 2;
			intecol += 2;
			int starti = -1, startj = -1;
			//计算行影响因子,列影响因子
			getImpactFactors(inputrowf, inputcolf, rowImFac, colImFac,starti,startj);
			//计算输出图像(row,col)的值
			Vec3f tempvec(0, 0, 0);
			for (int i = starti; i < starti+4; i++)
			{
				for (int j = startj; j < startj+4; j++)
				{
					tempvec += (Vec3f)(tmmat.at(interow + i, intecol + j) * rowImFac[i - starti] * colImFac[j - startj]);
				}
			}
			outputMat.at(row, col) = tempvec;
		}
	}
}
int main(int argc, char** argv)
{
	Mat srcmat = cv::imread("Lena.png");
	if (srcmat.empty())
		return 0;

	Mat dst;
	Mat dst1;
	Size size(500, 256);
	myBicubicResize(srcmat, dst, size);
	dst.convertTo(dst, CV_8UC3);
	resize(srcmat, dst1, size, 0, 0, INTER_CUBIC);
	
	imshow("dst", dst);
	imshow("dst1", dst1);

    waitKey(0);
	return 0;
}
opencv的双立方插值_第2张图片 自己写的BicuBic算法结果
opencv的双立方插值_第3张图片 resize函数的INTER_CUBIC

这里要说一点,opencv里面a取的是-0.75,我这里取的是0.25,

这里我试验过几次,我的a值取-0.5或者-0.75的时候,会出现问题,会有一些竖向的痕迹,

a值取0.25或者0.5的时候就没有问题。

opencv的双立方插值_第4张图片

除此之外,如果a值取-0.5或者-0.75,并且图像size(col,row)以相同比例缩放,也不会出现竖向的痕迹。

总的来说不是太复杂,,,,

不过还有很多需要学习的地方,

参考的文章:(除了a的取值不同,自己还做了一些其他的试验,比如最近的16个点)

https://blog.csdn.net/qq_29058565/article/details/52769497

你可能感兴趣的:(opencv)