How to create a Blur effect in C - c

Part of a problem set for a course im doing (CS50) requires us to do apply a blur filter on an image. From a two dimensional array[i][j] we need to find the adjacent pixels to the one we want to blur and take the average RGB values and exchange them for the values in the pixel.
This is the code that I came up with yet it does not work.
I have watched some tutorials and they say to find the relative position of the pixel but i cannot really get my head aroud it.
Can anyone help me?
Here is the code I wrote for now:
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
int red = 0;
int green = 0;
int blue = 0;
int counter_pixel = 0;
//I would assume that we would need to tell the computer to free up space for the new imafe with malloc()
RGBTRIPLE temporary[height][width];
for (int i = 0; i < height; i++)
{
// go through every column
for (int j = 0; j < width; j++)
{
temporary[i][j] = image[i][j];
}
}
// go through every row
for (int i = 0; i < height; i++)
{
// go through every column
for (int j = 0; j < width; j++)
{
//checking if the pixel is inside the image
red = green = blue = 0;
if (i < 0 || j < 0 || i > height +1 || j > width + 1)
{
image[i + 1][j].rgbtRed = temporary[i + 1][j].rgbtRed;
image[i - 1][j].rgbtRed = temporary[i - 1][j].rgbtRed;
image[i][j + 1].rgbtRed = temporary[i][j + 1].rgbtRed;
image[i][j - 1].rgbtRed = temporary[i][j - 1].rgbtRed;
image[i + 1][j].rgbtGreen = temporary[i + 1][j].rgbtGreen;
image[i - 1][j].rgbtGreen = temporary[i - 1][j].rgbtGreen;
image[i][j + 1].rgbtGreen = temporary[i][j + 1].rgbtGreen;
image[i][j - 1].rgbtGreen = temporary[i][j - 1].rgbtGreen;
image[i + 1][j].rgbtBlue = temporary[i + 1][j].rgbtBlue;
image[i - 1][j].rgbtBlue = temporary[i - 1][j].rgbtBlue;
image[i][j + 1].rgbtBlue = temporary[i][j + 1].rgbtBlue;
image[i][j - 1].rgbtBlue = temporary[i][j - 1].rgbtBlue;
counter_pixel++;
red = round(((temporary[i + 1][j].rgbtRed + temporary[i - 1][j].rgbtRed + temporary[i][j + 1].rgbtRed + temporary[i][j -1].rgbtRed) / counter_pixel));
green = round(((temporary[i + 1][j].rgbtGreen + temporary[i - 1][j].rgbtGreen + temporary[i][j + 1].rgbtGreen + temporary[i][j -1].rgbtGreen) / counter_pixel));
blue = round(((temporary[i + 1][j].rgbtBlue + temporary[i - 1][j].rgbtBlue + temporary[i][j + 1].rgbtBlue + temporary[i][j -1].rgbtBlue) / counter_pixel));
}
}
}
return;
}

Related

Blurring an image.bmp with "box blur" technique in C

So in this project , I need to take an image.bmp file and blur it using "box blur".
The instructions for Box Blurring as follows:
For this problem, we’ll use the “box blur,” which works by taking each pixel and, for each color value, giving it a new value by averaging the color values of neighboring pixels.
(example) The new value of each pixel would be the average of the values of all of the pixels that are within 1 row and column of the original pixel (forming a 3x3 box). For example, each of the color values for pixel 6 would be obtained by averaging the original color values of pixels 1, 2, 3, 5, 6, 7, 9, 10, and 11 (note that pixel 6 itself is included in the average). Likewise, the color values for pixel 11 would be be obtained by averaging the color values of pixels 6, 7, 8, 10, 11, 12, 14, 15 and 16.
For a pixel along the edge or corner, like pixel 15, we would still look for all pixels within 1 row and column: in this case, pixels 10, 11, 12, 14, 15, and 16.
Now I know my code is a bit long and amateur,but it is only because I am an amateur but I have come this far without any help:
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;
}
Now at this point, program somewhat blurs the image, but not for the right amount. When I test it via cs50's pre-set test cases, my RGB ratios are correct for corner indexes, but off for all the others. Why that might be happening?
first make shure to copy the orignal image's pixels into another varial of type RGBTRIPLE pixel by pixel using forloop if not the first blured pixel would affect the next pixel to abe blured then do you math.
this works for me!
// 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;
}

CS50 pset4 filter blur function

I wrote a code for the blur function, but it returns a wrong output for reason which is not known for me (it just looks fine for me), here is an example (always same):
:( blur correctly filters middle pixel
expected "127 140 149\n", not "126 140 149\n"
:) blur correctly filters pixel on edge
:) blur correctly filters pixel in corner
:( blur correctly filters 3x3 image
expected "70 85 95\n80 9...", not "70 85 95\n80 9..."
:( blur correctly filters 4x4 image
expected "70 85 95\n80 9...", not "70 85 95\n80 9..."
and the code is here:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE original[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
original[i][j] = image[i][j];
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i == 0)
{
if (j == 0)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i][j + 1].rgbtRed + original[i + 1][j + 1].rgbtRed) / 4);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i + 1][j].rgbtGreen + original[i][j + 1].rgbtGreen + original[i + 1][j + 1].rgbtGreen) / 4);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i + 1][j].rgbtBlue + original[i][j + 1].rgbtBlue + original[i + 1][j + 1].rgbtBlue) / 4);
}
else if (j == width - 1)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i][j - 1].rgbtRed + original[i + 1][j - 1].rgbtRed) / 4);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i + 1][j].rgbtGreen + original[i][j - 1].rgbtGreen + original[i + 1][j - 1].rgbtGreen) / 4);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i + 1][j].rgbtBlue + original[i][j - 1].rgbtBlue + original[i + 1][j - 1].rgbtBlue) / 4);
}
else
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i][j - 1].rgbtRed + original[i + 1][j - 1].rgbtRed + original[i][j + 1].rgbtRed + original[i + 1][j + 1].rgbtRed) / 6);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i + 1][j].rgbtGreen + original[i][j - 1].rgbtGreen + original[i + 1][j - 1].rgbtGreen + original[i][j + 1].rgbtGreen + original[i + 1][j + 1].rgbtGreen) / 6);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i + 1][j].rgbtBlue + original[i][j - 1].rgbtBlue + original[i + 1][j - 1].rgbtBlue + original[i][j + 1].rgbtBlue + original[i + 1][j + 1].rgbtBlue) / 6);
}
}
else if (i > 0 && i < height - 1)
{
if (j == 0)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i - 1][j].rgbtRed + original[i + 1][j + 1].rgbtRed + original[i][j + 1].rgbtRed + original[i - 1][j + 1].rgbtRed) / 6);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i + 1][j].rgbtGreen + original[i- 1][j].rgbtGreen + original[i + 1][j + 1].rgbtGreen + original[i][j + 1].rgbtGreen + original[i - 1][j + 1].rgbtGreen) / 6);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i + 1][j].rgbtBlue + original[i - 1][j].rgbtBlue + original[i + 1][j + 1].rgbtBlue + original[i][j + 1].rgbtBlue + original[i - 1][j + 1].rgbtBlue) / 6);
}
else if (j == width - 1)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i - 1][j].rgbtRed + original[i + 1][j - 1].rgbtRed + original[i][j - 1].rgbtRed + original[i - 1][j - 1].rgbtRed) / 6);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i + 1][j].rgbtGreen + original[i- 1][j].rgbtGreen + original[i + 1][j - 1].rgbtGreen + original[i][j - 1].rgbtGreen + original[i - 1][j - 1].rgbtGreen) / 6);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i + 1][j].rgbtBlue + original[i - 1][j].rgbtBlue + original[i + 1][j - 1].rgbtBlue + original[i][j - 1].rgbtBlue + original[i - 1][j - 1].rgbtBlue) / 6);
}
else
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i][j - 1].rgbtRed + original[i][j + 1].rgbtRed + original[i + 1][j - 1].rgbtRed + original[i + 1][j + 1].rgbtRed + original[i + 1][j].rgbtRed + original[i - 1][j - 1].rgbtRed + original[i - 1][j + 1].rgbtRed + original[i - 1][j].rgbtRed) / 9);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i][j - 1].rgbtGreen + original[i][j + 1].rgbtGreen + original[i + 1][j - 1].rgbtGreen + original[i + 1][j + 1].rgbtGreen+ original[i + 1][j].rgbtGreen + original[i - 1][j - 1].rgbtGreen + original[i - 1][j + 1].rgbtGreen + original[i - 1][j].rgbtGreen) / 9);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i][j - 1].rgbtBlue + original[i][j + 1].rgbtBlue + original[i + 1][j - 1].rgbtBlue + original[i + 1][j + 1].rgbtBlue + original[i + 1][j].rgbtBlue + original[i - 1][j - 1].rgbtBlue + original[i - 1][j + 1].rgbtBlue + original[i - 1][j].rgbtBlue) / 9);
}
}
else if (i == height - 1)
{
if (j == 0)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i - 1][j].rgbtRed + original[i][j + 1].rgbtRed + original[i - 1][j + 1].rgbtRed) / 4);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i - 1][j].rgbtGreen + original[i][j + 1].rgbtGreen + original[i - 1][j + 1].rgbtGreen) / 4);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i - 1][j].rgbtBlue + original[i][j + 1].rgbtBlue + original[i - 1][j + 1].rgbtBlue) / 4);
}
else if (j == width - 1)
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i - 1][j].rgbtRed + original[i][j - 1].rgbtRed + original[i - 1][j - 1].rgbtRed) / 4);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i - 1][j].rgbtGreen + original[i][j - 1].rgbtGreen + original[i - 1][j - 1].rgbtGreen) / 4);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i - 1][j].rgbtBlue + original[i][j - 1].rgbtBlue + original[i - 1][j - 1].rgbtBlue) / 4);
}
else
{
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i - 1][j].rgbtRed + original[i][j - 1].rgbtRed + original[i - 1][j - 1].rgbtRed + original[i][j + 1].rgbtRed + original[i - 1][j + 1].rgbtRed) / 6);
image[i][j].rgbtGreen = round((original[i][j].rgbtGreen + original[i - 1][j].rgbtGreen + original[i][j - 1].rgbtGreen + original[i - 1][j - 1].rgbtGreen + original[i][j + 1].rgbtGreen + original[i - 1][j + 1].rgbtGreen) / 6);
image[i][j].rgbtBlue = round((original[i][j].rgbtBlue + original[i - 1][j].rgbtBlue + original[i][j - 1].rgbtBlue + original[i - 1][j - 1].rgbtBlue + original[i][j + 1].rgbtBlue + original[i - 1][j + 1].rgbtBlue) / 6);
}
}
}
}
}
if the members of the structure RGBTRIPLE has integer types, integer division happens in the lines like
image[i][j].rgbtRed = round((original[i][j].rgbtRed + original[i + 1][j].rgbtRed + original[i][j + 1].rgbtRed + original[i + 1][j + 1].rgbtRed) / 4);
and the results are truncated to integers before passed to the round() function.
The dividers should be floating-point numbers like 4.0 instead of integers like 4.
If the judge still rejects your answer after applying this change, it should be due to the calculation errors in floating-point numbers. In this case, you should avoid using floating-point number calculation and think how to calculate the desired values using only calculation in integers.
My solution is much short I guess
void blur(int height, int width, RGBTRIPLE image[height][width])
{
//Iterates through all the pixels
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
//Stores average of all the pixels around the certain color
int avgrgb[3] = {0,0,0}, n = 0;
// Matrix “a” and “b” represent the nine pixels address around the pixel of address i and j
int a[3][3] = { {i-1, i-1, i-1}, {i, i, i}, {i+1, i+1,i+1} }, b[3][3] = { {j-1, j, j+1}, {j-1, j, j+1}, {j-1, j, j+1} };
//Iterating through the pixels around the middle pixel
for(int x = 0; x < 3; x++)
{
for(int y = 0; y < 3; y++)
{
// Checking if the index contains any negative integer(negative integer represents a pixel outside the image for corner or edge pixel)
if (a[x][y] >= 0 && a[x][y] >= 0)
{
// Calculates the sum of the valid pixel colours
avgrgb[0] += image[a[x][y]][b[x][y]].rgbtRed;
avgrgb[1] += image[a[x][y]][b[x][y]].rgbtGreen;
avgrgb[2] += image[a[x][y]][b[x][y]].rgbtBlue;
n++;
}
}
}
// Calculates the actual average
avgrgb[0] /= n;
avgrgb[1] /= n;
avgrgb[2] /= n;
// Assigning new pixel values
image[i][j].rgbtRed = avgrgb[0];
image[i][j].rgbtGreen = avgrgb[1];
image[i][j].rgbtBlue = avgrgb[2];
}
}
return;
}
MikeCAT's answer is surely right. Just as an alternative to his suggestion, you could avoid the conversions to and from floating point by adding half the divisor before the integer division, e. g.
image[i][j].rgbtRed = (original[i][j].rgbtRed + … + original[i+1][j+1].rgbtRed + 2) / 4;
…
image[i][j].rgbtRed = (original[i][j].rgbtRed + … + original[i-1][j ].rgbtRed + 4) / 9;

CS50 - PSet4 (Filter) - Blur

I'm running the following code
void blur(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int div = 1;
if ( j + 1 < width - 1 && j + 1 > 0)
{
div++;
}
else
{
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
}
if ( i + 1 < height - 1 && i + 1 > 0)
{
div++;
}
else
{
image[i + 1][j].rgbtRed = 0;
image[i + 1][j].rgbtRed = 0;
image[i + 1][j].rgbtRed = 0;
}
if ( j + 1 < width - 1 && j + 1 > 0 && i + 1 < height - 1 && i + 1 > 0)
{
div++;
}
else
{
image[i + 1][j + 1].rgbtRed = 0;
image[i + 1][j + 1].rgbtRed = 0;
image[i + 1][j + 1].rgbtRed = 0;
}
if ( i - 1 < height - 1 && i - 1 > 0)
{
div++;
}
else
{
image[i - 1][j].rgbtRed = 0;
image[i - 1][j].rgbtRed = 0;
image[i - 1][j].rgbtRed = 0;
}
if ( i - 1 < height - 1 && i - 1 > 0 && j + 1 < width - 1 && j + 1 > 0)
{
div++;
}
else
{
image[i - 1][j + 1].rgbtRed = 0;
image[i - 1][j + 1].rgbtRed = 0;
image[i - 1][j + 1].rgbtRed = 0;
}
if ( j - 1 < width - 1 && j - 1 > 0)
{
div++;
}
else
{
image[i][j - 1].rgbtRed = 0;
image[i][j - 1].rgbtRed = 0;
image[i][j - 1].rgbtRed = 0;
}
if ( j - 1 < width - 1 && j - 1 > 0 && i + 1 < height - 1 && i + 1 > 0)
{
div++;
}
else
{
image[i + 1][j - 1].rgbtRed = 0;
image[i + 1][j - 1].rgbtRed = 0;
image[i + 1][j - 1].rgbtRed = 0;
}
if ( j - 1 < width - 1 && j - 1 > 0 && i - 1 < height - 1 && i - 1 > 0)
{
div++;
}
else
{
image[i - 1][j - 1].rgbtRed = 0;
image[i - 1][j - 1].rgbtRed = 0;
image[i - 1][j - 1].rgbtRed = 0;
}
int averageR = (float)(image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i - 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed) / div;
int averageG = (float)(image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen) / div;
int averageB = (float)(image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue) / div;
image[i][j].rgbtRed = round(averageR);
image[i][j].rgbtGreen = round(averageG);
image[i][j].rgbtBlue = round(averageB);
}
}
return;
}
Unfortnately, everytime I try to run it in the blur part it appears this message:
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==8771==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x7f7a4ec2890a (pc 0x000000427faa bp 0x7ffd07cd9170 sp 0x7ffd07cd7560 T8771)
==8771==The signal is caused by a WRITE memory access.
#0 0x427fa9 (/home/ubuntu/pset4/filter/filter+0x427fa9)
#1 0x4232b1 (/home/ubuntu/pset4/filter/filter+0x4232b1)
#2 0x7f7a4db1bb96 (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
#3 0x402dd9 (/home/ubuntu/pset4/filter/filter+0x402dd9)
UndefinedBehaviorSanitizer can not provide additional info.
==8771==ABORTING
Any idea what this might be?
You are accessing out of the bounds of your image 2D array.
This happens in several points.
Consider your loops:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
}
}
i and j are indexes that can vary respectively from 0 and height and from 0 and width.
But for both these loops you access beyond this limit. For example if j = width-1:
if ( j + 1 < width - 1 && j + 1 > 0)
{
div++;
}
else
{
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
}
The first conditional won't be true as width-1+1 > width -1, so you will end up in the else section, in which you will access
image[i][width].rgbtRed = 0;
that is out of bounds!
And the same happens whenever i = height-1: rows such as image[i + 1][j] will access
image[height][j].rgbtRed = 0;
that is out of bounds as well.
Accessing arrays out of bounds results in undefined behavior, and that's what your sanitizer detects.
Note: although it is unrelated to the error you are asking for, you might also want to correct the mistake in
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
image[i][j + 1].rgbtRed = 0;
and in similar parts all over the function. Note that only Red level is affected (three times!); I suppose that you intended affect also Green and Blue, instead.
How to proceed
Implementing the whole function for you would be beyond the scope of this question, but I'll try to suggest how to proceed.
For each pixel, you currently
Count the elements that are not in the edge of the image (div++)
Set to 0 the elements that should not contribute to the average (that are actually out of bounds and caused your undefined behavior)
Sum all the values of the elements surrounding the pixel (including those you set to 0) and divide by div
But what forces you to sum all the elements? Just sum those which are actually useful! You already have a correct place in which to perform this sum: it's the place in which you increment div.
Something like that:
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int div = 1;
int curRedSum = 0, curGReenSum = 0, curBlueSum = 0;
if ( j + 1 < width - 1 && j + 1 > 0)
{
div++;
curRedSum += image[i][j + 1].rgbtRed;
curGreenSum += image[i][j + 1].rgbtGreen;
curBlueSum += image[i][j + 1].rgbtBlue;
}
if ( i + 1 < height - 1 && i + 1 > 0)
{
div++;
curRedSum += image[i+1][j].rgbtRed;
curGreenSum += image[i+1][j].rgbtGreen;
curBlueSum += image[i+1][j].rgbtBlue;
}
/* ... */
float averageR = (float)(curRedSum / ( float )div );
float averageG = (float)(curGreenSum / ( float )div );
float averageB = (float)(curBlueSum / ( float )div );
image[i][j].rgbtRed = round(averageR); // Shouldn't this assignemnt be performed on a copy of the image?
image[i][j].rgbtGreen = round(averageG); // Shouldn't this assignemnt be performed on a copy of the image?
image[i][j].rgbtBlue = round(averageB); // Shouldn't this assignemnt be performed on a copy of the image?
}
}
Disclaimer: this suggestion is supposed to be just an hint. I don't guarantee this will compile and work without any further adjustment.

CS50x - Filter (blur) - Receiving a runtime error on first nested else state + seeking for feedback on length of code

Terminal photo HERE!I'm currently having a runtime error and have tried modifying my code but it will not pass.
If there is any specific pointers I could get (no pun intended) to help me approach this issue.
I'm also seeking some feedback on the length of my code - I wrote it as it came to my head and I'm aware that I could make this more short and coherent.
I'm currently working on filtering each independent pixel within the image grid.
Would one suggest writing code as it comes to our head or spend more time trying to decipher an algorithm much simpler.
The code would be the following:
any feedback is welcomed!
// Blur image
void
blur(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int redAvg, greenAvg, blueAvg;
if (i == 0) {
if (j == 0) {
redAvg = image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed / 4.0;
greenAvg = image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen / 4.0;
blueAvg = image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue / 4.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
if (j == width - 1) {
redAvg = image[i][j].rgbtRed + image[i][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed / 4.0;
greenAvg = image[i][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen / 4.0;
blueAvg = image[i][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue / 4.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
else {
redAvg = 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 + image[i][j + 1].rgbtRed / 6.0;
greenAvg = 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 + image[i][j - +1].rgbtGreen / 6.0;
blueAvg = 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 + image[i][j + 1].rgbtBlue / 6.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
}
if (i > 0 && i < i - 2) {
if (j == 0) {
redAvg = image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed / 6.0;
greenAvg = image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen / 6.0;
blueAvg = image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue / 6.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
if (j == width - 1) {
redAvg = image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed / 6.0;
greenAvg = image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen / 6.0;
blueAvg = image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j - 1].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue / 6.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
}
else if (i == i - 1) {
if (j == 0) {
redAvg = image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j + 1].rgbtRed / 4.0;
greenAvg = image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j + 1].rgbtGreen / 4.0;
blueAvg = 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 = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
if (j == width - 1) {
redAvg = image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed + image[i][j - 1].rgbtRed / 4.0;
greenAvg = image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen + image[i][j - 1].rgbtGreen / 4.0;
blueAvg = 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 = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
else {
redAvg = 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 + image[i][j + 1].rgbtRed / 6.0;
greenAvg = 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 + image[i][j + 1].rgbtGreen / 6.0;
blueAvg = 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 + image[i][j + 1].rgbtBlue / 6.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
}
else {
redAvg = image[i][j].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed + image[i][j - 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed + image[i][j + 1].rgbtRed + image[i - 1][j + 1].rgbtRed / 9.0;
greenAvg = image[i][j].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen + image[i][j - 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen + image[i][j + 1].rgbtGreen + image[i - 1][j + 1].rgbtGreen / 9.0;
blueAvg = image[i][j].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j - 1].rgbtBlue + image[i][j - 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue + image[i][j + 1].rgbtBlue + image[i - 1][j + 1].rgbtBlue / 9.0;
image[i][j].rgbtRed = redAvg;
image[i][j].rgbtGreen = greenAvg;
image[i][j].rgbtBlue = blueAvg;
}
}
}
}
As others have mentioned, you need a separate output matrix to prevent average of averages.
Using relative offset values and some limit checks, you can simplify the function.
Also, you may need to do "saturation math" (e.g. prevent a 256 value from wrapping to 1 because it gets stored into a byte). This may not be necessary if avg / count is always <= 255, but I've included the code to show this
Here's a refactored version:
// Blur image
void
blur(int height, int width,
RGBTRIPLE image[height][width],
RGBTRIPLE imgout[height][width])
{
//RGBTRIPLE *src;
RGBTRIPLE *dst;
for (int i = 0; i < height; i++) {
dst = &imgout[i][0];
for (int j = 0; j < width; j++, dst++) {
int redAvg = 0, greenAvg = 0, blueAvg = 0;
int curcnt = 0;
for (int yoff = -1; yoff <= 1; ++yoff) {
int ycur = i + yoff;
// row index out of range
if (ycur < 0)
continue;
if (ycur >= height)
continue;
RGBTRIPLE *yptr = &image[ycur][0];
for (int xoff = -1; xoff <= 1; ++xoff) {
int xcur = j + xoff;
// index into row (i.e. column index) out of range
if (xcur < 0)
continue;
if (xcur >= width)
continue;
RGBTRIPLE *xptr = &yptr[xcur];
redAvg += xptr->rgbtRed;
greenAvg += xptr->rgbtGreen;
blueAvg += xptr->rgbtBlue;
++curcnt;
}
}
redAvg /= curcnt;
blueAvg /= curcnt;
greenAvg /= curcnt;
// prevent (e.g.) 256 from wrapping to 1 -- clip to max of byte
// NOTE: _may_ not be necessary
if (redAvg > 255)
redAvg = 255;
if (greenAvg > 255)
greenAvg = 255;
if (blueAvg > 255)
blueAvg = 255;
dst->rgbtRed = redAvg;
dst->rgbtBlue = blueAvg;
dst->rgbtGreen = greenAvg;
}
}
}
Note this could be made faster if the border pixels were handled outside the main loop
UPDATE:
Here's a version that might be slightly faster:
// Blur image
void
blur(int height, int width,
RGBTRIPLE image[height][width],
RGBTRIPLE imgout[height][width])
{
int ylim = height - 1;
int xlim = width - 1;
//RGBTRIPLE *src;
RGBTRIPLE *dst;
for (int i = 0; i < height; i++) {
dst = &imgout[i][0];
for (int j = 0; j < width; j++, dst++) {
int redAvg = 0, greenAvg = 0, blueAvg = 0;
int curcnt = 0;
int ylo = i - 1;
if (ylo < 0)
ylo = 0;
int yhi = i + 1;
if (yhi > ylim)
yhi = ylim;
for (int ycur = ylo; ycur <= yhi; ++ycur) {
RGBTRIPLE *yptr = &image[ycur][0];
int xlo = j - 1;
if (xlo < 0)
xlo = 0;
int xhi = j + 1;
if (xhi > xlim)
xhi = xlim;
for (int xcur = xlo; xcur <= xhi; ++xcur) {
RGBTRIPLE *xptr = &yptr[xcur];
redAvg += xptr->rgbtRed;
greenAvg += xptr->rgbtGreen;
blueAvg += xptr->rgbtBlue;
++curcnt;
}
}
redAvg /= curcnt;
blueAvg /= curcnt;
greenAvg /= curcnt;
// prevent (e.g.) 256 from wrapping to 1 -- clip to max of byte
// NOTE: _may_ not be necessary
if (redAvg > 255)
redAvg = 255;
if (greenAvg > 255)
greenAvg = 255;
if (blueAvg > 255)
blueAvg = 255;
dst->rgbtRed = redAvg;
dst->rgbtBlue = blueAvg;
dst->rgbtGreen = greenAvg;
}
}
}
UPDATE #2:
Here's a version that moves more of the limit checks out of the inner loops:
// Blur image
void
blur(int height, int width,
RGBTRIPLE image[height][width],
RGBTRIPLE imgout[height][width])
{
int ylim = height - 1;
int xlim = width - 1;
//RGBTRIPLE *src;
RGBTRIPLE *dst;
for (int i = 0; i < height; i++) {
dst = &imgout[i][0];
int ylo = i - 1;
if (ylo < 0)
ylo = 0;
int yhi = i + 1;
if (yhi > ylim)
yhi = ylim;
for (int j = 0; j < width; j++, dst++) {
int redAvg = 0, greenAvg = 0, blueAvg = 0;
int curcnt = 0;
int xlo = j - 1;
if (xlo < 0)
xlo = 0;
int xhi = j + 1;
if (xhi > xlim)
xhi = xlim;
for (int ycur = ylo; ycur <= yhi; ++ycur) {
RGBTRIPLE *yptr = &image[ycur][0];
for (int xcur = xlo; xcur <= xhi; ++xcur) {
RGBTRIPLE *xptr = &yptr[xcur];
redAvg += xptr->rgbtRed;
greenAvg += xptr->rgbtGreen;
blueAvg += xptr->rgbtBlue;
++curcnt;
}
}
redAvg /= curcnt;
blueAvg /= curcnt;
greenAvg /= curcnt;
// prevent (e.g.) 256 from wrapping to 1 -- clip to max of byte
// NOTE: _may_ not be necessary
if (redAvg > 255)
redAvg = 255;
if (greenAvg > 255)
greenAvg = 255;
if (blueAvg > 255)
blueAvg = 255;
dst->rgbtRed = redAvg;
dst->rgbtBlue = blueAvg;
dst->rgbtGreen = greenAvg;
}
}
}

Logical flaw in CS50 Problem Set 4 - Filter (Edges)?

I am having some issues fulfilling the requirements for the edges filter in Problem Set 4 of CS50. A description of the problem can be found here: https://cs50.harvard.edu/x/2020/psets/4/filter/more/. My code makes sense to me, so hopefully someone can shed some light on this for me, as I have been staring at my code for days on end now ): To be clear, my code does compile, so I do not think there are any bugs per se, but probably a logical flaw in my thinking.
My code is as follows:
void edges(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE tempimage[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
tempimage[i][j] = image[i][j];
int sGxRed = 0;
int sGxGreen = 0;
int sGxBlue = 0;
int sGyRed = 0;
int sGyGreen = 0;
int sGyBlue = 0;
if (j + 1 < width)
{
sGxRed += 2 * image[i][j + 1].rgbtRed;
sGxGreen += 2 * image[i][j + 1].rgbtGreen;
sGxBlue += 2 * image[i][j + 1].rgbtBlue;
}
if (j > 0)
{
sGxRed += -2 * image[i][j - 1].rgbtRed;
sGxGreen += -2 * image[i][j - 1].rgbtGreen;
sGxBlue += -2 * image[i][j - 1].rgbtBlue;
}
if (i + 1 < height)
{
sGyRed += 2 * image[i + 1][j].rgbtRed;
sGyGreen += 2 * image[i + 1][j].rgbtGreen;
sGyBlue += 2 * image[i + 1][j].rgbtBlue;
}
if (i > 0)
{
sGyRed += -2 * image[i - 1][j].rgbtRed;
sGyGreen += -2 * image[i - 1][j].rgbtGreen;
sGyBlue += -2 * image[i - 1][j].rgbtBlue;
}
if (i + 1 < height && j + 1 < width)
{
sGxRed += image[i + 1][j + 1].rgbtRed;
sGxGreen += image[i + 1][j + 1].rgbtGreen;
sGxBlue += image[i + 1][j + 1].rgbtBlue;
sGyRed += image[i + 1][j + 1].rgbtRed;
sGyGreen += image[i + 1][j + 1].rgbtGreen;
sGyBlue += image[i + 1][j + 1].rgbtBlue;
}
if (i > 0 && j + 1 < width)
{
sGxRed += image[i - 1][j + 1].rgbtRed;
sGxGreen += image[i - 1][j + 1].rgbtGreen;
sGxBlue += image[i - 1][j + 1].rgbtBlue;
sGyRed += -1 * image[i - 1][j + 1].rgbtRed;
sGyGreen += -1 * image[i - 1][j + 1].rgbtGreen;
sGyBlue += -1 * image[i - 1][j + 1].rgbtBlue;
}
if (i > 0 && j > 0)
{
sGxRed += -1 * image[i - 1][j - 1].rgbtRed;
sGxGreen += -1 * image[i - 1][j - 1].rgbtGreen;
sGxBlue += -1 * image[i - 1][j - 1].rgbtBlue;
sGyRed += -1 * image[i - 1][j - 1].rgbtRed;
sGyGreen += -1 * image[i - 1][j - 1].rgbtGreen;
sGyBlue += -1 * image[i - 1][j - 1].rgbtBlue;
}
if (i + 1 < height && j > 0)
{
sGxRed += -1 * image[i + 1][j - 1].rgbtRed;
sGxGreen += -1 * image[i + 1][j - 1].rgbtGreen;
sGxBlue += -1 * image[i + 1][j - 1].rgbtBlue;
sGyRed += image[i + 1][j - 1].rgbtRed;
sGyGreen += image[i + 1][j - 1].rgbtGreen;
sGyBlue += image[i + 1][j - 1].rgbtBlue;
}
int sRed = 0;
int sGreen = 0;
int sBlue = 0;
sRed = round((float)(sqrt(sGxRed^2 + sGyRed^2)));
if (sRed > 255)
{
sRed = 255;
}
sGreen = round((float)(sqrt(sGxGreen^2 + sGyGreen^2)));
if (sGreen > 255)
{
sGreen = 255;
}
sBlue = round((float)(sqrt(sGxBlue^2 + sGyBlue^2)));
if (sBlue > 255)
{
sBlue = 255;
}
tempimage[i][j].rgbtRed = sRed;
tempimage[i][j].rgbtGreen = sGreen;
tempimage[i][j].rgbtBlue = sBlue;
}
}
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
image[i][j].rgbtRed = tempimage[i][j].rgbtRed;
image[i][j].rgbtGreen = tempimage[i][j].rgbtGreen;
image[i][j].rgbtBlue = tempimage[i][j].rgbtBlue;
}
}
return;
}
I am very new to coding. Prior to taking this course, I have only tried my hand at a little VBA. This is my first time coding in C and the learning curve for CS50 is steep, so pardon me if my question is trivial!
Thank you all in advance! :)
P.S Apart from my actual question, please feel free to comment on how my code can be more efficient/shortened as well. I am always open to different points of view!
Common misunderstanding: ^ does not mean power-of, it means bit-wise XOR, which is not what you want here. Replace it with pow() from math.h.
Or in case of power of 2 specifically, simply do variable * variable.

Resources