0. 完整仓库 & 教程:
这一章节的完整代码在:Chapter 2. Image Reduction, Enlargement and Negative
如果你喜欢这个系列的文章或者感觉对你有帮助,请给我的仓库一个⭐️。
1. 图像缩小
-
1.1 交替行缩小算法
算法:
假设原始图像尺寸为 ,缩小比例为
,输出尺寸则为
。
图像(每行和每列)每隔 个像素再取下一个像素,其间隔内的像素则被忽略。
后续代码中图像的缩放比例将被设置为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 分数线性缩小图像算法
算法:
定义 为输出图像的缩放比例(当
是缩小)。
输出图像与原图像之间的对应关系将是:
后续的代码可以根据输入的缩放比例将图像缩小到任意较小尺寸。
图像和结果对比(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 像素复制法:
算法:
假设原始图像尺寸为 ,缩小比例为
,
,输出尺寸则为
。
在处理过程中,原图中的每个像素在放大后将占据 个像素,颜色值与原像素相同。
后续代码固定将图像放大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 最近邻放大算法:
算法:
假设原始图像尺寸为 ,缩小比例为
,
,输出尺寸则为
。
记录输出像素的相对位置(水平和垂直)分别为 和
,并使用它们找到原图像素的相应相对位置。算法为:
图像和结果对比(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 分数线性扩展算法以将图像扩展到任意较大尺寸:
算法:
定义为输出图像的缩放比例(当
时为放大)。
输出图像与原图像之间的对应关系将是:
接下来的代码可以根据输入的缩放比例将图像放大到任意较大尺寸。
图像和结果对比(包括图片)(缩放比例=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-