cs50 pset4 filter swapping structs - c

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;
}

Related

C issue, blur filter not working properly

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);
}
}
}

Dynamically allocate 2-dimensional structure array in C

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));

invalid operands to binary expression ('RGBTRIPLE' and 'int')

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.

Why can't I create copies of these 2D arrays in C?

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]

Reflecting (flipping) an image horizontally in C using 'temp' array

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

Resources