Solved

Marr-Hildreth Program not Giving Desired Result

Posted on 2009-07-13
8
572 Views
Last Modified: 2012-08-13
Hi Experts,

The c++ code below on the lena image in .pgm format is not giving very good edge detection. The threshold value of 100 yields the best result; however, this is quite inferior to the results of the matlab edge detection using the same algorithm.

I am not sure where I am going wrong in the algorithm. Below a threshold value of 100, the resulting image doesn't detect edges anymore.

Thanks,

Dennis
#include <iostream>

#include <fstream>

#include <string>

#include <math.h>

#include <time.h>
 

 

using namespace std;
 

/*** New Data Types ***/

typedef unsigned char BYTE;
 

// create data structure to hold image

struct PIC

{

    unsigned int nChannel;

    bool InterLeaved;

    unsigned int Width, Height, Maxval;

    BYTE *img;

};
 

template <typename T>
 

T **AllocateDynamicArray( int nRows, int nCols)

{
 

    T **dynamicArray;

    dynamicArray = new T*[nRows];

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

    dynamicArray[i] = new T [nCols];

    return dynamicArray;

}
 

template <typename T>
 

void FreeDynamicArray(T** dArray)

{

    delete [] *dArray;

    delete [] dArray;

}
 
 
 

//function that loads in the header

bool LoadP5Header(ifstream &infile, PIC &pic)

{

    bool rtv = true;

    char buf[16];

    int bufIndex;

    int width, height, maxval;
 

    infile.read(buf, 2); // get the magic number

    buf[2]='\0';
 

    if(buf[0] == 'P' && buf[1] == '5')

	{

        infile.read(buf, 1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

		}
 

        // get width

        bufIndex = 0;

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        width = atoi(buf);
 

        // get height

        infile.read(buf,1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

        }

        bufIndex = 0;  //line 

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        height = atoi(buf);
 

       // get Maxval

		infile.read(buf,1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

        }

        bufIndex = 0;

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        maxval = atoi(buf);
 

		// Skip white space(s)

		//infile.read(buf,1);
 

        // set the image information in the struct

        pic.InterLeaved = false;

        pic.Width = width;

        pic.Height = height;

		pic.Maxval = maxval;
 

    }

    else rtv = false;
 

    return rtv;

}; // end of LoadP5Header()
 

//function that accepts an infile object and a PIC Object

//and reads in the PIC object

void LoadImage(ifstream &infile, PIC &pic)

{

    infile.read(reinterpret_cast<char *>(pic.img), pic.Width*pic.Height);

}
 

//function that accepts an outstream file and a PIC object to

//and writes the output stream to the PIC object

void WritePGM(ofstream & outfile, PIC pic)

{

    outfile << "P5" << endl;

    outfile << pic.Width << " " << pic.Height << endl;

	outfile << pic.Maxval << endl;
 

    outfile.write(reinterpret_cast<char *>(pic.img), pic.Width*pic.Height);

}
 
 

void MaskFiltering(PIC Pin_t, int Mask[5][5], char *outFileName_Pout)

{

    

        ofstream outfile_Pout;
 

        outfile_Pout.open(outFileName_Pout, ios::binary);

        

        int **IMG_matrix = AllocateDynamicArray<int>(Pin_t.Width+6,Pin_t.Height+6);

        int **IMG_temp_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);

   

        int Npixels, pixelCnt, LoGValue;

        int threshVal = 100;

            

		Npixels = Pin_t.Width*Pin_t.Height;

		Pin_t.Maxval = 255;
 

		        //create a two pixel layer of black border around the original image to apply the mask to boundary values

 

        for(int j = 0; j <= Pin_t.Height+3; j++)

        {

             IMG_matrix[0][j] = 0;

             IMG_matrix[1][j] = 0;

             IMG_matrix[Pin_t.Width+2][j] = 0; 

             IMG_matrix[Pin_t.Width+3][j] = 0; 

        }

        

        for(int k = 0; k <= Pin_t.Width+3; k++)

        {

             IMG_matrix[k][0] = 0;

             IMG_matrix[k][1] = 0;

             IMG_matrix[k][Pin_t.Height+2] = 0;

             IMG_matrix[k][Pin_t.Height+3] = 0;

        }

 

        pixelCnt = 0;

        //make 2D matrix of input

 

        for(int j = 2; j < Pin_t.Height + 2; j++)

        {

              for(int k = 2; k < Pin_t.Width + 2; k++)

              {

                    IMG_matrix[k][j] = (int) Pin_t.img[pixelCnt];

                    pixelCnt++;

              }

         }
 

        

        for(int j=2; j <= Pin_t.Height+1; j++)

        {           

            for(int k=2; k <= Pin_t.Width+1; k++)

            {      
 

                      LoGValue = Mask[2][2]*IMG_matrix[k][j] + Mask[3][2]*IMG_matrix[k+1][j] + Mask[4][2]*IMG_matrix[k+2][j] + Mask[1][2]*IMG_matrix[k-1][j] + Mask[0][2]*IMG_matrix[k-2][j]

                                     + Mask[2][3]*IMG_matrix[k][j+1] + Mask[2][4]*IMG_matrix[k][j+2] + Mask[2][1]*IMG_matrix[k][j-1] + Mask[2][0]*IMG_matrix[k][j-2]

                                     + Mask[3][1]*IMG_matrix[k+1][j-1] + Mask[3][4]*IMG_matrix[k+1][j+1]

									 + Mask[1][1]*IMG_matrix[k-1][j-1] + Mask[1][4]*IMG_matrix[k-1][j+1];
 

                                     

                 if(LoGValue < threshVal) LoGValue = 0;

                 else if(LoGValue < threshVal) LoGValue = 255;
 

                 IMG_temp_matrix[k-2][j-2] = LoGValue;

            } 

        }

        

        //output the calculated 2D matrix to original 1D

        pixelCnt = 0;

        for(int j = 0; j < Pin_t.Height; j++)

        {

              for(int k = 0; k < Pin_t.Width; k++)

              {

                    Pin_t.img[pixelCnt] = (unsigned char) (IMG_temp_matrix[k][j]);

                    pixelCnt++;

              }

         }
 

        WritePGM(outfile_Pout, Pin_t);

 }
 
 

int main()

{  

    

	ifstream infile_Pin1;                /* input file */

    char inFileName_Pin1[128]="Lena.pgm";            /* input file name */

    PIC Pin1;            //source image

    

    /* open input/output file */

    infile_Pin1.open(inFileName_Pin1, ios::binary);
 

	/* check input file */

    if(!infile_Pin1)

    {

        cout<<"Cannot open input file "<< inFileName_Pin1 <<endl;

        return 1;

    }
 
 

   int LaplacianOfGaussian[5][5] = {{0, 0, 1, 0, 0},

                                 {0, 1, 2, 1, 0},

                                 {1, 2, -16, 2, 1},

								 {0, 1, 2, 1, 0},

                                 {0, 0, 1, 0, 0}};
 
 
 

    if (LoadP5Header(infile_Pin1, Pin1)) // load pgm (Pin) image header information

    {

        // allocate the memory for the input image

        //the dimensions of the original
 

        Pin1.img = new BYTE[Pin1.Width*Pin1.Height];
 

        LoadImage(infile_Pin1, Pin1);

   

       MaskFiltering(Pin1,LaplacianOfGaussian, "Lena_Hildreth_1.pgm");   
 

   }

   

}

Open in new window

0
Comment
Question by:datopdogg7
  • 4
  • 3
8 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24842850
If you would post the .pgm files I would try to find out where it failed (though it might be difficult if not comparing it with working code).
0
 

Author Comment

by:datopdogg7
ID: 24842905
I found an issue with the program, it had to do with the computation of the mask products. However, the output image is still unstaisfactory.

I shall post the image result as well as the updated code.
#include <iostream>

#include <fstream>

#include <string>

#include <math.h>

#include <time.h>
 

 

using namespace std;
 

/*** New Data Types ***/

typedef unsigned char BYTE;
 

// create data structure to hold image

struct PIC

{

    unsigned int nChannel;

    bool InterLeaved;

    unsigned int Width, Height, Maxval;

    BYTE *img;

};
 

template <typename T>
 

T **AllocateDynamicArray( int nRows, int nCols)

{
 

    T **dynamicArray;

    dynamicArray = new T*[nRows];

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

    dynamicArray[i] = new T [nCols];

    return dynamicArray;

}
 

template <typename T>
 

void FreeDynamicArray(T** dArray)

{

    delete [] *dArray;

    delete [] dArray;

}
 
 
 

//function that loads in the header

bool LoadP5Header(ifstream &infile, PIC &pic)

{

    bool rtv = true;

    char buf[16];

    int bufIndex;

    int width, height, maxval;
 

    infile.read(buf, 2); // get the magic number

    buf[2]='\0';
 

    if(buf[0] == 'P' && buf[1] == '5')

	{

        infile.read(buf, 1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

		}
 

        // get width

        bufIndex = 0;

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        width = atoi(buf);
 

        // get height

        infile.read(buf,1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

        }

        bufIndex = 0;  //line 

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        height = atoi(buf);
 

       // get Maxval

		infile.read(buf,1);

        while(isspace(buf[0])) // Skip white space(s)

		{

            infile.read(buf,1);

        }

        bufIndex = 0;

        while(bufIndex < 15 && !isspace(buf[bufIndex]))

		{

            bufIndex++;

            infile.read(buf+bufIndex, 1);

        }

        buf[bufIndex] = NULL;  // null terminated string

        maxval = atoi(buf);
 

		// Skip white space(s)

		//infile.read(buf,1);
 

        // set the image information in the struct

        pic.InterLeaved = false;

        pic.Width = width;

        pic.Height = height;

		pic.Maxval = maxval;
 

    }

    else rtv = false;
 

    return rtv;

}; // end of LoadP5Header()
 

//function that accepts an infile object and a PIC Object

//and reads in the PIC object

void LoadImage(ifstream &infile, PIC &pic)

{

    infile.read(reinterpret_cast<char *>(pic.img), pic.Width*pic.Height);

}
 

//function that accepts an outstream file and a PIC object to

//and writes the output stream to the PIC object

void WritePGM(ofstream & outfile, PIC pic)

{

    outfile << "P5" << endl;

    outfile << pic.Width << " " << pic.Height << endl;

	outfile << pic.Maxval << endl;
 

    outfile.write(reinterpret_cast<char *>(pic.img), pic.Width*pic.Height);

}
 
 

void MaskFiltering(PIC Pin_t, int Mask[5][5], char *outFileName_Pout)

{

    

        ofstream outfile_Pout;
 

        outfile_Pout.open(outFileName_Pout, ios::binary);

        

        int **IMG_matrix = AllocateDynamicArray<int>(Pin_t.Width+6,Pin_t.Height+6);

        int **IMG_temp_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);

   

        int Npixels, pixelCnt, LoGValue;

        int threshVal = 75;

            

		Npixels = Pin_t.Width*Pin_t.Height;

		Pin_t.Maxval = 255;
 

		//create a two pixel layer of black border around the original image to apply the mask to boundary values

 

        for(int j = 0; j <= Pin_t.Height+3; j++)

        {

             IMG_matrix[0][j] = 0;

             IMG_matrix[1][j] = 0;

             IMG_matrix[Pin_t.Width+2][j] = 0; 

             IMG_matrix[Pin_t.Width+3][j] = 0; 

        }

        

        for(int k = 0; k <= Pin_t.Width+3; k++)

        {

             IMG_matrix[k][0] = 0;

             IMG_matrix[k][1] = 0;

             IMG_matrix[k][Pin_t.Height+2] = 0;

             IMG_matrix[k][Pin_t.Height+3] = 0;

        }

 

        pixelCnt = 0;

        //make 2D matrix of input

 

        for(int j = 2; j < Pin_t.Height + 2; j++)

        {

              for(int k = 2; k < Pin_t.Width + 2; k++)

              {

                    IMG_matrix[k][j] = (int) Pin_t.img[pixelCnt];

                    pixelCnt++;

              }

         }
 

        

        for(int j=2; j <= Pin_t.Height+1; j++)

        {           

            for(int k=2; k <= Pin_t.Width+1; k++)

            {      
 

                      LoGValue = Mask[2][2]*IMG_matrix[k][j] + Mask[3][2]*IMG_matrix[k+1][j] + Mask[4][2]*IMG_matrix[k+2][j] + Mask[1][2]*IMG_matrix[k-1][j] + Mask[0][2]*IMG_matrix[k-2][j]

                                     + Mask[2][3]*IMG_matrix[k][j+1] + Mask[2][4]*IMG_matrix[k][j+2] + Mask[2][1]*IMG_matrix[k][j-1] + Mask[2][0]*IMG_matrix[k][j-2]

                                     + Mask[3][1]*IMG_matrix[k+1][j-1] + Mask[3][3]*IMG_matrix[k+1][j+1]

									 + Mask[1][1]*IMG_matrix[k-1][j-1] + Mask[1][3]*IMG_matrix[k-1][j+1];
 

                                     

                 if(LoGValue < threshVal) LoGValue = 0;

                 else if(LoGValue < threshVal) LoGValue = 255;
 

                 IMG_temp_matrix[k-2][j-2] = LoGValue;

            } 

        }

        

        //output the calculated 2D matrix to original 1D

        pixelCnt = 0;

        for(int j = 0; j < Pin_t.Height; j++)

        {

              for(int k = 0; k < Pin_t.Width; k++)

              {

                    Pin_t.img[pixelCnt] = (unsigned char) (IMG_temp_matrix[k][j]);

                    pixelCnt++;

              }

         }
 

        WritePGM(outfile_Pout, Pin_t);

 }
 
 

int main()

{  

    

	ifstream infile_Pin1;                /* input file */

    char inFileName_Pin1[128]="Lena.pgm";            /* input file name */

    PIC Pin1;            //source image

    

    /* open input/output file */

    infile_Pin1.open(inFileName_Pin1, ios::binary);
 

	/* check input file */

    if(!infile_Pin1)

    {

        cout<<"Cannot open input file "<< inFileName_Pin1 <<endl;

        return 1;

    }
 
 

   int LaplacianOfGaussian[5][5] = {{0, 0, 1, 0, 0},

                                 {0, 1, 2, 1, 0},

                                 {1, 2, -16, 2, 1},

								 {0, 1, 2, 1, 0},

                                 {0, 0, 1, 0, 0}};
 
 
 

    if (LoadP5Header(infile_Pin1, Pin1)) // load pgm (Pin) image header information

    {

        // allocate the memory for the input image

        //the dimensions of the original
 

        Pin1.img = new BYTE[Pin1.Width*Pin1.Height];
 

        LoadImage(infile_Pin1, Pin1);

   

       MaskFiltering(Pin1,LaplacianOfGaussian, "Lena_Hildreth_1.pgm");   
 

   }

   

}

Open in new window

Lena-Marr-Hidlreth.jpg
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24843344
The program opens lena.pgm as input.

 
0
 

Author Comment

by:datopdogg7
ID: 24843407
Yes, I cannot upload .pgm files to this question. Only .jpeg, etc.

I took a screen capture of the output image and saved it as a .jpeg

Here is the link to Lena.pgm

http://www.ece.umd.edu/class/enee631.F2001/am/am3/bb2.htm
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 53

Accepted Solution

by:
Infinity08 earned 250 total points
ID: 24847113
Could it be because of this :

>>                  if(LoGValue < threshVal) LoGValue = 0;
>>                  else if(LoGValue < threshVal) LoGValue = 255;

The else if checks the same condition as the if ... Did you mean :

                 if (LoGValue < threshVal) LoGValue = 0;
                 else if (LoGValue >= threshVal) LoGValue = 255;

or just :

                 if (LoGValue < threshVal) LoGValue = 0;
                 else LoGValue = 255;

?
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 250 total points
ID: 24847424
I debugged a little bit and some hundred values for LogValue all were in a range [-1500,-300] what makes them all 0 as you don't seem to expect negative values. I added variables for each term

       int t1 = Mask[2][2]*IMG_matrix[k][j];
       int t2 = Mask[3][2]*IMG_matrix[k+1][j];
       int t3 = Mask[4][2]*IMG_matrix[k+2][j];
       int t4 = Mask[1][2]*IMG_matrix[k-1][j];
       int t5 = Mask[0][2]*IMG_matrix[k-2][j];
       int t6 = Mask[2][3]*IMG_matrix[k][j+1];  
       int t7 = Mask[2][4]*IMG_matrix[k][j+2];
       int t8 = Mask[2][1]*IMG_matrix[k][j-1];
       int t9 = Mask[2][0]*IMG_matrix[k][j-2];
       int ta = Mask[3][1]*IMG_matrix[k+1][j-1];
       int tb = Mask[3][3]*IMG_matrix[k+1][j+1];
       int tc = Mask[1][1]*IMG_matrix[k-1][j-1];
       int td = Mask[1][3]*IMG_matrix[k-1][j+1];

and it turned out that t1 is nearly almost less than -2000 because of Mask[2][2] is -16, while the other values were about 100 in average what is not sufficient to make the LogValue a positive..

In the middle of the picture (column 250) things were better but still more than 50 percent negative values (mostly a series of 5 or 6).  

>>>>                 if(LoGValue < threshVal) LoGValue = 0;
>>>>                  else if(LoGValue < threshVal) LoGValue = 255;

Here that if/else doesn't consider negative values for LogValue ???



>>>> int **IMG_matrix = AllocateDynamicArray<int>(Pin_t.Width+6,Pin_t.Height+6);
you were allocating 6 pixels more in width though you only have a border of 4. Is there a reason I didn't see?

>>>> void FreeDynamicArray(T** dArray)
>>>> {
>>>>     delete [] *dArray;
>>>>     delete [] dArray;
>>>> }
 
You never call the FreeDynamicArray what doesn't matter much as it would delete only the first row. The deletion must be done in a loop same as the allocation.

I used a vector instead of int **IMG_matrix what is the better way as it initializes the matrix with zeros as well and you don't need to care for deallocation.

#include <vector>
using namespace std;

....

        // int **IMG_matrix = AllocateDynamicArray<int>(Pin_t.Width+6,Pin_t.Height+6);
        // int **IMG_temp_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);
        vector<vector<int> >  IMG_matrix(Pin_t.Width+6, vector<int>(Pin_t.Height+6, 0));
        vector<vector<int> >  IMG_temp_matrix(Pin_t.Width, vector<int>(Pin_t.Height, 0));
 
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24847462
>>>> The else if checks the same condition as the if ...

Good catch ;-)
0
 

Author Comment

by:datopdogg7
ID: 24862999
Thanks guys. That was the problem.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Fast access to array, using indexes, smart iterative search 2 108
Dice Roll Probabilities 3 82
Safe conversion? 4 58
What is sub-make ? 2 40
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now