CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Oct 2015
    Posts
    18

    Extracting RGB values from Bitmap Image

    Hello. I am currently trying to extract R, G, B values from a 256 colour bitmap image (using for testing purposes a fixed width of 152 and height 150). I have checked using BITMAPINFOHEADER and BITMAPFILEHEADER that the offset is 1078 and bytes per pixel is 1.

    The image data is initially placed in a 2 dimensional array before being placed into a 1 dimensional array. Three 2 dimensional arrays were allocated to hold the R, G, B values from each pixel.

    When I run the program, the following Debug Assertion Failed! message appears:
    Expression: _BLOCK_TYPE_IS_VALID (pHead->nBlockUse)

    Below is the code and I would value your expert feedback and how to fix this error.

    Code:
    unsigned char** Allocate2DArray(unsigned char** buffer, int w, int h) 
    {  
    	buffer = new unsigned char*[h];  
    	if(buffer == NULL) return 0; // return if memory not allocated  
    	// For each of these pointers, allocate memory of size ‘w’  
    	for(int j=0; j<h; j++)  
    	{   buffer[j] = new unsigned char[w];   
    	         if(buffer[j] == NULL) return 0;// return if not allocated  
    	}  
    	return buffer; 
    }  
    
    void DeAllocate2DArray(unsigned char** buffer, int h) 
    {  
    	// After complete usage, delete the memory dynamically allocated  
    	for(int j=h-1; j>= 0; j--) 
    		delete[] buffer[j]; //delete rows  
    	delete[] buffer; //delete the pointer to pointer 
    }
    
    
    using namespace std;
    
    int main()
    {
    	ifstream image;
    	image.open("image.bmp",std::ios_base::binary);
    
    	if (image.is_open()) 
    	{
    		cout<< "function success\n";
    	} 
    	else 
    	{
    		cout<< "unable to open file";
    	}
    
    
                 const int width = 152;
                 const int height = 150;
    	 
    	unsigned char m_cHeaderData[1078];
    	unsigned char** m_cImageData = new unsigned char* [height];
    	
    	for( int i = 0; i <height; i++)
    	{
    	      m_cImageData[i] = new unsigned char [width];
    	}
    
    	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), 1078); //bitmap bits start at offset 1078
    
    	for(int i = 0; i <height; i++)
    	{
    		m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width); 
    	}
    
    	m_pInFile->close();
    
    
    	// Declare a pointer of the type you want. 
    	// This will point to the 1D array 
    	unsigned char* array_1D; 
    
    	// Now allocate memory for array_1D
    	array_1D = new unsigned char[height*width]; 
    	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 * j;  
    		for(int i=0; i<width; 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(arrayR_2D, width, height); 
    	arrayG_2D = Allocate2DArray(arrayG_2D, width, height); 
    	arrayB_2D = Allocate2DArray(arrayB_2D, 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 
    	int offsetx = 0; 
    	int counter = 0; 
    	int bytesPerPixel = 1;
    
    	for(int j=0; j<height; j++)  // traverse height (or rows) 
    	{  
    		offset = width * j;  
    		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];  
    		}  
    		counter = 0; 
    	}
    
    
    	// After complete usage, delete the memory dynamically allocated 
    	DeAllocate2DArray(arrayR_2D, height); 
    	DeAllocate2DArray(arrayG_2D, height); 
    	DeAllocate2DArray(arrayB_2D, height);
    
    	// After complete usage, delete the memory dynamically allocated 
    	delete[] array_1D; //delete the pointer to pointer 
    
    	//deallocate memory:
    	delete m_pInFile;
    	delete m_pOutFile;
    	for(int i = 0; i <height; i++)
    	{
    		delete[] m_cImageData[i];
    	}
    	delete[] m_cImageData;
    
    	
    	system("pause");
    
    	return 0;
    }

  2. #2
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721

    Re: Extracting RGB values from Bitmap Image

    Some quick thoughts:

    1) you don't want to pass the unsigned** variable to the Allocate
    functions. Also, it is written inefficiently. You only need
    two calls to new. Re-written allocate and dellaocate functions:

    Code:
    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
    }
    
    
    // usage
    
    unsigned char ** arrayR_2D = Allocate2DArray(width, height); 
    
    DeAllocate2DArray(arrayR_2D);

    2) Even better, use std::vector

    3) you open the image file twice, but do not close it in between.
    The second open could fail.

    4) You have:
    Code:
        for(int j=0; j<height; j++)  // traverse height (or rows) 
        {  
            offset = width * j;  
            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];  
            }  
            counter = 0; 
        }
    a) you set offset, but never use it

    b) counter will end up larger than the width, causing a memory write problem.

  3. #3
    Join Date
    Oct 2015
    Posts
    18

    Re: Extracting RGB values from Bitmap Image

    Thanks for your input, I appreciate the time taken.

    I have applied some of the changes expressed in your comment, but the program still does not work.

    'offset' has now changed to the correct 'offsetx'.
    And the first image file closes before opening a new image file.
    The new 2D allocation and deallocation array functions have also been taken into account.

  4. #4
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721

    Re: Extracting RGB values from Bitmap Image

    1) What do you mean by: "the program still does not work". Are values incorrect ? Does it crash ?

    2) you need to post your current code.

  5. #5
    Join Date
    Oct 2015
    Posts
    18

    Re: Extracting RGB values from Bitmap Image

    Hello. When running the program, the message "Program.exe has stopped working" is received. So I have not been able to retrieve any values to test if it's correct (yet).

    Below is the updated code:


    Code:
    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 = 152;
          const int height = 150;
    		
                  unsigned char m_cHeaderData[1078];
    	unsigned char** m_cImageData = new unsigned char* [height];
    	
    	for( int i = 0; i <height; i++)
    	{
    		m_cImageData[i] = new unsigned char [width];
    	}
    
    	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), 1078); 
                 //bitmap bits start at offset 1078
    
    	for(int i = 0; i <height; i++)
    	{
    		m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width); 
    	}
    
    	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]; 
    	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 * j;  
    		for(int i=0; i<width; 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 
    	int offsetx = 0; 
    	int counter = 0; 
    	int bytesPerPixel = 1;
    
    	for(int j=0; j<height; j++)  // traverse height (or rows) 
    	{  
    		offsetx = width * j;  
    		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];  
    		}  
    		counter = 0; 
    	}
    
    
    	
    	// 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 
    
    	//deallocate memory:
    
    	for(int i = 0; i <height; i++)
    	{
    		delete[] m_cImageData[i];
    	}
    	delete[] m_cImageData;
    
    	
    	system("pause");
    
    	return 0;
    }

  6. #6
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721

    Re: Extracting RGB values from Bitmap Image

    You did not do anything about one of my comments. Look at the loop:

    Code:
           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];  
            }
    When i = width -1 , counter will have the values of 453,454,455 in the loop.
    The second dimension of the arrays is only dimensioned at 152.

  7. #7
    Join Date
    Oct 2015
    Posts
    18

    Re: Extracting RGB values from Bitmap Image

    Could you advise as to how I can correct this? Thank you.

  8. #8
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721

    Re: Extracting RGB values from Bitmap Image

    It should probably be:

    Code:
           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];  
    
                ++counter;
            }
    Also note: usually you would not have 3 different arrays. You would create
    a class and use it. Something like:

    Code:
    struct RGB_triple
    {
        unsigned char r,g,b;
    };

  9. #9
    Join Date
    Oct 2015
    Posts
    18

    Re: Extracting RGB values from Bitmap Image

    [QUOTE=Philip Nicoletti;2187943]It should probably be:

    Code:
           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];  
    
                ++counter;
            }
    Thank you. I have altered my program and it does not crash anymore. Testing a bitmap (white), the RGB values are not 255, 255, 255, rather 205, 205, 205 repeatedly. I am writing the RGB values to a text file using the code below:

    Code:
                  ofstream RGBdata;
    	RGBdata.open("RGBdata.txt");    
    	
                  // Extract R,G,B planes from the existing composite 1D array 
    	int offsetx = 0; 
    	int counter = 0; 
    	int bytesPerPixel = 1;
    
    	for(int j=0; j<height; j++)  // traverse height (or rows) 
    	{  
    	    offsetx = width * j;  
    	   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];  
    
    	RGBdata<<"R: "<< (int)arrayR_2D[j][counter] << " G: " << (int)arrayG_2D[j][counter]<< " B: " 
                        << (int)arrayB_2D[j][counter]<< endl;
    
                ++counter;
    			
    	}
    
    	counter = 0; 
    }
    
    RGBdata.close();

  10. #10
    Join Date
    Oct 2015
    Posts
    18

    Re: Extracting RGB values from Bitmap Image

    Thanks for your guidance; this part of the program works now.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured