Solved

Padding of Image Error C++

Posted on 2009-07-12
5
363 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 500 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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

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…
One of Google's most recent algorithm changes affecting local searches is entitled "The Pigeon Update." This update has dramatically enhanced search inquires for the keyword "Yelp." Google searches with the word "Yelp" included will now yield Yelp a…
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.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

738 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