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]
Related
I want to make a grayscale filter so I have to assign the average of all 3 RGB values to each. I use a 2D array because this is a bitmap image and I'm filtering it by changing each pixel.
This is how the struct is defined (where BYTE is uint8_t):
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
Do I need to assign the value to each element of struct separately, like I did below, or is there a way to assign that value to all elements of the struct (since they are the same type) in that specific location in the array at once?
This is the code for the filtering function.
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0 ; j < width; j++)
{
image[i][j].rgbtBlue = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
image[i][j].rgbtGreen = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
image[i][j].rgbtRed = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen)/3;
}
}
return;
}
You can do it with a compound literal:
RGBTRIPLE x = image[i][j]; // Use temporary to reduce repetition.
BYTE t = (x.rgbtBlue + x.rgbtRed + x.rgbtGreen)/3;
image[i][j] = (RGBTRIPLE) { t, t, t };
You can certainly avoid making the calculation three times on each loop. Two obvious ways to do this are:
(1) Chain the assignments (note that expressions like a = b = 3; are valid C and the = operator associates right-to-left);
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtBlue = image[i][j].rgbtGreen = image[i][j].rgbtRed =
(image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen) / 3;
}
}
return;
}
(2) Calculate that 'gray' value and assign that to the array element (in one go) using a compound literal constructed from that calculated value:
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
BYTE gray = (image[i][j].rgbtBlue + image[i][j].rgbtRed + image[i][j].rgbtGreen) / 3;
image[i][j] = (RGBTRIPLE){ gray, gray, gray };
}
}
return;
}
Whether or not either of the above actually constitutes an improvement is subjective (and a good compiler will likely generate the same code in both cases). However, for more complex situations, these techniques can make your code clearer and its purpose easier for a reader to understand.
Note also that, as pointed out in the comments, the above two examples will assign the same value to each of the three components of the image[i][j] element. In your posted code, the second and third recalculations use one or two values that will have been modified by the previous line(s).
The image comes out as static with various colours instead of a blur where you can still see the image, can't find the bug
void blur(int height, int width, RGBTRIPLE image[height][width]){
RGBTRIPLE copy[height][width];
int pixle1;
int pixle2;
int pixle3;
//copy original image to copy
for(int f = 0; f < height; f++){
for(int b = 0; b < width; b++){
copy[f][b] = image[f][b];
}
}
//go through each pixel at i's row and j's column
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
//make boundaries surrounding the original pixel to iterate through
for(int x = i - 1; x <= i + 1 && x >= 0; x++){
for(int y = j + 1; y <= j + 1 && y >= 0; y++){
//add the RGB values to later use to find the average
pixle1 = pixle1 + copy[x][y].rgbtRed;
pixle2 = pixle2 + copy[x][y].rgbtGreen;
pixle3 = pixle3 + copy[x][y].rgbtBlue;
}
//find the average of the pixels surrounding the original and original pixel
//then add that average to original pixel to create a blur
image[i][j].rgbtRed = round((pixle1) / 9.0);
image[i][j].rgbtGreen = round((pixle2) / 9.0);
image[i][j].rgbtBlue = round((pixle3) / 9.0);
// 'And then read pixels’ colours from a copy but write (i.e., change) pixels’ colours in the image?'
}
}
}
return;
}
**it blurs a bmp file and for each pixel, I find all the pixels surrounding the copied 2d array it and find the average from them all including the main pixel and then add that to the image 2d array which has a struct data type **
italiwedfewfEWFEfc
qugewGEWGEote
I have been trying to create an edges filter as per CS50 problem set 4. I have seen several solutions, however I would like to know if my approach can work. I'm trying to expand the input image by a black border of one pixel width. For this I want to expand my two-dimensional RGBTRIPLE structure by one pixel on either side. I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.
I am defining a variable-length two-dimensional structure RGBTRIPLE which contains three values of the datatype BYTE:
RGBTRIPLE temp[height+2][width+2] = {};
I'm getting the error message that because of the variable length it may not have been initialized, which I understand. I have seen several solutions using pointers and malloc, which I hopefully implemented correctly in the first line. I have been trying to connect the RGBTRIPLE to the pointer as per the following two lines:
RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height+2)*(width+2)*sizeof(RGBTRIPLE));
RGBTRIPLE temp[height+2][width+2] = &ptr;
temp[height+2][width+2] = {0};
Setting all the values to zero here does also not work, but that's another issue.
I want to use the original RGBTRIPLE in a for-loop and I cannot get this to work. All examples I have seen use the pointers afterwards to add any information. Is there any way to define the RGBTRIPLE using malloc so that I can afterwards use it in code as a "normal" element of the structure as seen with temp[][]:
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
temp[i+1][j+1] = image[i][j];
}
}
for(int i = 1; i <= height; i++)
{
for(int j = 1; j <= width; j++)
{
int counter = 0;
float gxr, gxb, gxg, gyr, gyb, gyg = 0;
//right pixel
gxb += (2*temp[i][j+1].rgbtBlue);
gxg += (2*temp[i][j+1].rgbtGreen);
gxr += (2*temp[i][j+1].rgbtRed);
etc. for all surrounding pixels.
Any help is appreciated.
You might initialize as in the following sample code.
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char BYTE;
typedef struct tagRGBTRIPLE
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} RGBTRIPLE;
int main()
{
int height = 400;
int width = 600;
RGBTRIPLE img[height][width];
RGBTRIPLE temp[height+2][width+2];
for (int i = 0; i < height; i++) /* Build a sample image file */
{
for (int j = 0; j < width; j++)
{
img[i][j].rgbtRed = 68;
img[i][j].rgbtGreen = 188;
img[i][j].rgbtBlue = 32;
}
}
for (int i = 0; i < (height + 2); i++) /* Initialize the temporary RGBTRIPLE structure*/
for (int j = 0; j < (width + 2); j++)
{
temp[i][j].rgbtRed = 0;
temp[i][j].rgbtGreen = 0;
temp[i][j].rgbtBlue = 0;
}
for(int i = 0; i < height; i++) /* Imported code from the issue */
{
for(int j = 0; j < width; j++)
{
temp[i+1][j+1] = img[i][j];
}
}
for(int i = 0; i <= (height + 2); i++) /* Right and left edges*/
{
float gxr = 0, gxb = 0, gxg = 0;
temp[i][0].rgbtRed = gxr;
temp[i][0].rgbtGreen = gxg;
temp[i][0].rgbtBlue = gxb;
temp[i][width + 1].rgbtRed = gxr;
temp[i][width + 1].rgbtGreen = gxg;
temp[i][width + 1].rgbtBlue = gxb;
}
for(int i = 0; i <= (width + 2); i++) /* Top and bottom edges */
{
float gyr = 0, gyb = 0, gyg = 0;
temp[0][i].rgbtRed = gyr;
temp[0][i].rgbtGreen = gyg;
temp[0][i].rgbtBlue = gyb;
temp[height + 1][i].rgbtRed = gyr;
temp[height + 1][i].rgbtGreen = gyg;
temp[height + 1][i].rgbtBlue = gyb;
}
/* See what we have at a pixel point */
printf("Top edge RGBTRIPLE %d, %d, %d \n", temp[0][144].rgbtRed, temp[0][144].rgbtGreen, temp[0][144].rgbtBlue);
printf("Left edge RGBTRIPLE %d, %d, %d \n", temp[144][0].rgbtRed, temp[144][0].rgbtGreen, temp[144][0].rgbtBlue);
printf("RGBTRIPLE within image %d, %d, %d \n", temp[144][144].rgbtRed, temp[144][144].rgbtGreen, temp[144][144].rgbtBlue);
return 0;
}
C does not really provide a simple way to initialize tuples so you probably would need "for" loops to do this. Experiment with this scenario and see if it applies to the spirit of your project.
Some issues:
Use mem...() where possible.
To zero byte fill an entire variable length array:
// RGBTRIPLE temp[height+2][width+2] = {};
RGBTRIPLE temp[height+2][width+2];
memset(temp, 0, sizeof temp);
I am setting all values of RGB to 0 (aka black) in the first line and then copy the original image into the temporary structure, substituting all except the border values with the respective colours.
Alternative:
// Given image[][] is a 2D array
for(int i = 0; i < height; i++) {
memcpy(temp[i+1], image[i], sizeof image[i]);
}
Initialize properly
float gxr, gxb, gxg, gyr, gyb, gyg = 0; only initializes gyg.
float gxr = 0;
float gxb = 0;
...
float gyg = 0;
Advanced: int math vs. size_t math
int*int*size_t may overflow int*int where size_t*int*int does not.
Cast not needed in C.
Size to the referenced object, not the type.
// RGBTRIPLE *ptr = (RGBTRIPLE *)malloc((height+2)*(width+2)*sizeof(RGBTRIPLE));
RGBTRIPLE *ptr = malloc(sizeof ptr[0] * (height+2) * (width+2));
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;
}
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