This code for cs50 filter "blur" compiles, but when I run it, it says, index 600 out of bounds for type 'RGBTRIPLE [width].'. I somewhat understand what it means, but I dont know why its saying that I exceeded the array limit.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
int counter = 0;
int sumGreen = 0;
int sumRed = 0;
int sumBlue = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int k = i - 1; k <= i + 1; k++)
{
for (int m = j - 1; m <= j + 1; m++)
{
if (k >= 0 && m >= 0 && k <= height && m <= width)
{
sumGreen += image[k][m].rgbtGreen;
sumBlue += image[k][m].rgbtBlue;
sumRed += image[k][m].rgbtRed;
counter++;
}
}
}
image[i][j].rgbtGreen = sumGreen / counter;
image[i][j].rgbtBlue = sumBlue / counter;
image[i][j].rgbtRed = sumRed / counter;
counter = 0;
sumGreen = 0;
sumBlue = 0;
sumRed = 0;
}
}
return;
}
In C, even in CS50, arrays of size N have highest legal index N-1 and start at 0.
With your loops
i gets up to height-1, correct
j gets up to width-1, correct
k starts at -1, incorrect but the if protects
m starts at -1, incorrect but the if protects
k gets up to i+1 which is heigth, incorrect and the if does not protect either
m gets up to j+1 which is width, incorrect and the if does not protect either
You get the "index 600 out of bounds for type 'RGBTRIPLE [width]" because you access
image[k][m].rgbtGreen
with m being equal to width, because of the last bullet point.
That is forbidden because of the first sentence in this answer.
What you need is to change your loops to go from 0 to width-1, especially for the inner loops. For that I would change the outer loops, make them go from 1 to width-2. At that point the protective if should become unneeded, it is broken anyway. It should use < instead of <=.
Then you probably need to treat the picture edges specially.
Same for the height-related parts obviously.
Related
Got a problem with code in C, the purpose is to blur given image working as a filter. The code reads height and width from RGBTRIPLE bmp.h file, makes a copy of each pixel in advance to compute the average in the middle pixel (when its 3x3 pixels chunk) or the boundary pixel's average (when its 2x3 chunk). I nested for-loops, 2 outer ones to copy each pixel from 'image', defined there 4 integers (3 doubles, 1 int.) to count each pixel's red, green and blue. The last int. is named counter to be my denominator in division.
The problem occurs not in syntax, but on the image. 4 down rows of pixels are like rainbow, each is different, not blurred. And the image is darkened.
When I don't use the pixels' copy it seems to work fine.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// make a copy of rgbtriple image
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
// i need to ensure that image's pixels wont be out of bounds of rows/columns
// it's inappropriate to have static division by 9 because sometimes there will be less pixels to divide by
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++)
{
for (int jj = j - 1; jj <= j + 1; jj++)
{
if (ii >= 0 && ii < height && jj >= 0 && jj < width)
{
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
if (count != 0 && count <= 9)
{
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}
return;
}
Thanks in advance!
You compute the new value of the image pixels from the data in the copy matrix, but you did not copy the whole image before hand, only pixel values up to the current pixel. Hence the results are incorrect.
You should copy the whole image in a separate loop or using memcpy.
Here is a modified version:
#include <string.h>
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width]) {
RGBTRIPLE copy[height][width];
// make a copy of rgbtriple image
#if 1 // using memcpy
memcpy(copy, image, sizeof(copy));
#else
// if you cannot use memcpy
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
copy[i][j] = image[i][j];
}
}
#endif
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Mix the color values with the adjacent pixels
// making sure the pixels are inside the image.
// It is inappropriate to always divide by 9
// because depending on the pixel position and image size
// count can be 1, 2, 3, 4, 6 or 9
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++) {
for (int jj = j - 1; jj <= j + 1; jj++) {
if (ii >= 0 && ii < height && jj >= 0 && jj < width) {
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
// no need to test count: there is at least one pixel
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}
I'm stuck on my code for too much time now and needing some help. I'm working on CS50 pset4 blur filter and I keep getting either a "Segmentation fault" or "Floating point exception" depending if try to change my " neighbour variables" on float instead of int. Can someone have any idea what I'm doing wrong with that ?
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// Copy image to "copy"
RGBTRIPLE copy[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
// Loop through all the neighbour's pixel and calculate the average RGB in each
int RedNeighbour = 0; int BlueNeighbour = 0; int GreenNeighbour = 0; int neighbourSum = 0;
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
for(int k = i - 1; k < i + 1; k++)
{
for(int l = j - 1 ; l < j + 1; l++)
{
if(k >= 0 && k < height && l >= 0 && l < width)
{
RedNeighbour += copy[l][k].rgbtRed;
BlueNeighbour += copy[l][k].rgbtBlue;
GreenNeighbour += copy[l][k].rgbtGreen;
neighbourSum++;
}
else
{
continue;
}
}
}
// Divide each color by the sum of the neighbouring pixels and copy the pixe into original image
image[i][j].rgbtRed = round(fmin(255, RedNeighbour/neighbourSum));
image[i][j].rgbtBlue = round(fmin(255, BlueNeighbour/neighbourSum));
image[i][j].rgbtGreen = round(fmin(255, GreenNeighbour/neighbourSum));
}
}
return;
}
Thanks !
I'd recommend just using a debugger (gdb, or your IDE's if you're using one) for that kind of thing.
That said, I'm noticing that on the following lines, you are potentially accessing out of bound indices in your copy array:
RedNeighbour += copy[l][k].rgbtRed;
BlueNeighbour += copy[l][k].rgbtBlue;
GreenNeighbour += copy[l][k].rgbtGreen;
In your code, l is constrained by your width, while k is constrained by your height. However, the definition of the copy array is RGBTRIPLE copy[height][width];, which means that you should probably be accessing your copy array with copy[k][l] rather than copy[l][k].
I am receiving a Segmentation fault (core dumped) error when trying to blur an image, but I cannot find out why. To achieve a blur, I loop through each element in the 2x2 image array. I then check each of the 9x9 squares around & including it - if they exist, their RGB values are added to a sum (sumRed, sumGreen, sumBlue) for each color. I also increment a counter called numPixel each time this is successful so I can average the RGB values at the end.
There are other parts of the code, but I am certain that this blur() function is causing the segfault. This is because when I comment out the body of the function, the segfault goes away.
However, within the function I do not see what is triggering the segfault. I don't think I'm going out of bound in an array, which has been the cause of most of my segfaults in the past. From commenting out certain portions of the code, I also gathered that memcpy() is not the cause of the error (or at least not the only cause).
There's also a custom header file, which includes definitions for BYTE and RGBTRIPLE:
typedef uint8_t BYTE;
...
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
The actual code is:
// TODO: Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE new_image[height][width];
BYTE sumRed, sumGreen, sumBlue;
BYTE numPixels;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; w++)
{
sumRed = sumGreen = sumBlue = 0;
numPixels = 0;
// Check from 1 higher to 1 lower
for (int h = i - 1; h <= i + 1; h++)
{
// Check from 1 left to 1 right
for (int w = j - 1; w <= j + 1; j++)
{
// If neither index is out of bound, add neighboring RGB values
if (0 <= h < height && 0 <= w < width)
{
sumRed += image[h][w].rgbtRed;
sumGreen += image[h][w].rgbtGreen;
sumBlue += image[h][w].rgbtBlue;
numPixels++;
}
}
}
new_image[i][j].rgbtRed = (BYTE) sumRed / numPixels;
new_image[i][j].rgbtGreen = (BYTE) sumGreen / numPixels;
new_image[i][j].rgbtBlue = (BYTE) sumBlue / numPixels;
}
}
memcpy(&image[0][0], &new_image[0][0], sizeof(image[0][0]) * height * width);
return;
}
Be sure of your logic, not relying on braces to save the day. Use simple short names in "local context". "Ease of reading" trumps being "Overly explicit."
for (int h = 0; h < height; h++)
for (int w = 0; w < width; w++) {
// bigger accumulators, short names, declared & init'd locally
uint16_t sumR = 0;
uint16_t sumG = 0;
uint16_t sumB = 0;
int nPix = 0;
for (int hO = -1; hO <= 1; hO++) // height offset range
for (int wO = -1; wO <= 1; wO++) { // width offset range
int indH = h + hO; // Simple!
int indW = w + wO;
if (0 <= indH && indH < height && 0 <= indW && indW < width) {
RGBTRIPLE *p = &image[ indH ][ indW ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
new_image[i][j].rgbtRed = (BYTE)( sumR / nPix );
new_image[i][j].rgbtGreen = (BYTE)( sumG / nPix );
new_image[i][j].rgbtBlue = (BYTE)( sumB / nPix );
}
/* memcpy....*/
I'm still uneasy with possible confusion between "Height/width" and "vertical/Horizontal".
Here's an alternative for the two inner loops. Don't bother to set-up the width if the height is out-of-frame...
// From -1 offset, examine >>3<< pixels: -1, 0, 1...
for( int ih = h-1, limH = ih+3; ih < limH; ih++ ) { // height range
if( ih < 0 || height <= ih ) continue;
for( int iw = w-1, limW = iw+3; iw < limW; iw++) { // width range
if( iw < 0 || width <= iw ) continue;
RGBTRIPLE *p = &image[ ih ][ iw ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
This is a problem form cs50 problem set 4 (less comfortable). I'm currently stuck on the blur part. It compiles fine but the output is "invalid or unsupported image format".
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float red_sum = 0;
float blue_sum = 0;
float green_sum = 0;
int count = 0;
for (int x = i-1 ; x <= i+1 ; i++)
{
for (int y = j-1 ; y <= j+1 ; j++)
{
if ( x >= 0 && x < height && y >= 0 && y < width )
{
red_sum += image[x][y].rgbtRed;
blue_sum += image[x][y].rgbtBlue;
green_sum += image[x][y].rgbtGreen;
count ++;
}
}
}
int red_avg = round(red_sum/count);
int blue_avg = round(blue_sum/count);
int green_avg = round(green_sum/count);
temp[i][j].rgbtRed = red_avg;
temp[i][j].rgbtBlue = blue_avg;
temp[i][j].rgbtGreen = green_avg;
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j]=temp[i][j];
}
}
You have 2 typos which cause that you are corrupting lots of memory
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float red_sum = 0;
float blue_sum = 0;
float green_sum = 0;
int count = 0;
for (int x = i-1 ; x <= i+1 ; i++) // << This loops until i overflows
{
for (int y = j-1 ; y <= j+1 ; j++) // << this loop until j overflows
{
// in second iteration you will already have negative values but due to these checks you don't access `image` out of bounds.
if ( x >= 0 && x < height && y >= 0 && y < width )
{
red_sum += image[x][y].rgbtRed;
blue_sum += image[x][y].rgbtBlue;
green_sum += image[x][y].rgbtGreen;
count ++;
}
}
}
int red_avg = round(red_sum/count);
int blue_avg = round(blue_sum/count);
int green_avg = round(green_sum/count);
// After processing data for first pixel, both `i`and `j` contain negative values causing out of bounds accesses.
temp[i][j].rgbtRed = red_avg;
temp[i][j].rgbtBlue = blue_avg;
temp[i][j].rgbtGreen = green_avg;
}
}
Due to overflow and out of bounds accesses you have lots of undefined behaviour in your program.
You can corrupt any kind of memory including your own counter variables, the image header or anything else.
Anything can happen...
The statement about negative values assumes that two's complement is used and integers overflow from highest positive value to lowest negative value. Generally this is implementation defined/undefined.
I only wonder why file type error is given because I would assume that is done before your function is called. But maybe CS50 does it again afterwards.
close to the finish I've encountered a problem I can't solve. Maybe one of you can:
The compiling of the following code works fine but when I fire the program I get this error message:
helpers.c:228:42: runtime error: 8.13802e+06 is outside the range of representable values of type 'unsigned char'
The code is a function to blur an image blockwise, but the very first pixel [0][0] does not get a correct average value and I don't know why I get that error message instead.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
int i;
int j;
int m;
int n;
int averageRed;
int averageBlue;
int averageGreen;
RGBTRIPLE average[height][width];
// For each row of the image...
for (i = 0; i < height; i++)
{
//...take each pixel.
for (j = 0; j < width; j++)
//If current height equals 0 AND current width equals 0..
if (i == 0 && j == 0)
{
//..take 2 rows of the picture..
for (m = i; m <= i + 1; m++)
{
//..and take 2 pixels of each row.
for (n = j; n <= j + 1; n++)
{
//Sum up the rgb-values for each of the 2 pixel of the 2 rows.
averageRed = averageRed + image[m][n].rgbtRed;
averageGreen = averageGreen + image[m][n].rgbtGreen;
-> The error line averageBlue = averageBlue + image[m][n].rgbtBlue;
}
}
//Save the average of the values in a separate array after the 2x2 pixel-block
average[i][j].rgbtRed = round((float)averageRed / 4);
average[i][j].rgbtGreen = round((float)averageGreen / 4);
average[i][j].rgbtBlue = round((float)averageBlue / 4);
//Set average-variables to 0
averageRed = 0;
averageGreen = 0;
averageBlue = 0;
}
//From each row of the image...
for (i = 0; i < height; i++)
{
//...take each pixel..
for (j = 0; j < width; j++)
{
//...and update the original value with the temporary stored value.
image[i][j].rgbtRed = average[i][j].rgbtRed;
image[i][j].rgbtGreen = average[i][j].rgbtGreen;
image[i][j].rgbtBlue = average[i][j].rgbtBlue;
}
}
}
Thanks in advance for any hint!
Another facepalm-answer :-)..
The solution was quite simple. It was just the missing initialization of the averageRed/Green/Blue-variables.
Didn't get it because the error message pointed only to the averageBlue.
Thanks to M Oehm again :-)