所以在这个项目中,我需要获取一个 image.bmp 文件并使用“框模糊”对其进行模糊处理。
方框模糊说明如下:
对于这个问题,我们将使用“框模糊”,它的工作原理是获取每个像素,并针对每个颜色值,通过对相邻像素的颜色值进行平均来为其赋予一个新值。
(示例)每个像素的新值将是原始像素 1 行和列内的所有像素值的平均值(形成 3x3 框)。例如,像素 6 的每个颜色值将通过对像素 1、2、3、5、6、7、9、10 和 11 的原始颜色值进行平均来获得(请注意,像素 6 本身包含在平均的)。同样,像素 11 的颜色值可以通过对像素 6、7、8、10、11、12、14、15 和 16 的颜色值进行平均来获得。
对于沿着边缘或角的像素,例如像素 15,我们仍然会查找 1 行和 1 列内的所有像素:在本例中,为像素 10、11、12、14、15 和 16。
现在我知道我的代码有点长而且业余,但这只是因为我是业余爱好者,但我在没有任何帮助的情况下走到了这一步:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// iterate through every row
for (int i = 0; i < height; i++)
{
//for every column
for (int j = 0; j < width; j++)
{
int avRed = 0;
int avGreen = 0;
int avBlue = 0;
// check if the current index is an index of an edge
if ((i == 0 && (j >= 0 && j <= width - 1))
|| ((i >= 0 && i <= height - 1) && j == 0)
|| (i == height - 1 && (j >= 0 && j <= width - 1))
|| ((i >= 0 && i <= height -1) && j == width - 1))
{
// if it is : check if it is a corner
if ((i == 0 && j == 0)
|| (i == 0 && j == width - 1)
|| (i == height - 1 && j == 0)
|| (i == height - 1 && j == width - 1))
{
if (i == 0 && j == 0)
{
avRed = round((image[i][j].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed + image[i][j + 1].rgbtRed) / 4.0);
avGreen = round((image[i][j].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen + image[i][j + 1].rgbtGreen) / 4.0);
avBlue = round((image[i][j].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue + image[i][j + 1].rgbtBlue) / 4.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if (i == 0 && j == width - 1)
{
avRed = round((image[i][j].rgbtRed + image[i +1 ][j].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i][j - 1].rgbtRed) / 4.0);
avGreen = round((image[i][j].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i][j - 1].rgbtGreen) / 4.0);
avBlue = round((image[i][j].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i][j - 1].rgbtBlue) / 4.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if(i == height - 1 && j == 0)
{
avRed = round((image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j + 1].rgbtRed) / 4.0);
avGreen= round((image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j + 1].rgbtGreen) / 4.0);
avRed = round((image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j + 1].rgbtBlue) / 4.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if (i == height - 1 && j == width - 1)
{
avRed = round((image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed + image[i][j - 1].rgbtRed) / 4.0);
avGreen = round((image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen + image[i][j - 1].rgbtGreen) / 4.0);
avBlue = round((image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j - 1].rgbtBlue + image[i][j - 1].rgbtBlue) / 4.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
}
else // if it is not a corner index
{
if (i == 0 && (j >= 1 && j <= width - 2))
{
avRed = round((image[i][j].rgbtRed + image[i][j - 1].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j + 1].rgbtRed) / 6.0);
avGreen = round((image[i][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 6.0);
avBlue = round((image[i][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 6.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if ((i >= 1 && i <= height - 2) && j == 0)
{
avRed = round((image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i + 1][j].rgbtRed + image[i][j + 1].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i + 1][j + 1].rgbtRed) / 6.0);
avGreen = round((image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i + 1][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 6.0);
avBlue = round((image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i + 1][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 6.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if (i == height - 1 && (j >= 1 && j <= width - 2))
{
avRed = round((image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i][j - 1].rgbtRed + image[i][j + 1].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i - 1][j - 1].rgbtRed) / 6.0);
avGreen = round((image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j + 1].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i - 1][j - 1].rgbtGreen) / 6.0);
avBlue = round((image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j + 1].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i - 1][j - 1].rgbtBlue) / 6.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
if ((i >= 1 && i <= height -2) && j == width - 1)
{
avRed = round((image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i + 1][j].rgbtRed + image[i][j - 1].rgbtRed + image[i - 1][j - 1].rgbtRed + image[i + 1][j - 1].rgbtRed) / 6.0);
avGreen = round((image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i + 1][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i - 1][j - 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen) / 6.0);
avBlue = round((image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i + 1][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i - 1][j - 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue) / 6.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
}
}
else // if it is not an index of an edge at all
{
avRed = round(((image[i - 1][j - 1].rgbtRed) + (image[i - 1][j].rgbtRed) + (image[i - 1][j + 1].rgbtRed) + (image[i][j - 1].rgbtRed) + (image[i][j].rgbtRed) + (image[i][j + 1].rgbtRed) + (image[i + 1][j - 1].rgbtRed) + (image[i + 1][j].rgbtRed) + (image[i + 1][j + 1].rgbtRed)) / 9.0);
avGreen = round(((image[i - 1][j - 1].rgbtGreen) + (image[i - 1][j].rgbtGreen) + (image[i - 1][j + 1].rgbtGreen) + (image[i][j - 1].rgbtGreen) + (image[i][j].rgbtGreen) + (image[i][j + 1].rgbtGreen) + (image[i + 1][j - 1].rgbtGreen) + (image[i + 1][j].rgbtGreen) + (image[i + 1][j + 1].rgbtGreen)) / 9.0);
avBlue = round(((image[i - 1][j - 1].rgbtBlue) + (image[i - 1][j].rgbtBlue) + (image[i - 1][j + 1].rgbtBlue) + (image[i][j - 1].rgbtBlue) + (image[i][j].rgbtBlue) + (image[i][j + 1].rgbtBlue) + (image[i + 1][j - 1].rgbtBlue) + (image[i + 1][j].rgbtBlue) + (image[i + 1][j + 1].rgbtBlue)) / 9.0);
image[i][j].rgbtRed = avRed;
image[i][j].rgbtGreen = avGreen;
image[i][j].rgbtBlue = avBlue;
}
}
}
return;
}
此时,程序对图像进行了一定程度的模糊处理,但模糊程度不正确。当我通过 cs50 的预设测试用例对其进行测试时,我的 RGB 比率对于 corner 索引是正确的,但对于所有其他索引则不正确。为什么会发生这种情况?
首先使用 forloop 将原始图像的像素复制到 RGBTRIPLE 类型的另一个变量中,如果不是第一个模糊像素会影响下一个要模糊的像素,那么你做数学运算。
这对我有用!
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
copy[i][j] = image[i][j];
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// check for an edge
if ((i == 0 && (j >= 0 && j <= width - 1))
|| ((i >= 0 && i <= height - 1) && j == 0)
|| (i == height - 1 && (j >= 0 && j <= width - 1))
|| ((i >= 0 && i <= height -1) && j == width - 1))
{
//check if it is a corner
if ((i == 0 && j == 0)
|| (i == 0 && j == width - 1)
|| (i == height - 1 && j == 0)
|| (i == height - 1 && j == width - 1))
{
if (i == 0 && j == 0)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i + 1][j].rgbtRed + copy[i + 1][j + 1].rgbtRed + copy[i][j + 1].rgbtRed) / 4.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i + 1][j].rgbtGreen + copy[i + 1][j + 1].rgbtGreen + copy[i][j + 1].rgbtGreen) / 4.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i + 1][j].rgbtBlue + copy[i + 1][j + 1].rgbtBlue + copy[i][j + 1].rgbtBlue) / 4.0);
}
if (i == 0 && j == width - 1)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i +1 ][j].rgbtRed + copy[i + 1][j - 1].rgbtRed + copy[i][j - 1].rgbtRed) / 4.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i + 1][j].rgbtGreen + copy[i + 1][j - 1].rgbtGreen + copy[i][j - 1].rgbtGreen) / 4.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i + 1][j].rgbtBlue + copy[i + 1][j - 1].rgbtBlue + copy[i][j - 1].rgbtBlue) / 4.0);
}
if (i == height - 1 && j == 0)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i - 1][j].rgbtRed + copy[i - 1][j + 1].rgbtRed + copy[i][j + 1].rgbtRed) / 4.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i - 1][j].rgbtGreen + copy[i - 1][j + 1].rgbtGreen + copy[i][j + 1].rgbtGreen) / 4.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i - 1][j].rgbtBlue + copy[i - 1][j + 1].rgbtBlue + copy[i][j + 1].rgbtBlue) / 4.0);
}
if (i == height - 1 && j == width - 1)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i - 1][j].rgbtRed + copy[i - 1][j - 1].rgbtRed + copy[i][j - 1].rgbtRed) / 4.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i - 1][j].rgbtGreen + copy[i - 1][j - 1].rgbtGreen + copy[i][j - 1].rgbtGreen) / 4.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i - 1][j].rgbtBlue + copy[i - 1][j - 1].rgbtBlue + copy[i][j - 1].rgbtBlue) / 4.0);
}
}
// if not a corner index
else
{
if (i == 0 && (j >= 1 && j <= width - 2))
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i][j - 1].rgbtRed + copy[i][j + 1].rgbtRed + copy[i + 1][j].rgbtRed + copy[i + 1][j - 1].rgbtRed + copy[i + 1][j + 1].rgbtRed) / 6.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i][j - 1].rgbtGreen + copy[i][j + 1].rgbtGreen + copy[i + 1][j].rgbtGreen + copy[i + 1][j - 1].rgbtGreen + copy[i + 1][j + 1].rgbtGreen) / 6.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i][j - 1].rgbtBlue + copy[i][j + 1].rgbtBlue + copy[i + 1][j].rgbtBlue + copy[i + 1][j - 1].rgbtBlue + copy[i + 1][j + 1].rgbtBlue) / 6.0);
}
if ((i >= 1 && i <= height - 2) && j == 0)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i - 1][j].rgbtRed + copy[i + 1][j].rgbtRed + copy[i][j + 1].rgbtRed + copy[i - 1][j + 1].rgbtRed + copy[i + 1][j + 1].rgbtRed) / 6.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i - 1][j].rgbtGreen + copy[i + 1][j].rgbtGreen + copy[i][j + 1].rgbtGreen + copy[i - 1][j + 1].rgbtGreen + copy[i + 1][j + 1].rgbtGreen) / 6.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i - 1][j].rgbtBlue + copy[i + 1][j].rgbtBlue + copy[i][j + 1].rgbtBlue + copy[i - 1][j + 1].rgbtBlue + copy[i + 1][j + 1].rgbtBlue) / 6.0);
}
if (i == height - 1 && (j >= 1 && j <= width - 2))
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i - 1][j].rgbtRed + copy[i][j - 1].rgbtRed + copy[i][j + 1].rgbtRed + copy[i - 1][j + 1].rgbtRed + copy[i - 1][j - 1].rgbtRed) / 6.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i - 1][j].rgbtGreen + copy[i][j - 1].rgbtGreen + copy[i][j + 1].rgbtGreen + copy[i - 1][j + 1].rgbtGreen + copy[i - 1][j - 1].rgbtGreen) / 6.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i - 1][j].rgbtBlue + copy[i][j - 1].rgbtBlue + copy[i][j + 1].rgbtBlue + copy[i - 1][j + 1].rgbtBlue + copy[i - 1][j - 1].rgbtBlue) / 6.0);
}
if ((i >= 1 && i <= height -2) && j == width - 1)
{
image[i][j].rgbtRed = (int) round((copy[i][j].rgbtRed + copy[i - 1][j].rgbtRed + copy[i + 1][j].rgbtRed + copy[i][j - 1].rgbtRed + copy[i - 1][j - 1].rgbtRed + copy[i + 1][j - 1].rgbtRed) / 6.0);
image[i][j].rgbtGreen = (int) round((copy[i][j].rgbtGreen + copy[i - 1][j].rgbtGreen + copy[i + 1][j].rgbtGreen + copy[i][j - 1].rgbtGreen + copy[i - 1][j - 1].rgbtGreen + copy[i + 1][j - 1].rgbtGreen) / 6.0);
image[i][j].rgbtBlue = (int) round((copy[i][j].rgbtBlue + copy[i - 1][j].rgbtBlue + copy[i + 1][j].rgbtBlue + copy[i][j - 1].rgbtBlue + copy[i - 1][j - 1].rgbtBlue + copy[i + 1][j - 1].rgbtBlue) / 6.0);
}
}
}
// for normal pixel no edge at all
else
{
image[i][j].rgbtRed = (int) round(((copy[i - 1][j - 1].rgbtRed) + (copy[i - 1][j].rgbtRed) + (copy[i - 1][j + 1].rgbtRed) + (copy[i][j - 1].rgbtRed) + (copy[i][j].rgbtRed) + (copy[i][j + 1].rgbtRed) + (copy[i + 1][j - 1].rgbtRed) + (copy[i + 1][j].rgbtRed) + (copy[i + 1][j + 1].rgbtRed)) / 9.0);
image[i][j].rgbtGreen = (int) round(((copy[i - 1][j - 1].rgbtGreen) + (copy[i - 1][j].rgbtGreen) + (copy[i - 1][j + 1].rgbtGreen) + (copy[i][j - 1].rgbtGreen) + (copy[i][j].rgbtGreen) + (copy[i][j + 1].rgbtGreen) + (copy[i + 1][j - 1].rgbtGreen) + (copy[i + 1][j].rgbtGreen) + (copy[i + 1][j + 1].rgbtGreen)) / 9.0);
image[i][j].rgbtBlue = (int) round(((copy[i - 1][j - 1].rgbtBlue) + (copy[i - 1][j].rgbtBlue) + (copy[i - 1][j + 1].rgbtBlue) + (copy[i][j - 1].rgbtBlue) + (copy[i][j].rgbtBlue) + (copy[i][j + 1].rgbtBlue) + (copy[i + 1][j - 1].rgbtBlue) + (copy[i + 1][j].rgbtBlue) + (copy[i + 1][j + 1].rgbtBlue)) / 9.0);
}
}
}
return;
}
虽然您可以继续执行上面的代码,但您可以尝试迭代内核本身,如下例所示,这可能更具可读性且更少重复 `
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// Creating a copy of the image to keep original pixels when doing math
RGBTRIPLE (*copy)[width] = calloc(height, width * sizeof(RGBTRIPLE));
// Checking if the pointer isn't null
if (copy == NULL)
{
return;
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
// Iterating over the whole image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// Declaring and resetting gradients' values
int sum_red = 0, sum_green = 0, sum_blue = 0;
int counter = 0;
// Iterating over a 3x3 kernel
for (int ki = -1; ki < 2; ki++)
{
for (int kj = -1; kj < 2; kj++)
{
// Creating the new indices using the 3x3 kernel
int new_i = i + ki;
int new_j = j + kj;
// Considering the edges
if (new_i >= 0 && new_i < height && new_j >= 0 && new_j < width)
{
// Updating variables to further calculate the average
sum_red += copy[new_i][new_j].rgbtRed;
sum_green += copy[new_i][new_j].rgbtGreen;
sum_blue += copy[new_i][new_j].rgbtBlue;
counter++;
}
// Calculating the average value for each gradient
float avg_red = sum_red / (float) counter;
float avg_green = sum_green / (float) counter;
float avg_blue = sum_blue / (float) counter;
// Update the value in the original image
image[i][j].rgbtRed = round(avg_red);
image[i][j].rgbtGreen = round(avg_green);
image[i][j].rgbtBlue = round(avg_blue);
}
}
}
}
// Clearing dynamically allocated memory
free(copy);
return;
}`