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;
相关推荐
Elastic 中国社区官方博客3 分钟前
使用 Azure SRE Agent 和 Elasticsearch 提升 SRE 生产力
大数据·人工智能·elasticsearch·microsoft·搜索引擎·云原生·azure
發糞塗牆5 分钟前
【Azure 架构师学习笔记 】- Azure AI(19) - Agent升级增强
人工智能·ai·azure
luoganttcc6 小时前
自动驾驶 世界模型 有哪些(二)
人工智能·机器学习·自动驾驶
人工智能AI技术6 小时前
315曝光AI投毒!用C#构建GEO污染检测与数据安全防护方案
人工智能·c#
Hamm6 小时前
不想花一分钱玩 OpenClaw?来,一起折腾这个!
javascript·人工智能·agent
_李小白7 小时前
【AI大模型学习笔记之平台篇】第二篇:Gemini
人工智能·音视频
一点一木7 小时前
🚀 2026 年 2 月 GitHub 十大热门项目排行榜 🔥
人工智能·github
理性的曜7 小时前
VoloData——基于LangChain的智能数据分析系统
人工智能·vscode·数据分析·npm·reactjs·fastapi·ai应用
flying_13147 小时前
图神经网络分享系列-MPNN(Neural Message Passing for Quantum Chemistry)(二)
人工智能·深度学习·神经网络·图神经网络·消息传递·门控机制·mpnn
HyperAI超神经7 小时前
AI驱动量子精修,卡内基梅隆大学等提出AQuaRef,首次用量子力学约束精修蛋白质全原子模型
人工智能·深度学习·机器学习·架构·机器人·cpu·量子计算