cs50 Pset4 : Filter Step-by-Step Walk Through explained

I was seriously stuck on pset4 for about 3 months? Well, in reality, I was stuck for a week and then gave up until strangers from the internet sent me really nice messages. I was shocked – I’ve added some screenshots of feel-good comments. The difficulty really put me off and I stopped doing it but getting those messages has actually given me motivation and that boost to continue doing the course and writing it up knowing that it helps others. You guys rule! 🥰

Also… I realised I have been calling pseudocode = SUDOCODE for the past 2 years. Why did no one tell me? I’m cringing so much as I go through all my posts to update the word 😂


I had no idea where to start so I tried doing the pseudocode for the greyscale filter. Do you see me? I used the right word and not “sudo” anymore 😂


According to the video; for each pixel, which is 8 bytes or 1 bit, there are 3 colours, RGB and in order to convert it to greyscale, you need all the values of R, G and B to be the same. Here is what I wrote out.

   // iterate through i to get to each row
   // iterate through j - to get into each byte per row
   // find values of R, G and B
   // find average of R, G and B
   // implemennt back into R, G, B new values.
   // the values to new average

For the filter, you want to find out what each value of R, G and B is per pixel so therefore you must iterate through the first row of the bitmap image.

 for (int i = 0; i < height; i++)


Then you iterate again through each individual column in that row to collect the values of R, G, B per bit.

for (int j = 0; j < width; j++) { }

As provided by cs50, we know that to access the pixels in the 2D array we do:


Then you added them together divide by 3 to find the average. I decided to convert them all into a new int to use for the multiplication. I kept getting errors here so struggled a bit when I was checking the code as it wasn’t rounding up correctly. A quick google I found if I used float it would retain the decimal value of average then I could round it up after. For some reason it wouldn’t work any otherwise – so if you know a better way PLEASE do let me know!

            // get values of each colour
            int red = image[i][j].rgbtRed;
            int blue = image[i][j].rgbtBlue;
            int green = image[i][j].rgbtGreen;

            // find average
            float average = (round(red) + round(blue) + round(green)) / 3;
            average = round(average);

Then you use this same number to put back into each R,G,B value per pixel of the image. Basically finishing the conversion ^_^

            // implement average back into each colour
            image[i][j].rgbtRed = average;
            image[i][j].rgbtBlue = average;
            image[i][j].rgbtGreen = average;

Then the huge struggle came when I tried to compile. I kept compiling the helpers file and it was giving me mahusive errors like

My step by step walkthrough of pset4 filter challenge from the cs50 edx harvardx course

Another quick search on the cs50 Facebook Group (which btw is a blessing and you MUST join) and StackOverflow I found that you had to compile filter.c.

Then after all this, I used check50 to check the code. I don’t know any other way but it was a pass so HUZZAH! Now onto the next one 🙂


So this is the “sepia formula” algorithm. In the video, he explains the output will not be an integer. We need to round the number to the nearest whole number between the range of a 8 bits of memory (256) so the values must be between 0-255. It must not go over 255, therefore, we need to cap it at 255.

  sepiaRed = .393 * originalRed + .769 * originalGreen + .189 * originalBlue
  sepiaGreen = .349 * originalRed + .686 * originalGreen + .168 * originalBlue
  sepiaBlue = .272 * originalRed + .534 * originalGreen + .131 * originalBlue

Here is my pseudocode:

// iterate through i to get to each row
// iterate through j - to get into each byte per row
// find values of R, G and B
// convert each value to the sepia value
// round number sto nearest whole number 
// check whether the value is between 0 - 255
// if value > 255 then make it 255
// input back into R, G, B

So the next bit. I just did lots of guess work. It’s not exactly the most minimalistic code but hey, it worked 😂

I basically first took the same code from the greyscale filter: the beginning for loop within for loop and then converting each value of colour to its own integer and copy & pasta’d that.

The main bit I changed was adding the sepia code and trying to round up the number. I don’t know how this worked but I copied I what I did before which was round up the equation total.

int  sepiaRed = round(.393 * red + .769 * green + .189 * blue);
int sepiaGreen = round(.349 * red + .686 * green + .168 * blue);
int  sepiaBlue = round(.272 * red + .534 * green + .131 * blue);

Then I just did simple if and else statements to check through if the values are more than 255. If they were I would equate the corresponding colour = 255.

if (sepiaRed < 256)

image[i][j].rgbtRed = sepiaRed;

else {

image[i][j].rgbtRed = 255;


If it wasn’t more than 255 then I would input that value back into that pixel. And then do that for each colour and then a voila! A quick check50 and it works. Great news and all ready to go to the next step 🙂

It’s now nearly 11pm and the latest I’ve slept ALL WEEK! I’ve literally spent about 8 hours on this lol. I will return tomorrow morning to finish it off.


For this task, we are trying to flip the bitmap image horizontally. In order to do so, the video dude explains that we have to take each pixel in each row and reflect it so if it was numbered like 1, 2, 3, 4, 5, 6 the algorithm would reverse it to become 6, 5, 4, 3, 2, 1.

If there are an odd number of pixels the middle pixel stays in it’s place but if there are an even number of pixels every single pixel will switch sides and be on the opposite sides to their original position.

So I guess it’s time for psedocode.

// iterate through row
// iterate through columns
// half width
// swap left hand with direct right-hand values (middle is static if odd number)
// re-insert back into location

Something like this should work. After a quick Google I found how to reverse an array on StackOverflow.

// do not use - copied from StackOverflow as reference.

void ReverseArray(int arr[], int size)
    for (int i = 0; i < size/2; ++i)
        int temp = arr[i];
        arr[i] = arr[size - 1 - i];
        arr[size - 1 - i] = temp;

So I ended up writing pseudocode from the above to help convert into my own.

First I wanted to iterate through only half of the full width of the image because as mentioned earlier we are only swapping the left hand side of pixels with the right. If we iterate through the full width it would mean swapping them all…back to the same position.

Therefor we do width / 2 to half the length. In the video he mentions if it’s an even number we can directly halve with no remainders but if it’s an odd it would become a decimal.

Even number
6 / 2 = 3

Odd number
7 / 2 = 3.5 

Good thing with integars is that if the decimal is .5 or below it rounds DOWN. So 7 / 2 would become 3. Which ignores the middle value in an array. You don’t need to swap that anyways.

After you interate through each pixel you need to create a temporary value where you put the image[i][j] in. Then you would make the new image[i][j] equate the same array that picks j away from the full width. For example…

      arr[j] = arr[width - 1 - j];
This means fullwidth would be - j as you are you trying to swap the j value with same value j away from width. 

array location: 0 1 2 3 4 5
value in array: 7 2 5 7 3 1

As you can see if j was array[1] then you would want to swap it with array[4] which is 5 – j = 5 – 1. 5 being “max width”

You do width – 1 – j as in an array it starts from 0 so you end up with having a length of 6 even though the last value in the array is array[5]

Which ended up with this error.

 error: assigning to 'int' from incompatible type

I realised as I was calling int instead of the RGBTRIPLE struct. It wouldn’t let me do int = RGBTRIPLE. So your new value needs to be called as an RGBTRIPLE struct.

Wow, it’s 7am on Sunday I honestly spend all day yesterday confused on just this section and now it looks so simple after you complete it FML.


We want to blur this image by converting each pixel to an average of the surrounding pixels. From this video we know that:

  • Corner pixel = average of R, G and then B of the 4 pixels around that pixel. 1 row and 1 column surrounding.
  • Side pixel = average of R, G and then B of 6 pixels around that pixel. 1 row and 1 column
  • Any other pixel = average of R, G and then B of 9 pixels around that pixel. 1 row and 1 column.

In order to calculate the average colour we add all Red values and divide between all pixels and then the same for Green and Blue in each pixel then you equal the inial pixel to the new value.

This one sounds so bloody trick o.m.g 😵

I’ve been doing this for over 15 hours now. Seriously kill me.


I’m going to re-do the code in another method. Let’s get down to pseoducode.

The Rest …. TBC

💌 Subscribe to our newsletter and join 10 other housemates.
☕️ ️ Did you found this article helpful? If so, please feel free to buy me a coffee :)

Buy Me a Coffee at ko-fi.com


A forever-learner and explorer. My favourite thing in life is helping people using the skills that I have. I love blogging as it gives me a safe place to document and explore my thoughts, dreams and ideas that I am too scared to speak about IRL. I love having deep chats, internetting, art and design thingies, handcrafting, experiencing new things and learning more about people and the world we live in.


  1. Here is my public github for helpers.c. I’ve done the first 3, working on blur. The greyscale and sephia were easy for me, under an hour total. Not sure where to go from here. I used your PSET3 stuff to help get my voting tally right as I couldn’t figure how how to link the struct with the candidate. Your solution of preferences[voter][rank] = i did it. I’m not a programmer just doing this for some learning experience. I like how you write up your summaries, as I don’t want to cheat but sometimes need a little push and help.


    1. Thanks, @inline-five for your feedback and link; that’s super helpful as I’m just settling into the reflect task. I kind of like working it out myself too so I’m too scared to look at those spoilers lol but will defo check it out when I get stuck ✨

  2. Just stopping by again. Sorry not trying to bother you. But I finished this (blur) last night. I actually was able to avoid cheating on it. It took me forever to come up with the correct if () statement to constrain the loops, it was driving me nuts . There is a CS50 reddit group that is pretty good and I have posted my solution on there and they noticed some clerical errors I made but otherwise it passed. Can’t believe it. I know there are still some things like not allocating temporary memory that I am not doing but I can always revisit that when I understand it more. I like looking at others solutions once finished because then you can see other ways of doing things and if they are more efficient etc., it’s a great way to learn. Good luck, I’m not looking forward to Recover!!

    1. You are not bothering at all – I love comments!
      I also hope you come back and see this one lol because I’ve been stuck on blur for about 3 days now. If possible are you able to take a look at my code and see where I might be going wrong: https://pastebin.com/rN4JVU3R

      I’ve bee checking other people’s codes and I got the jist of one did it all and it flopped – was painful as I wrote it ALL manually and so I changed direction after checking StackOverflow and decided to try checking if the pixel above, around the sides and in the corners were inside all edges anyways it’s not working >.< p.s WELL DONE FOR PASSING PSET4 ^_^

      1. The main mistake i see is the way you are doing the checking of whether the pixel is on the edge. I did not look through all of the conditions but im sure at least 1 is wrong. Based on pset 4, the main idea is to look around that pixel and add whatever is one pixel away.

        What you could have done instead is to introduce an additional helper function or loop to check this for you.

        Without spoiling too much. this is the condition required by pset4.
        (i >= 0 && i = 0 && j < width) // this must return true to do the addition.

        1. (i >= 0 && i = 0 && j < width)

          so typo in my above comment. this i and j is different from the "base" pixel. Now all you have to do is to somehow loop a variable that can -1,0,+1 to the "original" i and j of the base pixel.

  3. So actually I found out my solution only worked for square images but I did fix it. I transposed the width and height in my if statement. Anyway, aside from that now it’s working 100%. It passes the check50 because those were all squares, but anyway. Phew.

    So I looked at your link. I’ll be honest, I’m really not the person to ask to debug stuff because I have a hard enough time following my own stuff. But I think you are almost there and have the right idea. I initially thought about doing it the way you went but I’m kinda lazy it seemed like a lot of scenarios. So I sat down and thought about how I could do the same thing with another loop inside the i/j loop with an IF statement checking to see if the pixel was within bounds (ie using a loop to check i -1, i -0, i+1 an and j-1, j-0, j+1). Amazingly I was able to get it to work. But this is what I did. I created my own 3 x 3 bmp with a single white square in an overall black image. This allowed me to use the printf function to print out each pixel’s RGB\n and see where the program was getting the values from. Then I could tweak it to make it work. Oh and BTW the way it works in the actual program is the bottom left corner is the first [0][0] IIRC and each array value increases in the x and y coordinate plane, which is slightly different than the top to bottom population that is presented in our PSETs. Making a square with various positions of the white pixel with 255 255 255 RGB values that print first is how you figure that out. Ha.

    It’s funny, when you get done look at some others solutions. There are two types, some go the way you did and some go the way I did. It’s almost uncanny how similar the prose is between everyone down to the variable names.

    If you get stuck, here is my working helpers.c in pastebin:


    1. Hey,

      Can you please explain your if() condition a bit. Trouble understanding what you have done there.

      Best Regards

  4. Just checking in. Hope you didn’t get too stuck. Stop by r/CS50 if you want. Lots of good help there. Plus you can help others in earlier weeks which helps reinforce what you are learning.

    I’m on week six now. This was probably the hardest problem set (so far). Week 5 wasn’t too bad, but pointers are a PITA.

    Watching week six lecture today and python is way easier.

    1. Hey, I actually got demotivated and moved onto other projects 🙁 I keep looking at it and being confused. I will get back to it fo shizzle when I have brain energy well done for getting so far along! Thanks for the encouragement =D

  5. No don’t get demotivated. Looking at your sepia helped my solve a totally easy problem I didn’t see. Try it again with new eyes or ask they group for help they are great. Keep going we got this!!

  6. Thanks for these walkthroughs Bexa – I’ve found them really useful to check my Sudocode since I started CS50.

    I am getting the same irritating message as you did – linker command failed with exit code 1 and I can’t fix it. For clarity, was your solution simply to run ‘make filter’ from the terminal before making helpers? I feel like I’m missing something really obvious but I can’t work out what!

  7. Hey Bexa,

    In your if ((i – 1 > -1) && (0 => j -1 )and (0 => j <= height). I am stuck myself too. A little insight might help.

  8. First I like how u sharing and helping ppl with this
    for the first function, u have to round it all, not every peace
    u rounding RGB values which are already integers so no point there
    for the second u can test ur code by testing it on the images they already provided in the image directory and see if its close to what they supposed to or not then check50 (or at least that’s what I know too)
    and last please don’t let go I came here to make a push on for that f** blur which am struggling at too

  9. // Blur image
    void blur(int height, int width, RGBTRIPLE image[height][width])
    int i, j;
    // create a copy of array to new image to blur
    RGBTRIPLE newImage[height][width];

    for (i = 0; i < height; i++)
    for (j = 0; j < width; j++)
    // !!!!
    newImage[i][j].rgbt.Blue= image[i][j].rgbt.Blue;
    newImage[i][j].rgbt.Red= image[i][j].rgbt.Red;
    newImage[i][j].rgbt.Green= image[i][j].rgbt.Green;

    // interate through rows
    for (i = 0; i < height; i++)
    // iterate through columns

    for (j = 0; j -1) && (0 => j -1 ) && (0 => i <= height)){
    sumRed += newImage[i][j – 1].rgbtRed;
    sumGreen += newImage[i][j – 1].rgbtGreen;
    sumBlue += newImage[i][j – 1].rgbtBlue;
    counter ++;

    // check if there is a column to the right (6)
    if ( j + 1 < width )
    sumRed += newImage[i][j + 1].rgbtRed;
    sumGreen += newImage[i][j + 1].rgbtGreen;
    sumBlue += newImage[i][j + 1].rgbtBlue;
    counter ++;

    // check if there is a row below pixel (0)
    if ((i + 1 = j = 0) && (j – 1 >= 0)) {
    sumRed += newImage[i – 1 ][j – 1].rgbtRed;
    sumGreen += newImage[i – 1][j – 1].rgbtGreen;
    sumBlue += newImage[i – 1][j – 1].rgbtBlue;
    counter ++;

    // if there is a right corner (1)
    if ((i + 1 <= 0) && (j + 1 <= width)) {
    sumRed += newImage[i + 1][j + 1].rgbtRed;
    sumGreen += newImage[i + 1][j + 1].rgbtGreen;
    sumBlue += newImage[i + 1][j + 1].rgbtBlue;
    counter ++;


    // if there is a bottom left corner (3)
    if ((i + 1 = 0)) {
    sumRed += newImage[i + 1][j – 1].rgbtRed;
    sumGreen += newImage[i + 1][j – 1].rgbtGreen;
    sumBlue += newImage[i + 1][j – 1].rgbtBlue;
    counter ++;


    // if there is a bottom right corner (8)
    if ((i + 1 <= height) && (j + 1 <= width)) {
    sumRed += newImage[i – 1][j – 1].rgbtRed;
    sumGreen += newImage[i – 1][j – 1].rgbtGreen;
    sumBlue += newImage[i – 1][j – 1].rgbtBlue;
    counter ++;


    // add the middle pixel

    sumRed += newImage[i][j].rgbtRed;
    sumGreen += newImage[i][j].rgbtGreen;
    sumBlue += newImage[i][j].rgbtBlue;

    // find average of everything

    newImage[i][j].rgbtRed = round(sumRed / counter);
    newImage[i][j].rgbtBlue = round(sumBlue / counter);
    newImage[i][j].rgbtGreen = round(sumGreen / counter);

    /*replace old image with new blurred pixels
    image[i][j].rgbtRed = newImage[i][j].rgbtRed;
    image[i][j].rgbtBlue = newImage[i][j].rgbtBlue;
    image[i][j].rgbtGreen = newImage[i][j].rgbtGreen;

    /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    here you can't replace it with image[i][j] yet……
    imagine there is a pixel 8 1 2 3 4 5
    6 7 8 9 10
    11 12 13 14 15

    you changed the value of 8 by using the above algorithm.
    But then if we take pixel 9 then the value of 8 will not be the original value, it would be the updated value.

    so all you got to do is make a loop after this loop gets over and change the values.



    for (int a = 0; a < height; a++)
    for (int b = 0; b< width; b++)
    image[a][b].rgbt.Blue= newimage[a][b].rgbt.Blue;
    image[a][b].rgbt.Red= newimage[a][b].rgbt.Red;
    image[a][b].rgbt.Green= newimage[a][b].rgbt.Green;


  10. Hey Becky, it’s Jordan

    Nice to see you keep going!

    Blur is quite tough but I managed to do it in the end (spent many hours on it)

    I basically found a solution very similar to what Raj wrote above.
    Let me know if you still need help / want to discuss it.

    I’m now starting Recover and it’s a tough one!

  11. Hey, I have a question about your code for geyscale. I was wondering why you rounded each of image.rgbt values before working out the average? Also i just wanted to say thank you! This was very helpful

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.