C语言数字图像处理(二):图像缩放和负片处理

0. 完整仓库 & 教程:

这一章节的完整代码在:Chapter​​ ​​​​​2. Image Reduction, Enlargement and Negative

如果你喜欢这个系列的文章或者感觉对你有帮助,请给我的仓库一个⭐️

1. 图像缩小

  • 1.1 交替行缩小算法

算法:

假设原始图像尺寸为 m \times n,缩小比例为f_x (0 < f_x < 1),输出尺寸则为(m \times f_x) \times (n \times f_x)

图像(每行和每列)每隔 \text{round}(1/f_x) 个像素再取下一个像素,其间隔内的像素则被忽略。

后续代码中图像的缩放比例将被设置为0.5。​​​​​​​

图像和结果对比(lena, bridge, noise;  ratio = 0.5):

结果分析:

该算法根据图像的缩小比例选择并丢弃每行和列的像素。因此,输出图像中的所有像素都直接来自原图。这种方法简单有效地确定了输出像素的值,但由于缺失了一些像素行和列,使得物体边缘锯齿化。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < image->Height/2 - 1; i++) {
    for(int j = 0; j < image->Width/2 - 1; j++) {
        tempout[(outimage->Width)*i + j] = tempin[(image->Width)*row + column];
        column += 2;
    }
    row += 2;
    column = 0;
}

  • 1.2 分数线性缩小图像算法

算法:

定义 f_x为输出图像的缩放比例(当 0<f_x<1是缩小)。

输出图像与原图像之间的对应关系将是:

后续的代码可以根据输入的缩放比例将图像缩小到任意较小尺寸。

图像和结果对比(lena, bridge, noise;  ratio = 0.5):

结果分析:

该算法根据图像的缩小比例在原图中选择对应位置的像素,因此图像中的所有像素也都来自原图。这种方法取像素简单,并且可以将图像缩小到我们想要的任意尺寸,但可以清楚地看到图像变得模糊和锯齿化。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < outimage->Height; i++) {
    for(int j = 0; j < outimage->Width; j++) {
        x_in = round((float)j / ratio);
        y_in = round((float)i / ratio);
        tempout[outimage->Width * i + j] = tempin[image->Width * y_in + x_in];
    }
}

2. 图像放大

  • 2.1 像素复制法

算法:

假设原始图像尺寸为 m \times n,缩小比例为f_x(f_x > 1),输出尺寸则为(m \times f_x) \times (n \times f_x)

在处理过程中,原图中的每个像素在放大后将占据round(f_x) \times round(f_x) 个像素,颜色值与原像素相同。

后续代码固定将图像放大3倍。

图像和结果对比(lena, bridge, noise;  ratio = 3):

结果分析:

该算法按比例放大原图中的每个像素。它不增加原图中不存在的信息。因此它只是放大了图像尺寸,没有使其变得更清晰。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < image->Height - 1; i++) {
    for(int j = 0; j < image->Width - 1; j++) {
        unsigned char currPixel = tempin[(image->Width)*i + j];
        for(int x = row; x <= row+2; x++) {
            for(int y = column; y <= column+2; y++) {
                tempout[(outimage->Width)*x + y] = currPixel;
            }
        }
        column += 3;
    }
    row += 3;
    column = 0;
}

  • 2.2 最近邻放大算法

算法:

假设原始图像尺寸为 m \times n,缩小比例为f_x(f_x > 1),输出尺寸则为(m \times f_x) \times (n \times f_x)

记录输出像素的相对位置(水平和垂直)分别为 x\_ratio​ 和 y\_ratio​,并使用它们找到原图像素的相应相对位置。算法为:

图像和结果对比(lena, bridge, noise;  ratio = 3):

结果分析:

该算法根据新像素在图像中的相对位置找到原图中最接近的像素。因此,它不增加原图中不存在的信息。这种方法占用内存少,没有颜色失真。但是它也是简单地将原图中的像素信息复制到新图像中,不会使图像变得更清晰。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < outimage->Height - 1; i++) {
    ratio_column = (float)(i) / (float)outimage->Height;
    for(int j = 0; j < outimage->Width - 1; j++) {
        ratio_row = (float)(j) / (float)outimage->Width;
        int temp = image->Width * round(image->Height * ratio_column) + round(image->Width * ratio_row);
        tempout[outimage->Width * i + j] = tempin[temp];
    }
}

  • 2.3 双线性插值算法

算法:

如上所示,Q11、Q12、Q21、Q22是已知像素,P是待插值点。

首先,在x轴上插值两点R1、R2:

然后基于R1和R2插值点P:

公式简化为:

接下来的代码可以根据输入的缩放比例将图像放大到任意较大尺寸。

图像和结果对比(lena, bridge, noise;  ratio = 3):

结果分析

双线性插值算法是将原采样点附近四个像素的值乘以权重,以获得新图像的像素信息。因此,生成的图像包含原图中不存在的像素(加权值),使整个图像看起来更平滑。这种方法可以有效地抗锯齿,并将图像放大到任意尺寸。然而,它没有考虑边缘梯度变化,会使图像模糊。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < outimage->Height; i++) {
    for(int j = 0; j < outimage->Width; j++) {
        if(ratio <= 1) {
            // In case the input ratio <1.
            x_in = (float)j / 3;
            y_in = (float)i / 3;
        }
        else {
            x_in = (float)j / ratio;
            y_in = (float)i / ratio;
        }
        x1 = (int)(x_in + 1);
        x2 = (int)(x_in - 1);
        y1 = (int)(y_in + 1);
        y2 = (int)(y_in - 1);
        color1 = tempin[image->Width * y1 + x1];
        color2 = tempin[image->Width * y2 + x1];
        color3 = tempin[image->Width * y1 + x2];
        color4 = tempin[image->Width * y2 + x2];
        tempout[outimage->Width * i + j] = (unsigned char)(((color1*(x2-x_in)*(y2-y_in)) + (color2*(x2-x_in)*(y_in-y1)) + (color3*(x_in-x1)*(y2-y_in)) + (color4*(x_in-x1)*(y_in-y1))) / ((x2-x1) * (y2-y1)));
    }
}

​​​​​​​

  • 2.4 分数线性扩展算法以将图像扩展到任意较大尺寸

算法:

定义f_x为输出图像的缩放比例(当f_x > 1 时为放大)。

输出图像与原图像之间的对应关系将是:

接下来的代码可以根据输入的缩放比例将图像放大到任意较大尺寸。

图像和结果对比(包括图片)(缩放比例=10)

结果分析:

该算法根据图像的放大比例在原图中选择对应位置的像素,因此图像中的所有像素也都来自原图。这种方法取像素简单,并且可以将图像放大到我们想要的任意尺寸,但它不会增加任何新细节。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < outimage->Height; i++) {
    for(int j = 0; j < outimage->Width; j++) {
        x_in = round((float)j / ratio);
        y_in = round((float)i / ratio);
        tempout[outimage->Width * i + j] = tempin[image->Width * y_in + x_in];
    }
}

3 . 负片操作

算法

图像和结果对比(包括图片)

结果分析

灰色图像中含有256个量化层级,用255减去原图像中每个像素的值即为新图像的颜色。

处理后,图片的层次更分明,色彩对比更强烈。因此我们可以在新图像中看到更多细节。

代码实现(完整代码见顶部GitHub):
for(int i = 0; i < size; i++) {
    *tempout = 255 - *tempin;
    tempin++;
    tempout++;
}

4. 完整代码

这一章节的完整代码在:Chapter​​ ​​​​​2. Image Reduction, Enlargement and Negative​​​​​​​

更多关于数字图像处理的章节,以及所有的原图像在:Introduction to Digital Image Processing

整理代码、翻译原理,和可视化每一个章节的工作非常耗时耗力,并且不会有任何收入和回报。如果你喜欢这个系列的文章或者感觉对你有帮助,请给我的仓库一个⭐️,这将是对独立作者最大的鼓励。

-END-

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值