图像插值处理

图像插值处理


问题描述:读取图像,然后对图像进行最近邻插值、双线性插值、双三次插值处理。

本文主要侧重于代码的实现,相关的原理性介绍可参考

最邻近插值

最近邻插值 法的优点是计算量很小,算法也简单,因此运算速度较快。但它仅使用离待测采样点最近的像素的灰度值作为该采样点的灰度值,而没考虑其他相邻像素点的影响,因而重新采样后灰度值有明显的不连续性,图像质量损失较大,会产生明显的马赛克和锯齿现象。

可采用下述公示进行图像的最邻近插值,其中 I ′ I' I为放大后图像, I I I为放大前图像, a a a为放大率,方括号是四舍五入取整操作:

I ′ ( x , y ) = I ( [ x a ] , [ y a ] ) I'(x,y) = I([\frac{x}{a}], [\frac{y}{a}]) I(x,y)=I([ax],[ay])

// 最近邻插值
cv::Mat nearest_neighbor(cv::Mat img, double rx, double ry)
{
    int row = img.rows;
    int col = img.cols;
    int channel = img.channels();

    // Resize width and height
    int resized_col = (int)(col * rx);
    int resized_row = (int)(row * ry);


    cv::Mat new_image = cv::Mat::zeros(resized_row, resized_col, CV_8UC3);

    int pos_before_x, pos_before_y;

    // nearest_neighbor
    for (int i = 0; i < resized_row; i++)
    {
        pos_before_y = (int)round(i / ry);
        pos_before_y = fmin(pos_before_y, row - 1);
        for (int j = 0; j < resized_col; j++)
        {
            pos_before_x = (int)round(j / rx);
            pos_before_x = fmin(pos_before_x, col - 1);

            for (int chan = 0; chan < channel; chan++)
            {
                new_image.at<cv::Vec3b>(i, j)[chan] = img.at<cv::Vec3b>(pos_before_y, pos_before_x)[chan];
            }
        }
    }

    return new_image;
}
输入图像 (fate.jpeg)输出图像 (fate_nearest_neighbor.jpeg)
在这里插入图片描述在这里插入图片描述

双线性插值

双线性插值考察 4 4 4邻域的像素点,并根据距离设置权值。虽然计算量增大使得处理时间变长,但是可以有效抑制画质劣化。

  1. 放大后图像的座标 ( x ′ , y ′ ) (x',y') (x,y)除以放大率 a a a,可以得到对应原图像的座标 ( ⌊ x ′ a ⌋ , ⌊ y ′ a ⌋ ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor) (ax,ay)

  2. 求原图像的座标 ( ⌊ x ′ a ⌋ , ⌊ y ′ a ⌋ ) (\lfloor \frac{x'}{a}\rfloor , \lfloor \frac{y'}{a}\rfloor) (ax,ay)周围 4 4 4邻域的座标 I ( x , y ) I(x,y) I(x,y) I ( x + 1 , y ) I(x+1,y) I(x+1,y) I ( x , y + 1 ) I(x,y+1) I(x,y+1) I ( x + 1 , y + 1 ) I(x+1, y+1) I(x+1,y+1)

  3. 分别求这4个点与 ( x ′ a , y ′ a ) (\frac{x'}{a}, \frac{y'}{a}) (ax,ay)的距离,根据距离设置权重: w = d ∑   d w = \frac{d}{\sum\ d} w= dd

  4. 根据下式求得放大后图像 ( x ′ , y ′ ) (x',y') (x,y)处的像素值:
    d x = x ′ a − x d y = y ′ a − y I ′ ( x ′ , y ′ ) = ( 1 − d x )   ( 1 − d y )   I ( x , y ) + d x   ( 1 − d y )   I ( x + 1 , y ) + ( 1 − d x )   d y   I ( x , y + 1 ) + d x   d y   I ( x + 1 , y + 1 ) d_x = \frac{x'}{a} - x\\ d_y = \frac{y'}{a} - y\\ I'(x',y') = (1-d_x)\ (1-d_y)\ I(x,y) + d_x\ (1-d_y)\ I(x+1,y) + (1-d_x)\ d_y\ I(x,y+1) + d_x\ d_y\ I(x+1,y+1) dx=axxdy=ayyI(x,y)=(1dx) (1dy) I(x,y)+dx (1dy) I(x+1,y)+(1dx) dy I(x,y+1)+dx dy I(x+1,y+1)

// 双线性插值
cv::Mat bilinear(cv::Mat img, double rx, double ry)
{
    int row = img.rows;
    int col = img.cols;
    int channel = img.channels();

    // Resize width and height
    int resized_col = (int)(col * rx);
    int resized_row = (int)(row * ry);


    cv::Mat new_image = cv::Mat::zeros(resized_row, resized_col, CV_8UC3);

    int pos_before_j, pos_before_i;
    double dx, dy;
    double val;

    // bilinear
    for (int i = 0; i < resized_row; i++)
    {
        pos_before_i = (int)round(i / ry);
        pos_before_i = fmin(pos_before_i, row - 1);
        dy = round(i / ry) - pos_before_i;

        for (int j = 0; j < resized_col; j++)
        {
            pos_before_j = (int)round(j / rx);
            pos_before_j = fmin(pos_before_j, col - 1);
            dx = round(j / rx) - pos_before_j;

            for (int chan = 0; chan < channel; chan++)
            {
                val = (1 - dx) * (1 - dy) * img.at<cv::Vec3b>(pos_before_i, pos_before_j)[chan] +
                        dx * (1 - dy) * img.at<cv::Vec3b>(pos_before_i, pos_before_j + 1)[chan] +
                        (1 - dx) * dy * img.at<cv::Vec3b>(pos_before_i + 1, pos_before_j)[chan] +
                        dx * dy * img.at<cv::Vec3b>(pos_before_i + 1, pos_before_j + 1)[chan];
                new_image.at<cv::Vec3b>(i, j)[chan] = (uchar)val;
            }
        }
    }

    return new_image;
}
输入图像 (fate.jpeg)输出图像 (fate_nearest_neighbor.jpeg)
在这里插入图片描述在这里插入图片描述

双三次插值

双三次插值是双线性插值的扩展,使用邻域 16 16 16像素进行插值。

各自像素间的距离由下式决定:
d x 1 = ∣ x ′ a   x − ( x − 1 ) ∣ d x 2 = ∣ x ′ a   x − x ∣ d x 3 = ∣ x ′ a   x − ( x + 1 ) ∣ d x 4 = ∣ x ′ a   x − ( x + 2 ) ∣ d y 1 = ∣ x ′ a   y − ( y − 1 ) ∣ d y 2 = ∣ x ′ a   y − y ∣ d y 3 = ∣ x ′ a   y − ( y + 1 ) ∣ d y 4 = ∣ x ′ a   y − ( y + 2 ) ∣ d_{x_1} = |\frac{x'}{a\ x} - (x-1)|\quad d_{x_2} = |\frac{x'}{a\ x}- x| \quad d_{x_3} = |\frac{x'}{a\ x}- (x+1)|\quad d_{x_4} = |\frac{x'}{a\ x} - (x+2)|\\ d_{y_1} = |\frac{x'}{a\ y} - (y-1)|\quad d_{y_2} = |\frac{x'}{a\ y} - y| \quad d_{y_3} = |\frac{x'}{a\ y} - (y+1)| \quad d_{y_4} = |\frac{x'}{a\ y} - (y+2)| dx1=a xx(x1)dx2=a xxxdx3=a xx(x+1)dx4=a xx(x+2)dy1=a yx(y1)dy2=a yxydy3=a yx(y+1)dy4=a yx(y+2)
权重由基于距离的函数取得。 a a a在大部分时候取 − 1 -1 1。权重公示如下:
h ( t ) = { ( a + 2 )   ∣ t ∣ 3 − ( a + 3 )   ∣ t ∣ 2 + 1 when ∣ t ∣ ≤ 1 a   ∣ t ∣ 3 − 5   a   ∣ t ∣ 2 + 8   a   ∣ t ∣ − 4   a when 1 < ∣ t ∣ ≤ 2 0 else h(t)= \begin{cases} (a+2)\ |t|^3 - (a+3)\ |t|^2 + 1 &\text{when}\quad |t|\leq 1 \\ a\ |t|^3 - 5\ a\ |t|^2 + 8\ a\ |t| - 4\ a&\text{when}\quad 1<|t|\leq 2\\ 0&\text{else} \end{cases} h(t)=(a+2) t3(a+3) t2+1a t35 a t2+8 a t4 a0whent1when1<t2else
利用上面得到的权重,通过下面的式子扩大图像。将每个像素与权重的乘积之和除以权重的和。
I ′ ( x ′ , y ′ ) = 1 ∑ j = 1 4   ∑ i = 1 4   h ( d x i )   h ( d y j )   ∑ j = 1 4   ∑ i = 1 4   I ( x + i − 2 , y + j − 2 )   h ( d x i )   h ( d y j ) I'(x', y')=\frac{1}{\sum\limits_{j=1}^4\ \sum\limits_{i=1}^4\ h(d_{xi})\ h(d_{yj})}\ \sum\limits_{j=1}^4\ \sum\limits_{i=1}^4\ I(x+i-2,y+j-2)\ h(d_{xi})\ h(d_{yj}) I(x,y)=j=14 i=14 h(dxi) h(dyj)1 j=14 i=14 I(x+i2,y+j2) h(dxi) h(dyj)

// weight function
double weight(double t)
{
    double a = -1;
    if (fabs(t) <= 1)
    {
        return (a + 2) * pow(fabs(t), 3) - (a + 3) * pow(fabs(t), 2) + 1;
    } else if (fabs(t) <= 2)
    {
        return a * pow(fabs(t), 3) - 5 * a * pow(fabs(t), 2) + 8 * a * fabs(t) - 4 * a;
    }
    return 0;
}

cv::Mat bicubic(cv::Mat img, double rx, double ry)
{
    int row = img.rows;
    int col = img.cols;
    int channel = img.channels();

    // Resize width and height
    int resized_col = (int)(col * rx);
    int resized_row = (int)(row * ry);
    int pos_before_j, pos_before_i;
    int pos_j, pos_i;
    double dx, dy, weight_j, weight_i, weight_sum;
    double val;

    cv::Mat new_image = cv::Mat::zeros(resized_row, resized_col, CV_8UC3);

    // bicubic
    for (int i = 0; i < resized_row; i++)
    {
        dy = i / ry;
        pos_before_i = (int)floor(dy);

        for (int j = 0; j < resized_col; j++)
        {
            dx = j / rx;
            pos_before_j = (int)floor(dx);

            for (int chan = 0; chan < channel; chan++)
            {
                weight_sum = 0;
                val = 0;
                for (int di = -1; di < 3; di++)
                {
                    pos_i = fmin(fmax(pos_before_i + di, 0), row - 1);
                    weight_i = weight(fabs(dy - pos_i));
                    for (int dj = -1; dj < 3; dj++)
                    {
                        pos_j = fmin(fmax(pos_before_j + dj, 0), col - 1);
                        weight_j = weight(fabs(dx - pos_j));
                        weight_sum += weight_i * weight_j;
                        val += (double)img.at<cv::Vec3b>(pos_i, pos_j)[chan] * weight_i * weight_j;
                    }
                }
                val /= weight_sum;
                val = fmin(fmax(val, 0), 255);
                new_image.at<cv::Vec3b>(i, j)[chan] = (uchar)val;
            }
        }
    }

    return new_image;
}

int main(){
    // read image
    cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);

//    cv::Mat new_image = nearest_neighbor(img, 1.5, 1.5);  // 最近临插值
//    cv::Mat new_image = bilinear(img, 1.3, 1.3);  // 双线性插值
    cv::Mat new_image = bicubic(img, 1.4, 1.4);   // 双三次插值

//    cv::imwrite("../1-10/fate_nearest_neighbor.jpeg", new_image);
//    cv::imwrite("../1-10/fate_bilinear.jpeg", new_image);
    cv::imwrite("../1-10/fate_bicubic.jpeg", new_image);
    cv::imshow("vv", new_image);
    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}
输入图像 (fate.jpeg)输出图像 (fate_bicubic.jpeg)
在这里插入图片描述在这里插入图片描述
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在MATLAB中,有许多图像处理的函数可供使用。下面我来介绍一些常用的函数及其用法。 1. imresize函数 imresize函数可以对图像进行缩放或放大操作,同时也可以进行处理。其基本用法如下: ``` B = imresize(A, scale) ``` 其中A为原始图像,scale为缩放比例,B为缩放后的图像。imresize函数默认使用双线性方法。如果要使用其他方法,可以通过设置参数method来实现。例如: ``` B = imresize(A, scale, 'bicubic') ``` 此时使用的是双三次方法。 2. interp2函数 interp2函数可以进行二维处理,可以用于图像的放大、缩小、平移、旋转等操作。其基本用法如下: ``` B = interp2(X, Y, Z, Xi, Yi) ``` 其中X和Y是原始图像的x和y坐标,Z是原始图像的像素,Xi和Yi是图像的x和y坐标,B是后的图像像素。interp2函数的第五个参数method可以设置方法,例如: ``` B = interp2(X, Y, Z, Xi, Yi, 'cubic') ``` 此时使用的是三次样条方法。 3. griddata函数 griddata函数可以将不规则的数据点到规则的网格上,可以用于图像的转换和变形。其基本用法如下: ``` F = griddata(X, Y, Z, Xi, Yi) ``` 其中X、Y、Z是原始数据点的坐标和,Xi、Yi是后网格上的坐标,F是后网格上的。griddata函数的第五个参数method可以设置方法,例如: ``` F = griddata(X, Y, Z, Xi, Yi, 'v4') ``` 此时使用的是分段三次Hermite方法。 以上就是MATLAB中常用的图像处理函数,你可以根据实际需要选择合适的函数来处理图像

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值