Kwsswart
Kwsswart

Reputation: 541

Why are these two filter functions not operating accordingly? cs50

I am trying to do make a function that will take an image and edit its properties to produce a grey-scale and a blue effect.

The aim of the grayscale function is simply to convert the pixels to greyscale by finding the average of the rbg and then assigning it, however it whenever running the check 50 to see if working it seems to be converting pixels of singular and simple images but cannot handle more complex ones.

The check50 results are here:

> :) grayscale correctly filters single pixel with whole number average
> Log testing with pixel (20, 40, 90) running ./testing 0 0... checking
> for output "50 50 50\n"... :( grayscale correctly filters single pixel
> without whole number average expected "28 28 28\n", not "27 27 27\n"
> Log testing with pixel (27, 28, 28) running ./testing 0 1... checking
> for output "28 28 28\n"...
> 
> Expected Output: 28 28 28 Actual Output: 27 27 27 :) grayscale leaves
> alone pixels that are already gray Log testing with pixel (50, 50, 50)
> running ./testing 0 2... checking for output "50 50 50\n"... :)
> grayscale correctly filters simple 3x3 image Log testing with sample
> 3x3 image first row: (255, 0, 0), (255, 0, 0), (255, 0, 0) second row:
> (0, 255, 0), (0, 255, 0), (0, 0, 255) third row: (0, 0, 255), (0, 0,
> 255), (0, 0, 255) running ./testing 0 3... checking for output "85 85
> 85\n85 85 85\n85 85 85\n85 85 85\n85 85 85\n85 85 85\n85 85 85\n85 85
> 85\n85 85 85\n"... :( grayscale correctly filters more complex 3x3
> image expected "20 20 20\n50 5...", not "20 20 20\n50 5..." Log
> testing with sample 3x3 image first row: (10, 20, 30), (40, 50, 60),
> (70, 80, 90) second row: (110, 130, 140), (120, 140, 150), (130, 150,
> 160) third row: (200, 210, 220), (220, 230, 240), (240, 250, 255)
> running ./testing 0 4... checking for output "20 20 20\n50 50 50\n80
> 80 80\n127 127 127\n137 137 137\n147 147 147\n210 210 210\n230 230
> 230\n248 248 248\n"...
> 
> Expected Output: 20 20 20 50 50 50 80 80 80 127 127 127 137 137 137
> 147 147 147 210 210 210 230 230 230 248 248 248 Actual Output: 20 20
> 20 50 50 50 80 80 80 126 126 126 136 136 136 146 146 146 210 210 210
> 230 230 230 248 248 248 :( grayscale correctly filters 4x4 image
> expected "20 20 20\n50 5...", not "20 20 20\n50 5..." Log testing with
> sample 4x4 image first row: (10, 20, 30), (40, 50, 60), (70, 80, 90),
> (100, 110, 120) second row: (110, 130, 140), (120, 140, 150), (130,
> 150, 160), (140, 160, 170) third row: (195, 204, 213), (205, 214,
> 223), (225, 234, 243), (245, 254, 253) fourth row: (50, 28, 90), (0,
> 0, 0), (255, 255, 255), (85, 85, 85) running ./testing 0 5... checking
> for output "20 20 20\n50 50 50\n80 80 80\n110 110 110\n127 127
> 127\n137 137 137\n147 147 147\n157 157 157\n204 204 204\n214 214
> 214\n234 234 234\n251 251 251\n56 56 56\n0 0 0\n255 255 255\n85 85
> 85\n"...
> 
> Expected Output: 20 20 20 50 50 50 80 80 80 110 110 110 127 127 127
> 137 137 137 147 147 147 157 157 157 204 204 204 214 214 214 234 234
> 234 251 251 251 56 56 56 0 0 0 255 255 255 85 85 85 Actual Output: 20
> 20 20 50 50 50 80 80 80 110 110 110 126 126 126 136 136 136 146 146
> 146 156 156 156 204 204 204 214 214 214 234 234 234 250 250 250 56 56
> 56 0 0 0 255 255 255 85 85 85

I am going to be using a box blur to do this and I tried to determine the sum of the unit with all surrounding items and then getting the average.

First I tried to assign the value individually with:

image[i][j].rbgtRed = round((image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 4)

Then I realized that it was taking the new values and thus just resetting the whole image basically. I thought to use an array to switch the values similar to the reflection and used:

        int tmpR[height][width];
        int tmpG[height][width];
        int tmpB[height][width];

It didn't work so I worked on the count to count the unites and reset the array values to respond. After I had done this i have been trying to go through the code slowly but have yet to determine the factor. Below is the code.

```C
// Convert image to grayscale
void grayscale(int height, int width, RGBTRIPLE image[height][width])
{
    int gscale;
    //loop for all pixels in rows
    for (int i = 0; i < height; i++)
    {
        //loop for pixels in columns
        for (int j = 0; j < width; j++)
        {
            //get the average of all the variables
            gscale = round((image[i][j].rgbtRed + image[i][j].rgbtGreen + image[i][j].rgbtBlue) / 3);

            image[i][j].rgbtRed = gscale;
            image[i][j].rgbtGreen = gscale;
            image[i][j].rgbtBlue = gscale;

        }

    }

    return;
}
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
    //set sepia float
    float sRed;
    float sGreen;
    float sBlue;
    // loop through pixels:rows
    for (int i = 0; i <= height; i++)
    {
        // loop through pixels:columns
        for (int j = 0; j < width; j++)
        {
            // change pixels to float
            float r = image[i][j].rgbtRed;
            float g = image[i][j].rgbtGreen;
            float b = image[i][j].rgbtBlue;

            //calculations
            sRed = ((.393 * r) + (.769 * g) + (.189 * b));
            sGreen = ((.349 * r) + (.686 * g) + (.168 * b));
            sBlue = ((.272 * r) + (.534 * g) + (.131 * b));

            //Limits
            if (sRed > 255)
            {
                sRed = 255;
            }
            if (sGreen > 255)
            {
                sGreen = 255;
            }
            if (sBlue > 255)
            {
                sBlue = 255;
            }

            //Reset pixels
            image[i][j].rgbtRed = round(sRed);
            image[i][j].rgbtGreen = round(sGreen);
            image[i][j].rgbtBlue = round(sBlue);
        }
    }
    return;
}

// Reflect image horizontally
void reflect(int height, int width, RGBTRIPLE image[height][width])
{

    for (int i = 0; i <= height; i++)
    {
        for (int j = 0; j < width / 2; j++)
        {
            
            //temp variables
            int tmpR = image[i][j].rgbtRed;
            int tmpG = image[i][j].rgbtGreen;
            int tmpB = image[i][j].rgbtBlue;
            // opposite end is = width - unit
            //Swap
            image[i][j].rgbtRed = image[i][(width - 1) - j].rgbtRed;
            image[i][j].rgbtGreen = image[i][(width - 1) - j].rgbtGreen;
            image[i][j].rgbtBlue = image[i][(width - 1) - j].rgbtBlue;

            image[i][(width - 1) - j].rgbtRed = tmpR;
            image[i][(width - 1) - j].rgbtGreen = tmpG;
            image[i][(width - 1) - j].rgbtBlue = tmpB;
            
        }
    }
    return;
}

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    //count total pixels
    int counth = 0;
    int countw = 0;
    for (int a = 0; a <= height; a++)
    {
        for (int b = 0; b < width; b++)
        {
            countw++;
        }
        counth++;
    }
    //Temp arrays
    int tmpR[counth][countw];
    int tmpG[counth][countw];
    int tmpB[counth][countw];
    
    for (int i = 0; i <= height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            
            
            if(i == 0 && j == 0)
            {
                //build box for calculation for left top of box
                tmpR[i][j] = round((image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) / 4);
                tmpG[i][j] = round((image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 4);
                tmpB[i][j] = round((image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 4);

            }
            else if (i == 0 && j == (width - 1))
            {
                //build box for calculation for right top corner of box
                tmpR[i][j] = round((image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed) / 4);
                tmpG[i][j] = round((image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen) / 4);
                tmpB[i][j] = round((image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue) / 4);

            }
            else if (i == height  && j == 0)
            {
                //build box for calculation for left bottom corner of box
                tmpR[i][j] = round((image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed) / 4);
                tmpG[i][j] = round((image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen) / 4);
                tmpB[i][j] = round((image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue) / 4);
            ;

            }
            else if (i == height && j ==  (width - 1))
            {
                //build box for calculation for right bottom corner of box
                tmpR[i][j] = round((image[i - 1][j - 1].rgbtRed + image[i - 1][j].rgbtRed + image[i][j - 1].rgbtRed + image[i][j].rgbtRed) / 4);
                tmpG[i][j] = round((image[i - 1][j - 1].rgbtGreen + image[i - 1][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen) / 4);
                tmpB[i][j] = round((image[i - 1][j - 1].rgbtBlue + image[i - 1][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue) / 4);

            }
            else if (i == 0)
            {
                //build box for calculation for top of box
                tmpR[i][j] = round((image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) / 6);
                tmpG[i][j] = round((image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 6);
                tmpB[i][j] = round((image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 6);

            }
            else if (i == (height - 1))
            {
                //build box for calculation for bottom of box
                tmpR[i][j] = round((image[i - 1][j - 1].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed) / 6);
                tmpG[i][j] = round((image[i - 1][j - 1].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen) / 6);
                tmpB[i][j] = round((image[i - 1][j - 1].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue) / 6);

            }
            else if (j == 0)
            {
                //build box for calculation for left of box
                tmpR[i][j] = round((image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) / 6);
                tmpG[i][j] = round((image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 6);
                tmpB[i][j] = round((image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 6);

            }
            else if (j == (width - 1))
            {
                //build box for calculation for right of box
                tmpR[i][j] = round((image[i - 1][j - 1].rgbtRed + image[i - 1][j].rgbtRed + image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed) / 6);
                tmpG[i][j] = round((image[i - 1][j - 1].rgbtGreen + image[i - 1][j].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen) / 6);
                tmpB[i][j] = round((image[i - 1][j - 1].rgbtBlue + image[i - 1][j].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue) / 6);

            }
            else
            {
                //build box for calculation for center digits
                tmpR[i][j] = round((image[i - 1][j - 1].rgbtRed + image[i - 1][j].rgbtRed + image[i - 1][j + 1].rgbtRed + image[i][j - 1].rgbtRed + image[i][j].rgbtRed + image[i][j + 1].rgbtRed + image[i + 1][j - 1].rgbtRed + image[i + 1][j].rgbtRed + image[i + 1][j + 1].rgbtRed) / 9);
                tmpG[i][j] = round((image[i - 1][j - 1].rgbtGreen + image[i - 1][j].rgbtGreen + image[i - 1][j + 1].rgbtGreen + image[i][j - 1].rgbtGreen + image[i][j].rgbtGreen + image[i][j + 1].rgbtGreen + image[i + 1][j - 1].rgbtGreen + image[i + 1][j].rgbtGreen + image[i + 1][j + 1].rgbtGreen) / 9);
                tmpB[i][j] = round((image[i - 1][j - 1].rgbtBlue + image[i - 1][j].rgbtBlue + image[i - 1][j + 1].rgbtBlue + image[i][j - 1].rgbtBlue + image[i][j].rgbtBlue + image[i][j + 1].rgbtBlue + image[i + 1][j - 1].rgbtBlue + image[i + 1][j].rgbtBlue + image[i + 1][j + 1].rgbtBlue) / 9);

            }
        }
    }
    
    // Reset new values
    for (int i = 0; i <= height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image[i][j].rgbtRed = tmpR[i][j];
            image[i][j].rgbtGreen = tmpG[i][j];
            image[i][j].rgbtBlue = tmpB[i][j];
        }
    }
    return;
}

I know the code isn't as elegant as it can be, however I am looking for guidance as I am learning and if I can improve in any way I would appreciate the advice and help to find out why this isn't working.

Upvotes: 1

Views: 3458

Answers (1)

Enis Arik
Enis Arik

Reputation: 677

For the issue with grayscale

If we read your error carefully;

:( grayscale correctly filters single pixel without whole number average expected "28 28 28\n", not "27 27 27\n".

This means your greyscale calculation is not right. The way that you round the average values of RGB values does not seem correct. When you divide three integers to 3, the result will be integer. This brings precision issue.

For instance 2/3 will result in 0. round(0) => 0.

If you do 2/3.0 = 0.6666.. (double precision), round(0.6666..) will be 1.

Calculate everything in double first, then round them into integer in the final step.

Upvotes: 3

Related Questions