CS50 blur filter(less) - c

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

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

CS50 PS4 filter-less blur

I'm having issues getting my code to return correct values and I can't stare at it anymore or my eyeballs will fall out.
Specifically, the test I've failed are
-blur correctly filters middle pixel
-blur correctly filters pixel on edge
-blur correctly filters 3x3 image
-blur correctly filters 4x4 image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
for (int i = 0; i < height; i++) // Go through rows
{
for (int j = 0; j < width; j++) // Go through columns
{
// Reset counters
float totalblue = 0.0; // Total of values
float totalgreen = 0.0; // Total of values
float totalred = 0.0; // Total of values
int counter = 0;
for (int k = -1; k < 2; k++) // To make 3x3 square
{
for (int l = -1; l < 2; l++) // To make 3x3 square
{
if (i + k >= 0 && i + k < height && j + l >= 0 && j + j < width) // Determine if pixel exists
{
// Update totals
totalblue += image[i+k][j+l].rgbtBlue;
totalgreen += image[i+k][j+l].rgbtGreen;
totalred += image[i+k][j+l].rgbtRed;
counter++;
}
}
}
// Set new values
image[i][j].rgbtBlue = round(totalblue / counter);
image[i][j].rgbtGreen = round(totalgreen / counter);
image[i][j].rgbtRed = round(totalred / counter);
}
}
return;
}
I've tried playing with the data type (but that doesn't seem to be the issue) and reworking the parameters for determining whether a pixel exists. It seems like that test is what's giving me the problem? Or an issue with my counting?

PSET4: Filter (more comfortable): blur function

This is an exercise from CS50 pset4 (more comfortable). This is part of a larger piece of code and it is the blur function. I am having trouble fixing my code.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp_img[height][width];
// copy original image array
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
temp_img[i][j] = image[i][j];
}
}
// iterate throughout the image
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int sumBlue = 0;
int sumGreen = 0;
int sumRed = 0;
float count_pix = 0;
// obtain value of original colour values around target pixel- red green blue
for (int r = -1; r <= 1; r++)
{
for (int c = -1; c <= 1; c++)
{
// logic to determine if pixel is existent
if ((0 <= i + r && i + r < height) && (0 <= j + c && j + c < width))
{
// add all RGB values accordingly, with counter
sumBlue += temp_img[i + r][j + r].rgbtBlue;
sumGreen += temp_img[i + r][j + r].rgbtGreen;
sumRed += temp_img[i + r][j + r].rgbtRed;
count_pix ++; //count number of iterations to average out later
}
}
}
// average out and add replace values into original image for output
image[i][j].rgbtBlue = round(sumBlue / count_pix);
image[i][j].rgbtGreen = round(sumGreen / count_pix);
image[i][j].rgbtRed = round(sumRed / count_pix);
}
}
return;
}
Below is the list of expected output and output from this code
:( blur correctly filters middle pixel
expected "127 140 149\n", not "123 137 145\n
:( blur correctly filters pixel on edge
expected "80 95 105\n", not "85 100 110\n
:( blur correctly filters pixel in corner
expected "70 85 95\n", not "65 80 90\n

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]

Blur function for cs50 PSET4, where are the errors?

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

Resources