C++ Image Processing - Reading an Image file into 2D Array

MathanMV picture MathanMV · Dec 6, 2012 · Viewed 41.2k times · Source

I'm an absolute noobie at C++ as I've only been familiar with Java programming. What I'm trying to do is to read an Image file (.bmp) into a matrix where I can perform a convolution with a 3x3 matrix (filter) on the matrix to produce a new image file with the convoluted image.

I've looked around google and managed to come up with the following implementation:

Image.h file:

//  Image.h

#include <fstream> // for file I/O

using namespace std;
typedef unsigned char unchar; // Easier to understand & code.

class MImage {

public:
    MImage(const char* fileName); //Constructor
    ~MImage(); //Deconstructor
    void write(const char* fileName);
    void smoothFilter(); //smoothing filer.
private:
    ifstream* pInFile; 
    ofstream* pOutFile;
    unchar imageHeaderData[1078]; //.bmp header data with offset 1078.
    unchar** imageData;
    unchar m_smoothFilter[3][3]; // Smoothing Filter.
    unchar**  filteredData;
};

Image.cpp file:

//  Image.cpp
//

#ifndef _Image_h
#define _Image_h
#define WIDTH 128
#define HEIGHT 128

#include "Image.h"
#include <cmath>

#endif

using namespace std;
typedef unsigned char unchar;

//Constructor

MImage::MImage(const char* fileName){

    imageData = new unchar* [HEIGHT]; // create new array size: height of image.
    filteredData = new unchar* [HEIGHT];// create new array size: height of image.

    for (int i = 0; i < HEIGHT; i++) {

        imageData[i] = new unchar [WIDTH]; //create matrix.
        filteredData[i] = new unchar [WIDTH]; //create matrix.
    }

    //image I/O
    pInFile = new ifstream;
    pInFile->open(fileName, ios::in | ios::binary); // open fileName and read as binary.
    pInFile->seekg(0, ios::beg); //pos filter at beginning of image file.
    pInFile->read(reinterpret_cast<char*>(imageHeaderData),1078); //read bmp header data into array.

    for(int i=0; i<HEIGHT; i++) {
        pInFile->read(reinterpret_cast<char*>(imageData[i]),WIDTH);//read row into each array entry.
    }

    pInFile->close(); //close stream.

    char m_smoothFilter[3][3] = {
                                 {1,1,1},
                                 {1,2,1},
                                 {1,1,1}
                                };

}

MImage::~MImage(){

    delete pInFile;
    delete pOutFile;

    for(int i=0; i<HEIGHT; i++){
        delete[] imageData[i];
        delete[] filteredData[i];
    }

    delete[] imageData;
    delete[] filteredData;
}

void MImage::write(const char* fileName) {

    smoothFilter();
    pOutFile = new ofstream;
    pOutFile->open(fileName, ios::out | ios::trunc | ios::binary);
    pOutFile->write(reinterpret_cast<char*>(imageHeaderData), 1078); //write header data onto output

    for(int i = 0; i < HEIGHT; i++){

        pOutFile->write(reinterpret_cast<char*>(filteredData[i]),WIDTH); // write new image data.

    }

    pOutFile->close(); //close stream
}

void MImage::smoothFilter(){

    //copy input image into new image
    for(int i = 0; i < HEIGHT; i++) {
        strcpy(reinterpret_cast<char*>(filteredData[i]), reinterpret_cast<char*>(imageData[i]));
    }

    int sumOfPixels = 0;

    for(int i = 1; i < HEIGHT -1; i++) {

        for(int j = 1; j < WIDTH -1; j++) {

            sumOfPixels = m_smoothFilter[0][0] * imageData[i+1][j-1] + // top left corner
                          m_smoothFilter[0][1] * imageData[i+1][j]   + // top center
                          m_smoothFilter[0][2] * imageData[i+1][j+1] + // top right corner
                          m_smoothFilter[1][0] * imageData[i][j-1]   + // center left
                          m_smoothFilter[1][1] * imageData[i][j]     + // center center
                          m_smoothFilter[1][2] * imageData[i][j+1]   + // center right
                          m_smoothFilter[2][0] * imageData[i-1][j-1] + // bottom left corner
                          m_smoothFilter[2][1] * imageData[i-1][j]   + // bottom center
                          m_smoothFilter[2][2] * imageData[i-1][j+1];  // bottom right corner

            filteredData[i][j] = (sumOfPixels / ( m_smoothFilter[0][0] + m_smoothFilter[0][1] +
                                                  m_smoothFilter[0][2] + m_smoothFilter[1][0] +
                                                  m_smoothFilter[1][1] + m_smoothFilter[1][2] +
                                                  m_smoothFilter[2][0] + m_smoothFilter[2][1] +
                                                 m_smoothFilter[2][2]));
        }
    }

}

Main.cpp file:

//
//  Main.cpp
//

#include <iostream>
#include "Image.cpp"
#include <fstream>

using namespace std;

int main() {

    MImage img("test.bmp");
    img.write("output.bmp");
    return 0;

}

When I try to run the following file with:

g++ Main.cpp -o main

./main

I get a segmentation:11 error and not sure what is causing this error!

Note: I have to use a pure C++ implementation so cannot use other libraries.

HELP!

EDIT: I think the code thats giving me the segmentation error is :

for(int i = 0; i < HEIGHT; i++) {
        strcpy(reinterpret_cast<char*>(filteredData[i]), reinterpret_cast<char*>(imageData[i]));
}

But not sure why!

EDIT #3: Works after replacing above code with :

for(int i= 0; i<HEIGHT; i++) {
        strncpy (reinterpret_cast<char*>(filteredData[i]), 
                 reinterpret_cast<char*>(imageData[i]), 
                 sizeof(reinterpret_cast<char*>(filteredData[i])));
    }

Answer

MathanMV picture MathanMV · Dec 6, 2012

replaced strcpy() with strncpy() which is much safer apparently and that removed the segmentation fault.