Pillow

Форк
0
/
_imagingmorph.c 
278 строк · 7.8 Кб
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)
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
    UINT8 **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;
44
    }
45

46
    if (!PyBytes_Check(py_lut)) {
47
        PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
48
        return NULL;
49
    }
50

51
    lut_len = PyBytes_Size(py_lut);
52

53
    if (lut_len < LUT_SIZE) {
54
        PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
55
        return NULL;
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_UINT8 || imgin->bands != 1) {
66
        PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
67
        return NULL;
68
    }
69
    if (imgout->type != IMAGING_TYPE_UINT8 || imgout->bands != 1) {
70
        PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
71
        return NULL;
72
    }
73

74
    inrows = imgin->image8;
75
    outrows = imgout->image8;
76

77
    for (row_idx = 0; row_idx < height; row_idx++) {
78
        UINT8 *outrow = outrows[row_idx];
79
        UINT8 *inrow = inrows[row_idx];
80
        UINT8 *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
    UINT8 **inrows;
138
    PyObject *ret = PyList_New(0);
139
    if (ret == NULL) {
140
        return NULL;
141
    }
142

143
    if (!PyArg_ParseTuple(args, "On", &py_lut, &i0)) {
144
        Py_DECREF(ret);
145
        PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
146
        return NULL;
147
    }
148

149
    if (!PyBytes_Check(py_lut)) {
150
        Py_DECREF(ret);
151
        PyErr_SetString(PyExc_RuntimeError, "The morphology LUT is not a bytes object");
152
        return NULL;
153
    }
154

155
    lut_len = PyBytes_Size(py_lut);
156

157
    if (lut_len < LUT_SIZE) {
158
        Py_DECREF(ret);
159
        PyErr_SetString(PyExc_RuntimeError, "The morphology LUT has the wrong size");
160
        return NULL;
161
    }
162

163
    lut = PyBytes_AsString(py_lut);
164
    imgin = (Imaging)i0;
165

166
    if (imgin->type != IMAGING_TYPE_UINT8 || imgin->bands != 1) {
167
        Py_DECREF(ret);
168
        PyErr_SetString(PyExc_RuntimeError, "Unsupported image type");
169
        return NULL;
170
    }
171

172
    inrows = imgin->image8;
173
    width = imgin->xsize;
174
    height = imgin->ysize;
175

176
    for (row_idx = 1; row_idx < height - 1; row_idx++) {
177
        UINT8 *inrow = inrows[row_idx];
178
        UINT8 *prow, *nrow;
179

180
        prow = inrows[row_idx - 1];
181
        nrow = inrows[row_idx + 1];
182

183
        for (col_idx = 1; col_idx < width - 1; col_idx++) {
184
            int cim = col_idx - 1;
185
            int cip = col_idx + 1;
186
            unsigned char b0 = prow[cim] & 1;
187
            unsigned char b1 = prow[col_idx] & 1;
188
            unsigned char b2 = prow[cip] & 1;
189

190
            unsigned char b3 = inrow[cim] & 1;
191
            unsigned char b4 = inrow[col_idx] & 1;
192
            unsigned char b5 = inrow[cip] & 1;
193

194
            unsigned char b6 = nrow[cim] & 1;
195
            unsigned char b7 = nrow[col_idx] & 1;
196
            unsigned char b8 = nrow[cip] & 1;
197

198
            int lut_idx =
199
                (b0 | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) | (b5 << 5) |
200
                 (b6 << 6) | (b7 << 7) | (b8 << 8));
201
            if (lut[lut_idx]) {
202
                PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
203
                PyList_Append(ret, coordObj);
204
                Py_XDECREF(coordObj);
205
            }
206
        }
207
    }
208

209
    return ret;
210
}
211

212
/* Return a list of the coordinates of all turned on pixels in an image.
213
   May be used to extract features after a sequence of MorphOps were applied.
214
   This is faster than match as only 1x1 lookup is made.
215
*/
216
static PyObject *
217
get_on_pixels(PyObject *self, PyObject *args) {
218
    Py_ssize_t i0;
219
    Imaging img;
220
    UINT8 **rows;
221
    int row_idx, col_idx;
222
    int width, height;
223
    PyObject *ret = PyList_New(0);
224
    if (ret == NULL) {
225
        return NULL;
226
    }
227

228
    if (!PyArg_ParseTuple(args, "n", &i0)) {
229
        Py_DECREF(ret);
230
        PyErr_SetString(PyExc_RuntimeError, "Argument parsing problem");
231
        return NULL;
232
    }
233
    img = (Imaging)i0;
234
    rows = img->image8;
235
    width = img->xsize;
236
    height = img->ysize;
237

238
    for (row_idx = 0; row_idx < height; row_idx++) {
239
        UINT8 *row = rows[row_idx];
240
        for (col_idx = 0; col_idx < width; col_idx++) {
241
            if (row[col_idx]) {
242
                PyObject *coordObj = Py_BuildValue("(nn)", col_idx, row_idx);
243
                PyList_Append(ret, coordObj);
244
                Py_XDECREF(coordObj);
245
            }
246
        }
247
    }
248
    return ret;
249
}
250

251
static PyMethodDef functions[] = {
252
    /* Functions */
253
    {"apply", (PyCFunction)apply, METH_VARARGS, NULL},
254
    {"get_on_pixels", (PyCFunction)get_on_pixels, METH_VARARGS, NULL},
255
    {"match", (PyCFunction)match, METH_VARARGS, NULL},
256
    {NULL, NULL, 0, NULL}
257
};
258

259
PyMODINIT_FUNC
260
PyInit__imagingmorph(void) {
261
    PyObject *m;
262

263
    static PyModuleDef module_def = {
264
        PyModuleDef_HEAD_INIT,
265
        "_imagingmorph",                       /* m_name */
266
        "A module for doing image morphology", /* m_doc */
267
        -1,                                    /* m_size */
268
        functions,                             /* m_methods */
269
    };
270

271
    m = PyModule_Create(&module_def);
272

273
#ifdef Py_GIL_DISABLED
274
    PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
275
#endif
276

277
    return m;
278
}
279

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.