Sign in to follow this  
tadobie

pixel color detection

Recommended Posts

Can anyone tell me, or direct me to an article that can explain how to detect a particular color in a direct draw surface. I want to do some collision detection based on color.

Share this post


Link to post
Share on other sites
Lock the surface, then with the array it gives you, find the pixel you want.



//Declare and Zero the struct
DDSURFACEDESC2 sd = { sizeof ( sd ) };

//if you set this rect, then you
//only lock the area inside it
LPRECT rct = NULL;

lpsrf->Lock(rct, &sd, DDLOCK_WAIT | DDLOCK_READONLY, NULL);

//pitch is the number of bytes in each row
DWORD pitch = sd.lPitch;
LPDWORD pixels = (LPDWORD)(sd.lpSurface);

int x = 25, int y = 25;

//since it only gives you a 1 dimensional array
//you need to specify the pixel in an odd manner.
//Of course, there are much more efficient ways of
//accessing these values, such as a lookup table,
//but this is the math you need. bpp is bits per pixel
DWORD color = pixels[x * (bpp/8) + (y*pitch)];

//you must remember to unlock the surface before continuing
lpsrf->Unlock(rct);






You dont want to lock your surface too many times in one frame, however, because its slow.

You would have to loop through your entire surface to detect a particular color and where it lies.

Share this post


Link to post
Share on other sites
I've been looking for the same info.

What I basically want to do is to check for a single point (the "attack point" in a fist, for example), and test for that being inside the RECT of another surface (actually, the ideal thing to do is to test if it's in contact with the surface minus the transparent colour). How would I adapt this part to test for that kind of collision?


int x = 25, int y = 25;

//since it only gives you a 1 dimensional array
//you need to specify the pixel in an odd manner.
//Of course, there are much more efficient ways of
//accessing these values, such as a lookup table,
//but this is the math you need. bpp is bits per pixel
DWORD color = pixels[x * (bpp/8) + (y*pitch)];



I also have trouble seeing what those x and y values are used for, and how they are set... Are they widths and heights, or what?

Share this post


Link to post
Share on other sites
I'm also a little confused by this section:


int x = 25, int y = 25;
DWORD color = pixels[x * (bpp/8) + (y*pitch)];



Firstly are the int's just arbitary values or are they specific to the mathematical solution?

Could you please explain this part a little further?
I'm not sure if the index in the pixels array points to an entire pixel meaning you traverse through the array one index (ie. one pixel) at a time to see the colour of each pixel.
If so could I simply do something like this to test if the RECT in question contains a particular pixel colour?

DWORD colour = pixels[0];
i = 0;

while(colour != NULL)
{
colour = pixels[i];
if(colour == MY_COLOUR)
{
Surface->Unlock(rct);
return true;
}

i++;
}


Share this post


Link to post
Share on other sites
You shouldn't do that. There might be padding that just happened to contain your colour. Plus, testing color against NULL is bad. NULL (aka, 0) is almost always black. If there's no black in the image, it will crash because it will keep reading into no man's land.

Share this post


Link to post
Share on other sites
I have adjusted my code to avoid the "NULL" indicator and now have this:


LPDWORD pixels = (LPDWORD)(sd.lpSurface);
DWORD colour = pixels[0];

for(int i=0;i<sizeof(pixels);i++)
{
colour = pixels[i];
if(colour == COL_COLLISION)
{
Attacker->UnlockSurface(rct);
return true;
}
}



IT CRASHES and BURNS!
I'm obviously screwing up somewhere.
I'm still not sure if the index in the pixels array points to an entire pixel meaning you traverse through the array one index (ie. one pixel) at a time to see the colour of each pixel.
I'm also not sure if the "sizeof" function is the right way to go.

Can anyone help on this?

Share this post


Link to post
Share on other sites
Yes, the values for x and y are arbitrary. Sorry I didn't mention that.

as for the confusion around the issue of:

DWORD color = pixels[x * (bpp/8) + (y*pitch)];

if your image is laid out like this:

|0 |1 |2 |3 |4 |
|5 |6 |7 |8 |9 |
|10|11|12|13|14|

(where each space is a pixel)

in this 1D array, it is actually stored like this:

|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|

so to get the value at (2, 2), (using coordinates), we would have to multiply the y value by the width and add the x value.

thus (x + w*y), which is 2 + 2*5 = 12 (lies at space (2, 2))

this works in 8 bit mode fine, but when in other modes, you need to multiply x by bpp/8 because bpp/8 = the number of bytes per pixel. It just means that you only want to index every (bpp/8)'th byte.

Share this post


Link to post
Share on other sites
Try doing a loop like this:
(completely ignores my last post's explanation)

This way actually accesses each scanline's x value, then
at the end it increments the scanline to the next one.



LPWORD ptr = (LPDWORD)(sd.lpSurface);
DWORD color;
register int x=0;
register int y=0;
bool collision=false;

do
{
do
{
color = ptr[x];
if (color == COL_COLLISION)
{
collision = true;
break;
}
x++;
} while (x < width);

//heres where we move to the next scanline
ptr += pitch;

x = 0;
y++;
} while (y < height);

srf->unlock()

return collision;




This way is like 10000 times better that the other way.

[Edited by - squicklid on October 18, 2004 2:14:03 AM]

Share this post


Link to post
Share on other sites
COOL,
A couple of questions:
1)What type should MY_COLOR be and how should it be used to represent a particular color eg. RGB(1, 1, 1)

2) I am only locking a RECT within a surface and only want to test within that. How is pitch effected ie. does the pitch that is returned represent the pitch of the whole surface or just the locked portion?

3) Would width and height be rect.right and rect.bottom in the case of testing a part of the surface

Thanks for the help on this so far SQUICKLID and friends :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this