7 Replies - 2182 Views - Last Post: 05 May 2013 - 04:16 PM Rate Topic: -----

#1 Elrim  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 05-May 13

Sobel edge detector using c++ only

Posted 05 May 2013 - 03:05 AM

I have a problem with the following code. The processed image does not show right (it becomes all messy and gray). AFter spending a ridiculous number of hours trying to fix the code, I still don't know what the problem is. I'd be super grateful for any help.

 

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cmath>

using namespace std;

//a class that represents the three colour values (R,G,B)/>/> in each pixel.
class Pixel
{
  private:

  unsigned int P1, P2, P3;


  public:

  Pixel () {};
  void setPixels (unsigned int Pixel1, unsigned int Pixel2, unsigned int Pixel3);
  unsigned int getPixel1 ();
  unsigned int getPixel2 ();
  unsigned int getPixel3 ();
};


  void Pixel::setPixels (unsigned int Pixel1, unsigned int Pixel2, unsigned int Pixel3)
  {
      P1 = Pixel1;
      P2 = Pixel2;
      P3 = Pixel3;
  }

  unsigned int Pixel::getPixel1 ()
  {
      return P1;
  }

  unsigned int Pixel::getPixel2 ()
  {
      return P2;
  }

  unsigned int Pixel::getPixel3 ()
  {
      return P3;
  }


//*****************int main () stars here! ******************************************************************************

int main ()
{
    //information contained in the header file is represented by the following variables
    unsigned char Magic [2];
    unsigned int TotRows = 512;
    unsigned int TotCol = 512;
    unsigned int MaxVal = 255;



    int size = (3 * TotRows * TotCol);

    char *charImage = new char [size];

    //opening original image
    ifstream OldImage;
    OldImage.open ("image.ppm", ios::in | ios::binary);

    if (!OldImage)
    {
       cout << "\nError: Cannot open image file! " << endl;
    }

     //reading the header of the original image file
     OldImage >> Magic [0] >> Magic [1] >>  TotRows >>  TotCol >> MaxVal;

       OldImage.read(charImage, size);

         unsigned int val1, val2, val3;

         //an array of pixels, which is used to represent the image
         Pixel **PixelVal;

         PixelVal = new Pixel* [TotRows];
         int T=0;

//Reading the image data and setting the pixels values as unsigned integers
    for(int i=0; i < TotRows; i++)
    {
        PixelVal[i] = new Pixel [TotCol];

        for(int j=0; j < TotCol; j++)
        {
            val1 = (unsigned int)charImage[T];
            val2 = (unsigned int)charImage[T+1];
            val3 = (unsigned int)charImage[T+2];
            PixelVal[i][j].setPixels (val1, val2, val3);
            T=T+3;
        }
    }


   if (OldImage.fail())
    {
        cout << "Can't read image " << endl;
    }

OldImage.close();


//Calculating the grayscale in each pixel. The values of the 3 colours (R, B and G) are all the same
 for(int i=0; i < TotRows; i++)
    {
        for(int j=0; j < TotCol; j++)
        {
            val1=(PixelVal[i][j].getPixel1()+PixelVal[i][j].getPixel1()+PixelVal[i][j].getPixel1())/3;
            val2=val1;
            val3=val1;
            PixelVal[i][j].setPixels(val1, val2, val3);
        }
    }


unsigned int valX, valY = 0;
unsigned int GX [3][3];
unsigned int GY [3][3];

//Sobel Horizontal Mask
	GX[0][0] = 1; GX[0][1] = 0; GX[0][2] = -1;
	GX[1][0] = 2; GX[1][1] = 0; GX[1][2] = -2;
	GX[2][0] = 1; GX[2][1] = 0; GX[2][2] = -1;

//Sobel Vertical Mask
	GY[0][0] =  1; GY[0][1] = 2; GY[0][2] =   1;
	GY[1][0] =  0; GY[1][1] = 0; GY[1][2] =   0;
	GY[2][0] = -1; GY[2][1] =-2; GY[2][2] =  -1;


//SOBEL edge detector implementation. Note: in each Pixel, the values of the 3 colours is the same.
//Therefore the calculation is performed on the first one only. The other 2 colours are then set to be = to the first one.

 for(int i=0; i < TotRows; i++)
    {
        for(int j=0; j < TotCol; j++)
        {

            //setting the pixels around the border to 0, because the Sobel kernel cannot be allied to them
            if ((i==0)||(i==TotRows-1)||(j==0)||(j==TotCol-1))
            {
               valX=0;
               valY=0;
            }

            else
            {
                //calculating the X and Y convolutions
                for (int x = -1; x <= 1; x++)
                {
                    for (int y = -1; y <= 1; y++)
                    {
                        valX = valX + PixelVal[i+x][j+y].getPixel1() * GX[1+x][1+y];
                        valY = valY + PixelVal[i+x][j+y].getPixel1() * GY[1+x][1+y];
                    }
                }
            }

            //Gradient magnitude
             val1 = sqrt(valX*valX + valY*valY);

            //setting the new pixel value
            PixelVal[i][j].setPixels(val1, val1, val1);
        }
    }

//creating a new file to host the copied image
    ofstream NewImage;
    NewImage.open ("image1.ppm", ios::out | ios::binary);

    if (!NewImage)
    {
        cout << "\nError: Cannot open image file! " <<endl;
    }

//writing the header in the new image file
    NewImage << "P6" << endl << TotRows << " " << TotCol << " " << MaxVal << endl;


T=0;
     for(int i=0; i < TotRows; i++)
    {
        for(int j=0; j < TotCol; j++)
        {
        val1 = PixelVal[i][j].getPixel1();
        val2 = PixelVal[i][j].getPixel2();
        val3 = PixelVal[i][j].getPixel3();
        charImage[T]=(unsigned char)val1;
        charImage[T+1]=(unsigned char)val2;
        charImage[T+2]=(unsigned char)val3;
        T=T+3;
        }
    }

cout << T;

    NewImage.write(charImage, size);

    if (NewImage.fail())
    {
        cout << "Can't write image " << endl;
    }

NewImage.close();
delete [] charImage;


    return 0;
}






Is This A Good Question/Topic? 0
  • +

Replies To: Sobel edge detector using c++ only

#2 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3469
  • View blog
  • Posts: 10,698
  • Joined: 05-May 12

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 10:49 AM

A few things standout:

1. In the else case on lines 156-165, it looks like you use the previous value of valX and valY from the previous column. I don't know the algorithm, and so I'm not sure if it's intentional or not.

2. On lines 162-163, i+x and i+y will underrun your PixelVal 2 dimensional arrays when x == -1 or y == -1, and i == 0 or j == 0.

3. On lines 162-163, 1+x and 1+y will overrun your GX and GY matrices when x == 1 or y == 1.

4. Your computation for grayscale on line 117 looks very very wrong even for a naive approach without factoring in any color perception theory.

This post has been edited by Skydiver: 05 May 2013 - 04:38 PM
Reason for edit:: Struck out the points on which I struck out.

Was This Post Helpful? 2
  • +
  • -

#3 Elrim  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 05-May 13

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 12:27 PM

Thanks for checking my code out! Yes, you are right about point 1 - I should reset the valX and valY values to 0 before each iteration. I am not sure what you mean in your points 2 and 3. The idea is to apply the GX and GY masks on the Pixels array. I will double check the numbers on those lines anywas, thanks so much!
Was This Post Helpful? 0
  • +
  • -

#4 snoopy11  Icon User is online

  • Engineering ● Software
  • member icon

Reputation: 765
  • View blog
  • Posts: 2,225
  • Joined: 20-March 10

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 01:28 PM

Skydiver is of course correct,

your lines at 117 for calculating the grayscale is plain wrong.

The way you calculate the grayscale is to find the average luminance

of the pixel. Each pixel is composed of Red , Green and Blue color information

For red the weighted average is 30%

For green the weighted average is 59%

For blue the weighted average is 11%

so therefore average luminance can be calculated as follows.

Luminance = ((30*Red)+(59*Green)+(11*Blue))/100;


once you have the average luminance set RGB values as follows.

Red = Luminance;
Green = Red;
Blue = Green;


basically all three values are set to luminance.

Try sorting that bit out and see how far that gets you.

Regards

Snoopy.
Was This Post Helpful? 1
  • +
  • -

#5 Elrim  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 05-May 13

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 01:38 PM

I understand now, thanks!
Was This Post Helpful? 0
  • +
  • -

#6 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3469
  • View blog
  • Posts: 10,698
  • Joined: 05-May 12

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 03:25 PM

Yup, point 3, won't overrun. When x == 1, then 1 + x == 1 + 1 == 2. This is still within range for your 3x3 matrix.

As for point 2, it will overrun when x == -1 and i == 0. x + i == -1 + 0 == -1. The way you are using PixelVal array, I don't see -1 as a valid index.
Was This Post Helpful? 0
  • +
  • -

#7 Elrim  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 05-May 13

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 03:53 PM

ok i understand what you mean, but

//setting the pixels around the border to 0, because the Sobel kernel cannot be allied to them  

151             if ((i==0)||(i==TotRows-1)||(j==0)||(j==TotCol-1))  

152             {  

153                valX=0;  

154                valY=0;  

155             }  





should keep x and y from being on the borders of the array, so that should take care of it no? The second nested loop does not start in that case, I think.
Thanks again for helping me out with this!

sorry I meant i and j are never 0 nor ==TotRows or TotColinside the second loop
Was This Post Helpful? 0
  • +
  • -

#8 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3469
  • View blog
  • Posts: 10,698
  • Joined: 05-May 12

Re: Sobel edge detector using c++ only

Posted 05 May 2013 - 04:16 PM

Excellent! That means point 2 is also invalid.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1