Solved

Padding of Image Error C++

Posted on 2009-07-12
5
346 Views
Last Modified: 2012-05-07
Hi Experts,
I am trying to runn my edge detection algorithm, but there is an error with my padding algorithm. The algorithm follows directly after the commented line "//creats a single pixel layer of black border around the original image to apply the mask to boundary values"

Please let me know where I am going wrong. The mask I am applying to the image is a 5x5. Is the padding determined by the size of the input image?

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 = 300;

            

		Npixels = Pin_t.Width*Pin_t.Height;

		Pin_t.Maxval = 255;

        

        //creats a single 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[Pin_t.Width+3][j] = 0; 

        }

        

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

        {

             IMG_matrix[k][0] = 0;

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

        }

   

        pixelCnt = 0;

        //make 2D matrix of input
 

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

        {

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

              {

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

                    pixelCnt++;

              }

         }

  

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

        {           

            for(int k=1; k <= Pin_t.Width; 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-1][j-1] = 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
  • 3
  • 2
5 Comments
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
Since your max is 5x5 pixels, you'll have to add a black border of 2 pixels wide, not just 1 pixel wide.

Part of your code already supports that, by looping from 0 to (Pin_t.Height+3), which gives you enough room for the image height itself, and two pixels before and two pixels after (for the border).
But you then proceed to add only one pixel border, with the image not properly centered in it.

To add a two pixel border, and center the image, you can do something like below.


Another thing I noticed, is that you use the width and height indexes in a non-standard manner. Normally, the first index of a 2D array is the row number (ie. along the height of the image), and the second is the column number (ie. along the width of the image).
As long as you do that consistently, there's no problem, but you should realize that it's non-standard, and thus potentially error prone, especially when other people work with the code too.
        //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++;

              }

         }
 

// etc. Remember that the real image goes from 2 to Pin_t.Height + 1 in the vertical direction and 2 to Pin_t.Width + 1 in the horizontal direction, so you'll have to adapt the masking code for that too ...

Open in new window

0
 

Author Comment

by:datopdogg7
Comment Utility
Hi Infinity,

Thanks Infinity. Unfortunately, when I updated the code with the one you supplied, I still get the same error. The main loop (with the mask multiplication) doesn't even go one iteration through, still k=1, and j=1.

This is the error I am getting. which appears in the line:

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

Unhandled exception at 0x008b1e74 in Marr-Hildreth.exe: 0xC0000005: Access violation reading location 0xfdfdfe01.
0
 

Author Comment

by:datopdogg7
Comment Utility
To confirm the 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 = 300;

            

		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=1; j <= Pin_t.Height; j++)

        {           

            for(int k=1; k <= Pin_t.Width; 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-1][j-1] = 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
 
LVL 53

Accepted Solution

by:
Infinity08 earned 500 total points
Comment Utility
It seems you haven't updated the rest of the code, more specifically the loop where the mask is applied, and the output loop. You have to make sure that they refer to the part of the IMG_matrix 2D array that contains the original image, ie. from 2 to Pin_t.Height + 1 in the vertical direction and 2 to Pin_t.Width + 1 in the horizontal direction (as I explained in my previous post).
0
 

Author Comment

by:datopdogg7
Comment Utility
Excellent. Thank you Infinity.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Okay. So what exactly is the problem here? How often have we come across situations where we need to know if two strings are 'similar' but not necessarily the same? I have, plenty of times. Until recently, I thought any functionality like that wo…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

763 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

13 Experts available now in Live!

Get 1:1 Help Now