Solved

Canny Edge Algorithm Problem C++

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

I am getting very large values for Gx and Gy when running the code. I think this has something to do with a conversion error or something of that nature because the sobel filter stores values like -1,2, 1, and in the first iteration the IMG_temp_matrix_2  has all zero values, yet Gx becomes 1768515943 as does Gy.

This is extremely frustrating and I do not know how to fix it.

Thanks,

Dennis
#include <iostream>
#include <fstream>
#include <string>
#include <math.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 Canny_Edge(PIC Pin_t, int Mask[5][5], char *outFileName_Pout)
{
    
        ofstream outfile_Pout;
 
        outfile_Pout.open(outFileName_Pout, ios::binary);
        
        int **IMG__gaussian_matrix = AllocateDynamicArray<int>(Pin_t.Width+6,Pin_t.Height+6);
        int **IMG_temp_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);
		int **IMG_temp_matrix_2 = AllocateDynamicArray<int>(Pin_t.Width+2,Pin_t.Height+2);
		int **IMG_final_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);
 
		int **IMG__sobel_matrix = AllocateDynamicArray<int>(Pin_t.Width+2,Pin_t.Height+2);
		float **IMG__gradient_matrix = AllocateDynamicArray<float>(Pin_t.Width,Pin_t.Height);
		int **IMG__direction_matrix = AllocateDynamicArray<int>(Pin_t.Width,Pin_t.Height);
		
		int Sobel_Filter_x [3][3] = {{-1,0,1},
								{-2,0,2},
								{-1,0,1}};
 
		int Sobel_Filter_y [3][3] = {{1,2,1},
								{0,0,0},
								{-1,-2,-1}};
   
        int Npixels, pixelCnt, gaussianValue, Gx, Gy, finalAngle;
		float tempAngle;
        int upperThresh, lowerThresh;
            
		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 gaussian mask to boundary values
 
        for(int j = 0; j <= Pin_t.Height+3; j++)
        {
             IMG__gaussian_matrix[0][j] = 0;
             IMG__gaussian_matrix[1][j] = 0;
             IMG__gaussian_matrix[Pin_t.Width+2][j] = 0; 
             IMG__gaussian_matrix[Pin_t.Width+3][j] = 0; 
        }
        
        for(int k = 0; k <= Pin_t.Width+3; k++)
        {
             IMG__gaussian_matrix[k][0] = 0;
             IMG__gaussian_matrix[k][1] = 0;
             IMG__gaussian_matrix[k][Pin_t.Height+2] = 0;
             IMG__gaussian_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__gaussian_matrix[k][j] = (int) Pin_t.img[pixelCnt];
                    pixelCnt++;
              }
         }
 
 
		// Gaussian Smooth the Original Image
 
        
        for(int j=2; j <= Pin_t.Height+1; j++)
        {           
            for(int k=2; k <= Pin_t.Width+1; k++)
            {      
 
                      gaussianValue = Mask[0][0]*IMG__gaussian_matrix[k-2][j-2] + Mask[0][1]*IMG__gaussian_matrix[k-2][j-1] + Mask[0][2]*IMG__gaussian_matrix[k-2][j] + Mask[0][3]*IMG__gaussian_matrix[k-2][j+1] + Mask[0][3]*IMG__gaussian_matrix[k-2][j+2]
					             + Mask[1][0]*IMG__gaussian_matrix[k-1][j-2] + Mask[1][1]*IMG__gaussian_matrix[k-1][j-1] + Mask[1][2]*IMG__gaussian_matrix[k-1][j] + Mask[1][3]*IMG__gaussian_matrix[k-1][j+1] + Mask[1][4]*IMG__gaussian_matrix[k-1][j+2]
								 + Mask[2][0]*IMG__gaussian_matrix[k][j-2] + Mask[2][1]*IMG__gaussian_matrix[k][j-1] + Mask[2][2]*IMG__gaussian_matrix[k][j] + Mask[2][3]*IMG__gaussian_matrix[k][j+1] + Mask[2][4]*IMG__gaussian_matrix[k][j+2]
                                 + Mask[3][0]*IMG__gaussian_matrix[k+1][j-2] + Mask[3][1]*IMG__gaussian_matrix[k+1][j-1] + Mask[3][2]*IMG__gaussian_matrix[k+1][j] + Mask[3][3]*IMG__gaussian_matrix[k+1][j+1] + Mask[3][4]*IMG__gaussian_matrix[k+1][j+2]
                                 + Mask[4][0]*IMG__gaussian_matrix[k+2][j-2] + Mask[4][1]*IMG__gaussian_matrix[k+2][j-1] + Mask[4][2]*IMG__gaussian_matrix[k+2][j] + Mask[4][3]*IMG__gaussian_matrix[k+2][j+1] + Mask[4][4]*IMG__gaussian_matrix[k+2][j+2];
								
 
                 IMG_temp_matrix[k-2][j-2] = (int)(gaussianValue/159);
            } 
        }
 
		
 
		//Create a single pixel layer of black border around the smoothed image to apply the sobel mask to boundary values
 
        for(int j = 0; j <= Pin_t.Height+1; j++)
        {
 
             IMG_temp_matrix_2[0][j] = 0;
             IMG_temp_matrix_2[Pin_t.Width+1][j] = 0; 
        }
        
        for(int k = 0; k <= Pin_t.Width+1; k++)
        {
             IMG_temp_matrix_2[k][0] = 0;
             IMG_temp_matrix_2[k][Pin_t.Height+1] = 0;
        }
 
		// Filter the Smoothed Image with both the x and y direction sobel masks and in each iteration determine the magnitude of the gradient as well as the direction
 
		for(int j=1; j <= Pin_t.Height; j++)
				{           
					for(int k=1; k <= Pin_t.Width; k++)
					{      
 
							 Gx = Sobel_Filter_x[1][1]*IMG_temp_matrix_2[k][j]        
											 + Sobel_Filter_x[2][1]*IMG_temp_matrix_2[k+1][j]
											 + Sobel_Filter_x[0][1]*IMG_temp_matrix_2[k-1][j]
											 + Sobel_Filter_x[1][2]*IMG_temp_matrix_2[k][j+1]
											 + Sobel_Filter_x[1][0]*IMG_temp_matrix_2[k][j-1]
											 + Sobel_Filter_x[0][0]*IMG_temp_matrix_2[k-1][j-1]
											 + Sobel_Filter_x[2][0]*IMG_temp_matrix_2[k+1][j-1]
											 + Sobel_Filter_x[0][2]*IMG_temp_matrix_2[k-1][j+1]
											 + Sobel_Filter_x[2][2]*IMG_temp_matrix_2[k+1][j+1];
 
 							 Gy = Sobel_Filter_y[1][1]*IMG_temp_matrix_2[k][j]        
											 + Sobel_Filter_y[2][1]*IMG_temp_matrix_2[k+1][j]
											 + Sobel_Filter_y[0][1]*IMG_temp_matrix_2[k-1][j]
											 + Sobel_Filter_y[1][2]*IMG_temp_matrix_2[k][j+1]
											 + Sobel_Filter_y[1][0]*IMG_temp_matrix_2[k][j-1]
											 + Sobel_Filter_y[0][0]*IMG_temp_matrix_2[k-1][j-1]
											 + Sobel_Filter_y[2][0]*IMG_temp_matrix_2[k+1][j-1]
											 + Sobel_Filter_y[0][2]*IMG_temp_matrix_2[k-1][j+1]
											 + Sobel_Filter_y[2][2]*IMG_temp_matrix_2[k+1][j+1];
						   
 
							// Compute gradient value
 
							IMG__gradient_matrix[k-1][j-1] = sqrt(pow(Gx,2.0) + pow(Gy,2.0));
 
							// Calculate direction of edge
 
							tempAngle = (atan2((float)Gx, (float)Gy)/3.14159) * 180.0;		
			
							// Convert edge direction to approximate value //
 
							if ( ( (tempAngle < 22.5) && (tempAngle > -22.5) ) || (tempAngle > 157.5) || (tempAngle < -157.5) )
								finalAngle = 0;
							if ( ( (tempAngle > 22.5) && (tempAngle < 67.5) ) || ( (tempAngle < -112.5) && (tempAngle > -157.5) ) )
								finalAngle = 45;
							if ( ( (tempAngle > 67.5) && (tempAngle < 112.5) ) || ( (tempAngle < -67.5) && (tempAngle > -112.5) ) )
								finalAngle = 90;
							if ( ( (tempAngle > 112.5) && (tempAngle < 157.5) ) || ( (tempAngle < -22.5) && (tempAngle > -67.5) ) )
								finalAngle = -45;
 
							IMG__direction_matrix[k-1][j-1] = finalAngle;
 
					} 
				}
 
		// Perform Nonmaxima suppression 
 
		for(int j=0; j < Pin_t.Height; j++)
				{           
					for(int k=0; k < Pin_t.Width; k++)
					{  
 
						switch (IMG__direction_matrix[k][j]){		
							
							case 0:
								
								if(j == 0)
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k][j+1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
 
								else if( j == (Pin_t.Height - 1))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k][j-1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else
								{
 
									if((IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k][j-1]) || (IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k][j+1]))
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
 
								break;
 
							case 45:
								
								if((k == 0) && (j == (Pin_t.Height - 1)))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j-1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else if((k == Pin_t.Width -1) && (j == 0))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j+1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else
								{
 
									if((IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j+1]) || (IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j-1]))
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
							
 
								break;
 
							case 90:
								
								if(k == 0)
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
 
								else if( k == (Pin_t.Width - 1))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else
								{
 
									if((IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j]) || (IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j]))
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
								break;
 
							case -45:
 
								if((k == 0) && (j == 0))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j+1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else if((k == Pin_t.Width -1) && (j == (Pin_t.Height -1)))
								{
									if(IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j-1])
									{
										IMG__gradient_matrix[k][j] = 0;
									}
								}
 
								else
								{
 
									if((IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j+1]) || (IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j-1]))
									{
										IMG__gradient_matrix[k][j] = 0;
									}
 
								}
 
								break;
							}
 
					}
 
		}
 
		// Insert Hysterisys Algorithm here //
 
 
        
        //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__gradient_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 Gaussian_Mask[5][5] = {{2, 4, 5, 4, 2},
                                 {4, 9, 12, 9, 4},
                                 {5, 12, 15, 12, 5},
								 {4, 9, 12, 9, 4},
                                 {2, 4, 5, 4, 2}};
 
 
    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);
   
       Canny_Edge(Pin1,Gaussian_Mask, "Lena_Canny_1.pgm");   
 
   }
   
}

Open in new window

0
Comment
Question by:datopdogg7
  • 2
  • 2
  • 2
  • +2
8 Comments
 
LVL 7

Expert Comment

by:samenglish
ID: 24846802
I don't have the ability to paste your code into a C++ development environment, but might I suggest stepping through your loop. Is Gx and Gy always equal to 1768515943 at the end of the first iteration even though you say IMG_temp_matrix_2 is all zeros at that stage (it doesn't look like this is true to me). It looks like you are doing some complex graphics stuff, odds are the problem is in your algorithm, not a conversion error. At this stage all I am prepared to say is that

for(int j = 0; j <= Pin_t.Height+1; j++)
        {
              IMG_temp_matrix_2[0][j] = 0;
             IMG_temp_matrix_2[Pin_t.Width+1][j] = 0;
        }
       
 for(int k = 0; k <= Pin_t.Width+1; k++)
        {
             IMG_temp_matrix_2[k][0] = 0;
             IMG_temp_matrix_2[k][Pin_t.Height+1] = 0;
        }

does NOT create an array full of zeros.

If you know which values you are expecting, check that your expectations match the results by stepping through your code, you'll find the offending variable when you find the line of code where results don't match expectations.

Good Luck, Sam.
0
 

Author Comment

by:datopdogg7
ID: 24846817
The input image matrix is from an image, which has grayscale values, i.e. 0 to 255... .
0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 500 total points
ID: 24847073
I think you simply forgot to copy the IMG_temp_matrix image into the IMG_temp_matrix_2 2D array before applying the Sobel filter.

You initialized the border in IMG_temp_matrix_2, but you never copied the image in there.
0
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24847607
>>>> I think you simply forgot to copy the IMG_temp_matrix image into the IMG_temp_matrix_2
Good catch again.


@datopdogg7

For what were you using so much temp buffers? There is no reason for using IMG_temp_matrix and IMG_temp_matrix_2  as they never were used same time. If you need a border you also could add it to one of these tables.

0
 
LVL 7

Expert Comment

by:samenglish
ID: 24855162
1. Defintely no conversion error here
2. Problem is in the algorithm
3. Infinity08 is right, you forgot to copy the image into IMG_temp_matrix_2
4. The reason for those large values in Gx and Gy is because you didn't initialise every element of the dynamic array IMG_temp_matrix_2. Who knows what the contents of that chunk of memory were before they were allocated to IMG_temp_matrix_2. I suspect you know how to initialise each element to zero, but I also suspect that Infinity08 was on the money when he suggested that you simplly forgot to copy IMG_temp_matrix into IMG_temp_matrix_2. If IMG_temp_matrix_2 contained only values from 0..255 then Gx and Gy would probably match your expectations.

Initialising variables is a good habit.

Sam.
0
 

Expert Comment

by:Gabriela1
ID: 25117639
Hi ,

I am now trying to use this code, and i tried the solution proposed but something is wrong. I put the code that we had to add for copying.
But is seems like another bug is come up...I have

Unhandled exception at 0x0042bcde in I90Controller.exe: 0xC0000005:

if((IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k+1][j+1]) || (IMG__gradient_matrix[k][j] < IMG__gradient_matrix[k-1][j-1]))

probably is because I did not copy it right.
Can you help me please?

Thanks
for(int j = 0; j <= Pin_t.Height+1; j++)
        {
 
             IMG_temp_matrix_2[0][j] = 0;
             IMG_temp_matrix_2[Pin_t.Width+1][j] = 0; 
        }
        
        for(int k = 0; k <= Pin_t.Width+1; k++)
        {
             IMG_temp_matrix_2[k][0] = 0;
             IMG_temp_matrix_2[k][Pin_t.Height+1] = 0;
        }
		for(int i=1; i <= Pin_t.Width;i++)
		{
			for(int j =1; j <=Pin_t.Height;j++)
			{
				IMG_temp_matrix_2[i][j]=IMG_temp_matrix[i-1][j-1];
			}
		}

Open in new window

0
 
LVL 53

Expert Comment

by:Infinity08
ID: 25117693
Gabriela1, that depends on what k and j are, and how the matrices were dimensioned and initialized.

But you're probably better off posting your own question about this. You can use the "Ask a related question" link for that.
0
 

Expert Comment

by:Gabriela1
ID: 25118582
Thank you,

I posted a new question..nobody answered yet.
0

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
maze travler 6 55
Retrieve PID of MicrosoftEdge.exe with GetForegroundWindow() 6 147
Fully specialized class template function 21 136
Issues with C++ Class 19 92
When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

805 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