Hi to everyone who did CS50,
Currently, I am doing pset4 filter, reflect and struggling with the code I wrote. It compiles fine, but the output picture looks like the one that I attached. Has any a clue for me how I could fix this? (If possible without the solution; a hint is totally fine :))
#include "helpers.h"
#include <stdio.h>
#include <math.h>
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
for (int j = 0; j < (width - 1); j++)
{
//get the average
float average = 0;
average = (image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3;
//set color channels with the average value
image[i][j].rgbtRed = round(average);
image[i][j].rgbtGreen = round(average);
image[i][j].rgbtBlue = round(average);
}
}
return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
for (int j = 0; j < (width - 1); j++)
{
//calculate the new values
float red = 0;
float green = 0;
float blue = 0;
red = .393 * image[i][j].rgbtRed + .769 * image[i][j].rgbtGreen + .189 * image[i][j].rgbtBlue;
if (round(red) > 255)
{
image[i][j].rgbtRed = 255;
}
else if (round(red <= 255))
{
image[i][j].rgbtRed = red;
}
green = .349 * image[i][j].rgbtRed + .686 * image[i][j].rgbtGreen + .168 * image[i][j].rgbtBlue;
if (round(green) > 255)
{
image[i][j].rgbtGreen = 255;
}
else if (round(green) <= 255)
{
image[i][j].rgbtGreen = green;
}
blue = .272 * image[i][j].rgbtRed + .534 * image[i][j].rgbtGreen + .131 * image[i][j].rgbtBlue;
if (round(blue) > 255)
{
image[i][j].rgbtBlue = 255;
}
else if (round(blue) <= 255)
{
image[i][j].rgbtBlue = blue;
}
}
}
return;
}
// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < (height - 1); i++)
{
//RGBTRIPLE
int a[width - 1 /2];
int b[width - 1 /2];
int c[width - 1 /2];
for (int j = 0; j < ((width/2) - 1); j++)
{
a[j] = image[i][(width - 1) - j].rgbtRed;
b[j] = image[i][(width - 1) - j].rgbtGreen;
c[j] = image[i][(width - 1) - j].rgbtBlue;
}
// GERADE / UNGERADE ZAHLEN VERARBEITEN
for (int n = 0; (n + (width - 1) /2) < (width - 1); n++)
{
image[i][((width - 1)/2) - n].rgbtRed = image[i][((width - 1)/2) - n].rgbtRed;
image[i][((width - 1)/2) - n].rgbtGreen = image[i][((width - 1)/2) - n].rgbtGreen;
image[i][((width - 1)/2) - n].rgbtBlue = image[i][((width - 1)/2) - n].rgbtBlue;
}
for (int m = 0; m < ((width/2) - 1); m++)
{
image[i][m].rgbtRed = a[m];
image[i][m].rgbtRed = b[m];
image[i][m].rgbtRed = c[m];
}
}
return;
}
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
return;
}
Input:
./filter -r stadium.bmp outfile.bmp
(stadium.bmp is just a file that I choose. You can choose any file as the input)
Output: compiles successfully, please see attached pictureenter image description here
Your code is too complicated. You do not need to divide image into RGB values. You need to swap the image values from left to right or vice versa to achieve reflection.
For this you may need to create a temporary data structure which is the same as "image".
RGBTRIPLE temp[width];
With temp, you need to store values from image, and swap them. Following is a design pattern which you can use.
//Pseudo code
1. //Loop though the row of an image (start from row = 0). We need to iterate every row.
2. // Loop through the height of an image to save current row in an image to the temp.
3. // Swap the values in image by using the temp.
If you want to filter this one dimensional image below.
val1, val2, valn, val3, val4
After reflection filter, it will be like this.
val4, val3, valn, val2, val1
Related
I am trying to write a function that applies a sepia filter to the images,
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
int r = image[i][j].rgbtRed;
int g = image[i][j].rgbtGreen;
int b = image[i][j].rgbtBlue;
image[i][j].rgbtRed = round((0.393 * r) + (0.769 * g) + (0.189 * b));
image[i][j].rgbtGreen = round((0.349 * r) + (0.686 * g) + (0.168 * b));
image[i][j].rgbtBlue = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if(image[i][j].rgbtRed > 255)
{
image[i][j].rgbtRed = 255;
}
if(image[i][j].rgbtGreen > 255)
{
image[i][j].rgbtGreen = 255;
}
if(image[i][j].rgbtBlue > 255)
{
image[i][j].rgbtBlue = 255;
}
}
}
}
when I used this code, it does not raise any error, but the if conditions do not work at all, and the resulting image has many creepy pixels.
but when I used intermediate variables like this code below:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int i=0; i<height; i++)
{
for(int j=0; j<width; j++)
{
int r = image[i][j].rgbtRed;
int g = image[i][j].rgbtGreen;
int b = image[i][j].rgbtBlue;
int sr = round((0.393 * r) + (0.769 * g) + (0.189 * b));
int sg = round((0.349 * r) + (0.686 * g) + (0.168 * b));
int sb = round((0.272 * r) + (0.534 * g) + (0.131 * b));
if(sr > 255)
{
sr = 255;
}
if(sg > 255)
{
sg = 255;
}
if(sb > 255)
{
sb = 255;
}
image[i][j].rgbtRed = sr;
image[i][j].rgbtGreen = sg;
image[i][j].rgbtBlue = sb;
}
}
}
the if statements worked perfectly.
my question is what is wrong in the first code that makes the if statements don't work?
image[i][j].rgbtRed > 255 is never true as .rgbtRed is 8-bit. Use an int to save the sum.
The structure members are eight-bit unsigned integers. When you assign to them, values over 255 are lost. (They are wrapped modulo 256.)
When you assign to the intermediate int variables, they retain the full values.
I got this error when I tried to look particular value exist or not. I used a custom data type called RGBTRIPLE that cs50 provides me. If the value is not exist in the memory I will get 'segmentation fault' because I need to find out top left, top middle, top right, value that I have its previous value and next value, bottom left, bottom middle, bottom right value. So for that I used a function called isNull. It will check whether the value exists in the memory or not. If it is not null It will return 1, otherwise 0.
Here is my code
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// entering the array of the image
for (int i = 0; i < height; i++)
{
// entering the array of the row
for (int j = 0; j < width; j++)
{
/* blur: the element we select we need to get the value
of its neighbour value and adding this all including it
then get the avg value of pixel that need to set
*/
int element = 0;
int blueSum = 0;
int greenSum = 0;
int redSum = 0;
RGBTRIPLE pixels[] = {
image[i][j], image[i][j - 1], image[i][j + 1],
image[i - 1][j - 1], image[i - 1][j], image[i - 1][i + 1],
image[i + 1][j - 1], image[i + 1][j], image[i + 1][j + 1]
};
for (int k = 0; k < 9; k++)
{
if (isNull(pixels[k]) == 1)
{
element++;
blueSum += pixels[k].rgbtBlue;
greenSum += pixels[k].rgbtGreen;
redSum += pixels[k].rgbtRed;
}
}
image[i][j].rgbtBlue = round(blueSum / element);
image[i][j].rgbtGreen = round(greenSum / element);
image[i][j].rgbtRed = round(redSum / element);
}
}
return;
}
// check whether it is null or not
int isNull(RGBTRIPLE pixel)
{
if (pixel != 0)
{
return 1;
}
return 0;
}
Error I got:
$ make filter
helpers.c:142:15: error: invalid operands to binary expression ('RGBTRIPLE' and 'int')
if (pixel != 0)
~~~~~ ^ ~
1 error generated.
make: *** [Makefile:2: filter] Error 1
the type RGBTRIPLE is defined in bmp.h as:
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
It is a structure: you cannot compare structures with the == operator, you must compare members individually.
The problem is: what do you mean by check whether it is null or not?
If you mean "is the pixel black?", you should test if all 3 components are 0:
// check whether it is black or not
int isBlack(RGBTRIPLE pixel) {
return ((pixel.rgbtBlue | pixel.rgbtGreen | pixel.rgbtRed) == 0);
}
You get a segmentation fault because you read pixels beyond the boundaries of the matrix image:
the 6th initializer image[i - 1][i + 1] has a typo
you must make special cases for the image boundaries (i == 0, j == 0, i == height - 1 and j == width - 1).
Here is a simple fix:
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a < b ? b : a; }
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// entering the array of the image
for (int i = 0; i < height; i++) {
// entering the array of the row
for (int j = 0; j < width; j++) {
/* blur: compute the new color by averaging the components
of all pixels in a 3x3 area around the pixel.
assume that pixel colors continue beyond the image
borders.
*/
unsigned blueSum = 0;
unsigned greenSum = 0;
unsigned redSum = 0;
int i1 = max(0, i - 1);
int i2 = min(height - 1, i + 1);
int j1 = max(0, j - 1);
int j2 = min(width - 1, j + 1);
RGBTRIPLE pixels[] = {
image[i][j1], image[i][j], image[i][j2],
image[i1][j1], image[i1][j], image[i1][j2],
image[i2][j1], image[i2][j], image[i2][j2]
};
for (int k = 0; k < 9; k++) {
blueSum += pixels[k].rgbtBlue;
greenSum += pixels[k].rgbtGreen;
redSum += pixels[k].rgbtRed;
}
image[i][j].rgbtBlue = round(blueSum / 9);
image[i][j].rgbtGreen = round(greenSum / 9);
image[i][j].rgbtRed = round(redSum / 9);
}
}
}
Note however that the above function cannot work as coded because it overwrites the pixel values that will be used for the next column and for the next row. To perform this transformation in place, you can use a 3 line buffer to keep the previous values.
Here is a modified version:
typedef unsigned char BYTE;
typedef struct {
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} RGBTRIPLE;
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE row[3][width + 2];
// populate the initial the row cache
row[1][0] = row[2][0] = image[0][0];
row[1][width + 1] = row[2][width + 1] = image[0][width - 1];
for (int j = 0; j < width; j++) {
row[1][j + 1] = row[2][j + 1] = image[0][j];
}
// entering the array of the image
for (int i = 0; i < height; i++) {
// update the row cache
for (int j = 0; j < width + 2; j++) {
row[0][j] = row[1][j];
row[1][j] = row[2][j];
}
if (i < height - 2) {
row[2][0] = image[i + 1][0];
row[2][width + 1] = image[i + 1][width - 1];
for (int j = 0; j < width; j++)
row[2][j + 1] = image[i + 1][j + 1];
}
// update the image row
for (int j = 0; j < width; j++) {
/* blur: compute the new color by averaging the components
of all pixel values in a 3x3 area around the pixel.
Assume that pixel colors are extended beyond the image
borders.
*/
unsigned blueSum = 0;
unsigned greenSum = 0;
unsigned redSum = 0;
for (int ii = 0; ii < 3; ii++) {
for (int jj = j; jj < j + 3; jj++) {
blueSum += row[ii][jj].rgbtBlue;
greenSum += row[ii][jj].rgbtGreen;
redSum += row[ii][jj].rgbtRed;
}
}
image[i][j].rgbtBlue = (BYTE)((blueSum + 4) / 9);
image[i][j].rgbtGreen = (BYTE)((greenSum + 4) / 9);
image[i][j].rgbtRed = (BYTE)((redSum + 4) / 9);
}
}
}
You cannot compare scalar types with a struct or an array. That is what the error message is telling you.
What condition should be true to make a struct of multiple unrelated bytes to compare with a numerical value?
That's not how it works. You can only compare the fields separately or compare whole struct with another variable of same struct type.
Besides that, you have a few misconceptions in your code.
If the value is not exist in the memory I will get 'segmentation fault'
You got a segmentation fault because the memory you want to read is not your memory. You have no access privileges to read or write.
It will check whether the value exists in the memory or not.
If you provide some value to a function, it will always "exist in memory". You have provided a value in the calling function. How would it not exist?
You cannot detect if the memory location where you copied it from was valid by just looking at the copied value.
Your underlying problem is that you do not verify that you are withing bounds of your array before reading the values.
You must compare row and column index with the limits and only access the array element if you are not out of bounds.
You need to rework your approach to collect pixels to blur.
I wrote code for the sepia function of the filter pset. The code compiles without any errors but the output image is not entirely sepia. However, after I wrote the code in different way it works fine. Can someone explain why this happens?
First code:
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={0,0,0};
RGBTRIPLE pix = image[i][j];
pixel.rgbtBlue = round(0.272 * pix.rgbtRed + 0.534 * pix.rgbtGreen + 0.131 * pix.rgbtBlue);
pixel.rgbtGreen = round(0.349 * pix.rgbtRed + 0.686 * pix.rgbtGreen + 0.168 * pix.rgbtBlue);
pixel.rgbtRed = round(0.393 * pix.rgbtRed + 0.769 * pix.rgbtGreen + 0.189 * pix.rgbtBlue);
if(pixel.rgbtBlue > 255)
{
pixel.rgbtBlue = 255;
}
if(pixel.rgbtGreen > 255)
{
pixel.rgbtGreen = 255;
}
if(pixel.rgbtRed > 255)
{
pixel.rgbtRed = 255;
}
image[i][j] = pixel;
}
}
return;
}
first code output image:
Second Code:
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int red = image[i][j].rgbtRed;
int green = image[i][j].rgbtGreen;
int blue = image[i][j].rgbtBlue;
//calculate sepia values
int sepiaRed = round(.393 * red + .769 * green + .189 * blue);
if(sepiaRed > 255)
{
sepiaRed = 255;
}
int sepiaGreen = round(.349 * red + .686 * green + .168 * blue);
if(sepiaGreen > 255)
{
sepiaGreen = 255;
}
int sepiaBlue = round(.272 * red + .534 * green + .131 * blue);
if(sepiaBlue > 255)
{
sepiaBlue = 255;
}
image[i][j].rgbtRed = sepiaRed;
image[i][j].rgbtGreen = sepiaGreen;
image[i][j].rgbtBlue = sepiaBlue;
}
}
return;
}
Second code output:
The difference between the two versions is that the type in which you compute the new pixel value
In the first version the type is whatever the constituent members of RGBTRIPLE are - which I assume is an unsigned 8-bit integer.
pixel.rgbtBlue = round(0.272 * pix.rgbtRed + 0.534 * pix.rgbtGreen + 0.131 * pix.rgbtBlue);
In this line (and the equivalents for green and red pixels),
the value can exceeded 255 which then gets truncated by assignment to an 8-bit unsigned int on assignment to pixel.rgbtBlue.
The following clamp to saturation:
if(pixel.rgbtBlue > 255)
{
pixel.rgbtBlue = 255;
}
Will always excute false, as pixel.rgbtBlue cannot hold a value bigger than 255.
In the second version of the code, an int is used, which is larger, and in which truncation does not occur, allowing the clamp-to-255 to work correct.
As people above already comment, the first one has a truncated value in the if conditions, as the avarage operation is resulting in a number bigger than 255... That's why the filter does not work properly.
I would consider as well less "if/else" on the second one, using perhaps a "Ternary Operator", for a cleaner code:
image[i][j].rgbtGreen = (sepiaGreen > 255) ? 255 : sepiaGreen;
image[i][j].rgbtRed = (sepiaRed > 255) ? 255 : sepiaRed;
image[i][j].rgbtBlue = (sepiaBlue > 255) ? 255 : sepiaBlue;
I am working on the CS50 filter challenge and specifically the blur challenge.
It compiles nicely, but when I create the image the image is turned 90 degrees and at the bottom of the image is an image error.
Do you know what the problem is?
This is my code:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
float sum_blue;
float sum_green;
float sum_red;
float counter;
RGBTRIPLE temp[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
sum_blue = 0;
sum_green = 0;
sum_red = 0;
counter = 0;
for (int h= -1; h < 2; h++)
{
if (j + h < 0 || j + h > width - 1)
{
continue;
}
for (int v = -1; v < 2; v++)
{
if (i + v < 0 || i + v > height - 1)
{
continue;
}
sum_red += image[j + h][i + v].rgbtRed;
sum_blue += image[j + h][i + v].rgbtBlue;
sum_green += image[j + h][i + v].rgbtGreen;
counter++;
}
}
//summarize all values and save the pixels in a temporary image to transfer it later
temp[i][j].rgbtRed = round(sum_red / counter);
temp[i][j].rgbtBlue = round(sum_blue / counter);
temp[i][j].rgbtGreen = round(sum_green / counter);
}
}
// transfer temporary to real image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
image[i][j].rgbtRed = temp[i][j].rgbtRed;
image[i][j].rgbtBlue = temp[i][j].rgbtBlue;
image[i][j].rgbtGreen = temp[i][j].rgbtGreen;
}
}
}
You appear to have swapped width and height here:
sum_red += image[j + h][i + v].rgbtRed;
sum_blue += image[j + h][i + v].rgbtBlue;
sum_green += image[j + h][i + v].rgbtGreen;
I would expect:
sum_red += image[i + v][j + h].rgbtRed;
sum_blue += image[i + v][j + h].rgbtBlue;
sum_green += image[i + v][j + h].rgbtGreen;
since the image array is [height][width] and i is the vertical iterator and j the horizontal. Possibly only i and j are swapped, and i + h and j + v are intended.
Possibly the variables are swapped elsewhere in the algorithm. Better variable naming might help - so the names indicate what they represent. Even x and y would be clearer since that is a convention for cartesian coordinates - though a comment indicating top-left origin and y increasing down might be advisable.
By getting the indexes in the wrong order you have rotated and mirrored it and processed data from the wrong part of the image or not in the image at all.
I am doing cs50 pset4 sepia filter. The tests results from check50 show that the last two tests fail, but all the other tests are okay. I can't figure out what is the problem, because the expected output and my actual output are the same.
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
float orginalRed = image[i][j].rgbtRed;
float originalGreen = image[i][j].rgbtGreen;
float originalBlue = image[i][j].rgbtBlue;
float spRed = round(.393 * orginalRed + .769 * originalGreen + .189 * originalBlue);
float spGreen = round(.349 * orginalRed + .686 * originalGreen + .168 * originalBlue);
float spBlue = round(.272 * orginalRed + .534 * originalGreen + .131 * originalBlue);
if (spRed > 255.0)
{
spRed = 225;
}
if (spBlue > 255.0)
{
spBlue = 255;
}
if (spGreen > 255.0)
{
spGreen = 255;
}
image[i][j].rgbtRed = spRed;
image[i][j].rgbtGreen = spGreen;
image[i][j].rgbtBlue = spBlue;
}
}
}
The one thing sticking out is that you set red to 225 if it exceeds 255. That looks wrong.
Anyway, simplify:
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 x = image[i][j];
#define X(r, g, b) fmin(255, round(r * x.rgbtRed + g * x.rgbtGreen + b * x.rgbtBlue))
image[i][j].rgbtRed = X(.393, .769, .189);
image[i][j].rgbtGreen = X(.349, .686, .168);
image[i][j].rgbtBlue = X(.272, .534, .131);
#undef X
}
}
}
If you look closely at the results from the 2 check50 tests that were wrong, line 7-9 of the expected output is:
255 251 195
255 255 214
255 255 232
Then lines 7-9 of the actual output are:
225 251 195
225 255 214
225 255 232
The red values of the actual output should have been rounded to 255 instead of 225. The bug is at line 17, where you say:
spRed = 225; instead of spRed = 255;
I also replaced the if statements with a ternary operator and replaced the use of variables orginalRed, orginalBlue, and orginalGreen with the actual pixel values, for better run time and simplicity.
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++)
{
for (int x = 0; x < width; x++)
{
float spRed = round(.393 * image[i][x].rgbtRed + .769 * image[i][x].rgbtGreen + .189 * image[i][x].rgbtBlue);
float spGreen = round(.349 * image[i][x].rgbtRed + .686 * image[i][x].rgbtGreen + .168 * image[i][x].rgbtBlue);
float spBlue = round(.272 * image[i][x].rgbtRed + .534 * image[i][x].rgbtGreen + .131 * image[i][x].rgbtBlue);
image[i][x].rgbtRed = (spRed < 255) ? spRed : 255;
image[i][x].rgbtBlue = (spBlue < 255) ? spBlue : 255;
image[i][x].rgbtGreen = (spGreen < 255) ? spGreen : 255;
}
}
return;
}
The arrays could be the problem also you just return maybe it waits you to return 0 extra. But usually main problem in c I think arrays.
Have you use allocate memorty for this array : image[i][j]