实现部分图片插值算法(最近邻,双线性,双立方)
#include <iostream> #include <cmath> #include<highgui.h> #include <opencv2/core/mat.hpp> #include<opencv2/highgui/highgui.hpp> #include <opencv2/core/core.hpp> #include <opencv2/imgproc.hpp> 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; }
文章来源: 图片插值