Ajuda num problema

ric7

Power Member
Bom dia pessoal, de momento ando a fazer o curso cs50 introduction to CS, e gostava da vossa opinião/experiência num exercicio que resolvi mas que não fiquei satisfeito porque sei que existe uma solução mais elegante mas simplesmente não consegui chegar lá:
Código:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE image2[height][width];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image2[i][j] = image[i][j];
        }
    }

    for (int h = 0; h < height; h++)
    {
        for (int w = 0; w < width; w++)
        {
            int red = 0;
            int green = 0;
            int blue = 0;
            int counter = 0;


            if (h >= 0 && w >= 0)
            {
                red += image2[h][w].rgbtRed;
                green += image2[h][w].rgbtGreen;
                blue += image2[h][w].rgbtBlue;
                counter++;
            }
            if (h >= 0 && w - 1 >= 0)
            {
                red += image2[h][w-1].rgbtRed;
                green += image2[h][w-1].rgbtGreen;
                blue += image2[h][w-1].rgbtBlue;
                counter++;
            }
            if ((h >= 0 && w + 1 >= 0) && (h >= 0 && w + 1 < width))
            {
                red += image2[h][w+1].rgbtRed;
                green += image2[h][w+1].rgbtGreen;
                blue += image2[h][w+1].rgbtBlue;
                counter++;
            }
            if (h - 1 >= 0 && w >= 0)
            {
                red += image2[h-1][w].rgbtRed;
                green += image2[h-1][w].rgbtGreen;
                blue += image2[h-1][w].rgbtBlue;
                counter++;
            }
            if (h - 1 >= 0 && w - 1 >= 0)
            {
                red += image2[h-1][w-1].rgbtRed;
                green += image2[h-1][w-1].rgbtGreen;
                blue += image2[h-1][w-1].rgbtBlue;
                counter++;
            }
            if ((h - 1 >= 0 && w + 1 >= 0) && (h - 1 >= 0 && w + 1 < width))
            {
                red += image2[h-1][w+1].rgbtRed;
                green += image2[h-1][w+1].rgbtGreen;
                blue += image2[h-1][w+1].rgbtBlue;
                counter++;
            }
            if ((h + 1 >= 0 && w >= 0) && (h + 1 < height && w >= 0))
            {
                red += image2[h+1][w].rgbtRed;
                green += image2[h+1][w].rgbtGreen;
                blue += image2[h+1][w].rgbtBlue;
                counter++;
            }
            if ((h + 1 >= 0 && w - 1 >= 0) && (h + 1 < height && w - 1 >= 0))
            {
                red += image2[h+1][w-1].rgbtRed;
                green += image2[h+1][w-1].rgbtGreen;
                blue += image2[h+1][w-1].rgbtBlue;
                counter++;
            }
            if ((h + 1 >= 0 && w + 1 >= 0) && (h + 1 < height && w + 1 < width))
            {
                red += image2[h+1][w+1].rgbtRed;
                green += image2[h+1][w+1].rgbtGreen;
                blue += image2[h+1][w+1].rgbtBlue;
                counter++;
            }

            image[h][w].rgbtRed = round((float)red / counter);
            image[h][w].rgbtGreen = round((float)green / counter);
            image[h][w].rgbtBlue = round((float)blue / counter);
        }
    }
    return;
}

Sei que é possível colocar estes if statemants todos em 2 nested for loops, totalizando 4, mas não consigo fazer dessa forma, apenas desta maneira mais "feia", alguém consegue dar-me uma dica de como o conseguir?

cumps
 
Uma das maneiras mais faceis é fazeres a image2 ter uma borda de 0's à volta dos valores que copias da image. Ou seja image2[height+2][width+2].
Assim evitas os if cases todos.
No final podes guardar numa image3 com o tamanho da image (isto é sem a borda).
Usas temporariamente mais memória, mas ficas sem if cases.
 
Última edição:
Uma das maneiras mais faceis é fazeres a image2 ter uma borda de 0's à volta dos valores que copias da image. Ou seja image2[height+2][width+2].
Assim evitas os if cases todos.
No final podes guardar numa image3 com o tamanho da image (isto é sem a borda).
Usas temporariamente mais memória, mas ficas sem if cases.

Se calhar sou eu que não estou a perceber muito bem o que estás a dizer, mas nesse caso, não ficaria com alguns pixel de fora? Ou seja, os das duas primeiras colunas e linhas?

Eu na altura pensei em algo do género:
Código:
for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image2[i][j] = image[i][j];
       
            int red = 0;
            int green = 0;
            int blue = 0;
            int counter = 0;

    for (int h = 0; h < height; h++)
    {
       if  (i < 0) {
          i = 0;
       }
         
        for (int w = 0; w < width; w++)
        {
           if  (w <0);
        }

Mas lá está, está mal :P.
 
A ideia que eu tinha era mais eliminar a necessidade de teres esses casos especias em que tens sempre de verificar se estás a operar num pixel na borda da imagem.
Uma das formas mais simples de eliminar esses casos especiais é teres uma imagem com mais um 1 pixel toda a volta a 0 (assim não tem efeito na soma).
Desta forma podes sempre aceder a todos os pixeis à volta dos pixeis da imagem original.
Espero que isto ajude.

Código:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE image2[height+2][width+2];
   //por defeito colocar o counter a 9
    int counter[height][width] = {9};
  
    //image2 igual a image1, mas com borda de zeros à volta
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image2[i+1][j+1].rgbtRed = image[i][j].rgbtRed;
            image2[i+1][j+1].rgbtGreen = image[i][j].rgbtGreen;
            image2[i+1][j+1].rgbtBlue = image[i][j].rgbtBlue;
        }
    }

    //bordas verticais
    for (int i = 0; i < height+2; ++i)
    {
        //borda esquerda
        image2[i][0].rgbtRed = 0;
        image2[i][0].rgbtGreen = 0;
        image2[i][0].rgbtBlue = 0;
        //borda direita
        image2[i][width+1].rgbtRed = 0;
        image2[i][width+1].rgbtGreen = 0;
        image2[i][width+1].rgbtBlue = 0;

        //counter nas bordas é 6
        counter[i][0] = 6;
        counter[i][width-1] = 6;
    }
    //bordas horizontais
    for (int j = 0; j < width+2; ++j)
    {
        //borda superior
        image2[0][j].rgbtRed = 0;
        image2[0][j].rgbtGreen = 0;
        image2[0][j].rgbtBlue = 0;
        //borda inferior
        image2[height+1][j].rgbtRed = 0;
        image2[height+1][j].rgbtGreen = 0;
        image2[height+1][j].rgbtBlue = 0;

        //counter nas bordas é 6
        counter[i][0] = 6;
        counter[i][height-1] = 6;
    }

    //counters nos cantos são 4
    counter[0][0] = 4;
    counter[0][width-1] = 4;
    counter[height-1][0] = 4;
    counter[height-1][width-1] = 4;


    //somar os valores no 3x3 à volta de (i, j)
    for (int h = 0; h < height; h++)
    {
        for (int w = 0; w < width; w++)
        {
            int red = 0;
            int green = 0;
            int blue = 0;

            //centro
            red += image2[h][w].rgbtRed;
            green += image2[h][w].rgbtGreen;
            blue += image2[h][w].rgbtBlue;

            //esquerda
            red += image2[h][w-1].rgbtRed;
            green += image2[h][w-1].rgbtGreen;
            blue += image2[h][w-1].rgbtBlue;

            //direita
            red += image2[h][w+1].rgbtRed;
            green += image2[h][w+1].rgbtGreen;
            blue += image2[h][w+1].rgbtBlue;

            //cima
            red += image2[h-1][w].rgbtRed;
            green += image2[h-1][w].rgbtGreen;
            blue += image2[h-1][w].rgbtBlue;

            //baixo
            red += image2[h+1][w].rgbtRed;
            green += image2[h+1][w].rgbtGreen;
            blue += image2[h+1][w].rgbtBlue;

            //canto superior esquerdo
            red += image2[h-1][w-1].rgbtRed;
            green += image2[h-1][w-1].rgbtGreen;
            blue += image2[h-1][w-1].rgbtBlue;

            //canto superior direito
            red += image2[h-1][w+1].rgbtRed;
            green += image2[h-1][w+1].rgbtGreen;
            blue += image2[h-1][w+1].rgbtBlue;

            //canto inferior esquerdo
            red += image2[h+1][w-1].rgbtRed;
            green += image2[h+1][w-1].rgbtGreen;
            blue += image2[h+1][w-1].rgbtBlue;

            //canto inferior direito
            red += image2[h+1][w+1].rgbtRed;
            green += image2[h+1][w+1].rgbtGreen;
            blue += image2[h+1][w+1].rgbtBlue;

            //dividir pelo contador
            image[h][w].rgbtRed = round((float)red / counter[i][j]);
            image[h][w].rgbtGreen = round((float)green / counter[i][j]);
            image[h][w].rgbtBlue = round((float)blue / counter[i][j]);
        }
    }
    return;
}
 
A ideia que eu tinha era mais eliminar a necessidade de teres esses casos especias em que tens sempre de verificar se estás a operar num pixel na borda da imagem.
Uma das formas mais simples de eliminar esses casos especiais é teres uma imagem com mais um 1 pixel toda a volta a 0 (assim não tem efeito na soma).
Desta forma podes sempre aceder a todos os pixeis à volta dos pixeis da imagem original.
Espero que isto ajude.

Código:
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    RGBTRIPLE image2[height+2][width+2];
   //por defeito colocar o counter a 9
    int counter[height][width] = {9};
 
    //image2 igual a image1, mas com borda de zeros à volta
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            image2[i+1][j+1].rgbtRed = image[i][j].rgbtRed;
            image2[i+1][j+1].rgbtGreen = image[i][j].rgbtGreen;
            image2[i+1][j+1].rgbtBlue = image[i][j].rgbtBlue;
        }
    }

    //bordas verticais
    for (int i = 0; i < height+2; ++i)
    {
        //borda esquerda
        image2[i][0].rgbtRed = 0;
        image2[i][0].rgbtGreen = 0;
        image2[i][0].rgbtBlue = 0;
        //borda direita
        image2[i][width+1].rgbtRed = 0;
        image2[i][width+1].rgbtGreen = 0;
        image2[i][width+1].rgbtBlue = 0;

        //counter nas bordas é 6
        counter[i][0] = 6;
        counter[i][width-1] = 6;
    }
    //bordas horizontais
    for (int j = 0; j < width+2; ++j)
    {
        //borda superior
        image2[0][j].rgbtRed = 0;
        image2[0][j].rgbtGreen = 0;
        image2[0][j].rgbtBlue = 0;
        //borda inferior
        image2[height+1][j].rgbtRed = 0;
        image2[height+1][j].rgbtGreen = 0;
        image2[height+1][j].rgbtBlue = 0;

        //counter nas bordas é 6
        counter[i][0] = 6;
        counter[i][height-1] = 6;
    }

    //counters nos cantos são 4
    counter[0][0] = 4;
    counter[0][width-1] = 4;
    counter[height-1][0] = 4;
    counter[height-1][width-1] = 4;


    //somar os valores no 3x3 à volta de (i, j)
    for (int h = 0; h < height; h++)
    {
        for (int w = 0; w < width; w++)
        {
            int red = 0;
            int green = 0;
            int blue = 0;

            //centro
            red += image2[h][w].rgbtRed;
            green += image2[h][w].rgbtGreen;
            blue += image2[h][w].rgbtBlue;

            //esquerda
            red += image2[h][w-1].rgbtRed;
            green += image2[h][w-1].rgbtGreen;
            blue += image2[h][w-1].rgbtBlue;

            //direita
            red += image2[h][w+1].rgbtRed;
            green += image2[h][w+1].rgbtGreen;
            blue += image2[h][w+1].rgbtBlue;

            //cima
            red += image2[h-1][w].rgbtRed;
            green += image2[h-1][w].rgbtGreen;
            blue += image2[h-1][w].rgbtBlue;

            //baixo
            red += image2[h+1][w].rgbtRed;
            green += image2[h+1][w].rgbtGreen;
            blue += image2[h+1][w].rgbtBlue;

            //canto superior esquerdo
            red += image2[h-1][w-1].rgbtRed;
            green += image2[h-1][w-1].rgbtGreen;
            blue += image2[h-1][w-1].rgbtBlue;

            //canto superior direito
            red += image2[h-1][w+1].rgbtRed;
            green += image2[h-1][w+1].rgbtGreen;
            blue += image2[h-1][w+1].rgbtBlue;

            //canto inferior esquerdo
            red += image2[h+1][w-1].rgbtRed;
            green += image2[h+1][w-1].rgbtGreen;
            blue += image2[h+1][w-1].rgbtBlue;

            //canto inferior direito
            red += image2[h+1][w+1].rgbtRed;
            green += image2[h+1][w+1].rgbtGreen;
            blue += image2[h+1][w+1].rgbtBlue;

            //dividir pelo contador
            image[h][w].rgbtRed = round((float)red / counter[i][j]);
            image[h][w].rgbtGreen = round((float)green / counter[i][j]);
            image[h][w].rgbtBlue = round((float)blue / counter[i][j]);
        }
    }
    return;
}

É uma maneira diferente sim, não tinha pensado nisso (e acho que não iria, estive o dia todo a pensar neste problema :P). Ainda tenho que aprender, este curso está mesmo a testar a minha paciência, o exercício seguinte, recover , meu Deus, já assisti à palestra 2 vezes e mesmo assim estou com dificuldades em pensar na maneira correta de prosseguir, mas o facto de ter uma exercício onde posso escolher entre mobile e web development, está a motivar me. Gostava de conseguir concluir o curso até ao final desta semana, mas não estou a ver isso a acontecer...
 
Ainda bem que pude ajudar.
Às vezes ver outras maneira de resolver o mesmo problema pode sempre contribuir para aumentar o número de formas que tens para resolver problemas. O importante é compreenderes os conceitos usados e os prós e contras.
Neste caso usei mais memória para facilitar a lógica, pode haver alturas em que não tens tanta memória e terás que usar uma lógica mais complicada.
Vale mais tomares o teu tempo a compreender os problemas e respetivas soluções do que fazeres o curso de uma rajada. No fim vai render sempre mais.
Bom trabalho!
 
Back
Topo