Click here to Skip to main content
15,891,423 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello all.

I am currently working on imaging processing using arrays to store R,G,B values from a 24 bit BITMAP image of width 120 and height 100 pixels.
Visual Studio 2010 is being used.

I have currently extracted the individual R,G,B values into three separate2D arrays from the 24 bit bitmap (it is assumed correct as the correct R,G,B values have been written to a text file with the right pixel count as well).

These individual R,G,B values need to be restored back into an array (either 1D or 2D), which is then written to an image file. The output should be identical to the original image.

I have tried the following but the output is currently incorrect (same width, height and memory size but colouring is incorrect).

Appreciate your guidance and feedback.

C++
#include <iostream>
#include <fstream>
#include <windows.h>
#include <WinGDI.h>

unsigned char** Allocate2DArray(int w, int h)
{
     unsigned char ** buffer = new unsigned char * [h];  // allocate the rows

     unsigned char * memory_pool = new unsigned char [w*h];  // allocate memory pool
     for (int i = 0; i < h; ++i)
     {
         buffer[i] = memory_pool;   // point row pointer
         memory_pool += w;          // go to next row in memory pool
     }
     return buffer;
}

void DeAllocate2DArray(unsigned char** buffer) 
{  
    delete [] buffer[0];  // delete the memory pool
    delete [] buffer;     // delete the row pointers
}



using namespace std;

int main()
{

const int width = 120;
const int height = 100;

	int bytesPerPixel = 3;
	unsigned char m_cHeaderData[54];
	unsigned char** m_cImageData = new unsigned char* [height];
	
	for( int i = 0; i <height; i++)
	{
		m_cImageData[i] = new unsigned char [width*bytesPerPixel];
	}

	ifstream* m_pInFile;    
	m_pInFile = new ifstream;
	m_pInFile->open("image.bmp", ios::in | ios::binary);
	m_pInFile->seekg(0, ios::beg);
	m_pInFile->read(reinterpret_cast<char*>(m_cHeaderData), 54); 
	for(int i = 0; i <height; i++)
	{
		m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width*bytesPerPixel); 
		
	}

	m_pInFile->close();


	// Declare a pointer of the type you want. 
	// This will point to the 1D array 
	unsigned char* array_1D; 
	array_1D = new unsigned char[height*width*bytesPerPixel]; 
	if(array_1D == NULL) return 0;  // return if memory not allocated 

	// Copy contents from the existing 2D array
	int offset = 0;

	for(int j=0; j<height; j++)  // traverse height (or rows) 
	{  
		offset = width * bytesPerPixel* j;  
		for(int i=0; i<width*bytesPerPixel; i++) // traverse width  
		{   
			array_1D[offset + i] = m_cImageData[j][i]; 
                     // update value at current (i, j)  
			
		} 
	}


	// Declare three 2D arrays to store R,G, and B planes of image. 
	unsigned char**arrayR_2D, **arrayG_2D, **arrayB_2D;   
	arrayR_2D = Allocate2DArray(width, height); 
	arrayG_2D = Allocate2DArray(width, height); 
	arrayB_2D = Allocate2DArray(width, height); 

	// return if memory not allocated 
	if(arrayR_2D == NULL || arrayG_2D == NULL || arrayB_2D == NULL) return 0; 


	// Extract R,G,B planes from the existing composite 1D array 
	ofstream RGBdata2D;
	RGBdata2D.open("RGBdata2D.txt");    
	int pixelCount = 0;
	int offsetx = 0; 
	int counter = 0; 

	for(int j=0; j<height; j++)  // traverse height (or rows) 
	{  
	    offsetx = width * j * bytesPerPixel;  
	    for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width  
	    {   
            arrayB_2D[j][counter] = array_1D[offsetx + i+0];   
            arrayG_2D[j][counter] = array_1D[offsetx + i+1];   
            arrayR_2D[j][counter] = array_1D[offsetx + i+2];  

	     RGBdata2D<<"B: "<< (int)arrayB_2D[j][counter] << " G: " << (int)arrayG_2D[j][counter] << " R: " << (int)arrayR_2D[j][counter]<< endl;
		pixelCount++;

		++counter;
	    }

		counter = 0; 
	}

	RGBdata2D<<"count of pixels: "<< pixelCount << endl;
	RGBdata2D.close();

	
       //put RGB from 2D array contents back into a 1D array 
	offset = 0; 
	counter = 0; 
	for(int j=0; j<height; j++)  // traverse height (or rows) 
	{  
		offset = width * bytesPerPixel * j;  
		for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width  
		{   
			array_1D[offset + i+0] = arrayB_2D[j][counter++]; 
			array_1D[offset + i+1] = arrayG_2D[j][counter++]; 
			array_1D[offset + i+2] = arrayR_2D[j][counter++];

		} 
		counter = 0; 
	} 

	ofstream* m_pOutFileRGB;    
	m_pOutFileRGB = new ofstream;
	m_pOutFileRGB->open("imageCopyRGB.bmp", ios::out | ios::trunc | ios::binary);    
	m_pOutFileRGB->write(reinterpret_cast<char*>(m_cHeaderData), 54); //bitmap bits start at offset 1078

	for(int i = 0; i <height; i++)
	{
		m_pOutFileRGB->write(reinterpret_cast<char*>(array_1D), width*bytesPerPixel); 
		
	}

	m_pOutFileRGB->close();

	
	
    // After complete usage, delete the memory dynamically allocated 
	DeAllocate2DArray(arrayR_2D); 
	DeAllocate2DArray(arrayG_2D); 
	DeAllocate2DArray(arrayB_2D);


	// After complete usage, delete the memory dynamically allocated 
	delete[] array_1D; //delete the pointer to pointer 


	for(int i = 0; i <height; i++)
	{
		delete[] m_cImageData[i];
	}
	delete[] m_cImageData;

	
	system("pause");

	return 0;
}
Posted

1 solution

I do not know if this will fix all your problems but, try replacing this:

C++
array_1D[offset + i+0] = arrayB_2D[j][counter++];
array_1D[offset + i+1] = arrayG_2D[j][counter++];
array_1D[offset + i+2] = arrayR_2D[j][counter++];



... with this ...

C++
array_1D[offset + i+0] = arrayB_2D[j][counter];
array_1D[offset + i+1] = arrayG_2D[j][counter];
array_1D[offset + i+2] = arrayR_2D[j][counter];
counter++;


Some additional suggestions:

1. don't make gratuitous use of pointer and new. It often leads to memory leaks. Example:

C++
ifstream* m_pInFile;
m_pInFile = new ifstream;
m_pInFile->open("image.bmp", ios::in | ios::binary);
m_pInFile->seekg(0, ios::beg);
m_pInFile->read(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
    m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width*bytesPerPixel);

}

m_pInFile->close();


This could be written as:

C++
ifstream m_pInFile;
m_pInFile.open("image.bmp", ios::in | ios::binary);
m_pInFile.seekg(0, ios::beg);
m_pInFile.read(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
    m_pInFile.read(reinterpret_cast<char*>(m_cImageData[i]), width*bytesPerPixel);

}
m_pInFile.close();


The latter form does not leak memory.

For your arrays - use std::vector.
 
Share this answer
 
v2
Comments
binaryoffset 12-Oct-15 14:03pm    
Thanks. I notice that the correct R,G,B values are being written into array_1D, whereas initially, they were not. I still need to write this correctly to a new BITMAP file.
[no name] 12-Oct-15 14:04pm    
I did not dive into the code, but your hint makes sense, so a 5 from my side.
binaryoffset 12-Oct-15 14:11pm    
I'd actually removed some of the pointers where really unnecessary, but thank you all the same. I'd give a 10 if I could get this working, eventually.
jeron1 12-Oct-15 17:38pm    
How about starting with a much smaller bitmap and single step though each reading and writing portion and verify the values along the way.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900