I am trying to reflect(filp horizontally) an image and I can't quite seem figure out why the image does not reflect and stays in original condition. I've tried many different methods (adding -1 to [width - j] or assigning the tempArray as RGBTRIPLE tempArray;and dividing width with /2 as the loop condition.
No errors being thrown, and I've followed the solutions from Stackoverflow and it seems like I am not quite getting there, any advices?
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE tempArray[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
tempArray[i][j] = image[i][j];
image[i][j] = image[i][width - j];
image[i][width - j] = tempArray[i][j];
}
}
return;
}
As mentioned in the comments, you have 2 issues. First, since you iterate over the entire row, you end up swapping each item 2x. And that leaves just the original array.
Second, you access one past the end of the array with image[i][width - j] when j == 0. Valid indexes for an array are 0...(length-1).
Another, minor issue is that you don't need an array for the temp value.
// Reflect image horizontally
void reflect(int height, int width, int image[height][width])
{
int temp;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width / 2; j++)
{
temp = image[i][j];
image[i][j] = image[i][width - j - 1];
image[i][width - j - 1] = temp;
}
}
return;
}
Tested: https://ideone.com/EAALtI
Related
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].
Hello I am doing an assignment for Harvard CS50 please read the directions if you want to answer the question.
Here is my code for helpers.c
#include "helpers.h"
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
RGBTRIPLE pixel = image[i][j];
int newgray = round((pixel.rgbtBlue + pixel.rgbtGreen + pixel.rgbtRed)/ 3.00);
image[i][j].rgbtBlue = newgray;
image[i][j].rgbtGreen = newgray;
image[i][j].rgbtRed = newgray;
}
}
return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
RGBTRIPLE pixel = image[i][j];
//Reassign pixel colors based on formula
image[i][j].rgbtRed = .393 * pixel.rgbtRed + .769 * pixel.rgbtGreen + .189 * pixel.rgbtBlue;
image[i][j].rgbtGreen = .349 * pixel.rgbtRed + .686 * pixel.rgbtGreen + .168 * pixel.rgbtBlue;
image[i][j].rgbtBlue = .272 * pixel.rgbtRed + .534 * pixel.rgbtGreen + .131 * pixel.rgbtBlue;
}
}
return;
}
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width/2; j++)
{
temp[i][j] = image[i][j];
int reflected_j = width - j;
image[i][reflected_j] = image[i][j];
image[i][j] = temp[i][j];
}
}
return;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
return;
}
My first question is why is it that when I replace image[i][j].rgbtBlue = newgray; in the grayscale function with pixel.rgbtBlue = newgray; it doesn't work. Isn't the pixel variable literally a copy of image[i][j].
My second question lies in the reflection function where I make RGBTRIPLE temp[height][width]; (RGBTRIPLE is a data structure using 1 byte for each RGB color in the images picture) and assign it to copy the pixels of the original image. I made it so that it would copy the first half of the picture and reflect it to the other side from the original image then from the copy (temp) I would copy the second half and paste it in the first half of the original image. Why does the first half (left half) come up as black?
Input: image, terminal command: ./filter -r tower.bmp outfile.bmp
(tower.bmp is the input image and outfile is the output image)
Output: image
There are a few issues with reflect().
Only one element of temp is used at a time and never reused. Thus there is no need to create a potentially huge instance on stack.
Index reflected_j = width - j for j equal to 0 will be equal width what is out of bounds for array of length width. This invokes UB. It should be reflected_j = width - j - 1
It would be better to swap pixels while reflecting the image, not to play with half-copy.
Updated code:
void reflect(int height, int width, RGBTRIPLE image[height][width]) {
for (int y = 0; y < height; y++) {
for (int i = 0, j = width - 1; i < j; i++, j--) {
RGBTRIPLE temp = image[y][i];
image[y][i] = image[y][j];
image[y][j] = temp;
}
}
}
As for your first question, it is because pixel is only a value copy of image[i][j]. It has a separate memory location of it's own, so modifying it wont change the image[i][j].
As for your second question it is because this line
image[i][reflected_j] = image[i][j];
should be
image[i][j]=image[i][reflected_j]
and this line
image[i][j] = temp[i][j];
should be
image[i][reflected_j]=temp[i][j]
I got an assigment for a set of programs that manipulate PPM image files. One of these programs consists of adding a colored frame of width w around the original image.
It wasn't very hard finding a solution, but I'm curious if it can be optimized as it doesn't seem the most elegant way to do it.
Im using an array pixel ** (inside a struct ppmfile which also contains header data) to store the image data, it is allocated with this function:
pixel **imgdata(int xsize, int ysize)
{
pixel **imgdata;
imgdata = (pixel**)malloc(ysize*sizeof(pixel*));
for(int i = 0; i < ysize; i++)
(imgdata)[i] = (pixel*)malloc(xsize*sizeof(pixel));
return imgdata;
}
This is the function I came up with:
void frame(ppmfile *ppm, int width, pixel color)
{
pixel **new_image = imgdata(ppm->xsize + (width*2), ppm->ysize + (width*2));
//Copying to center of new pixel matrix
for(int i = 0; i < ppm->ysize; i++)
for(int j = 0; j < ppm->xsize; j++)
new_image[width + i][width + j] = ppm->imgdata[i][j];
free_ppmimgdata(ppm);
ppm->imgdata = new_image;
ppm->xsize += width*2;
ppm->ysize += width*2;
//frame sides
for (int i = 0; i < width; i++)
for(int j = 0; j < ppm->xsize; j++)
{
ppm->imgdata[i][j] = color;
ppm->imgdata[ppm->ysize - i - 1][j] = color;
}
//frame top and bottom
for(int i = width; i < ppm->ysize - width; i++)
for (int j = 0; j < width; j++)
{
ppm->imgdata[i][j] = color;
ppm->imgdata[i][ppm->xsize - j - 1] = color;
}
}
But this allocates an entirely new, bigger, array in memory while also having imo too many loops for something this simple... So my question is if it's possible to realloc() this type of matrix, while moving/copying/preserving its contents at the "center" of the new matrix - as (poorly) illustrated here? Are there any other ways you can see to optimize this?
Thanks in advance!
I have been stuck with this function for days now. I looked at other people questions, I watched youtube tutorials videos, but I can't get it right.
The task is part of Harvard's CS50 course (https://cs50.harvard.edu/x/2020/psets/4/filter/less/).
Any kind of help would be much appreciated! I really don't want to go on with the course without understanding what the problem is.
//check if pixels are valid
bool valid_pixel(int r, int c, int height, int width)
{
return r >= 0 && c >= 0 && r < height && c < width;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
//create a copy of the original image
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
temp[i][j] = image[i][j];
}
}
int red, green, blue, count;
red = green = blue = count = 0;
//iterate through rows
for (int i = 0; i < height; i++)
{
//iterate through columns
for (int j = 0; j < width; j++)
{
//move one pixel up to one pixel down in the rows
for (int r = i - 1; r <= i + 1; r++)
{
//move one pixel left to one pixel right in the columns
for (int c = j - 1; c <= j + 1; c++)
{
//check if they are unvalid pixels
if (valid_pixel(r, c, height, width))
{
//count every valid pixel
count ++;
//"store" every pixel color
red += image[r][c].rgbtRed;
green += image[r][c].rgbtGreen;
blue += image[r][c].rgbtBlue;
}
}
}
//calculate average values
temp[i][j].rgbtRed = round((float)red / count);
temp[i][j].rgbtGreen = round((float)green / count);
temp[i][j].rgbtBlue = round((float)blue / count);
}
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j] = temp[i][j];
}
}
return;
The primary problem is that you forget to reset red, blue and green variables (that you sum up) after each outer loop iteration. You should put this line inside the main loop-
red = green = blue = count = 0;
Also, you're copying the image into another temporary image and copying that temporary image into the original image again in the end. This is very in-efficient. You should not copy the pixels from the original image into the blurred image at first. You can put the modified values directly into this temporary image. And in the end, use memmove to efficiently move entire rows to the original image at once. (Remember to #include <string.h>)
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE blurred_img[height][width];
//iterate through rows
for (int i = 0; i < height; i++)
{
//iterate through columns
for (int j = 0, red, green, blue, count; j < width; j++)
{
// Reset the variables
red = blue = green = count = 0;
//move one pixel up to one pixel down in the rows
for (int r = i - 1; r <= i + 1; r++)
{
//move one pixel left to one pixel right in the columns
for (int c = j - 1; c <= j + 1; c++)
{
//check if they are unvalid pixels
if (valid_pixel(r, c, height, width))
{
//count every valid pixel
count++;
//"store" every pixel color
red += image[r][c].rgbtRed;
green += image[r][c].rgbtGreen;
blue += image[r][c].rgbtBlue;
}
}
}
//calculate average values
blurred_img[i][j].rgbtRed = round((float)red / count);
blurred_img[i][j].rgbtGreen = round((float)green / count);
blurred_img[i][j].rgbtBlue = round((float)blue / count);
}
}
for (int i = 0; i < height; i++)
{
// Copy the new image over to the original, row by row
memmove(image[i], blurred_img[i], sizeof(RGBTRIPLE) * width);
}
return;
}
This is assuming valid_pixel is correct. To determine whether the pixel position is valid you can just do-
if (k > 0 && k < height && l > -1 && l < width))
Notice however, when r (the row) is invalid, the innermost loop (column loop) is still iterated until c == width even though the entirety of this loop is useless, because r is invalid and it'll stay that way until the innermost loop completes and r increments.
For efficiency, you should break whenever r is invalid-
if (r < 0 || r > height - 1)
{
break;
}
if (c > -1 && c < width)
{
//count every valid pixel
count++;
//"store" every pixel color
red += image[r][c].rgbtRed;
green += image[r][c].rgbtGreen;
blue += image[r][c].rgbtBlue;
}
I'm facing some difficulties while doing the reflect portion of filter. Essentially the struct is
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
and I have been attempting to reflect the image by implementing this function.
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
if (width % 2 == 0)
{
for (int j = 0; j < width/2; j++)
{
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j];
image[i][width - j] = temp;
}
}
else if (width % 3 == 0)
{
for (int j = 0; j < (width - 1)/2; j++)
{
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j];
image[i][width - j] = temp;
}
}
}
return;
}
The code compiles fine but the end product is the same as the input image. Tried to run debug50 and i figured that my problem lies with the way i swap the RGBTRIPLE values. Any help would be good. Thanks!
What you need to do is to reverse the array.
Why? because you are reflecting image horizontally so you want the left side of the image to become the right side of the image.
Imagine you have this array and you want to reverse it:
int count = 5;
int numbers[count] = {0, 1, 2, 3, 4};
// middle here should be 2.5 but it will be 2 because we cast it to int
int middle = count / 2;
// Reverse array
for (int i = 0; i < middle; i++)
{
// when i is 0, numbers[i] is 0, numbers[count - 1 - i] is 4
temp = numbers[i];
numbers[i] = numbers[count - i - 1];
numbers[count - i - 1] = temp;
}
You should do the same in your function:
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
// The middle index
int middle = width / 2;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < middle; j++)
{
// Swap the left side element with right side element
RGBTRIPLE temp = image[i][j];
image[i][j] = image[i][width - j - 1];
image[i][width - j - 1] = temp;
}
}
return;
}