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++;
}
}
info about this task
when I try to implement blur function, It works fine to me on a picture, but check50 (cs50 test program) gives warning for my outputs.
Here is my code
void blur(int height, int width, RGBTRIPLE image[height][width])
{
float average_red = 0;
float average_green = 0;
float average_blue = 0;
float count = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// reset values
average_red = 0;
average_blue = 0;
average_green = 0;
count = 0;
// look for around a pixel 3x3 box
// column
for (int k = i - 1; k < i + 2; k++)
{
// row
for (int l = j - 1; l < j + 2; l++)
{
// if pixel on the top
if (k == -1)
{
// it skips a column because it is out of the border
break;
}
// if pixel is on the left side
if (l == -1)
{
// skips a row otherwise it is out of the border
continue;
}
// if pixel passes the bottom
if (k >= height)
{
break;
}
// if pixels passes the right side
if (l >= width)
{
continue;
}
// everything else
else
{
average_red += image[k][l].rgbtRed;
average_green += image[k][l].rgbtGreen;
average_blue += image[k][l].rgbtBlue;
count++;
}
}
}
average_red /= count;
average_green /= count;
average_blue /= count;
image[i][j].rgbtRed = round(average_red);
image[i][j].rgbtGreen = round(average_green);
image[i][j].rgbtBlue = round(average_blue);
}
}
return;
}
expected output vs my output is here (blur functions output very down bellow)
It is working fine on the corner but other pixel values are very close to correct output, but not the same.
Any help appreciated
The code needs to take several factors into consideration. Suggest:
if the resulting row number is <0 or >(height-1) then don't calc that pixel
if the resulting column number is <0 or >(width-1) then don't calc that pixel
Therefore, for each of the surrounding 8 pixels, apply the two above criteria.
I solved my own problem, thanks for helps anyway
problem in was my sum calculation. it keeps result in image[i][j] and than again uses this value again.
I copy image values to a new value and use on this. Here is my code
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// copy original value to a new value to keep changing values
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
copy[i][j] = image[i][j];
}
}
float average_red = 0.0f;
float average_green = 0.0f;
float average_blue = 0.0f;
float count = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// reset values
average_red = 0.0f;
average_blue = 0.0f;
average_green = 0.0f;
count = 0;
// look for around a pixel 3x3 box
// column
for (int k = i - 1; k < i + 2; k++)
{
// row
for (int l = j - 1; l < j + 2; l++)
{
// if pixel on the top
if (k == -1)
{
// it skips a column because it is out of the border
break;
}
// if pixel is on the left side
else if (l == -1)
{
// skips a row otherwise it is out of the border
continue;
}
// if pixel passes the bottom
else if (k >= height)
{
break;
}
// if pixels passes the right side
else if (l >= width)
{
continue;
}
// everything else
else
{
average_red += copy[k][l].rgbtRed;
average_green += copy[k][l].rgbtGreen;
average_blue += copy[k][l].rgbtBlue;
count++;
}
}
}
average_red /= count;
average_green /= count;
average_blue /= count;
image[i][j].rgbtRed = round(average_red);
image[i][j].rgbtGreen = round(average_green);
image[i][j].rgbtBlue = round(average_blue);
}
}
return;
}
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.
I have a question regarding FFT. I already manage to do FFT forward and backward using FFTW in C. Now, I want to apply high pass filter for edge detection, some of my source said that just zeroing the centre of the magnitude.
This is my input image
http://i62.tinypic.com/2wnxvfl.jpg
Basically what I do are :
Forward FFT
Convert the output to 2D array
Do forward FFT shifting
Make the real and imag value to 0 when the distance from the centre is 25% of the height
Generate the magnitude
Do backward FFT shifting
Convert into 1D array
Do Backward FFT.
This is the original magnitude, the processed magnitude, and the result
http://i58.tinypic.com/aysx9s.png
can someone help me, to tell me which part is wrong and how to do the high pass filtering using FFTW in C.
Thank You.
The Source Code:
unsigned char **FFT2(int width,int height, unsigned char **pixel, char line1[100],char line2[100], char line3[100],char filename[100])
{
fftw_complex* in, * dft, * idft, * dft2;
//fftw_complex tmp1,tmp2;
fftw_plan plan_f,plan_i;
int i,j,k,w,h,N,w2,h2;
w = width;
h = height;
N = w*h;
unsigned char **pixel_out;
pixel_out = malloc(h*sizeof(unsigned char*));
for(i = 0 ; i<h;i++)
pixel_out[i]=malloc(w*sizeof(unsigned char));
in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *N);
dft = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *N);
dft2 = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *N);
idft = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *N);
/*run forward FFT*/
plan_f = fftw_plan_dft_2d(w,h,in,dft,FFTW_FORWARD,FFTW_ESTIMATE);
for(i = 0,k = 0 ; i < h ; i++)
{
for(j = 0 ; j < w ; j++,k++)
{
in[k][0] = pixel[i][j];
in[k][1] = 0.0;
}
}
fftw_execute(plan_f);
double maxReal = 0.0;
for(i = 0 ; i < N ; i++)
maxReal = dft[i][0] > maxReal ? dft[i][0] : maxReal;
printf("MAX REAL : %f\n",maxReal);
/*fftshift*/
//convert to 2d
double ***temp1;
temp1 = malloc(h * sizeof (double**));
for (i = 0;i < h; i++){
temp1[i] = malloc(w*sizeof (double*));
for (j = 0; j < w; j++){
temp1[i][j] = malloc(2*sizeof(double));
}
}
double ***temp2;
temp2 = malloc(h * sizeof (double**));
for (i = 0;i < h; i++){
temp2[i] = malloc(w*sizeof (double*));
for (j = 0; j < w; j++){
temp2[i][j] = malloc(2*sizeof(double));
}
}
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
temp1[i][j][0] = dft[i*w+j][0];
temp1[i][j][1] = dft[i*w+j][1];
}
}
int m2 = h/2;
int n2 = w/2;
//forward shifting
for (i = 0; i < m2; i++)
{
for (k = 0; k < n2; k++)
{
double tmp13[2] = {temp1[i][k][0],temp1[i][k][1]};
temp1[i][k][0] = temp1[i+m2][k+n2][0];
temp1[i][k][1] = temp1[i+m2][k+n2][1];
temp1[i+m2][k+n2][0] = tmp13[0];
temp1[i+m2][k+n2][1] = tmp13[1];
double tmp24[2] = {temp1[i+m2][k][0],temp1[i+m2][k][1]};
temp1[i+m2][k][0] = temp1[i][k+n2][0];
temp1[i+m2][k][1] = temp1[i][k+n2][1];
temp1[i][k+n2][0] = tmp24[0];
temp1[i][k+n2][1] = tmp24[1];
}
}
//process
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
if(distance_to_center(i,j,m2,n2) < 0.25*h)
{
temp1[i][j][0] = (double)0.0;
temp1[i][j][1] = (double)0.0;
}
}
}
/* copy for magnitude */
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
temp2[i][j][0] = temp1[i][j][0];
temp2[i][j][1] = temp1[i][j][1];
}
}
//backward shifting
for (i = 0; i < m2; i++)
{
for (k = 0; k < n2; k++)
{
double tmp13[2] = {temp1[i][k][0],temp1[i][k][1]};
temp1[i][k][0] = temp1[i+m2][k+n2][0];
temp1[i][k][1] = temp1[i+m2][k+n2][1];
temp1[i+m2][k+n2][0] = tmp13[0];
temp1[i+m2][k+n2][1] = tmp13[1];
double tmp24[2] = {temp1[i+m2][k][0],temp1[i+m2][k][1]};
temp1[i+m2][k][0] = temp1[i][k+n2][0];
temp1[i+m2][k][1] = temp1[i][k+n2][1];
temp1[i][k+n2][0] = tmp24[0];
temp1[i][k+n2][1] = tmp24[1];
}
}
//convert back to 1d
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
dft[i*w+j][0] = temp1[i][j][0];
dft[i*w+j][1] = temp1[i][j][1];
dft2[i*w+j][0] = temp2[i][j][0];
dft2[i*w+j][1] = temp2[i][j][1];
}
}
/* magnitude */
double max = 0;
double min = 0;
double mag=0;
for (i = 0, k = 1; i < h; i++){
for (j = 0; j < w; j++, k++){
mag = sqrt(pow(dft2[i*w+j][0],2) + pow(dft2[i*w+j][1],2));
if (max < mag)
max = mag;
}
}
double **magTemp;
magTemp = malloc(h * sizeof (double*));
for (i = 0;i < h; i++){
magTemp[i] = malloc(w*sizeof (double));
}
for(i = 0,k = 0 ; i < h ; i++)
{
for(j = 0 ; j < w ; j++,k++)
{
double mag = sqrt(pow(dft2[i*w+j][0],2) + pow(dft2[i*w+j][1],2));
mag = 255*(mag/max);
//magTemp[i][j] = 255-mag; //Putih
magTemp[i][j] = mag; //Item
}
}
/* brightening magnitude*/
for(i = 0,k = 0 ; i < h ; i++)
{
for(j = 0 ; j < w ; j++,k++)
{
//double temp = magTemp[i][j];
double temp = (double)(255/(log(1+255)))*log(1+magTemp[i][j]);
pixel_out[i][j] = (unsigned char)temp;
}
}
generateImage(width,height,pixel_out,line1,line2,line3,filename,"magnitude");
/* backward fft */
plan_i = fftw_plan_dft_2d(w,h,dft,idft,FFTW_BACKWARD,FFTW_ESTIMATE);
fftw_execute(plan_i);
for(i = 0,k = 0 ; i < h ; i++)
{
for(j = 0 ; j < w ; j++,k++)
{
double temp = idft[i*w+j][0]/N;
pixel_out[i][j] = (unsigned char)temp; //+ pixel[i][j];
}
}
generateImage(width,height,pixel_out,line1,line2,line3,filename,"backward");
return pixel_out;
}
EDIT new source code
I add this part before the forward shifting, the result is as expected also.
//proses
//create filter
unsigned char **pixel_filter;
pixel_filter = malloc(h*sizeof(unsigned char*));
for(i = 0 ; i<h;i++)
pixel_filter[i]=malloc(w*sizeof(unsigned char));
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
if(distance_to_center(i,j,m2,n2) < 20)
{
pixel_filter[i][j] = 0;
}
else
{
pixel_filter[i][j] = 255;
}
}
}
generateImage(width,height,pixel_filter,line1,line2,line3,filename,"filter1");
for (i = 0; i < m2; i++)
{
for (k = 0; k < n2; k++)
{
unsigned char tmp13 = pixel_filter[i][k];
pixel_filter[i][k] = pixel_filter[i+m2][k+n2];
pixel_filter[i+m2][k+n2] = tmp13;
unsigned char tmp24 = pixel_filter[i+m2][k];
pixel_filter[i+m2][k] = pixel_filter[i][k+n2];
pixel_filter[i][k+n2] = tmp24;
}
}
generateImage(width,height,pixel_filter,line1,line2,line3,filename,"filter2");
for (i = 0;i < h; i++){
for (j = 0; j < w; j++){
temp1[i][j][0] *= pixel_filter[i][j];
temp1[i][j][1] *= pixel_filter[i][j];
}
}
Your general idea is OK. From the output, it's hard to tell whether there's simply an accounting problem in your program, or whether this is perhaps the expected result. Try padding the source image with much more empty space, and filter out a smaller area in the frequency domain.
As a side note, doing this in C appears incredibly painful. Here is an equivalent implementation in Matlab. Not including plotting, it's around 10 lines of code. You might also try Numerical Python (NumPy).
% Demonstrate frequency-domain image filtering in Matlab
% Define the grid
x = linspace(-1, 1, 1001);
y = x;
[X, Y] = meshgrid(x, y);
% Make a square (source image)
rect = (abs(X) < 0.1) & (abs(Y) < 0.1);
% Compute the transform
rect_hat = fft2(rect);
% Make the high-pass filter
R = sqrt(X.^2 + Y.^2);
filt = (R > 0.05);
% Apply the filter
rect_hat_filtered = rect_hat .* ifftshift(filt);
% Compute the inverse transform
rect_filtered = ifft2(rect_hat_filtered);
%% Plot everything
figure(1)
imagesc(rect);
title('source');
axis square
saveas(gcf, 'fig1.png');
figure(2)
imagesc(abs(fftshift(rect_hat)));
title('fft(source)');
axis square
saveas(gcf, 'fig2.png');
figure(3)
imagesc(filt);
title('filter (frequency domain)');
axis square
saveas(gcf, 'fig3.png');
figure(4)
imagesc(fftshift(abs(rect_hat_filtered)));
title('fft(source) .* filter');
axis square
saveas(gcf, 'fig4.png');
figure(5)
imagesc(abs(rect_filtered))
title('result');
axis square
saveas(gcf, 'fig5.png');
The source image:
Fourier transform of the source image:
The filter:
Result of applying (multiplying) the filter with the fourier transform of the source image:
Taking the inverse transform gives the final result: