-
October 9th, 2015, 06:12 AM
#1
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;
}
-
October 9th, 2015, 09:04 AM
#2
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.
-
October 9th, 2015, 09:53 AM
#3
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.
-
October 9th, 2015, 09:58 AM
#4
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.
-
October 9th, 2015, 10:11 AM
#5
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;
}
-
October 9th, 2015, 10:25 AM
#6
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.
-
October 9th, 2015, 10:32 AM
#7
Re: Extracting RGB values from Bitmap Image
Could you advise as to how I can correct this? Thank you.
-
October 9th, 2015, 10:40 AM
#8
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;
};
-
October 9th, 2015, 01:53 PM
#9
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();
-
October 12th, 2015, 07:23 AM
#10
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|