Mercurial > pygame
diff src/pixelarray_methods.c @ 992:1577bcf02ed5
Added threshold recognition using weighted euclideance distances to PixelArray.replace() and PixelArray.extract(). Fixed slice assignment issue.
| author | marcus |
|---|---|
| date | Sat, 05 Apr 2008 10:46:13 +0000 |
| parents | 684d96c73d0d |
| children | 78ab04b73064 |
line wrap: on
line diff
--- a/src/pixelarray_methods.c Fri Apr 04 10:40:09 2008 +0000 +++ b/src/pixelarray_methods.c Sat Apr 05 10:46:13 2008 +0000 @@ -18,6 +18,15 @@ */ +/* Simple weighted euclidian distance, which tries to get near to the + * human eye reception using the weights. + */ +#define COLOR_DIFF_RGB(r1,g1,b1,r2,g2,b2) \ + (sqrt (.299 * (r1 - r2) * (r1 - r2) + \ + .587 * (g1 - g2) * (g1 - g2) + \ + .114 * (b1 - b2) * (b1 - b2))) + + /** * Tries to retrieve a valid color for a Surface. */ @@ -304,13 +313,16 @@ } static PyObject* -_replace_color (PyPixelArray *array, PyObject *args) +_replace_color (PyPixelArray *array, PyObject *args, PyObject *kwds) { PyObject *delcolor = NULL; PyObject *replcolor = NULL; Uint32 dcolor; Uint32 rcolor; + Uint8 r1, g1, b1, r2, g2, b2, a2; SDL_Surface *surface; + float distance = 0; + char *type; Uint32 x = 0; Uint32 y = 0; @@ -320,9 +332,16 @@ Sint32 absystep; Uint8 *pixels; - if (!PyArg_ParseTuple (args, "OO", &delcolor, &replcolor)) + static char *keys[] = { "color", "repcolor", "distance", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwds, "OO|f", keys, &delcolor, + &replcolor, &distance)) return NULL; + if (distance < 0 || distance > 255) + return RAISE (PyExc_ValueError, + "distance must be in the range from 0.0 to 255.0"); + surface = PySurface_AsSurface (array->surface); if (!_get_color_from_object (delcolor, surface->format, &dcolor) || !_get_color_from_object (replcolor, surface->format, &rcolor)) @@ -334,6 +353,9 @@ absystep = ABS (array->ystep); y = array->ystart; + if (distance) + SDL_GetRGB (dcolor, surface->format, &r1, &g1, &b1); + switch (surface->format->BytesPerPixel) { case 1: @@ -346,7 +368,13 @@ while (posx < array->xlen) { pixel = ((Uint8 *) pixels + y * surface->pitch + x); - if (*pixel == dcolor) + if (distance) + { + GET_PIXELVALS_1 (r2, g2, b2, a2, pixel, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = (Uint8) rcolor; + } + else if (*pixel == dcolor) *pixel = (Uint8) rcolor; x += array->xstep; posx += absxstep; @@ -366,7 +394,14 @@ while (posx < array->xlen) { pixel = ((Uint16 *) (pixels + y * surface->pitch) + x); - if (*pixel == dcolor) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, (Uint32) *pixel, + surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = (Uint16) rcolor; + } + else if (*pixel == dcolor) *pixel = (Uint16) rcolor; x += array->xstep; posx += absxstep; @@ -390,7 +425,17 @@ px = (Uint8 *) (pixels + y * surface->pitch) + x * 3; #if SDL_BYTEORDER == SDL_LIL_ENDIAN pxcolor = (px[0]) + (px[1] << 8) + (px[2] << 16); - if (pxcolor == dcolor) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, pxcolor, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + { + *(px + (format->Rshift >> 3)) = (Uint8) (rcolor >> 16); + *(px + (format->Gshift >> 3)) = (Uint8) (rcolor >> 8); + *(px + (format->Bshift >> 3)) = (Uint8) rcolor; + } + } + else if (pxcolor == dcolor) { *(px + (format->Rshift >> 3)) = (Uint8) (rcolor >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (rcolor >> 8); @@ -398,7 +443,19 @@ } #else pxcolor = (px[2]) + (px[1] << 8) + (px[0] << 16); - if (pxcolor == dcolor) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, pxcolor, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + { + *(px + 2 - (format->Rshift >> 3)) = + (Uint8) (rcolor >> 16); + *(px + 2 - (format->Gshift >> 3)) = + (Uint8) (rcolor >> 8); + *(px + 2 - (format->Bshift >> 3)) = (Uint8) rcolor; + } + } + else if (pxcolor == dcolor) { *(px + 2 - (format->Rshift >> 3)) = (Uint8) (rcolor >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (rcolor >> 8); @@ -423,7 +480,13 @@ while (posx < array->xlen) { pixel = ((Uint32 *) (pixels + y * surface->pitch) + x); - if (*pixel == dcolor) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, *pixel, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = rcolor; + } + else if (*pixel == dcolor) *pixel = rcolor; x += array->xstep; posx += absxstep; @@ -437,9 +500,8 @@ Py_RETURN_NONE; } - static PyObject* -_extract_color (PyPixelArray *array, PyObject *args) +_extract_color (PyPixelArray *array, PyObject *args, PyObject *kwds) { PyObject *sf = NULL; PyObject *excolor = NULL; @@ -448,6 +510,8 @@ Uint32 white; Uint32 black; SDL_Surface *surface; + float distance = 0; + Uint8 r1, g1, b1, r2, g2, b2, a2; Uint32 x = 0; Uint32 y = 0; @@ -457,9 +521,16 @@ Sint32 absystep; Uint8 *pixels; - if (!PyArg_ParseTuple (args, "O", &excolor)) + static char *keys[] = { "color", "distance", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwds, "O|f", keys, &excolor, + &distance)) return NULL; + if (distance < 0 || distance > 255) + return RAISE (PyExc_ValueError, + "distance must be in the range from 0.0 to 255.0"); + surface = PySurface_AsSurface (array->surface); if (!_get_color_from_object (excolor, surface->format, &color)) return NULL; @@ -475,6 +546,8 @@ black = SDL_MapRGBA (surface->format, 0, 0, 0, 255); white = SDL_MapRGBA (surface->format, 255, 255, 255, 255); + if (distance) + SDL_GetRGB (color, surface->format, &r1, &g1, &b1); pixels = surface->pixels; absxstep = ABS (newarray->xstep); @@ -493,7 +566,16 @@ while (posx < newarray->xlen) { pixel = ((Uint8 *) pixels + y * surface->pitch + x); - *pixel = (*pixel == color) ? (Uint8) white : (Uint8) black; + if (distance) + { + GET_PIXELVALS_1 (r2, g2, b2, a2, pixel, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = (Uint8) white; + else + *pixel = (Uint8) black; + } + else + *pixel = (*pixel == color) ? (Uint8) white : (Uint8) black; x += newarray->xstep; posx += absxstep; } @@ -512,7 +594,18 @@ while (posx < newarray->xlen) { pixel = ((Uint16 *) (pixels + y * surface->pitch) + x); - *pixel = (*pixel == color) ? (Uint16) white : (Uint16) black; + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, (Uint32) *pixel, + surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = (Uint16) white; + else + *pixel = (Uint16) black; + } + else + *pixel = (*pixel == color) ? (Uint16) white : + (Uint16) black; x += newarray->xstep; posx += absxstep; } @@ -535,7 +628,23 @@ px = (Uint8 *) (pixels + y * surface->pitch) + x * 3; #if SDL_BYTEORDER == SDL_LIL_ENDIAN pxcolor = (px[0]) + (px[1] << 8) + (px[2] << 16); - if (pxcolor == color) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, pxcolor, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + { + *(px + (format->Rshift >> 3)) = (Uint8) (white >> 16); + *(px + (format->Gshift >> 3)) = (Uint8) (white >> 8); + *(px + (format->Bshift >> 3)) = (Uint8) white; + } + else + { + *(px + (format->Rshift >> 3)) = (Uint8) (black >> 16); + *(px + (format->Gshift >> 3)) = (Uint8) (black >> 8); + *(px + (format->Bshift >> 3)) = (Uint8) black; + } + } + else if (pxcolor == color) { *(px + (format->Rshift >> 3)) = (Uint8) (white >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (white >> 8); @@ -549,7 +658,28 @@ } #else pxcolor = (px[2]) + (px[1] << 8) + (px[0] << 16); - if (pxcolor == dcolor) + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, pxcolor, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= + distance) + { + *(px + 2 - (format->Rshift >> 3)) = + (Uint8) (white >> 16); + *(px + 2 - (format->Gshift >> 3)) = + (Uint8) (white >> 8); + *(px + 2 - (format->Bshift >> 3)) = (Uint8) white; + } + else + { + *(px + 2 - (format->Rshift >> 3)) = + (Uint8) (black >> 16); + *(px + 2 - (format->Gshift >> 3)) = + (Uint8) (black >> 8); + *(px + 2 - (format->Bshift >> 3)) = (Uint8) black; + } + } + else if (pxcolor == dcolor) { *(px + 2 - (format->Rshift >> 3)) = (Uint8) (white >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (white >> 8); @@ -580,7 +710,16 @@ while (posx < newarray->xlen) { pixel = ((Uint32 *) (pixels + y * surface->pitch) + x); - *pixel = (*pixel == color) ? white : black; + if (distance) + { + GET_PIXELVALS (r2, g2, b2, a2, *pixel, surface->format); + if (COLOR_DIFF_RGB (r1, g1, b1, r2, g2, b2) <= distance) + *pixel = white; + else + *pixel = black; + } + else + *pixel = (*pixel == color) ? white : black; x += newarray->xstep; posx += absxstep; }
