实现部分图片插值算法(最近邻,双线性,双立方)
#include
#include
#include
#include
#include
#include
#include
struct MyMat
{
u_char *data;
int w, h, c;
MyMat(){}
MyMat(cv::Mat &A){
w = A.cols, h = A.rows, c = A.channels();
data = (u_char *) malloc(w * h * c * sizeof(u_char));
memcpy(data, A.data, w * h * c * sizeof(u_char));
}
cv::Mat to_cvMat(){
cv::Mat A(h, w, CV_8UC3, cv::Scalar(0, 0, 0));
memcpy(A.data, data, w * h * c * sizeof(u_char));
return A;
}
};
double INTER_CUBIC_Fun(double x, double a = -0.5)
{
x = abs(x);
if(0 <= x && x <= 1){
return 1 - (a + 3) * x * x + (a + 2) * x * x * x;
}
else if(1 < x && x <= 2){
return 8 * a * x - 5 * a * x * x + a * x * x * x - 4 * a;
}
else return 0;
}
int dimtovec(MyMat &a, int i, int j,int k)
{
//return k * a.w * a.h + j * a.w + i;
return a.c * (a.w * j + i) + k;
}
/*
* A:数据矩阵 nw,nh:宽和长 interpolation_type:插值的方式
*/
MyMat resize(MyMat A, int nw, int nh, std::string interpolation_type)
{
MyMat B;
B.w = nw, B.h = nh, B.c = A.c;
B.data = (u_char *) malloc(sizeof(u_char) * B.w * B.h * B.c);
double dw = (double)A.w / nw;
double dh = (double)A.h / nh;
if(interpolation_type == "INTER_NEAREST"){ //最近邻插值
for(int i = 0; i < nw; i++){
for(int j = 0; j < nh; j++){
int nx = i * dw;
int ny = j * dh;
//B.data[i * nh + j] = A.data[nx * A.h + ny];
for(int k = 0; k < B.c; k++){
int t1 = dimtovec(B, i, j, k), t2 = dimtovec(A, nx, ny, k);
B.data[t1] = A.data[t2];
}
}
}
}
else if(interpolation_type == "INTER_LINEAR"){ //双线性插值
for(int i = 0; i < nw; i++){
for(int j = 0; j < nh; j++){
double nx = i * dw, ny = j * dh;
if(nx >= A.w - 1)
nx = A.w - 2;
if(ny >= A.h - 1)
ny = A.h - 2;
int x1 = floor(nx), x2 = floor(nx + 1), y1 = floor(ny + 1), y2 = floor(ny);
double alpha = (x2 - nx) / (x2 - x1), beta = (nx - x1) / (x2 - x1);
for(int k = 0; k < A.c; k++){
int Q11 = dimtovec(A, x1, y1 ,k);
int Q12 = dimtovec(A, x1, y2, k);
int Q21 = dimtovec(A, x2, y1, k);
int Q22 = dimtovec(A, x2, y2, k);
double R1 = alpha * A.data[Q11] + beta * A.data[Q21];
double R2 = alpha * A.data[Q12] + beta * A.data[Q22];
B.data[dimtovec(B, i, j, k)] = (y2 - ny) / (y2 -y1) * R1 + (ny - y1) / (y2 - y1) * R2;
}
}
}
}
else if(interpolation_type == "INTER_CUBIC"){ //4x4像素点领域内的双立方插值
for(int i = 0; i < nw; i++){
for(int j = 0; j < nh; j++){
int nx = i * dw, ny = j * dh;
double dx = i * dw - nx, dy = j * dh - ny;
for(int k = 0; k < B.c; k++){
double sum = 0;
for(int di = -1; di <= 2; di++){
for(int dj = -1; dj <= 2; dj++){
int x = nx + di, y = ny + dj;
if(x < 0) x = 0;
else if(x >= A.w){
x = A.w - 1;
}
if(y < 0 ) y = 0;
else if(y >= A.h){
y = A.h - 1;
}
sum += A.data[dimtovec(A, x, y, k)] * INTER_CUBIC_Fun(di - dx) * INTER_CUBIC_Fun(dy - dj);
}
}
if(sum > 255) sum = 255;
if(sum < 0) sum = 0;
B.data[dimtovec(B, i, j, k)] = sum;
}
}
}
}
else if(interpolation_type == "INTER_LANCZOS4"){ //8x8像素领域内的Lanczos插值
}
// for(int i = 0; i < B.w * B.h; i++) std::cout << (int)B.data[i] << " ";
// std::cout << std::endl;
return B;
}
int main()
{
//cv::Mat img(10, 10, CV_8UC3, cv::Scalar(255, 0, 0));
// u_char *p = (u_char *)malloc(240 * 320 * sizeof(u_char));
// memcpy(p, img.data, 5);
// for(int i = 0; i < 11; i++) std::cout << (int)p[i] << " ";
cv::Mat img = cv::imread("../test.jpg");
// cv::imshow("123", img);
//cv::waitKey(10);
//std::cout << img.channels() << std::endl;
MyMat A(img);
//for(int i = 0; i < A.w * A.h * A.c; i++) std::cout << (int)A.data[i] <<" ";
int x, y;
std::cin >> x >> y;
MyMat B = resize(A, x, y, "INTER_LINEAR");
cv::Mat C = B.to_cvMat();
// cv::Mat out;
// cv::resize(img, out, cv::Size(500, 500) ,cv::INTER_NEAREST);
cv::imshow("123",C);
// cv::imwrite("../data.jpg", out);
cv::waitKey();
return 0;
}