Sub-pixel algorithm (commercial source code, like and collect)

Subpixel algorithms are algorithms for image processing at the pixel level. A common subpixel algorithm is bilinear interpolation,
which can be used for operations such as image scaling and rotation.

1. Sub-pixel algorithms are usually used for interpolation operations in image processing, which can improve the accuracy of images. The following is a simple bilinear interpolation sub-pixel algorithm, you can refer to it:

#include <iostream>
using namespace std;

double bilinearInterpolation(double x, double y, double q11, double q12, double q21, double q22) {
  double r1, r2, r3, r4;
  r1 = q11 * (1 - x) * (1 - y);
  r2 = q21 * x * (1 - y);
  r3 = q12 * (1 - x) * y;
  r4 = q22 * x * y;
  return r1 + r2 + r3 + r4;
}

int main() {
  double x = 0.5;    // x坐标
  double y = 1.5;    // y坐标
  double q11 = 1.0;  // 点(1,1)的值
  double q12 = 2.0;  // 点(1,2)的值
  double q21 = 3.0;  // 点(2,1)的值
  double q22 = 4.0;  // 点(2,2)的值

  double result = bilinearInterpolation(x - floor(x), y - floor(y), q11, q12, q21, q22);
  cout << "双线性插值的结果为:" << result << endl;

  return 0;
}

Among them, x and y are the coordinate values, and q11, q12, q21, and q22 are the pixel values ​​of the four points to be interpolated. The algorithm converts x and y coordinates into fractional parts, and then performs bilinear interpolation calculations to obtain sub-pixel values ​​corresponding to x and y coordinates.

2. The following is the implementation of a simple bilinear interpolation algorithm, which is used to scale the original image according to a given scaling factor:

#include <opencv2/opencv.hpp>

using namespace cv;

Mat resize_subpixel(const Mat &src, double scale) {
    int new_width = int(src.cols * scale);
    int new_height = int(src.rows * scale);
    Mat dst = Mat::zeros(new_height, new_width, src.type());

    for (int j = 0; j < new_height - 1; j++) {
        float v = j / scale;
        int i_v = int(v);
        float ty = v - i_v;

        for (int i = 0; i < new_width - 1; i++) {
            float u = i / scale;
            int i_u = int(u);
            float tx = u - i_u;

            // 双线性插值
            dst.at<Vec3b>(j, i) =
                (1 - ty) * (1 - tx) * src.at<Vec3b>(i_v, i_u) +
                (1 - ty) * tx * src.at<Vec3b>(i_v, i_u + 1) +
                ty * (1 - tx) * src.at<Vec3b>(i_v + 1, i_u) +
                ty * tx * src.at<Vec3b>(i_v + 1, i_u + 1);
        }
    }

    return dst;
}

This function takes a source image and a scale and returns a new image scaled by the scale. The function loops through each pixel of the new image and calculates its corresponding position in the original image. Then, the value of the new pixel is calculated by bilinear interpolation algorithm and written into the target image. Finally, the function returns the target image.

It should be noted that this algorithm is only a simple example and may not meet all needs. In actual use, it may need to be adjusted and improved according to specific application scenarios.

3. The sub-pixel algorithm is usually used to enlarge or reduce the image to improve the clarity and quality of the image. Here is an example of a simple subpixel algorithm:

// image_width和image_height表示图像宽度和高度
// dest_width和dest_height表示目标图像宽度和高度
// source_data是源图像数据,dest_data是目标图像数据
void subpixel_scale(unsigned char* source_data, int image_width, int image_height, unsigned char* dest_data, int dest_width, int dest_height) {
    float x_ratio = (float)image_width / (float)dest_width;
    float y_ratio = (float)image_height / (float)dest_height;
    
    for (int i = 0; i < dest_height; i++) {
        for (int j = 0; j < dest_width; j++) {
            int x = (int)(j * x_ratio);
            int y = (int)(i * y_ratio);
            float x_diff = (j * x_ratio) - x;
            float y_diff = (i * y_ratio) - y;
            int index = (y * image_width + x) * 3;
            int dest_index = (i * dest_width + j) * 3;
            for (int k = 0; k < 3; k++) {
                dest_data[dest_index + k] = (unsigned char)(
                    (source_data[index + k] * (1 - x_diff) * (1 - y_diff)) +
                    (source_data[index + 3 + k] * x_diff * (1 - y_diff)) +
                    (source_data[index + image_width * 3 + k] * y_diff * (1 - x_diff)) +
                    (source_data[index + image_width * 3 + 3 + k] * x_diff * y_diff)
                );
            }
        }
    }
}

The algorithm assumes that both the source image and the target image are three-channel (R, G, B), and calculates each channel separately, and then combines them into the pixels of the target image. In this algorithm, for each pixel in the target image, it first calculates the position of the corresponding pixel in the source image in integer form, then calculates the difference between this pixel and its surrounding pixels, and calculates each pixel of the target pixel by the following formula Channel value:

Pixel value = (Top-left pixel value * (1 - x_diff) * (1 - y_diff)) + 
              (Top-right pixel value * x_diff * (1 - y_diff)) +
              (Bottom-left pixel value * y_diff * (1 - x_diff)) +
              (Bottom-right pixel value * x_diff * y_diff)

Among them, x_diff and y_diff are fractional parts, indicating the offset of the target pixel relative to the source pixel. Use the formula above to calculate the pixel value for each channel.

4. The sub-pixel algorithm is to interpolate the pixel points of the image to obtain a finer image. There are many kinds of algorithms, such as bilinear interpolation, bicubic interpolation and so on. Here I provide you a sample code of a sub-pixel algorithm for bilinear interpolation:

cv::Vec3b bilinearInterpolation(cv::Mat img, float x, float y)
{
    // 获取图像的宽和高
    int width = img.cols;
    int height = img.rows;
    
    // 计算四个最近的像素点坐标
    int x1 = (int)floor(x);
    int x2 = (int)ceil(x);
    int y1 = (int)floor(y);
    int y2 = (int)ceil(y);
    
    // 判断最近的像素点是否越界
    if (x1 < 0 || x2 >= width || y1 < 0 || y2 >= height) {
        return cv::Vec3b(0, 0, 0);
    }
    
    // 获取四个最近像素点的像素值
    cv::Vec3b p1 = img.at<cv::Vec3b>(y1, x1);
    cv::Vec3b p2 = img.at<cv::Vec3b>(y1, x2);
    cv::Vec3b p3 = img.at<cv::Vec3b>(y2, x1);
    cv::Vec3b p4 = img.at<cv::Vec3b>(y2, x2);
    
    // 计算双线性插值
    float u = x - x1;
    float v = y - y1;
    cv::Vec3b pixel;
    for (int i = 0; i < 3; i++) {
        float intensity = (1 - u) * (1 - v) * (float)p1[i] + u * (1 - v) * (float)p2[i] + (1 - u) * v * (float)p3[i] + u * v * (float)p4[i];
        pixel[i] = (int)intensity;
    }
    
    return pixel;
}

In the above code, the Mat type in the opencv library is used to store the image. The input parameter img of the function is the image to be sub-pixel interpolated, and x and y are the pixel coordinates to be interpolated. In the function, first calculate the coordinates of the four closest pixels to the target pixel, and judge whether these pixels are out of bounds. Then, calculate the pixel value of the target pixel according to the bilinear interpolation formula, and finally return the calculation result.

Note: This algorithm is just a sample code, and the specific application needs to be adjusted and optimized according to the actual situation.

5. Sub-pixel algorithm is a technique for interpolating images, which can improve the clarity and quality of images. Here's a simple subpixel algorithm:

Suppose there is an image of size nxm, and to reduce it to half (that is, become an image of size n/2xm/2), you can follow the steps below:

  1. Define a new nx/2xm/2 size image.

  2. For each pixel in the new image, compute the coordinates of its four neighbors in the original image.

  3. For each pixel, calculate the fractional part of its position in the original image, that is, calculate the relative distance of the four nearest pixels.

  4. Using a bilinear interpolation algorithm, calculate the value of a new pixel based on the values ​​and relative distances of the four pixels calculated in the previous step.

  5. Store the computed value at the corresponding pixel location in the new image.

  6. Repeat steps 2-5 until all pixel values ​​in the new image have been calculated.

For specific implementation, please refer to the following code snippet:

void downsample(const Mat& src, Mat& dst)
{
    //定义新图像大小
    int n = src.rows, m = src.cols;
    Mat newImg(n / 2, m / 2, CV_8UC3);
    //遍历新图像的每个像素
    for (int i = 0; i < newImg.rows; i++)
    {
        for (int j = 0; j < newImg.cols; j++)
        {
            //计算四个相邻像素坐标
            int x1 = i * 2, y1 = j * 2;
            int x2 = x1 + 1, y2 = y1;
            int x3 = x1, y3 = y1 + 1;
            int x4 = x1 + 1, y4 = y1 + 1;
            //计算每个像素的小数部分
            double dx = i * 2.0 - x1;
            double dy = j * 2.0 - y1;
            //使用双线性插值计算新像素的值
            Vec3b v1 = src.at<Vec3b>(x1, y1), 
                   v2 = src.at<Vec3b>(x2, y2), 
                   v3 = src.at<Vec3b>(x3, y3), 
                   v4 = src.at<Vec3b>(x4, y4);
            Vec3b v = (1 - dx) * (1 - dy) * v1 + dx * (1 - dy) * v2 +
                      (1 - dx) * dy * v3 + dx * dy * v4;
            //将计算得到的像素值存储到新图像中
            newImg.at<Vec3b>(i, j) = v;
        }
    }
    //将结果复制到输出矩阵中
    dst = newImg.clone();
}

This is a simple sub-pixel algorithm implementation. If you need higher quality image interpolation, you can consider using more complex algorithms, such as bicubic interpolation, etc.

6. The main purpose of the sub-pixel interpolation algorithm is to improve the resolution of the image and make it look clearer. The following is an implementation of a simple subpixel interpolation algorithm:

#include <opencv2/opencv.hpp>

using namespace cv;

Mat subPixelInterpolate(Mat image, float x, float y) {
    int x1 = floor(x);
    int x2 = ceil(x);
    int y1 = floor(y);
    int y2 = ceil(y);
    float frac_x = x - x1;
    float frac_y = y - y1;
    Mat I11 = image.at<Vec3b>(y1, x1);
    Mat I12 = image.at<Vec3b>(y1, x2);
    Mat I21 = image.at<Vec3b>(y2, x1);
    Mat I22 = image.at<Vec3b>(y2, x2);
    Mat R1 = I11 * (1 - frac_x) + I12 * frac_x;
    Mat R2 = I21 * (1 - frac_x) + I22 * frac_x;
    Mat R = R1 * (1 - frac_y) + R2 * frac_y;
    return R;
}

int main() {
    Mat image = imread("test.jpg");
    float x = 5.5;
    float y = 10.3;
    Mat result = subPixelInterpolate(image, x, y);
    imshow("result", result);
    waitKey(0);
    return 0;
}

In this implementation, we first calculate the four adjacent points of x and y through the floor and ceil functions: (x1,y1), (x1,y2), (x2,y1) and (x2,y2). We then calculate the offsets of x and y from their nearest bottom left corner point (x1, y1): frac_x and frac_y. Next, we use these values ​​to calculate the final interpolated values ​​as follows:

  1. Calculate R1 = I11 * (1 - frac_x) + I12 * frac_x by interpolating I11 and I12.
  2. Use I21 and I22 for interpolation calculation R2 = I21 * (1 - frac_x) + I22 * frac_x.
  3. Interpolate R1 and R2 to calculate the final result: R = R1 * (1 - frac_y) + R2 * frac_y.

Finally, we can use this function to interpolate anywhere in the image, not just at integer coordinates.

7. Sub-pixel algorithm is often used in image processing. It can split a pixel into smaller sub-pixels for processing, thereby improving the accuracy of image processing.

Here is an example of a simple subpixel algorithm implementation:

#include <iostream>
#include <cmath>

// 亚像素算法,将一个像素拆分成多个子像素进行处理
double subPixel(double x, double y, double (*func)(double, double))
{
    double sum = 0.0;
    for(int i = -1; i <= 1; i++)
    {
        for(int j = -1; j <= 1; j++)
        {
            sum += func(x + i/3.0, y + j/3.0);
        }
    }
    return sum/9.0;
}

// 示例函数,计算sin(x*y)
double func(double x, double y)
{
    return std::sin(x*y);
}

int main()
{
    double x = 1.0, y = 2.0;
    double result = subPixel(x, y, func);
    std::cout << "subPixel result: " << result << std::endl;
    std::cout << "sin(x*y) result: " << std::sin(x*y) << std::endl;
    return 0;
}

In the above example, we define a subPixelfunction that accepts two parameters x and y of type double, and a function pointer func to calculate the pixel value at (x, y) position. subPixelThe function splits the nine positions around (x, y) into sub-pixels, and the position of each sub-pixel is (x+i/3.0, y+j/3.0), where i and j take values ​​-1, 0 and 1 respectively . Then, the pixel value of each sub-pixel is passed to functhe function for processing, and finally the average value of the pixel values ​​of all sub-pixels is returned.

In the example, we have used a simple function functo demonstrate how to use subPixelfunctions. funcThe function calculates the value of sin(x*y). We can see that with sub-pixel algorithms, more accurate results can be obtained.

8. The sub-pixel algorithm is usually used for image interpolation processing to improve the accuracy and clarity of the image. The following is a simple sub-pixel algorithm example, the specific implementation may need to be modified according to actual needs:

#include <opencv2/opencv.hpp>

using namespace cv;

void subpixel(Mat& img, float x, float y, float& val)
{
    int ix = (int)x; // 获取坐标整数部分
    int iy = (int)y;
    float dx = x - ix; // 获取坐标小数部分
    float dy = y - iy;

    // 获取像素值
    float p00 = img.at<float>(iy, ix);
    float p01 = img.at<float>(iy, ix+1);
    float p10 = img.at<float>(iy+1, ix);
    float p11 = img.at<float>(iy+1, ix+1);

    // 双线性插值
    float val1 = (1-dx)*p00 + dx*p01;
    float val2 = (1-dx)*p10 + dx*p11;
    val = (1-dy)*val1 + dy*val2;
}

int main()
{
    Mat img = imread("test.png", IMREAD_GRAYSCALE);
    Mat img_f;
    img.convertTo(img_f, CV_32F);

    float x = 10.3; // 坐标可以是浮点数
    float y = 20.8;
    float val;
    subpixel(img_f, x, y, val);
    std::cout << "Value at (" << x << ", " << y << ") is " << val << std::endl;

    return 0;
}

The algorithm regards the pixel value of the image as a two-dimensional function, and calculates the pixel value whose coordinates are (x, y) through bilinear interpolation. Among them, (ix, iy) is the integer part of the coordinate, and (dx, dy) is the fractional part of the coordinate. When obtaining pixel values, directly use the OpenCV library function Mat::at<float>(row, col). Converting the image to float type can avoid pixel value overflow problem.

9. Sub-pixel algorithm is a technology that can improve image precision and clarity, and is widely used in image processing. Here is a simple C++ implementation:

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

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("lena.jpg");
    Mat dst;
    resize(img, dst, Size(), 0.5, 0.5, INTER_LINEAR);
    resize(dst, dst, Size(), 2.0, 2.0, INTER_LINEAR);

    imshow("Original Image", img);
    imshow("Interpolated Image", dst);

    waitKey(0);
    return 0;
}

This program uses the resize function from the OpenCV library. First, the original image is doubled, and then the reduced image is doubled, so that a sub-pixel image is obtained. Among them, the INTER_LINEAR parameter indicates the use of bilinear interpolation method, which is a commonly used sub-pixel algorithm.

10. Sub-pixel algorithm is an image processing technique used to improve image quality and details. The following is a simple subpixel algorithm implementation:

// 输入图像和亚像素位移
Mat subpixel(Mat img, float dx, float dy)
{
    int src_width = img.cols;
    int src_height = img.rows;
    Mat dst = Mat::zeros(src_height, src_width, img.type());
    for (int y = 0; y < src_height; y++)
    {
        for (int x = 0; x < src_width; x++)
        {
            float x1 = x + dx;
            float y1 = y + dy;
            if (x1 >= 0 && x1 <= src_width - 1 && y1 >= 0 && y1 <= src_height - 1)
            {
                int fx = floor(x1);
                int fy = floor(y1);
                float wx = x1 - fx;
                float wy = y1 - fy;
                if (fx + 1 < src_width && fy + 1 < src_height)
                {
                    dst.at<uchar>(y, x) = (1 - wx)*(1 - wy)*img.at<uchar>(fy, fx) + wx * (1 - wy)*img.at<uchar>(fy, fx + 1) + (1 - wx)*wy*img.at<uchar>(fy + 1, fx) + wx*wy*img.at<uchar>(fy + 1, fx + 1);
                }
            }
        }
    }
    return dst;
}

This function accepts an input image and floating-point parameters dx and dy, which represent the sub-pixel displacement in the x and y directions. This function uses a bilinear interpolation algorithm to compute a new subpixel image. This function returns the processed subpixel image.

11. The sub-pixel algorithm is mainly used for image enlargement or reduction in image processing. A simple sub-pixel algorithm implementation is given below:

Suppose there is an original image Img with height H and width W, and it is to be enlarged by k times, then the height of the new image is kH, and the width is kW. In order to obtain the value of each pixel in the new image, the following steps can be taken:

1. Split the value of each pixel in the original image into three components of RGB, and perform the following operations on R, G, and B respectively.

2. For each pixel, calculate its coordinates in the new image.

3. From this coordinate, calculate the coordinates of the four closest pixels to it in the original image.

4. Calculate the weight, which is the reciprocal of the distance between the original pixel closest to the pixel and its distance.

5. According to the weight, the weighted average of the four closest pixels is obtained to obtain the value of the pixel in the new image.

6. Recombine the three components of RGB to obtain the value of the pixel in the new image.

A simple code implementation is given below:

void subPixelScaling(Mat& src, Mat& dst, float scale) {
    int width = dst.cols;
    int height = dst.rows;
    int srcWidth = src.cols;
    int srcHeight = src.rows;
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // 计算该像素在原图像中的坐标
            float srcX = (float)x / scale;
            float srcY = (float)y / scale;
            // 计算在原图像中四个最近的像素
            int x1 = cvFloor(srcX);
            int y1 = cvFloor(srcY);
            int x2 = x1 + 1;
            int y2 = y1 + 1;
            // 判断是否越界
            if (x2 >= srcWidth) x2 = srcWidth - 1;
            if (y2 >= srcHeight) y2 = srcHeight - 1;
            // 计算权值
            float dx1 = fabs(srcX - x1);
            float dx2 = fabs(srcX - x2);
            float dy1 = fabs(srcY - y1);
            float dy2 = fabs(srcY - y2);
            float w1 = (1 - dx1) * (1 - dy1);
            float w2 = dx2 * (1 - dy1);
            float w3 = (1 - dx1) * dy2;
            float w4 = dx2 * dy2;
            // 取出四个像素,并计算加权平均
            Vec3b v1 = src.at<Vec3b>(y1, x1);
            Vec3b v2 = src.at<Vec3b>(y1, x2);
            Vec3b v3 = src.at<Vec3b>(y2, x1);
            Vec3b v4 = src.at<Vec3b>(y2, x2);
            Vec3b dstV;
            dstV[0] = w1 * v1[0] + w2 * v2[0] + w3 * v3[0] + w4 * v4[0];
            dstV[1] = w1 * v1[1] + w2 * v2[1] + w3 * v3[1] + w4 * v4[1];
            dstV[2] = w1 * v1[2] + w2 * v2[2] + w3 * v3[2] + w4 * v4[2];
            dst.at<Vec3b>(y, x) = dstV;
        }
    }
}

The code implements a simple sub-pixel algorithm, which reduces the original image to 1/scale, and then scales it up to achieve sub-pixel processing of the image.

Advanced sub-pixel algorithm (Super Resolution Algorithm) is a technology that uses multiple low-resolution images to generate high-resolution images. The following is a common high-level subpixel algorithm:

  1. Image alignment: Align multiple low-resolution images such that their feature points coincide.

  2. Image preprocessing: Preprocessing each low-resolution image, such as denoising, enhancement, etc.

  3. Feature extraction: Extract feature information from each low-resolution image, such as edges, corners, textures, etc.

  4. Reconstruction: Use feature information to generate high-resolution images, which can be reconstructed using interpolation algorithms, convolutional neural networks, and other methods.

  5. Merge: Merge the generated multiple high-resolution images to obtain the final high-resolution image.

These steps can be adjusted and optimized on a case-by-case basis to improve the performance and speed of reconstruction.

12. The following is an example of a simple advanced sub-pixel algorithm, using bilinear interpolation:

#include <iostream>
#include <vector>

using namespace std;

// 二维向量
struct Vec2f {
    float x, y;
    Vec2f(float x = 0, float y = 0) : x(x), y(y) {}
};

// 双线性插值
float bilinear_interp(float x, float y, float q11, float q12, float q21, float q22) {
    float r1 = (q21 - q11) * x + q11;
    float r2 = (q22 - q12) * x + q12;
    return (r2 - r1) * y + r1;
}

// 高级亚像素算法
void super_sampling(vector<vector<float>>& img, int sampling_rate) {
    int num_rows = img.size();
    int num_cols = img[0].size();
    vector<vector<float>> new_img(num_rows * sampling_rate, vector<float>(num_cols * sampling_rate));
    for (int i = 0; i < num_rows - 1; ++i) {
        for (int j = 0; j < num_cols - 1; ++j) {
            float q11 = img[i][j];
            float q12 = img[i][j + 1];
            float q21 = img[i + 1][j];
            float q22 = img[i + 1][j + 1];
            for (int m = 0; m < sampling_rate; ++m) {
                for (int n = 0; n < sampling_rate; ++n) {
                    float x = m / static_cast<float>(sampling_rate);
                    float y = n / static_cast<float>(sampling_rate);
                    float new_val = bilinear_interp(x, y, q11, q12, q21, q22);
                    new_img[i * sampling_rate + m][j * sampling_rate + n] = new_val;
                }
            }
        }
    }
    img = new_img;
}

int main() {
    // 示例
    vector<vector<float>> img = {
   
   {1, 2}, {3, 4}};
    cout << "原始图像:" << endl;
    for (auto row : img) {
        for (auto val : row) {
            cout << val << " ";
        }
        cout << endl;
    }

    super_sampling(img, 3);
    cout << "高级亚像素算法后的图像:" << endl;
    for (auto row : img) {
        for (auto val : row) {
            cout << val << " ";
        }
        cout << endl;
    }
    return 0;
}

The functions in this example  super_sampling implement advanced subpixel algorithms that double the resolution of the input image  sampling_rate . Inside this function, the algorithm calculates the value of each pixel in the new image via bilinear interpolation. Finally, the function returns the new image.

It should be noted that this example is not complete, it is just an example demonstrating how to implement advanced sub-pixel algorithms, and you need to modify and improve it according to your actual needs.

13. The following is a simple advanced sub-pixel algorithm that can help you achieve higher quality image rotation, scaling, etc.:

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

using namespace std;
using namespace cv;

void subpixel(Mat& src, float x, float y, float& value)
{
    int px = floor(x);
    int py = floor(y);
    float fx = x - px;
    float fy = y - py;
    float a = src.at<float>(py, px);
    float b = src.at<float>(py, px+1);
    float c = src.at<float>(py+1, px);
    float d = src.at<float>(py+1, px+1);
    float m1 = a + fx * (b - a);
    float m2 = c + fx * (d - c);
    value = m1 + fy * (m2 - m1);
}

void warpAffine_subpixel(Mat& src, Mat& dst, Mat& M)
{
    Mat M_inv = M.inv();
    int width = dst.cols;
    int height = dst.rows;
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            float u = M_inv.at<float>(0, 0) * x + M_inv.at<float>(0, 1) * y + M_inv.at<float>(0, 2);
            float v = M_inv.at<float>(1, 0) * x + M_inv.at<float>(1, 1) * y + M_inv.at<float>(1, 2);
            float value;
            subpixel(src, u, v, value);
            dst.at<float>(y, x) = value;
        }
    }
}

int main(int argc, char** argv)
{
    Mat src = imread("input.jpg", IMREAD_GRAYSCALE);
    Mat dst(512, 512, CV_32F);
    Mat M = (Mat_<float>(2, 3) << 1.5, 0.3, 10, -0.3, 1.5, 20);
    warpAffine_subpixel(src, dst, M);
    imwrite("output.jpg", dst);
    return 0;
}

The main steps of the algorithm are as follows:

1. First  warpAffine perform affine transformation through the function to transform the input image to the target image.

2. For the position of each pixel on the target image, calculate the corresponding position on the input image by inverse affine transformation.

3. Use  subpixel the function to perform sub-pixel interpolation on the position on the input image to obtain the gray value of the pixel on the target image.

4. Save the gray value of each pixel on the target image to the output image.

The combination of these steps enables advanced sub-pixel algorithms.

14. The following is a simple C++ implementation of an advanced sub-pixel algorithm for improving image quality and sharpness:

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

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        cout << "Usage: " << argv[0] << " <image path>" << endl;
        return -1;
    }

    Mat src, dst;
    src = imread(argv[1], IMREAD_COLOR);

    if (src.empty())
    {
        cout << "Unable to open image file: " << argv[1] << endl;
        return -1;
    }

    // 将图像缩小 4 倍
    resize(src, dst, Size(), 0.25, 0.25, INTER_LINEAR);

    // 对缩小后的图像进行双三次插值
    resize(dst, dst, Size(), 4.0, 4.0, INTER_CUBIC);

    // 对缩小后的图像进行锐化操作
    Mat kernel = (Mat_<float>(3,3) << -1, -1, -1, -1, 9, -1, -1, -1, -1);
    filter2D(dst, dst, -1, kernel);

    // 显示结果
    namedWindow("Input Image", WINDOW_AUTOSIZE);
    namedWindow("Output Image", WINDOW_AUTOSIZE);
    imshow("Input Image", src);
    imshow("Output Image", dst);
    waitKey();

    return 0;
}

The algorithm takes the following steps:

  1. The original image is reduced to 1/4 of its original size, making the sub-pixel information more obvious.
  2. Bicubic interpolation is performed on the downscaled image to restore its original size.
  3. Sharpen the reduced image to make details clearer.
  4. Display the output.

Note: This is just a simple implementation, in fact there are more advanced sub-pixel algorithms, such as Super Resolution.

15. The following is a code example of a simple advanced sub-pixel algorithm:

#include <opencv2/opencv.hpp>

using namespace cv;

int main() {
    Mat img = imread("input.jpg");
    Mat img_upscaled, img_downscaled;

    resize(img, img_upscaled, Size(), 2, 2, INTER_LINEAR);
    resize(img_upscaled, img_downscaled, Size(), 0.5, 0.5, INTER_LINEAR);

    Mat img_subpix;
    img_downscaled.convertTo(img_subpix, CV_32FC3);

    Mat blurred;
    GaussianBlur(img_subpix, blurred, Size(0, 0), 2);

    Mat img_sharp;
    addWeighted(img_subpix, 1.5, blurred, -0.5, 0, img_sharp);

    Mat img_out;
    img_sharp.convertTo(img_out, CV_8UC3);

    imshow("Output", img_out);
    waitKey(0);
}

This algorithm achieves advanced subpixelation through the following steps:

  1. Upsample the image by a factor of two.
  2. Downsamples the upsampled image by a factor of one.
  3. Convert the downsampled image to float.
  4. Gaussian blurs the transformed image.
  5. The Gaussian blurred image and the original image are weighted and averaged to produce a sharpening effect.
  6. Convert the sharpened image back to an 8-bit unsigned integer type.
  7. Output the sharpened image.

This algorithm uses the OpenCV library. It can be used in the C++ programming language.

16. The following is a C++ source code example of a simple advanced sub-pixel algorithm that can implement bilinear interpolation:

#include <iostream>
#include <cmath>

using namespace std;

// 定义一个包含 RGBA 值的像素结构体
typedef struct Pixel {
    unsigned char r, g, b, a;
} Pixel;

// 获取矩阵中指定索引位置的值
double get_value(double *matrix, int width, int x, int y) {
    int index = y * width + x;
    return matrix[index];
}

// 设置矩阵中指定索引位置的值
void set_value(double *matrix, int width, int x, int y, double value) {
    int index = y * width + x;
    matrix[index] = value;
}

// 双线性插值函数
Pixel bilinear_interpolation(Pixel *image, int width, int height, double x, double y) {
    Pixel p;
    int x1 = (int) floor(x);
    int x2 = (int) ceil(x);
    int y1 = (int) floor(y);
    int y2 = (int) ceil(y);

    double alpha = x - x1;
    double beta = y - y1;

    double matrix_r[4];
    double matrix_g[4];
    double matrix_b[4];

    // 将矩阵中的四个值初始化为相应位置的颜色值
    set_value(matrix_r, 2, 0, 0, image[y1 * width + x1].r);
    set_value(matrix_r, 2, 1, 0, image[y1 * width + x2].r);
    set_value(matrix_r, 2, 0, 1, image[y2 * width + x1].r);
    set_value(matrix_r, 2, 1, 1, image[y2 * width + x2].r);

    set_value(matrix_g, 2, 0, 0, image[y1 * width + x1].g);
    set_value(matrix_g, 2, 1, 0, image[y1 * width + x2].g);
    set_value(matrix_g, 2, 0, 1, image[y2 * width + x1].g);
    set_value(matrix_g, 2, 1, 1, image[y2 * width + x2].g);

    set_value(matrix_b, 2, 0, 0, image[y1 * width + x1].b);
    set_value(matrix_b, 2, 1, 0, image[y1 * width + x2].b);
    set_value(matrix_b, 2, 0, 1, image[y2 * width + x1].b);
    set_value(matrix_b, 2, 1, 1, image[y2 * width + x2].b);

    // 计算插值结果
    double r = (1 - alpha) * (1 - beta) * get_value(matrix_r, 2, 0, 0) +
               alpha * (1 - beta) * get_value(matrix_r, 2, 1, 0) +
               (1 - alpha) * beta * get_value(matrix_r, 2, 0, 1) +
               alpha * beta * get_value(matrix_r, 2, 1, 1);

    double g = (1 - alpha) * (1 - beta) * get_value(matrix_g, 2, 0, 0) +
               alpha * (1 - beta) * get_value(matrix_g, 2, 1, 0) +
               (1 - alpha) * beta * get_value(matrix_g, 2, 0, 1) +
               alpha * beta * get_value(matrix_g, 2, 1, 1);

    double b = (1 - alpha) * (1 - beta) * get_value(matrix_b, 2, 0, 0) +
               alpha * (1 - beta) * get_value(matrix_b, 2, 1, 0) +
               (1 - alpha) * beta * get_value(matrix_b, 2, 0, 1) +
               alpha * beta * get_value(matrix_b, 2, 1, 1);

    p.r = (unsigned char) r;
    p.g = (unsigned char) g;
    p.b = (unsigned char) b;
    p.a = 255;

    return p;
}

int main() {
    // 定义测试图像的像素数组
    Pixel image[] = {
            {255, 0,   0,   255}, {0,   255, 0,   255}, {0,   0,   255, 255},
            {0,   255, 0,   255}, {255, 0,   0,   255}, {0,   255, 0,   255},
            {0,   0,   255, 255}, {0,   255, 0,   255}, {255, 0,   0,   255},
    };

    // 定义测试图像的尺寸
    int width = 3;
    int height = 3;

    // 将图像放大两倍,并进行插值
    int new_width = width * 2;
    int new_height = height * 2;
    Pixel new_image[new_width * new_height];
    for (int y = 0; y < new_height; y++) {
        for (int x = 0; x < new_width; x++) {
            double src_x = ((double) x) / 2.0;
            double src_y = ((double) y) / 2.0;
            Pixel p = bilinear_interpolation(image, width, height, src_x, src_y);
            new_image[y * new_width + x] = p;
            cout << "(" << (int) p.r << "," << (int) p.g << "," << (int) p.b << ") ";
        }
        cout << endl;
    }

    return 0;
}

This example doubles the original image size and uses bilinear interpolation to calculate new pixels to fill in missing pixel values.

Guess you like

Origin blog.csdn.net/weixin_56819992/article/details/130680236