123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * The Python Imaging Library
- *
- * A binary morphology add-on for the Python Imaging Library
- *
- * History:
- * 2014-06-04 Initial version.
- *
- * Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com>
- *
- * See the README file for information on usage and redistribution.
- */
- #include "Python.h"
- #include "Imaging.h"
- #include "py3.h"
- #define LUT_SIZE (1<<9)
- /* Apply a morphologic LUT to a binary image. Outputs a
- a new binary image.
- Expected parameters:
- 1. a LUT - a 512 byte size lookup table.
- 2. an input Imaging image id.
- 3. an output Imaging image id
- Returns number of changed pixels.
- */
- static PyObject*
- apply(PyObject *self, PyObject* args)
- {
- const char *lut;
- PyObject *py_lut;
- Py_ssize_t lut_len, i0, i1;
- Imaging imgin, imgout;
- int width, height;
- int row_idx, col_idx;
- UINT8 **inrows, **outrows;
- int num_changed_pixels = 0;
- if (!PyArg_ParseTuple(args, "Onn", &py_lut, &i0, &i1)) {
- PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
- return NULL;
- }
- if (!PyBytes_Check(py_lut)) {
- PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
- return NULL;
- }
- lut_len = PyBytes_Size(py_lut);
- if (lut_len < LUT_SIZE) {
- PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
- return NULL;
- }
- lut = PyBytes_AsString(py_lut);
- imgin = (Imaging) i0;
- imgout = (Imaging) i1;
- width = imgin->xsize;
- height = imgin->ysize;
- if (imgin->type != IMAGING_TYPE_UINT8 ||
- imgin->bands != 1) {
- PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
- return NULL;
- }
- if (imgout->type != IMAGING_TYPE_UINT8 ||
- imgout->bands != 1) {
- PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
- return NULL;
- }
- inrows = imgin->image8;
- outrows = imgout->image8;
- for (row_idx=0; row_idx < height; row_idx++) {
- UINT8 *outrow = outrows[row_idx];
- UINT8 *inrow = inrows[row_idx];
- UINT8 *prow, *nrow; /* Previous and next row */
- /* zero boundary conditions. TBD support other modes */
- outrow[0] = outrow[width-1] = 0;
- if (row_idx==0 || row_idx == height-1) {
- for(col_idx=0; col_idx<width; col_idx++)
- outrow[col_idx] = 0;
- continue;
- }
- prow = inrows[row_idx-1];
- nrow = inrows[row_idx+1];
- for (col_idx=1; col_idx<width-1; col_idx++) {
- int cim = col_idx-1;
- int cip = col_idx+1;
- unsigned char b0 = prow[cim] &1;
- unsigned char b1 = prow[col_idx]&1;
- unsigned char b2 = prow[cip]&1;
- unsigned char b3 = inrow[cim]&1;
- unsigned char b4 = inrow[col_idx]&1;
- unsigned char b5 = inrow[cip]&1;
- unsigned char b6 = nrow[cim]&1;
- unsigned char b7 = nrow[col_idx]&1;
- unsigned char b8 = nrow[cip]&1;
- int lut_idx = (b0
- |(b1 << 1)
- |(b2 << 2)
- |(b3 << 3)
- |(b4 << 4)
- |(b5 << 5)
- |(b6 << 6)
- |(b7 << 7)
- |(b8 << 8));
- outrow[col_idx] = 255*(lut[lut_idx]&1);
- num_changed_pixels += ((b4&1)!=(outrow[col_idx]&1));
- }
- }
- return Py_BuildValue("i",num_changed_pixels);
- }
- /* Match a morphologic LUT to a binary image and return a list
- of the coordinates of all matching pixels.
- Expected parameters:
- 1. a LUT - a 512 byte size lookup table.
- 2. an input Imaging image id.
- Returns list of matching pixels.
- */
- static PyObject*
- match(PyObject *self, PyObject* args)
- {
- const char *lut;
- PyObject *py_lut;
- Py_ssize_t lut_len, i0;
- Imaging imgin;
- int width, height;
- int row_idx, col_idx;
- UINT8 **inrows;
- PyObject *ret = PyList_New(0);
- if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) {
- PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
- return NULL;
- }
- if (!PyBytes_Check(py_lut)) {
- PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
- return NULL;
- }
- lut_len = PyBytes_Size(py_lut);
- if (lut_len < LUT_SIZE) {
- PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
- return NULL;
- }
- lut = PyBytes_AsString(py_lut);
- imgin = (Imaging) i0;
- if (imgin->type != IMAGING_TYPE_UINT8 ||
- imgin->bands != 1) {
- PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
- return NULL;
- }
- inrows = imgin->image8;
- width = imgin->xsize;
- height = imgin->ysize;
- for (row_idx=1; row_idx < height-1; row_idx++) {
- UINT8 *inrow = inrows[row_idx];
- UINT8 *prow, *nrow;
- prow = inrows[row_idx-1];
- nrow = inrows[row_idx+1];
- for (col_idx=1; col_idx<width-1; col_idx++) {
- int cim = col_idx-1;
- int cip = col_idx+1;
- unsigned char b0 = prow[cim] &1;
- unsigned char b1 = prow[col_idx]&1;
- unsigned char b2 = prow[cip]&1;
- unsigned char b3 = inrow[cim]&1;
- unsigned char b4 = inrow[col_idx]&1;
- unsigned char b5 = inrow[cip]&1;
- unsigned char b6 = nrow[cim]&1;
- unsigned char b7 = nrow[col_idx]&1;
- unsigned char b8 = nrow[cip]&1;
- int lut_idx = (b0
- |(b1 << 1)
- |(b2 << 2)
- |(b3 << 3)
- |(b4 << 4)
- |(b5 << 5)
- |(b6 << 6)
- |(b7 << 7)
- |(b8 << 8));
- if (lut[lut_idx]) {
- PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx);
- PyList_Append(ret, coordObj);
- }
- }
- }
- return ret;
- }
- /* Return a list of the coordinates of all turned on pixels in an image.
- May be used to extract features after a sequence of MorphOps were applied.
- This is faster than match as only 1x1 lookup is made.
- */
- static PyObject*
- get_on_pixels(PyObject *self, PyObject* args)
- {
- Py_ssize_t i0;
- Imaging img;
- UINT8 **rows;
- int row_idx, col_idx;
- int width, height;
- PyObject *ret = PyList_New(0);
- if (!PyArg_ParseTuple(args, "n", &i0)) {
- PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
- return NULL;
- }
- img = (Imaging) i0;
- rows = img->image8;
- width = img->xsize;
- height = img->ysize;
- for (row_idx=0; row_idx < height; row_idx++) {
- UINT8 *row = rows[row_idx];
- for (col_idx=0; col_idx<width; col_idx++) {
- if (row[col_idx]) {
- PyObject *coordObj = Py_BuildValue("(nn)",col_idx,row_idx);
- PyList_Append(ret, coordObj);
- }
- }
- }
- return ret;
- }
- static int
- setup_module(PyObject* m)
- {
- PyObject* d = PyModule_GetDict(m);
- PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1"));
- return 0;
- }
- static PyMethodDef functions[] = {
- /* Functions */
- {"apply", (PyCFunction)apply, METH_VARARGS, NULL},
- {"get_on_pixels", (PyCFunction)get_on_pixels, METH_VARARGS, NULL},
- {"match", (PyCFunction)match, METH_VARARGS, NULL},
- {NULL, NULL, 0, NULL}
- };
- #if PY_VERSION_HEX >= 0x03000000
- PyMODINIT_FUNC
- PyInit__imagingmorph(void) {
- PyObject* m;
- static PyModuleDef module_def = {
- PyModuleDef_HEAD_INIT,
- "_imagingmorph", /* m_name */
- "A module for doing image morphology", /* m_doc */
- -1, /* m_size */
- functions, /* m_methods */
- };
- m = PyModule_Create(&module_def);
- if (setup_module(m) < 0)
- return NULL;
- return m;
- }
- #else
- PyMODINIT_FUNC
- init_imagingmorph(void)
- {
- PyObject* m = Py_InitModule("_imagingmorph", functions);
- setup_module(m);
- }
- #endif
|