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;
相关推荐
明月_清风7 分钟前
用自然语言操控真机:Google Artemis 移动端 AI Agent 上手与实践
人工智能·后端
没落之王9 分钟前
三易五行看宋朝的三界确立
大数据·人工智能·算法
miofly18 分钟前
DeepSeek 开源 Super-agent 架构:AI 主动发现 Bug 并提交 PR
人工智能
kyrie_sakura23 分钟前
大模型学习20 大模型学习 - LangChain3 - Agents
人工智能·学习·langchain
zhangfeng113327 分钟前
2026 书生国智科探挑战赛暨飞翔杯 AI Agent/Skills 开发大赛全景介绍
人工智能
DevMemo42 分钟前
2026 AI外呼系统技术选型:全链路延迟预算与集成成本实测,10个品牌的架构真相
人工智能·架构
ZhuoAIStage1 小时前
契约与闸门打架该改谁?用 AI 智能体 preflight 把配置漂移挡在发版前——以舞台工艺审图专家包闸门冲突为例
人工智能·闸门·舞台工艺·配置漂移·专家包·preflight
Flynn Liang1 小时前
大模型怎么自己调函数?Spring AI 2.0 Tool Calling 自动循环原理 + 完整时序图
java·人工智能·spring·agent·函数调用·springai·toolcalling
深频率1 小时前
苹果AI入华:11月4日开测,千问只是个选项
人工智能