Algoritmo de subpíxeles (código fuente comercial, me gusta y recopilar)

Los algoritmos de subpíxeles son algoritmos para el procesamiento de imágenes a nivel de píxeles. Un algoritmo de subpíxel común es la interpolación bilineal,
que se puede utilizar para operaciones como el escalado y la rotación de imágenes.

1. Los algoritmos de subpíxeles generalmente se usan para operaciones de interpolación en el procesamiento de imágenes, lo que puede mejorar la precisión de las imágenes. El siguiente es un algoritmo de subpíxel de interpolación bilineal simple, puede consultarlo:

#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;
}

Entre ellos, x e y son los valores de las coordenadas, y q11, q12, q21 y q22 son los valores de píxel de los cuatro puntos a interpolar. El algoritmo convierte las coordenadas x e y en partes fraccionarias y luego realiza cálculos de interpolación bilineal para obtener valores de subpíxeles correspondientes a las coordenadas x e y.

2. La siguiente es la implementación de un algoritmo de interpolación bilineal simple, que se utiliza para escalar la imagen original de acuerdo con un factor de escala dado:

#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;
}

Esta función toma una imagen de origen y una escala y devuelve una nueva imagen escalada por la escala. La función recorre cada píxel de la nueva imagen y calcula su posición correspondiente en la imagen original. Luego, el valor del nuevo píxel se calcula mediante un algoritmo de interpolación bilineal y se escribe en la imagen de destino. Finalmente, la función devuelve la imagen de destino.

Cabe señalar que este algoritmo es solo un ejemplo simple y es posible que no satisfaga todas las necesidades. En el uso real, es posible que deba ajustarse y mejorarse según los escenarios de aplicación específicos.

3. El algoritmo de subpíxel generalmente se usa para ampliar o reducir la imagen para mejorar la claridad y la calidad de la imagen. Aquí hay un ejemplo de un algoritmo de subpíxel simple:

// 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)
                );
            }
        }
    }
}

El algoritmo asume que tanto la imagen de origen como la imagen de destino son de tres canales (R, G, B), calcula cada canal por separado y luego los combina en los píxeles de la imagen de destino. En este algoritmo, para cada píxel en la imagen de destino, primero calcula la posición del píxel correspondiente en la imagen de origen en forma de número entero, luego calcula la diferencia entre este píxel y los píxeles que lo rodean, y calcula cada píxel del píxel de destino por la siguiente fórmula Valor del canal:

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)

Entre ellos, x_diff e y_diff son partes fraccionarias que indican el desplazamiento del píxel de destino en relación con el píxel de origen. Utilice la fórmula anterior para calcular el valor de píxel de cada canal.

4. El algoritmo de subpíxel es para interpolar los puntos de píxel de la imagen para obtener una imagen más fina.Existen muchos tipos de algoritmos, como la interpolación bilineal, la interpolación bicúbica, etc. Aquí le proporciono un código de muestra de un algoritmo de subpíxel para interpolación bilineal:

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;
}

En el código anterior, el tipo Mat en la biblioteca opencv se usa para almacenar la imagen. El parámetro de entrada img de la función es la imagen que se interpolará en subpíxeles, y xey son las coordenadas de píxeles que se interpolarán. En la función, primero calcule las coordenadas de los cuatro píxeles más cercanos al píxel objetivo y juzgue si estos píxeles están fuera de los límites. Luego, calcule el valor de píxel del píxel de destino de acuerdo con la fórmula de interpolación bilineal y, finalmente, devuelva el resultado del cálculo.

Nota: este algoritmo es solo un código de muestra y la aplicación específica debe ajustarse y optimizarse de acuerdo con la situación real.

5. El algoritmo de subpíxel es una técnica para interpolar imágenes, que puede mejorar la claridad y la calidad de las imágenes. Aquí hay un algoritmo de subpíxel simple:

Supongamos que hay una imagen de tamaño nxm, y para reducirla a la mitad (es decir, convertirla en una imagen de tamaño n/2xm/2), puedes seguir los siguientes pasos:

  1. Defina una nueva imagen de tamaño nx/2xm/2.

  2. Para cada píxel de la nueva imagen, calcule las coordenadas de sus cuatro vecinos en la imagen original.

  3. Para cada píxel, calcule la parte fraccionaria de su posición en la imagen original, es decir, calcule la distancia relativa de los cuatro píxeles más cercanos.

  4. Usando un algoritmo de interpolación bilineal, calcule el valor de un nuevo píxel en función de los valores y las distancias relativas de los cuatro píxeles calculados en el paso anterior.

  5. Almacene el valor calculado en la ubicación de píxel correspondiente en la nueva imagen.

  6. Repita los pasos 2 a 5 hasta que se hayan calculado todos los valores de píxeles en la nueva imagen.

Para una implementación específica, consulte el siguiente fragmento de código:

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();
}

Esta es una implementación de algoritmo de subpíxel simple. Si necesita una interpolación de imagen de mayor calidad, puede considerar usar algoritmos más complejos, como la interpolación bicúbica.

6. El objetivo principal del algoritmo de interpolación de subpíxeles es mejorar la resolución de la imagen y hacer que se vea más clara. La siguiente es una implementación de un algoritmo de interpolación de subpíxel simple:

#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;
}

En esta implementación, primero calculamos los cuatro puntos adyacentes de x e y mediante las funciones suelo y techo: (x1,y1), (x1,y2), (x2,y1) y (x2,y2). Luego calculamos las compensaciones de x e y desde su punto de esquina inferior izquierda más cercano (x1, y1): frac_x y frac_y. A continuación, usamos estos valores para calcular los valores interpolados finales de la siguiente manera:

  1. Calcule R1 = I11 * (1 - frac_x) + I12 * frac_x interpolando I11 e I12.
  2. Use I21 e I22 para el cálculo de interpolación R2 = I21 * (1 - frac_x) + I22 * frac_x.
  3. Interpolar R1 y R2 para calcular el resultado final: R = R1 * (1 - frac_y) + R2 * frac_y.

Finalmente, podemos usar esta función para interpolar en cualquier parte de la imagen, no solo en coordenadas enteras.

7. El algoritmo de subpíxeles se usa a menudo en el procesamiento de imágenes. Puede dividir un píxel en subpíxeles más pequeños para el procesamiento, lo que mejora la precisión del procesamiento de imágenes.

Aquí hay un ejemplo de una implementación de algoritmo de subpíxel simple:

#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;
}

En el ejemplo anterior, definimos una subPixelfunción que acepta dos parámetros x e y de tipo doble, y una función de puntero de función para calcular el valor del píxel en la posición (x, y). subPixelLa función divide las nueve posiciones alrededor de (x, y) en subpíxeles, y la posición de cada subpíxel es (x+i/3.0, y+j/3.0), donde i y j toman valores -1 , 0 y 1 respectivamente . Luego, el valor de píxel de cada subpíxel se pasa a funcla función para su procesamiento y, finalmente, se devuelve el valor promedio de los valores de píxel de todos los subpíxeles.

En el ejemplo, hemos usado una función simple funcpara demostrar cómo usar subPixellas funciones. funcLa función calcula el valor de sin(x*y). Podemos ver que con los algoritmos de subpíxeles se pueden obtener resultados más precisos.

8. El algoritmo de subpíxel generalmente se usa para el procesamiento de interpolación de imágenes para mejorar la precisión y claridad de la imagen. El siguiente es un ejemplo simple de algoritmo de subpíxel, es posible que la implementación específica deba modificarse de acuerdo con las necesidades reales:

#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;
}

El algoritmo considera el valor de píxel de la imagen como una función bidimensional y calcula el valor de píxel cuyas coordenadas son (x, y) mediante interpolación bilineal. Entre ellos, (ix, iy) es la parte entera de la coordenada y (dx, dy) es la parte fraccionaria de la coordenada. Al obtener valores de píxeles, use directamente la función de biblioteca OpenCV Mat::at<float>(fila, columna). Convertir la imagen a tipo flotante puede evitar el problema de desbordamiento del valor de píxel.

9. El algoritmo de subpíxel es una tecnología que puede mejorar la precisión y claridad de la imagen y se usa ampliamente en el procesamiento de imágenes. Aquí hay una implementación simple de C++:

#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;
}

Este programa utiliza la función de cambio de tamaño de la biblioteca OpenCV. En primer lugar, se duplica la imagen original y luego se duplica la imagen reducida, de modo que se obtiene una imagen de subpíxeles. Entre ellos, el parámetro INTER_LINEAR indica el uso del método de interpolación bilineal, que es un algoritmo de subpíxel de uso común.

10. El algoritmo de subpíxel es una técnica de procesamiento de imágenes que se utiliza para mejorar la calidad y los detalles de la imagen. La siguiente es una implementación simple del algoritmo de subpíxeles:

// 输入图像和亚像素位移
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;
}

Esta función acepta una imagen de entrada y parámetros de coma flotante dx y dy, que representan el desplazamiento de subpíxeles en las direcciones x e y. Esta función utiliza un algoritmo de interpolación bilineal para calcular una nueva imagen de subpíxeles. Esta función devuelve la imagen de subpíxel procesada.

11. El algoritmo de subpíxeles se utiliza principalmente para ampliar o reducir imágenes en el procesamiento de imágenes. A continuación se muestra una implementación simple del algoritmo de subpíxeles:

Supongamos que hay una imagen original Img con altura H y ancho W, y se va a ampliar k veces, entonces la altura de la nueva imagen es kH y el ancho es kW. Para obtener el valor de cada píxel en la nueva imagen se pueden seguir los siguientes pasos:

1. Divida el valor de cada píxel de la imagen original en tres componentes de RGB y realice las siguientes operaciones en R, G y B respectivamente.

2. Para cada píxel, calcule sus coordenadas en la nueva imagen.

3. A partir de esta coordenada, calcule las coordenadas de los cuatro píxeles más cercanos a ella en la imagen original.

4. Calcule el peso, que es el recíproco de la distancia entre el píxel original más cercano al píxel y su distancia.

5. Según el peso se obtiene la media ponderada de los cuatro píxeles más cercanos para obtener el valor del píxel en la nueva imagen.

6. Recombinar los tres componentes de RGB para obtener el valor del píxel en la nueva imagen.

A continuación se muestra una implementación de código simple:

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;
        }
    }
}

El código implementa un algoritmo de subpíxeles simple, que reduce la imagen original a 1/escala, y luego la amplía para lograr el procesamiento de subpíxeles de la imagen.

El algoritmo avanzado de subpíxeles (algoritmo de superresolución) es una tecnología que utiliza múltiples imágenes de baja resolución para generar imágenes de alta resolución. El siguiente es un algoritmo común de subpíxeles de alto nivel:

  1. Alineación de imágenes: alinee múltiples imágenes de baja resolución de modo que sus puntos característicos coincidan.

  2. Preprocesamiento de imágenes: preprocesamiento de cada imagen de baja resolución, como eliminación de ruido, mejora, etc.

  3. Extracción de características: extraiga información de características de cada imagen de baja resolución, como bordes, esquinas, texturas, etc.

  4. Reconstrucción: use información de características para generar imágenes de alta resolución, que se pueden reconstruir mediante algoritmos de interpolación, redes neuronales convolucionales y otros métodos.

  5. Combinar: combine las múltiples imágenes de alta resolución generadas para obtener la imagen final de alta resolución.

Estos pasos se pueden ajustar y optimizar caso por caso para mejorar el rendimiento y la velocidad de la reconstrucción.

12. El siguiente es un ejemplo de un algoritmo de subpíxel avanzado simple, que usa interpolación bilineal:

#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;
}

Las funciones de este ejemplo  super_sampling implementan algoritmos avanzados de subpíxeles que duplican la resolución de la imagen de entrada  sampling_rate . Dentro de esta función, el algoritmo calcula el valor de cada píxel en la nueva imagen mediante interpolación bilineal. Finalmente, la función devuelve la nueva imagen.

Cabe señalar que este ejemplo no está completo, es solo un ejemplo que demuestra cómo implementar algoritmos avanzados de subpíxeles, y debe modificarlo y mejorarlo de acuerdo con sus necesidades reales.

13. El siguiente es un algoritmo de subpíxel avanzado simple que puede ayudarlo a lograr una rotación de imagen de mayor calidad, escalado, 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;
}

Los pasos principales del algoritmo son los siguientes:

1. Primero  warpAffine realice una transformación afín a través de la función para transformar la imagen de entrada en la imagen de destino.

2. Para la posición de cada píxel en la imagen de destino, calcule la posición correspondiente en la imagen de entrada mediante transformación afín inversa.

3. Utilice  subpixel la función para realizar una interpolación de subpíxeles en la posición de la imagen de entrada para obtener el valor de gris del píxel en la imagen de destino.

4. Guarde el valor de gris de cada píxel en la imagen de destino en la imagen de salida.

La combinación de estos pasos permite algoritmos avanzados de subpíxeles.

14. La siguiente es una implementación simple en C++ de un algoritmo avanzado de subpíxeles para mejorar la calidad y la nitidez de la imagen:

#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;
}

El algoritmo sigue los siguientes pasos:

  1. La imagen original se reduce a 1/4 de su tamaño original, lo que hace que la información de los subpíxeles sea más evidente.
  2. La interpolación bicúbica se realiza en la imagen reducida para restaurar su tamaño original.
  3. Enfoca la imagen reducida para que los detalles sean más claros.
  4. Muestre la salida.

Nota: Esta es solo una implementación simple, de hecho, existen algoritmos de subpíxeles más avanzados, como Super Resolución.

15. El siguiente es un ejemplo de código de un algoritmo de subpíxel avanzado simple:

#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);
}

Este algoritmo logra una subpixelación avanzada a través de los siguientes pasos:

  1. Muestrear la imagen por un factor de dos.
  2. Reduce la muestra de la imagen aumentada por un factor de uno.
  3. Convierta la imagen reducida en flotante.
  4. Gaussian desenfoca la imagen transformada.
  5. La imagen borrosa gaussiana y la imagen original se ponderan y promedian para producir un efecto de nitidez.
  6. Convierta la imagen afilada de nuevo a un tipo de entero sin signo de 8 bits.
  7. Salida de la imagen nítida.

Este algoritmo utiliza la biblioteca OpenCV. Se puede utilizar en el lenguaje de programación C++.

16. El siguiente es un ejemplo de código fuente C++ de un algoritmo de subpíxel avanzado simple que puede implementar la interpolación bilineal:

#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;
}

Este ejemplo duplica el tamaño de la imagen original y utiliza la interpolación bilineal para calcular nuevos píxeles para completar los valores de píxeles que faltan.

Supongo que te gusta

Origin blog.csdn.net/weixin_56819992/article/details/130680236
Recomendado
Clasificación