title: Sobel edge detector using C++ without any special library or tool
body: <p>I am trying to implement the SObel edge detector in C++ WITHOUT using any special library for image processing. I am not sure why the following code just doesn't do the job (the output image shows a messy grayish picture. THe image format is PPM. I'd be grateful for any advise/comment/help. Thanks</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;fstream&gt;
  #include &lt;string&gt;
  #include &lt;cstdlib&gt;
  #include &lt;cmath&gt;
  
  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 &lt;&lt; "\nError: Cannot open image file! " &lt;&lt; endl;
      }
  
       //reading the header of the original image file
       OldImage &gt;&gt; Magic [0] &gt;&gt; Magic [1] &gt;&gt;  TotRows &gt;&gt;  TotCol &gt;&gt; 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 &lt; TotRows; i++)
      {
          PixelVal[i] = new Pixel [TotCol];
  
          for(int j=0; j &lt; 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 &lt;&lt; "Can't read image " &lt;&lt; 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 &lt; TotRows; i++)
      {
          for(int j=0; j &lt; 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 &lt; TotRows; i++)
      {
          for(int j=0; j &lt; 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 &lt;= 1; x++)
                  {
                      for (int y = -1; y &lt;= 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 &lt;&lt; "\nError: Cannot open image file! " &lt;&lt;endl;
      }
  
  //writing the header in the new image file
      NewImage &lt;&lt; "P6" &lt;&lt; endl &lt;&lt; TotRows &lt;&lt; " " &lt;&lt; TotCol &lt;&lt; " " &lt;&lt; MaxVal &lt;&lt; endl;
  
  
  T=0;
       for(int i=0; i &lt; TotRows; i++)
      {
          for(int j=0; j &lt; 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 &lt;&lt; T;
  
      NewImage.write(charImage, size);
  
      if (NewImage.fail())
      {
          cout &lt;&lt; "Can't write image " &lt;&lt; endl;
      }
  
  NewImage.close(); delete [] charImage;
  
  for (int i = 0; i &lt; TotRows; i++)
       {
           delete [] PixelVal[i];
       }
  
       delete [] PixelVal;
  
  
      return 0; }
  </code></pre>