mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-13 05:06:49 +03:00
f79379ed7c
The file `libImaging/Imaging.h` gets installed flat on Ubuntus into the public Python includes. When building a newer version of Pillow from source and hinting the Python includes "too early" in includes, e.g. in package managers, this can confuse the two files and pick up the external file over the internal one. With different versions, this mismatch can lead to build errors, e.g. undefined macros. The most robust way to avoid this is to pre-fix the internal include accordingly, so that the relative path to the including file has to match as well.
296 lines
7.8 KiB
C
296 lines
7.8 KiB
C
/*
|
|
* 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 "libImaging/Imaging.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}
|
|
};
|
|
|
|
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;
|
|
}
|