问题
My blur function is behaving oddly. I've recreated the 3x3 bitmap from check50 to get more approximate results from my tests but, for some reason, every right or lower edge pixels are not working properly.
While debugging, I've found that, for some reason, my for loops are not behaving properly. I'll show my code and an example below.
Code:
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp[height][width]; // Declares temporary structure to avoid overwriting of original values while running loops
// For loop to set the value of i, rows or height
for (int i = 0; i < height; i++)
{
// For loop to set the value of j, columns or width
for (int j = 0; j < width; j++)
{
float counter = 0.0;
int sumRed = 0;
int sumGreen = 0;
int sumBlue = 0;
// For loop to set the value of k, to get surrounding pixels
for (int k = -1; k < 2; k++)
{
for (int m = -1; m < 2; m++)
{
if ((i - k) >= 0 && (i - k) < height && (j - m) >= 0 && (j - m) < width)
{
sumRed = sumRed + image[i - k][j - m].rgbtRed; // Adds the value of verified pixel to the sum
sumGreen = sumGreen + image[i - k][j - m].rgbtGreen;
sumBlue = sumBlue + image[i - k][j - m].rgbtBlue;
counter++; // To get the average
}
}
}
temp[i][j].rgbtRed = round(sumRed / counter); // Sets new color based on average of surrounding pixels
temp[i][j].rgbtGreen = round(sumGreen / counter);
temp[i][j].rgbtBlue = round(sumBlue / counter);
}
}
// Start new loops to switch original values with temp values
for (int i = 0; i < height - 1; i++)
{
for (int j = 0; j < width - 1; j++)
{
image[i][j].rgbtRed = temp[i][j].rgbtRed;
image[i][j].rgbtGreen = temp[i][j].rgbtGreen;
image[i][j].rgbtBlue = temp[i][j].rgbtBlue;
}
}
return;
}
And here's the output.
As an example of what I've found during the debug, let's say that:
i = 0
j = 2
k = 0
m = 0
Here, instead of sumRed
getting the value of image[0 - 0][2 - 0] (RGB 70, 80, 90)
, it's getting the values from image[2][2] (RGB 240, 250, 255)
.
I've not yet tested the other error cases, but I suppose something similar is happening there.
Any help would be greatly appreciated.
回答1:
This is prefaced by my top comment:
It might be better if
counter
were anint
. Then, do:round((double) sumRed / counter)
, But, the output cell is only eight bits. You may need:sumRed = round((double) sumRed / counter); temp[i][j].rgbtRed = (sumRed < 255) ? sumRed : 255;
This is saturation math. Otherwise, when you assign to an 8 bit cell, it's modulo math, equivalent tosumRed % 256
. That would yield257 --> 1
(nearly black) instead of257 --> 255
(bright red)
Your biggest problem is that your convolution kernel index calculations are incorrect.
Instead of:
(i - k)
(j - m)
You want:
(i + k)
(j + m)
Also, your the limits on your final loops to copy back from temp
to image
are off by 1.
Plus, I'd use more descriptive variables. And, your code can be simplified a bit. Here's a refactored version that incorporates the bug fixes:
#include <math.h>
typedef struct {
unsigned char rgbtRed;
unsigned char rgbtGreen;
unsigned char rgbtBlue;
} __attribute__((__packed__)) RGBTRIPLE;
// Blur image
void
blur(int height, int width, RGBTRIPLE image[height][width])
{
// Declares temporary structure to avoid overwriting of original values
// while running loops
RGBTRIPLE temp[height][width];
#if 1
RGBTRIPLE *tmp;
RGBTRIPLE *img;
#endif
// For loop to set the value of yctr, rows or height
for (int yctr = 0; yctr < height; yctr++) {
// For loop to set the value of xctr, columns or width
for (int xctr = 0; xctr < width; xctr++) {
#if 0
float counter = 0.0;
#else
int counter = 0;
#endif
int sumRed = 0;
int sumGreen = 0;
int sumBlue = 0;
// For loop to set the value of yoff, to get surrounding pixels
for (int yoff = -1; yoff < 2; yoff++) {
// NOTE/BUG: this is the main bug
#if 0
int ycur = yctr - yoff;
#else
int ycur = yctr + yoff;
#endif
if (ycur < 0)
continue;
if (ycur >= height)
continue;
for (int xoff = -1; xoff < 2; xoff++) {
// NOTE/BUG: this is the main bug
#if 0
int xcur = xctr - xoff;
#else
int xcur = xctr + xoff;
#endif
if (xcur < 0)
continue;
if (xcur >= width)
continue;
// Adds the value of verified pixel to the sum
tmp = &image[ycur][xcur];
sumRed += tmp->rgbtRed;
sumGreen += tmp->rgbtGreen;
sumBlue += tmp->rgbtBlue;
counter++; // To get the average
}
}
// Sets new color based on average of surrounding pixels
tmp = &temp[yctr][xctr];
#if 0
tmp->rgbtRed = round(sumRed / counter);
tmp->rgbtGreen = round(sumGreen / counter);
tmp->rgbtBlue = round(sumBlue / counter);
#else
sumRed = round((double) sumRed / counter);
tmp->rgbtRed = (sumRed < 255) ? sumRed : 255;
sumGreen = round((double) sumGreen / counter);
tmp->rgbtGreen = (sumGreen < 255) ? sumGreen : 255;
sumBlue = round((double) sumBlue / counter);
tmp->rgbtBlue = (sumBlue < 255) ? sumBlue : 255;
#endif
}
}
// Start new loops to switch original values with temp values
// NOTE/BUG: the for loop ranges are incorrect
#if 0
for (int yctr = 0; yctr < height - 1; yctr++) {
for (int xctr = 0; xctr < width - 1; xctr++) {
image[yctr][xctr].rgbtRed = temp[yctr][xctr].rgbtRed;
image[yctr][xctr].rgbtGreen = temp[yctr][xctr].rgbtGreen;
image[yctr][xctr].rgbtBlue = temp[yctr][xctr].rgbtBlue;
}
}
#endif
#if 0
for (int yctr = 0; yctr < height; yctr++) {
for (int xctr = 0; xctr < width; xctr++) {
image[yctr][xctr] = temp[yctr][xctr];
}
}
#endif
#if 1
tmp = &temp[0][0];
img = &image[0][0];
int idxlim = width * height;
for (int idxcur = 0; idxcur < idxlim; idxcur++)
img[idxcur] = tmp[idxcur];
#endif
}
来源:https://stackoverflow.com/questions/61394007/cs50-issue-with-pset4-filter-blur