实现插值类
#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;
}
效果展示