?
Solved

Padding of Image Error C++

Posted on 2009-07-12
5
Medium Priority
?
368 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
ID: 24837894
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
ID: 24840827
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
ID: 24840829
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 2000 total points
ID: 24841505
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
ID: 24841589
Excellent. Thank you Infinity.
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

Question has a verified solution.

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

Iteration: Iteration is repetition of a process. A student who goes to school repeats the process of going to school everyday until graduation. We go to grocery store at least once or twice a month to buy products. We repeat this process every mont…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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 be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

601 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