PDA

View Full Version : extracting RGB value of pixel



abhibhav
February 26, 2004, 20:18:52
Respected Sir,

I am a final year under graduate student new to the field of image processing. We are making a project that basically deals with following a particular path by recognising color.

I am using a Logitech web camera to input images in real time & process them to find out the color they contain. A software called Template for Real Time Image PrOcessing Development (TRIPOD), developed by Prof. Paul Y. Oh, helps us to input the images in real time.

I have a problem with extracting the RGB values of a pixel in real time. Infact I am clueless on the topic. I tried going through some of the same problem in the threads available on this site but could not understand much.

Hence I would be very garteful if you could help me out of this soup by providing me with some algorithm on which I can work. I am familiar with the C language and also have a good knowledge of the C++ knowledge also.

Thanking You,
Abhibhav.

Stefan Geissler
February 27, 2004, 12:05:57
Hello Abhibhav ,

I do not know Real Time Image Processing Development (TRIPOD), developed by Prof. Paul Y. Oh, therefore i do not know, how the image data is presented to your program.
May be you can find some help about this here:
http://groups.google.de/groups?hl=de&lr=&ie=UTF-8&group=sci.image.processing

abhibhav
February 29, 2004, 02:48:12
Respected Sir,

The software TRIPOD uses a Visual C++ environment and has been designed basically for users who do not have much knowledge about the MFC and API. All that the software does is to grab a frame and establish a pointer to it. You can then enter the code of your program for pixel processing which can also be in ANSI C.

TRIPOD haS been created only to run with the Logitech webcam and is uses the SDK provided with the same.

Also as our guide suggests that all devices operate on images using the RGB format.
So it would be of great help even if you gave us some idea on how, in general, do you extract the RGB contents from the pixel data.

Thanking You,

Abhibhav Sinha.

Stefan Geissler
March 1, 2004, 08:32:42
Dear Sir,

If you have established a pointer to the image data, as you wrote in your post, then you can access the components of each pixel. The components depend on the color format of you image data. (I do not know the color format you are using, because i do not know the software you use.) If you have an RGB24 color format, each pixel uses 3 bytes. First first byte contains the blue, the second the green and the third byte the red color component. If the image data is returned as pointer, the poitner should be declared as follows:


unsigned char *pImageData;
pImageData = This_Is_The_Unkown_Function_Of_Your_SDK_That_Retur ns_The_Pointer();

If you know the width, height and color format of your image, you can access each pixel as follows (for RGB24):


int x; /* Column */
int y; /* Row */
int index;

index = y*ImageWidth* 3 + x;

printf(“Blue color component at %d/%d is %d\n”,x,y, pImageData[index]);


I hope, this simple C codes helps. As i mentioned above, i do not know, what your SDK is doing, so i can not provide any support for it. May be you ask the author of your SDK for help?

Toan
March 7, 2007, 16:53:02
How can I get the pixel value of a RGB8 format image? After this operation:
BYTE* pbImgData = pActiveBuf->getPtr();

For Example, I need the value of the pixel with the coordonate: 200X100


Second question: when I open the device setup menu by doing this:


if( !setupDeviceFromFile( gr ) )
{
return -1;
}

I need RGB8 (576X576):

-I'd like to setup video size by myself
How can I do that?

Stefan Geissler
March 8, 2007, 09:10:25
Hello Toan,

If you got the image pointer in the BYTE* pbImgData, then you have a one dimensional array of bytes. Each byte represents one pixel. If you want to access the pixel on the coordinate 200/100 (row 200, column 100), then you must transform it to the one dimensional array of bytes. You need the length of a line in your image. To make it a little bit more sportive, lets say you image is PAL-B with 768*576 pixel, that means the length of a line is 768 bytes. Thus the formula is as follows:
int index = 200*768 + 100;
The pixel value is
int value = (int)pbImgData[index];

To your second question: You may use the ROI framefilter:
http://www.imagingcontrol.com/support/documentation/class/stdfilterROI.htm

Pleas leave the second parameter of FilterLoader::createFilter() empty:

smart_com pFilter = FilterLoader::createFilter( "ROI", "");

This differs a little from the documentation.

Toan
March 8, 2007, 11:03:25
If I want to draw a square with as center the coordonate x,y. I must put something like that?:

for (int j=x-2;j<=x+2;j++)
{
for(int i=y-2;i<=y+2;i++)
{
pbImgData[i*dim.cx + j]=255;
}
}

Stefan Geissler
March 8, 2007, 11:07:39
Yes,

I guess, this would work. Just try it.

Toan
March 8, 2007, 11:42:08
For the second question I did this but it doesn't build!

Grabber gr;

// Disable overlay. If it was in the graph, we could not get UYVY images.
gr.setOverlayBitmapPathPosition( ePP_NONE );

if( !setupDeviceFromFile( gr ) )
{
return -1;
}

smart_com m_pROIFilter = FilterLoader::createFilter( "ROI" );

// Set filter parameters.
tFrameFilterList filterList;

// Use .get to extract a plain pointer from the smart pointer.
filterList.push_back( m_pROIFilter.get() );

gr.setDisplayFrameFilters( filterList );

Toan
March 8, 2007, 12:08:10
One more question:

I'm doing a medical project at university. I need to detect as fast as possible changing image each time the surgeon takes radio picture.
I'm using snapImage, and I'm testint a region in which color change from gray to black each time the picture change.

Is there a better way to do that? Is it the fastest solution?


My problems:
I need to adapt the working image size to the signal size, that's why I ask you yesterday for the resize of the picture.
I'm afraid about the precision.



My code is like this:


int pix = 0,index;
// get pointer to the image data
// Calculate the index of the upper left pixel
// Images are stored upside down in the image buffer
Sleep( 250 ); // give the device time to adjust automatic settings i.e. auto exposure
pHandlerSink->snapImages( 1, 2000 );
pActiveBuf=pHandlerSink->getLastAcqMemBuffer();
BYTE* pbImgData = pActiveBuf->getPtr();
SIZE dim = pActiveBuf->getFrameType().dim;
pix=pbImgData[ y*dim.cx + x ];

bool test=true,change=false,cont_test=true;
while(test==true)
{
pHandlerSink->snapImages( 1, 2000 );
pActiveBuf=pHandlerSink->getLastAcqMemBuffer();
pbImgData = pActiveBuf->getPtr();
for (int i=y-2; i<=y+2 && cont_test==true;i++)
{
for(int j=x-2;j<=x+2 && cont_test==true;j++)
{
if (pbImgData [i*dim.cx + j < 10])
{
change=true;
}
else
{
change=false;
cont_test=false;
}
}
}

while (change==true)
{
std::cout << "Detect changing" << std::endl;
printf("Press any key to continue.");
getch();
pActiveBuf->save( "RGB8.bmp" );
}
change=false;
cont_test=true;
}

Stefan Geissler
March 8, 2007, 13:34:57
Hi Toan,

Thank you for the code. I guess, it does not terminate:

while (change==true)
{
std::cout << "Detect changing" << std::endl;
printf("Press any key to continue.");
getch();
pActiveBuf->save( "RGB8.bmp" );
}
Its a "concrete" loop, because change keeps staying true. I guess you want to wrtie something like:

if(change==true)
{
std::cout << "Detect changing" << std::endl;
printf("Press any key to continue.");
getch();
pActiveBuf->save( "RGB8.bmp" );
}

Let us summarize your task:
- snapImage
- compare it to the previous snapped image
- Do something if the image has change in comparison to the previous image.

Thus you need to save the previous image somewhere. I guess, the radio picture machine provides images the whole time like a camera, thus you get often the same image until the surgeon "clicks" to capture a new image. Thus, you need to capture each image. Sounds for a "CGrabberListener" job. I suggest to have a look into the "callback" sample. The frameReady() method will be called automatically for each incoming image.
I have created a sample for download that you can use. It is created with VC++ 2003 and also be used with VC++ 2005. The image processing is fast, but not optimized. I suggest to play around with the "m_Threshold" member and try different values. I hope this sample gives you an idea how get your problem solved.

The main trick is to keep the image buffer of the last changed image. This will be compared with the new incoming images. If there is a realy new image, then the new imagebuffer will be saved (in fact only the pointer to this will be saved):

//////////////////////////////////////////////////////////////////////////
// The image processing is done here.
//////////////////////////////////////////////////////////////////////////

void CListener::DoImageProcessing( smart_ptr<MemBuffer> pBuffer)
{
bool bChange = false;
// Get the bitmap info header from the membuffer. It contains the bits per pixel,
// width and height.
smart_ptr<BITMAPINFOHEADER> pInf = pBuffer->getBitmapInfoHeader();


BYTE* pNewImageData = pBuffer->getPtr();
BYTE* pOldImageData = m_pOldBuffer->getPtr();

// Calculate the size of the image.
int iImageSize = pInf->biWidth * pInf->biHeight * pInf->biBitCount / 8 ;

// Now loop through the data and change every byte, until end or a change was detected.
for( int i = 0; i < iImageSize && !bChange; i++)
{
if( abs( (int)(pNewImageData[i]) - (int)pOldImageData[i] ) > m_Threshold)
{
bChange = true;
}
}

if( bChange )
{
// Unlock the oldbuffer, so it can be used again.
m_pOldBuffer->unlock();
// Now "save" the new image to the old image. Keep in mind that the buffer is locked.
m_pOldBuffer = pBuffer;

// Draw the changed image on the screen.
DrawBuffer(m_pOldBuffer);
}
else
{
pBuffer->unlock();
}
}



Unzip the sample into your "samples\VC71" directory of your IC Imaging Control installation path. You may have to change the library pathes in the linker section.