【C++】双线性差值算法实现RGB图像缩放

23 篇文章 1 订阅

双线性差值算法

双线性插值(Bilinear Interpolation)并不是“双线性差值”,它是一种在二维平面上估计未知数据点的方法,通常用于图像处理中的图像缩放。

双线性插值的基本思想是:对于一个未知的数据点,我们找到其最近的4个已知数据点,然后根据这4个已知数据点的值以及它们与未知数据点的距离,来估计未知数据点的值。

具体到图像处理中,如果我们想要将一个图像从一个尺寸放大或缩小到另一个尺寸,我们可以使用双线性插值来估计新尺寸下每个像素点的颜色值。

以下是双线性插值的数学公式:

设我们要估计的点为P(x,y),其最近的4个已知点为A(x0,y0),B(x1,y0),C(x0,y1),D(x1,y1),则P点的值I_P可以表示为:

I_P = I_A * (x1-x)(y1-y) + I_B * (x-x0)(y1-y) + I_C * (x1-x)(y-y0) + I_D * (x-x0)(y-y0)

其中,I_A,I_B,I_C,I_D分别为A,B,C,D点的值。

在实际应用中,我们通常会使用浮点数来表示x和y,这样可以得到更精确的结果。但是,由于x和y可能是小数,所以我们需要使用floor和ceil函数来找到最近的4个整数坐标点。

 

 C++双线性差值算法RGB图像缩放

/**@func       Imresize
* @brief       双线性差值算法缩放RGB图片
* @param[out]  pfDst 目的图像地址
* @param[in]   nW   目的图像宽度
* @param[in]   nH  目的图像高度
* @param[in]   pfSrc 源图像地址
* @param[in]   nOriW   源图像宽度
* @param[in]   nOriH  源图像高度
*/
void Imresize(unsigned char *pfDst, int nH, int nW, unsigned char *pfSrc, int nOriH, int nOriW)
{
	for (int i = 0; i < nH * nW; i++)
	{
		int row = i / nW;
		int col = i % nW;
		float x = (row + 0.5) * nOriH / nH - 0.5;
		if (x < 0) x = 0;
		if (x >= nOriH - 1) x = nOriH - 2;
		int fx = (int)x;
		x = x - fx;
		float x1 = 1.0 - x;

		float y = (col + 0.5) * nOriW / nW - 0.5;
		if (y < 0) y = 0;
		if (y >= nOriW - 1) y = nOriW - 2;
		int fy = (int)y;
		y = y - fy;
		float y1 = 1.0 - y;

		float val_R = (pfSrc[fx * nOriW * 3 + 3 * fy] * x1 * y1 + pfSrc[(fx + 1) * nOriW * 3 + 3 * fy] * x * y1
			+ pfSrc[fx * nOriW * 3 + (fy + 1) * 3] * x1 * y + pfSrc[(fx + 1) * nOriW * 3 + (fy + 1) * 3] * x * y);
		float val_G = (pfSrc[fx * nOriW * 3 + 1 + 3 * fy] * x1 * y1 + pfSrc[(fx + 1) * nOriW * 3 + 1 + 3 * fy] * x * y1
			+ pfSrc[fx * nOriW * 3 + 1 + (fy + 1) * 3] * x1 * y + pfSrc[(fx + 1) * nOriW * 3 + 1 + (fy + 1) * 3] * x * y);
		float val_B = (pfSrc[fx * nOriW * 3 + 2 + 3 * fy] * x1 * y1 + pfSrc[(fx + 1) * nOriW * 3 + 2 + 3 * fy] * x * y1
			+ pfSrc[fx * nOriW * 3 + 2 + (fy + 1) * 3] * x1 * y + pfSrc[(fx + 1) * nOriW * 3 + 2 + (fy + 1) * 3] * x * y);

		pfDst[i * 3] = unsigned char(val_B);
		pfDst[i * 3 + 1] = unsigned char(val_G);
		pfDst[i * 3 + 2] = unsigned char(val_R);
	}
}

 

使用OpenCV库实现双线性差值算法RGB图像缩放

#include <opencv2/opencv.hpp>

cv::Mat bilinearInterpolation(const cv::Mat& src, int newWidth, int newHeight) {
    cv::Mat dst(newHeight, newWidth, CV_8UC3);
    float x_ratio = src.cols / (float)newWidth;
    float y_ratio = src.rows / (float)newHeight;

    for(int dst_y = 0; dst_y < newHeight; dst_y++) {
        for(int dst_x = 0; dst_x < newWidth; dst_x++) {
            // 计算源图像中的位置
            float src_x = (dst_x + 0.5f) * x_ratio - 0.5f;
            float src_y = (dst_y + 0.5f) * y_ratio - 0.5f;

            // 找到最邻近的四个像素点
            int x0 = floor(src_x);
            int y0 = floor(src_y);
            int x1 = ceil(src_x);
            int y1 = ceil(src_y);

            // 确保坐标在图像范围内
            x0 = std::min(std::max(0, x0), src.cols - 2);
            y0 = std::min(std::max(0, y0), src.rows - 2);
            x1 = std::min(std::max(0, x1), src.cols - 2);
            y1 = std::min(std::max(0, y1), src.rows - 2);

            // 双线性插值计算
            float dx = src_x - x0;
            float dy = src_y - y0;

            cv::Vec3b top = src.at<cv::Vec3b>(y0, x0) * (1 - dx) + src.at<cv::Vec3b>(y0, x1) * dx;
            cv::Vec3b bottom = src.at<cv::Vec3b>(y1, x0) * (1 - dx) + src.at<cv::Vec3b>(y1, x1) * dx;

            dst.at<cv::Vec3b>(dst_y, dst_x) = top * (1 - dy) + bottom * dy;
        }
    }

    return dst;
}

使用双线性差值算法需要注意的点

 使用双线性插值算法时,需要注意以下几点:

  1. 边界处理:在计算目标像素对应的源图像坐标时,可能会出现超出边界的情况。例如,如果目标像素对应的位置在源图像的边界之外,那么你就找不到四个邻近的像素。这时,你可能需要做一些特殊的处理,比如将坐标限制在图像的边界内,或者使用边界上的像素值进行插值。

  2. 精度问题:双线性插值涉及到浮点数运算,可能会有精度损失。此外,如果你的目标图像的尺寸远大于源图像,那么可能会出现“模糊”的效果,这是因为插值算法无法创造出新的信息。

  3. 颜色空间:如果你处理的是彩色图像,那么你需要对每个颜色通道分别进行插值。在某些情况下,可能需要考虑颜色空间的影响,例如在HSV颜色空间中,色相(H)通道的插值可能需要特殊处理,因为它是一个循环的量。

  4. 性能问题:双线性插值需要对每个像素进行四次访问和一次乘法操作,这可能会导致性能问题。如果你需要处理大尺寸的图像,或者需要实时处理图像,那么你可能需要考虑使用更高效的算法,或者使用硬件加速。

  5. 其他插值方法:双线性插值只是众多插值方法中的一种,还有最近邻插值、双三次插值等方法。不同的插值方法有不同的优缺点,你需要根据你的具体需求选择最适合的插值方法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangnaisheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值