File: | _imagingmorph.c |
Warning: | line 231, column 38 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * The Python Imaging Library | |||
3 | * | |||
4 | * A binary morphology add-on for the Python Imaging Library | |||
5 | * | |||
6 | * History: | |||
7 | * 2014-06-04 Initial version. | |||
8 | * | |||
9 | * Copyright (c) 2014 Dov Grobgeld <dov.grobgeld@gmail.com> | |||
10 | * | |||
11 | * See the README file for information on usage and redistribution. | |||
12 | */ | |||
13 | ||||
14 | #include "Python.h" | |||
15 | #include "libImaging/Imaging.h" | |||
16 | ||||
17 | #define LUT_SIZE(1 << 9) (1 << 9) | |||
18 | ||||
19 | /* Apply a morphologic LUT to a binary image. Outputs a | |||
20 | a new binary image. | |||
21 | ||||
22 | Expected parameters: | |||
23 | ||||
24 | 1. a LUT - a 512 byte size lookup table. | |||
25 | 2. an input Imaging image id. | |||
26 | 3. an output Imaging image id | |||
27 | ||||
28 | Returns number of changed pixels. | |||
29 | */ | |||
30 | static PyObject * | |||
31 | apply(PyObject *self, PyObject *args) { | |||
32 | const char *lut; | |||
33 | PyObject *py_lut; | |||
34 | Py_ssize_t lut_len, i0, i1; | |||
35 | Imaging imgin, imgout; | |||
36 | int width, height; | |||
37 | int row_idx, col_idx; | |||
38 | UINT8unsigned char **inrows, **outrows; | |||
39 | int num_changed_pixels = 0; | |||
40 | ||||
41 | if (!PyArg_ParseTuple(args, "Onn", &py_lut, &i0, &i1)) { | |||
42 | PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | |||
43 | return NULL((void*)0); | |||
44 | } | |||
45 | ||||
46 | if (!PyBytes_Check(py_lut)((((((PyObject*)(py_lut))->ob_type))->tp_flags & (( 1UL << 27))) != 0)) { | |||
47 | PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object"); | |||
48 | return NULL((void*)0); | |||
49 | } | |||
50 | ||||
51 | lut_len = PyBytes_Size(py_lut); | |||
52 | ||||
53 | if (lut_len < LUT_SIZE(1 << 9)) { | |||
54 | PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size"); | |||
55 | return NULL((void*)0); | |||
56 | } | |||
57 | ||||
58 | lut = PyBytes_AsString(py_lut); | |||
59 | ||||
60 | imgin = (Imaging)i0; | |||
61 | imgout = (Imaging)i1; | |||
62 | width = imgin->xsize; | |||
63 | height = imgin->ysize; | |||
64 | ||||
65 | if (imgin->type != IMAGING_TYPE_UINT80 || imgin->bands != 1) { | |||
66 | PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | |||
67 | return NULL((void*)0); | |||
68 | } | |||
69 | if (imgout->type != IMAGING_TYPE_UINT80 || imgout->bands != 1) { | |||
70 | PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | |||
71 | return NULL((void*)0); | |||
72 | } | |||
73 | ||||
74 | inrows = imgin->image8; | |||
75 | outrows = imgout->image8; | |||
76 | ||||
77 | for (row_idx = 0; row_idx < height; row_idx++) { | |||
78 | UINT8unsigned char *outrow = outrows[row_idx]; | |||
79 | UINT8unsigned char *inrow = inrows[row_idx]; | |||
80 | UINT8unsigned char *prow, *nrow; /* Previous and next row */ | |||
81 | ||||
82 | /* zero boundary conditions. TBD support other modes */ | |||
83 | outrow[0] = outrow[width - 1] = 0; | |||
84 | if (row_idx == 0 || row_idx == height - 1) { | |||
85 | for (col_idx = 0; col_idx < width; col_idx++) { | |||
86 | outrow[col_idx] = 0; | |||
87 | } | |||
88 | continue; | |||
89 | } | |||
90 | ||||
91 | prow = inrows[row_idx - 1]; | |||
92 | nrow = inrows[row_idx + 1]; | |||
93 | ||||
94 | for (col_idx = 1; col_idx < width - 1; col_idx++) { | |||
95 | int cim = col_idx - 1; | |||
96 | int cip = col_idx + 1; | |||
97 | unsigned char b0 = prow[cim] & 1; | |||
98 | unsigned char b1 = prow[col_idx] & 1; | |||
99 | unsigned char b2 = prow[cip] & 1; | |||
100 | ||||
101 | unsigned char b3 = inrow[cim] & 1; | |||
102 | unsigned char b4 = inrow[col_idx] & 1; | |||
103 | unsigned char b5 = inrow[cip] & 1; | |||
104 | ||||
105 | unsigned char b6 = nrow[cim] & 1; | |||
106 | unsigned char b7 = nrow[col_idx] & 1; | |||
107 | unsigned char b8 = nrow[cip] & 1; | |||
108 | ||||
109 | int lut_idx = | |||
110 | (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) | (b5 << 5) | | |||
111 | (b6 << 6) | (b7 << 7) | (b8 << 8)); | |||
112 | outrow[col_idx] = 255 * (lut[lut_idx] & 1); | |||
113 | num_changed_pixels += ((b4 & 1) != (outrow[col_idx] & 1)); | |||
114 | } | |||
115 | } | |||
116 | return Py_BuildValue("i", num_changed_pixels); | |||
117 | } | |||
118 | ||||
119 | /* Match a morphologic LUT to a binary image and return a list | |||
120 | of the coordinates of all matching pixels. | |||
121 | ||||
122 | Expected parameters: | |||
123 | ||||
124 | 1. a LUT - a 512 byte size lookup table. | |||
125 | 2. an input Imaging image id. | |||
126 | ||||
127 | Returns list of matching pixels. | |||
128 | */ | |||
129 | static PyObject * | |||
130 | match(PyObject *self, PyObject *args) { | |||
131 | const char *lut; | |||
132 | PyObject *py_lut; | |||
133 | Py_ssize_t lut_len, i0; | |||
134 | Imaging imgin; | |||
135 | int width, height; | |||
136 | int row_idx, col_idx; | |||
137 | UINT8unsigned char **inrows; | |||
138 | PyObject *ret = PyList_New(0); | |||
139 | ||||
140 | if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) { | |||
141 | PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | |||
142 | return NULL((void*)0); | |||
143 | } | |||
144 | ||||
145 | if (!PyBytes_Check(py_lut)((((((PyObject*)(py_lut))->ob_type))->tp_flags & (( 1UL << 27))) != 0)) { | |||
146 | PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object"); | |||
147 | return NULL((void*)0); | |||
148 | } | |||
149 | ||||
150 | lut_len = PyBytes_Size(py_lut); | |||
151 | ||||
152 | if (lut_len < LUT_SIZE(1 << 9)) { | |||
153 | PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size"); | |||
154 | return NULL((void*)0); | |||
155 | } | |||
156 | ||||
157 | lut = PyBytes_AsString(py_lut); | |||
158 | imgin = (Imaging)i0; | |||
159 | ||||
160 | if (imgin->type != IMAGING_TYPE_UINT80 || imgin->bands != 1) { | |||
161 | PyErr_SetString(PyExc_RuntimeError, "Unsupported image type"); | |||
162 | return NULL((void*)0); | |||
163 | } | |||
164 | ||||
165 | inrows = imgin->image8; | |||
166 | width = imgin->xsize; | |||
167 | height = imgin->ysize; | |||
168 | ||||
169 | for (row_idx = 1; row_idx < height - 1; row_idx++) { | |||
170 | UINT8unsigned char *inrow = inrows[row_idx]; | |||
171 | UINT8unsigned char *prow, *nrow; | |||
172 | ||||
173 | prow = inrows[row_idx - 1]; | |||
174 | nrow = inrows[row_idx + 1]; | |||
175 | ||||
176 | for (col_idx = 1; col_idx < width - 1; col_idx++) { | |||
177 | int cim = col_idx - 1; | |||
178 | int cip = col_idx + 1; | |||
179 | unsigned char b0 = prow[cim] & 1; | |||
180 | unsigned char b1 = prow[col_idx] & 1; | |||
181 | unsigned char b2 = prow[cip] & 1; | |||
182 | ||||
183 | unsigned char b3 = inrow[cim] & 1; | |||
184 | unsigned char b4 = inrow[col_idx] & 1; | |||
185 | unsigned char b5 = inrow[cip] & 1; | |||
186 | ||||
187 | unsigned char b6 = nrow[cim] & 1; | |||
188 | unsigned char b7 = nrow[col_idx] & 1; | |||
189 | unsigned char b8 = nrow[cip] & 1; | |||
190 | ||||
191 | int lut_idx = | |||
192 | (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) | (b5 << 5) | | |||
193 | (b6 << 6) | (b7 << 7) | (b8 << 8)); | |||
194 | if (lut[lut_idx]) { | |||
195 | PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx); | |||
196 | PyList_Append(ret, coordObj); | |||
197 | } | |||
198 | } | |||
199 | } | |||
200 | ||||
201 | return ret; | |||
202 | } | |||
203 | ||||
204 | /* Return a list of the coordinates of all turned on pixels in an image. | |||
205 | May be used to extract features after a sequence of MorphOps were applied. | |||
206 | This is faster than match as only 1x1 lookup is made. | |||
207 | */ | |||
208 | static PyObject * | |||
209 | get_on_pixels(PyObject *self, PyObject *args) { | |||
210 | Py_ssize_t i0; | |||
211 | Imaging img; | |||
212 | UINT8unsigned char **rows; | |||
213 | int row_idx, col_idx; | |||
214 | int width, height; | |||
215 | PyObject *ret = PyList_New(0); | |||
216 | ||||
217 | if (!PyArg_ParseTuple(args, "n", &i0)) { | |||
| ||||
218 | PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem"); | |||
219 | ||||
220 | return NULL((void*)0); | |||
221 | } | |||
222 | img = (Imaging)i0; | |||
223 | rows = img->image8; | |||
224 | width = img->xsize; | |||
225 | height = img->ysize; | |||
226 | ||||
227 | for (row_idx = 0; row_idx < height; row_idx++) { | |||
228 | UINT8unsigned char *row = rows[row_idx]; | |||
229 | for (col_idx = 0; col_idx < width; col_idx++) { | |||
230 | if (row[col_idx]) { | |||
231 | PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx); | |||
| ||||
232 | PyList_Append(ret, coordObj); | |||
233 | } | |||
234 | } | |||
235 | } | |||
236 | return ret; | |||
237 | } | |||
238 | ||||
239 | static int | |||
240 | setup_module(PyObject *m) { | |||
241 | PyObject *d = PyModule_GetDict(m); | |||
242 | ||||
243 | PyDict_SetItemString(d, "__version", PyUnicode_FromString("0.1")); | |||
244 | ||||
245 | return 0; | |||
246 | } | |||
247 | ||||
248 | static PyMethodDef functions[] = { | |||
249 | /* Functions */ | |||
250 | {"apply", (PyCFunction)apply, METH_VARARGS0x0001, NULL((void*)0)}, | |||
251 | {"get_on_pixels", (PyCFunction)get_on_pixels, METH_VARARGS0x0001, NULL((void*)0)}, | |||
252 | {"match", (PyCFunction)match, METH_VARARGS0x0001, NULL((void*)0)}, | |||
253 | {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)}}; | |||
254 | ||||
255 | PyMODINIT_FUNCPyObject* | |||
256 | PyInit__imagingmorph(void) { | |||
257 | PyObject *m; | |||
258 | ||||
259 | static PyModuleDef module_def = { | |||
260 | PyModuleDef_HEAD_INIT{ { 1, ((void*)0) }, ((void*)0), 0, ((void*)0), }, | |||
261 | "_imagingmorph", /* m_name */ | |||
262 | "A module for doing image morphology", /* m_doc */ | |||
263 | -1, /* m_size */ | |||
264 | functions, /* m_methods */ | |||
265 | }; | |||
266 | ||||
267 | m = PyModule_Create(&module_def)PyModule_Create2(&module_def, 1013); | |||
268 | ||||
269 | if (setup_module(m) < 0) { | |||
270 | return NULL((void*)0); | |||
271 | } | |||
272 | ||||
273 | return m; | |||
274 | } |
1 | #ifndef Py_BuildValue |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* Py_BuildValue(const char *format, ...) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API Py_BuildValue is defined as a macro." |
10 | #endif |