datopdogg7
asked on
Marr-Hildreth Program not Giving Desired Result
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
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");
}
}
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).
ASKER
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.
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");
}
}
Lena-Marr-Hidlreth.jpg
The program opens lena.pgm as input.
ASKER
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
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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
>>>> The else if checks the same condition as the if ...
Good catch ;-)
Good catch ;-)
ASKER
Thanks guys. That was the problem.