双三次插值、双线性插值、最临近插值 C++实现

双三次插值、双线性插值、最临近插值C++实现

实现插值类

#pragma once
#include<opencv2/opencv.hpp>
class Interpolation
{
public:
	Interpolation(cv::Mat src, float h_times, float w_times);
	~Interpolation() {};

	void Nearest_neighbor();//最临近插值
	void Bilinear_interpolation();//双线性插值
	void Cubic_inner();//双三次插值
	
private:
	cv::Mat m_src;
	float m_h_times;
	float m_w_times;
	float cubic_coeff(float x, const float& a);
	void cal_cubic_coeff(float x, float y, float* coeff, const float& a);
	void cubic_inner_single(const cv::Mat& A, float x_float, float y_float, 
		                       const float& a, float& sum, cv::Vec3f& sum3);
	
};
#include "Interpolation.h"

Interpolation::Interpolation(cv::Mat src, float h_times, float w_times)
{
	this->m_src = src;
	this->m_h_times = h_times;
	this->m_w_times = w_times;
}


void Interpolation::Nearest_neighbor()
{
	int src_h = this->m_src.size().height;
	int src_w = this->m_src.size().width;
	int dst_h = src_h * m_h_times;
	int dst_w = src_w * m_w_times;
	cv::Mat dst(dst_h, dst_w, this->m_src.type());
	int row, col;
	int channel = this->m_src.channels();
	for (int i = 1; i <= dst_h; ++i) {
		row = i * ((float)src_h / (float)dst_h) + 0.5;
		for (int j = 1; j <= dst_w; ++j) {
			col = j * ((float)src_w / (float)dst_w) + 0.5;
			if (channel == 1)
				dst.at<uchar>(i - 1, j - 1) = this->m_src.at<uchar>(row - 1, col - 1);
			else if (channel == 3)
				dst.at<cv::Vec3b>(i - 1, j - 1) = this->m_src.at<cv::Vec3b>(row - 1, col - 1);
		}
	}
	cv::namedWindow("Nearest", 1);
	cv::imshow("Nearest", dst);
}

void Interpolation::Bilinear_interpolation()
{
	int src_h = this->m_src.size().height;
	int src_w = this->m_src.size().width;
	int dst_h = src_h * m_h_times;
	int dst_w = src_w * m_w_times;
	cv::Mat dst(dst_h, dst_w, this->m_src.type());
	for (int i = 0; i < dst_h; ++i)
	{
		float srcX_h = i * ((float)src_h / (float)dst_h);
		for (int j = 0; j < dst_w; ++j)
		{
			float srcY_w = j * ((float)src_w / (float)dst_w);
			int n = (int)srcX_h;
			int m = (int)srcY_w;
			float n_res = srcX_h - n;
			float m_res = srcY_w - m;
			bool h_flag = false, w_flag = false;
			//偷个懒,边缘像素用临近插值
			if (n == src_h - 1)
				h_flag = true;
			if (m == src_w - 1)
				w_flag = true;			
			if (dst.channels() == 1)
			{
				if (!h_flag && !w_flag)
					dst.at<uchar>(i, j) = this->m_src.at<uchar>(n, m) * (1 - n_res) * (1 - m_res) + this->m_src.at<uchar>(n + 1, m) * n_res * (1 - m_res)
					+ this->m_src.at<uchar>(n, m + 1) * (1 - n_res) * m_res + this->m_src.at<uchar>(n + 1, m + 1) * n_res * m_res;
				else
					dst.at<uchar>(i, j) = this->m_src.at<uchar>(n, m);
			}
			else
			{
				if (!h_flag && !w_flag)
					dst.at<cv::Vec3b>(i, j) = this->m_src.at<cv::Vec3b>(n, m) * (1 - n_res) * (1 - m_res) + this->m_src.at<cv::Vec3b>(n + 1, m) * n_res * (1 - m_res)
					+ this->m_src.at<cv::Vec3b>(n, m + 1) * (1 - n_res) * m_res + this->m_src.at<cv::Vec3b>(n + 1, m + 1) * n_res * m_res;
				else
					dst.at<cv::Vec3b>(i, j) = this->m_src.at<cv::Vec3b>(n, m);
			}

		}
	}

	cv::namedWindow("Bilinear", 1);
	cv::imshow("Bilinear", dst);
}

float Interpolation::cubic_coeff(float x, const float& a)
{
	if (x <= 1) {
		return 1 - (a + 3) * x * x + (a + 2) * x * x * x;
	}
	else if (x < 2)
	{
		return -4 * a + 8 * a * x - 5 * a * x * x + a * x * x * x;
	}
	return 0.0;
}

void Interpolation::cal_cubic_coeff(float x, float y, float* coeff, const float& a)
{
	/*calc the coeff*/
	float u = x - floor(x);
	float v = y - floor(y);
	u += 1;
	v += 1;
	
	float A[4];
	A[0] = cubic_coeff(abs(u), a);
	A[1] = cubic_coeff(abs(u - 1), a);
	A[2] = cubic_coeff(abs(u - 2), a);
	A[3] = cubic_coeff(abs(u - 3), a);

	for (int s = 0; s < 4; s++)
	{
		float C = cubic_coeff(abs(v - s), a);
		coeff[s * 4] = A[0] * C;
		coeff[s * 4 + 1] = A[1] * C;
		coeff[s * 4 + 2] = A[2] * C;
		coeff[s * 4 + 3] = A[3] * C;
	}
}

void Interpolation::cubic_inner_single(const cv::Mat& A, float x_float, float y_float,
	const float& a, float& sum, cv::Vec3f& sum3)
{
	float coeff[16];
	this->cal_cubic_coeff(x_float, y_float, coeff, a);  //计算权重系数

	sum = 0.0;
	sum3 = { 0.0,0.0,0.0 };
	int x0 = floor(x_float) - 1;
	int y0 = floor(y_float) - 1;

	int num_channels = A.channels();
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (num_channels == 1)
				sum += coeff[i * 4 + j] * A.at<uchar>(x0 + i, y0 + j);
			else if (num_channels == 3)
				sum3 += coeff[i * 4 + j] * A.at<cv::Vec3b>(x0 + i, y0 + j);
		}
	}

}


void Interpolation::Cubic_inner()
{
	int src_h = this->m_src.size().height;
	int src_w = this->m_src.size().width;
	int dst_h = src_h * m_h_times;
	int dst_w = src_w * m_w_times;
	cv::Mat dst(dst_h, dst_w, this->m_src.type());
	cv::Mat src_padding;
	cv::copyMakeBorder(this->m_src, src_padding, 2, 2, 2, 2, 1);
	int num_channels = this->m_src.channels();
	float sum = 0.0;
	cv::Vec3f sum3{ 0.0,0.0,0.0 };
	float a = -0.5;
	for (int i = 0; i < dst_h; ++i)
	{
		float srcX_h = i * ((float)src_h / (float)dst_h);
		for (int j = 0; j < dst_w; ++j)
		{		
			float srcY_w = j * ((float)src_w / (float)dst_w);
			cubic_inner_single(src_padding, srcX_h + 2, srcY_w + 2, a, sum, sum3);
			if (num_channels == 1) {
				if (sum > 255) sum = 255.0;
				dst.at<uchar>(i, j) = (uchar)sum;
			}
			else if (num_channels == 3) {
				for (int k = 0; k < 3; k++) {
					if (sum3[k] > 255) sum3[k] = 255.0;
				}
				dst.at<cv::Vec3b>(i, j) = (cv::Vec3b)sum3;
			}
		}
	}

	cv::namedWindow("Cubic_inner", 1);
	cv::imshow("Cubic_inner", dst);
}

调用示例

#include<iostream>
#include<opencv2/opencv.hpp>

#include"Interpolation.h"

int main()
{
	cv::Mat src = cv::imread("G:/pictures/3.png",1);

	Interpolation First(src, 2, 2); //长宽放大2倍

	First.Nearest_neighbor();

	First.Bilinear_interpolation();

	First.Cubic_inner(); 


	cv::namedWindow("SRC", 1);

	cv::imshow("SRC", src);
	
	cv::waitKey(0);

	return 0;
}

效果展示

原图
最邻近插值
双线性插值
双三次插值

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值