OpenCV 之双线性插值

一、线性插值

https://blog.csdn.net/sinat_29957455/article/details/104584744

我们可以求出直线的方程,然后将x xx坐标代入到方程就可以求出对应的y yy值,通过直线方程的两点式可以得到

https://blog.csdn.net/sinat_29957455/article/details/104584744

二、双线性插值

双线性插值是:

在 x 方向做一次线性插值 +

在 y 方向再做一次线性插值。

1)坐标反变换(scale / affine 等)

2)找到左上整数网格像素

3)计算小数部分(偏移)

4)计算四个像素的权重

5)四邻域加权求和(真正计算)

案例说明:

三、流程

流程总览(工程版)

给定目标图像坐标 (x′,y′),求其在原图像的对应采样点:

  1. 坐标缩放反变换

  2. 找到左上整数像素 (i, j)

  3. 计算小数部分 a, b

  4. 计算 4 个像素的权重

  5. 加权求和

四、Matlab 与Opencv

matlab:

cs 复制代码
function I2 = bilinear_opencv(I, scale)

I = double(I);
[h, w] = size(I);

H = round(h * scale);
W = round(w * scale);

I2 = zeros(H, W);

for y2 = 1:H
    for x2 = 1:W
        
        % 1) 坐标反变换
        x = x2 / scale;
        y = y2 / scale;
        
        % 2) 找到整数网格
        i = floor(x);
        j = floor(y);
        
        % 边界处理
        if i < 1, i = 1; end
        if j < 1, j = 1; end
        if i > w-1, i = w-1; end
        if j > h-1, j = h-1; end
        
        % 3) 小数部分
        a = x - i;
        b = y - j;
        
        % 4) 权重
        w00 = (1-a)*(1-b);
        w10 = a*(1-b);
        w01 = (1-a)*b;
        w11 = a*b;
        
        % 5) 加权求和
        I2(y2,x2) = ...
            I(j,  i)   * w00 + ...
            I(j,  i+1) * w10 + ...
            I(j+1,i)   * w01 + ...
            I(j+1,i+1) * w11;
    end
end

I2 = uint8(I2);
end
cpp 复制代码
clc; clear; close all;

I = imread('abc.bmp');   % 灰度图
scale = 2;

I2 = bilinear_opencv(I, scale);
I_matlab = imresize(I, scale, 'bilinear');

figure;
subplot(1,3,1); imshow(I); title('原图');
subplot(1,3,2); imshow(I2); title('自己实现(OpenCV 版)');
subplot(1,3,3); imshow(I_matlab); title('MATLAB bilinear');

opencv

cpp 复制代码
void bilinearInterpolation(Mat& src, Mat& dst, double sx, double sy) {
    int dst_rows = static_cast<int>(src.rows * sy);
    int dst_cols = static_cast<int>(src.cols * sx);
    dst = Mat::zeros(cv::Size(dst_cols, dst_rows), src.type());

    dst.forEach<Pixel>([&](Pixel& p, const int* position) -> void {

        int row = position[0];
        int col = position[1];

        // (col,row)为目标图像坐标
        // (before_x,before_y)原图坐标
        double before_x = double(col + 0.5) / sx - 0.5f;
        double before_y = double(row + 0.5) / sy - 0.5;
        // 原图像坐标四个相邻点
        // 获得变换前最近的四个顶点,取整
        int top_y = static_cast<int>(before_y);
        int bottom_y = top_y + 1;
        int left_x = static_cast<int>(before_x);
        int right_x = left_x + 1;

        //计算变换前坐标的小数部分
        double u = before_x - left_x;
        double v = before_y - top_y;

        // 如果计算的原始图像的像素大于真实原始图像尺寸
        if ((top_y >= src.rows - 1) && (left_x >= src.cols - 1)) {//右下角
            for (size_t k = 0; k < src.channels(); k++) {
                dst.at<Vec3b>(row, col)[k] = (1. - u) * (1. - v) * src.at<Vec3b>(top_y, left_x)[k];
            }
        }
        else if (top_y >= src.rows - 1) { //最后一行
            for (size_t k = 0; k < src.channels(); k++) {
                dst.at<Vec3b>(row, col)[k]
                    = (1. - u) * (1. - v) * src.at<Vec3b>(top_y, left_x)[k]
                    + (1. - v) * u * src.at<Vec3b>(top_y, right_x)[k];
            }
        }
        else if (left_x >= src.cols - 1) {//最后一列
            for (size_t k = 0; k < src.channels(); k++) {
                dst.at<Vec3b>(row, col)[k]
                    = (1. - u) * (1. - v) * src.at<Vec3b>(top_y, left_x)[k]
                    + (v) * (1. - u) * src.at<Vec3b>(bottom_y, left_x)[k];
            }
        }
        else {
            for (size_t k = 0; k < src.channels(); k++) {
                dst.at<Vec3b>(row, col)[k]
                    = (1. - u) * (1. - v) * src.at<Vec3b>(top_y, left_x)[k]
                    + (1. - v) * (u)*src.at<Vec3b>(top_y, right_x)[k]
                    + (v) * (1. - u) * src.at<Vec3b>(bottom_y, left_x)[k]
                    + (u) * (v)*src.at<Vec3b>(bottom_y, right_x)[k];
            }
        }
        });
}
cpp 复制代码
		Mat img = imread("D:\\matlabplace\\abc.bmp");
		if (img.empty()) return -1;

		Mat out;
		double scale = 2.0;

		resize(img, out, Size(), scale, scale, INTER_LINEAR);

		imshow("original", img);
		imshow("bilinear resize", out);
		waitKey(0);
		return 0;
相关推荐
一点一木1 小时前
深度体验TRAE SOLO移动端7天:作为独立开发者,我把工作流揣进了兜里
前端·人工智能·trae
Lee川2 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
weelinking2 小时前
【产品】00_产品经理用Claude实现产品系列介绍
数据库·人工智能·sql·数据挖掘·github·产品经理
Agent产品评测局2 小时前
制造业模具管理AI系统,主流产品能力对比详解:2026年智能制造选型深度洞察
人工智能·ai·chatgpt·制造
研华科技Advantech3 小时前
如何用一套实训设备,打通工业AI预测性维护技术全流程?
人工智能
Lab_AI3 小时前
AI for Science: MaXFlow AI Agent+ 报告体验双升级,让AI智能体更高效易用!
人工智能·ai for science·ai agent·ai智能体
李坤3 小时前
让 Codex 和 Claude 互相 Review:告别手动复制
人工智能·openai·claude
南屹川4 小时前
【API设计】GraphQL实战:从REST到GraphQL的演进
人工智能
KJ_BioMed4 小时前
当计算生物学遇上生成式AI:从头设计生物分子的“新范式”初探
人工智能·从头设计·生命科学·生物医药·科研干货·科晶生物
明月醉窗台4 小时前
深度学习(17)YOLO训练中的超参数详解
人工智能·深度学习·yolo