/ components / micropython / port / src / omv / img / binary.c
binary.c
  1  /* This file is part of the OpenMV project.
  2   * Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
  3   * This work is licensed under the MIT license, see the file LICENSE for details.
  4   */
  5  
  6  #include "imlib.h"
  7  
  8  #ifdef IMLIB_ENABLE_BINARY_OPS
  9  void imlib_binary(image_t *out, image_t *img, list_t *thresholds, bool invert, bool zero, image_t *mask)
 10  {
 11      image_t bmp;
 12      bmp.w = img->w;
 13      bmp.h = img->h;
 14      bmp.bpp = IMAGE_BPP_BINARY;
 15      bmp.data = fb_alloc0(image_size(&bmp));
 16  
 17      for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) {
 18          color_thresholds_list_lnk_data_t lnk_data;
 19          iterator_get(thresholds, it, &lnk_data);
 20          switch(img->bpp) {
 21              case IMAGE_BPP_BINARY: {
 22                  for (int y = 0, yy = img->h; y < yy; y++) {
 23                      uint32_t *old_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
 24                      uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 25                      for (int x = 0, xx = img->w; x < xx; x++) {
 26                          if (COLOR_THRESHOLD_BINARY(IMAGE_GET_BINARY_PIXEL_FAST(old_row_ptr, x), &lnk_data, invert)) {
 27                              IMAGE_SET_BINARY_PIXEL_FAST(bmp_row_ptr, x);
 28                          }
 29                      }
 30                  }
 31                  break;
 32              }
 33              case IMAGE_BPP_GRAYSCALE: {
 34                  for (int y = 0, yy = img->h; y < yy; y++) {
 35                      uint8_t *old_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
 36                      uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 37                      for (int x = 0, xx = img->w; x < xx; x++) {
 38                          if (COLOR_THRESHOLD_GRAYSCALE(IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row_ptr, x), &lnk_data, invert)) {
 39                              IMAGE_SET_BINARY_PIXEL_FAST(bmp_row_ptr, x);
 40                          }
 41                      }
 42                  }
 43                  break;
 44              }
 45              case IMAGE_BPP_RGB565: {
 46                  for (int y = 0, yy = img->h; y < yy; y++) {
 47                      uint16_t *old_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
 48                      uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 49                      for (int x = 0, xx = img->w; x < xx; x++) {
 50                          if (COLOR_THRESHOLD_RGB565(IMAGE_GET_RGB565_PIXEL_FAST(old_row_ptr, x), &lnk_data, invert)) {
 51                              IMAGE_SET_BINARY_PIXEL_FAST(bmp_row_ptr, x);
 52                          }
 53                      }
 54                  }
 55                  break;
 56              }
 57              default: {
 58                  break;
 59              }
 60          }
 61      }
 62  
 63      switch(img->bpp) {
 64          case IMAGE_BPP_BINARY: {
 65              if (!zero) {
 66                  for (int y = 0, yy = img->h; y < yy; y++) {
 67                      uint32_t *old_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
 68                      uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 69                      uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
 70                      for (int x = 0, xx = img->w; x < xx; x++) {
 71                          int pixel = ((!mask) || image_get_mask_pixel(mask, x, y))
 72                              ? IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)
 73                              : IMAGE_GET_BINARY_PIXEL_FAST(old_row_ptr, x);
 74                          IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
 75                      }
 76                  }
 77              } else {
 78                  for (int y = 0, yy = img->h; y < yy; y++) {
 79                      uint32_t *old_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
 80                      uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 81                      uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
 82                      for (int x = 0, xx = img->w; x < xx; x++) {
 83                          int pixel = IMAGE_GET_BINARY_PIXEL_FAST(old_row_ptr, x);
 84                          if (((!mask) || image_get_mask_pixel(mask, x, y))
 85                              && IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)) pixel = 0;
 86                          IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
 87                      }
 88                  }
 89              }
 90              break;
 91          }
 92          case IMAGE_BPP_GRAYSCALE: {
 93              if (out->bpp == IMAGE_BPP_BINARY) {
 94                  if (!zero) {
 95                      for (int y = 0, yy = img->h; y < yy; y++) {
 96                          uint8_t *old_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
 97                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
 98                          uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
 99                          for (int x = 0, xx = img->w; x < xx; x++) {
100                              int pixel = ((!mask) || image_get_mask_pixel(mask, x, y))
101                                  ? IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)
102                                  : COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row_ptr, x));
103                              IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
104                          }
105                      }
106                  } else {
107                      for (int y = 0, yy = img->h; y < yy; y++) {
108                          uint8_t *old_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
109                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
110                          uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
111                          for (int x = 0, xx = img->w; x < xx; x++) {
112                              int pixel = COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row_ptr, x));
113                              if (((!mask) || image_get_mask_pixel(mask, x, y))
114                                  && IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)) pixel = 0;
115                              IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
116                          }
117                      }
118                  }
119              } else {
120                  if (!zero) {
121                      for (int y = 0, yy = img->h; y < yy; y++) {
122                          uint8_t *old_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
123                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
124                          uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(out, y);
125                          for (int x = 0, xx = img->w; x < xx; x++) {
126                              int pixel = ((!mask) || image_get_mask_pixel(mask, x, y))
127                                  ? COLOR_BINARY_TO_GRAYSCALE(IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x))
128                                  : IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row_ptr, x);
129                              IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, pixel);
130                          }
131                      }
132                  } else {
133                      for (int y = 0, yy = img->h; y < yy; y++) {
134                          uint8_t *old_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
135                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
136                          uint8_t *out_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(out, y);
137                          for (int x = 0, xx = img->w; x < xx; x++) {
138                              int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(old_row_ptr, x);
139                              if (((!mask) || image_get_mask_pixel(mask, x, y))
140                                  && IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)) pixel = 0;
141                              IMAGE_PUT_GRAYSCALE_PIXEL_FAST(out_row_ptr, x, pixel);
142                          }
143                      }
144                  }
145              }
146              break;
147          }
148          case IMAGE_BPP_RGB565: {
149              if (out->bpp == IMAGE_BPP_BINARY) {
150                  if (!zero) {
151                      for (int y = 0, yy = img->h; y < yy; y++) {
152                          uint16_t *old_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
153                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
154                          uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
155                          for (int x = 0, xx = img->w; x < xx; x++) {
156                              int pixel = ((!mask) || image_get_mask_pixel(mask, x, y))
157                                  ? IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)
158                                  : COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(old_row_ptr, x));
159                              IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
160                          }
161                      }
162                  } else {
163                      for (int y = 0, yy = img->h; y < yy; y++) {
164                          uint16_t *old_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
165                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
166                          uint32_t *out_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(out, y);
167                          for (int x = 0, xx = img->w; x < xx; x++) {
168                              int pixel = COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(old_row_ptr, x));
169                              if (((!mask) || image_get_mask_pixel(mask, x, y))
170                                  && IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)) pixel = 0;
171                              IMAGE_PUT_BINARY_PIXEL_FAST(out_row_ptr, x, pixel);
172                          }
173                      }
174                  }
175              } else {
176                  if (!zero) {
177                      for (int y = 0, yy = img->h; y < yy; y++) {
178                          uint16_t *old_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
179                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
180                          uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(out, y);
181                          for (int x = 0, xx = img->w; x < xx; x++) {
182                              int pixel = ((!mask) || image_get_mask_pixel(mask, x, y))
183                                  ? COLOR_BINARY_TO_RGB565(IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x))
184                                  : IMAGE_GET_RGB565_PIXEL_FAST(old_row_ptr, x);
185                              IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
186                          }
187                      }
188                  } else {
189                      for (int y = 0, yy = img->h; y < yy; y++) {
190                          uint16_t *old_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
191                          uint32_t *bmp_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&bmp, y);
192                          uint16_t *out_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(out, y);
193                          for (int x = 0, xx = img->w; x < xx; x++) {
194                              int pixel = IMAGE_GET_RGB565_PIXEL_FAST(old_row_ptr, x);
195                              if (((!mask) || image_get_mask_pixel(mask, x, y))
196                                  && IMAGE_GET_BINARY_PIXEL_FAST(bmp_row_ptr, x)) pixel = 0;
197                              IMAGE_PUT_RGB565_PIXEL_FAST(out_row_ptr, x, pixel);
198                          }
199                      }
200                  }
201              }
202              break;
203          }
204          default: {
205              break;
206          }
207      }
208  
209      fb_free();
210  }
211  
212  void imlib_invert(image_t *img)
213  {
214      switch(img->bpp) {
215          case IMAGE_BPP_BINARY: {
216              for (uint32_t *start = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, 0),
217                   *end = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, img->h);
218                   start < end; start++) {
219                  *start = ~*start;
220              }
221              break;
222          }
223          case IMAGE_BPP_GRAYSCALE: {
224              for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
225                   *end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
226                   start < end; start++) {
227                  *start = ~*start;
228              }
229              break;
230          }
231          case IMAGE_BPP_RGB565: {
232              for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
233                   *end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
234                   start < end; start++) {
235                  *start = ~*start;
236              }
237              break;
238          }
239          default: {
240              break;
241          }
242      }
243  }
244  
245  static void imlib_b_and_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
246  {
247      image_t *mask = (image_t *) data;
248  
249      switch(img->bpp) {
250          case IMAGE_BPP_BINARY: {
251              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
252  
253              if(!mask) {
254                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
255                      data[i] &= ((uint32_t *) other)[i];
256                  }
257              } else {
258                  for (int i = 0, j = img->w; i < j; i++) {
259                      if (image_get_mask_pixel(mask, i, line)) {
260                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
261                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
262                               & IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
263                      }
264                  }
265              }
266              break;
267          }
268          case IMAGE_BPP_GRAYSCALE: {
269              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
270  
271              if(!mask) {
272                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
273                      data[i] &= ((uint8_t *) other)[i];
274                  }
275              } else {
276                  for (int i = 0, j = img->w; i < j; i++) {
277                      if (image_get_mask_pixel(mask, i, line)) {
278                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
279                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
280                               & IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
281                      }
282                  }
283              }
284              break;
285          }
286          case IMAGE_BPP_RGB565: {
287              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
288  
289              if(!mask) {
290                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
291                      data[i] &= ((uint16_t *) other)[i];
292                  }
293              } else {
294                  for (int i = 0, j = img->w; i < j; i++) {
295                      if (image_get_mask_pixel(mask, i, line)) {
296                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
297                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
298                               & IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
299                      }
300                  }
301              }
302              break;
303          }
304          default: {
305              break;
306          }
307      }
308  }
309  
310  void imlib_b_and(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
311  {
312      //imlib_image_operation(img, path, other, scalar, imlib_b_and_line_op, mask);
313  }
314  
315  static void imlib_b_nand_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
316  {
317      image_t *mask = (image_t *) data;
318  
319      switch(img->bpp) {
320          case IMAGE_BPP_BINARY: {
321              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
322  
323              if(!mask) {
324                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
325                      data[i] &= ~((uint32_t *) other)[i];
326                  }
327              } else {
328                  for (int i = 0, j = img->w; i < j; i++) {
329                      if (image_get_mask_pixel(mask, i, line)) {
330                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
331                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
332                               & ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
333                      }
334                  }
335              }
336              break;
337          }
338          case IMAGE_BPP_GRAYSCALE: {
339              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
340  
341              if(!mask) {
342                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
343                      data[i] &= ~((uint8_t *) other)[i];
344                  }
345              } else {
346                  for (int i = 0, j = img->w; i < j; i++) {
347                      if (image_get_mask_pixel(mask, i, line)) {
348                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
349                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
350                               & ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
351                      }
352                  }
353              }
354              break;
355          }
356          case IMAGE_BPP_RGB565: {
357              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
358  
359              if(!mask) {
360                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
361                      data[i] &= ~((uint16_t *) other)[i];
362                  }
363              } else {
364                  for (int i = 0, j = img->w; i < j; i++) {
365                      if (image_get_mask_pixel(mask, i, line)) {
366                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
367                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
368                               & ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
369                      }
370                  }
371              }
372              break;
373          }
374          default: {
375              break;
376          }
377      }
378  }
379  
380  void imlib_b_nand(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
381  {
382      //imlib_image_operation(img, path, other, scalar, imlib_b_nand_line_op, mask);
383  }
384  
385  static void imlib_b_or_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
386  {
387      image_t *mask = (image_t *) data;
388  
389      switch(img->bpp) {
390          case IMAGE_BPP_BINARY: {
391              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
392  
393              if(!mask) {
394                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
395                      data[i] |= ((uint32_t *) other)[i];
396                  }
397              } else {
398                  for (int i = 0, j = img->w; i < j; i++) {
399                      if (image_get_mask_pixel(mask, i, line)) {
400                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
401                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
402                               | IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
403                      }
404                  }
405              }
406              break;
407          }
408          case IMAGE_BPP_GRAYSCALE: {
409              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
410  
411              if(!mask) {
412                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
413                      data[i] |= ((uint8_t *) other)[i];
414                  }
415              } else {
416                  for (int i = 0, j = img->w; i < j; i++) {
417                      if (image_get_mask_pixel(mask, i, line)) {
418                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
419                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
420                               | IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
421                      }
422                  }
423              }
424              break;
425          }
426          case IMAGE_BPP_RGB565: {
427              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
428  
429              if(!mask) {
430                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
431                      data[i] |= ((uint16_t *) other)[i];
432                  }
433              } else {
434                  for (int i = 0, j = img->w; i < j; i++) {
435                      if (image_get_mask_pixel(mask, i, line)) {
436                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
437                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
438                               | IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
439                      }
440                  }
441              }
442              break;
443          }
444          default: {
445              break;
446          }
447      }
448  }
449  
450  void imlib_b_or(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
451  {
452      //imlib_image_operation(img, path, other, scalar, imlib_b_or_line_op, mask);
453  }
454  
455  static void imlib_b_nor_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
456  {
457      image_t *mask = (image_t *) data;
458  
459      switch(img->bpp) {
460          case IMAGE_BPP_BINARY: {
461              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
462  
463              if(!mask) {
464                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
465                      data[i] |= ~((uint32_t *) other)[i];
466                  }
467              } else {
468                  for (int i = 0, j = img->w; i < j; i++) {
469                      if (image_get_mask_pixel(mask, i, line)) {
470                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
471                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
472                               | ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
473                      }
474                  }
475              }
476              break;
477          }
478          case IMAGE_BPP_GRAYSCALE: {
479              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
480  
481              if(!mask) {
482                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
483                      data[i] |= ~((uint8_t *) other)[i];
484                  }
485              } else {
486                  for (int i = 0, j = img->w; i < j; i++) {
487                      if (image_get_mask_pixel(mask, i, line)) {
488                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
489                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
490                               | ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
491                      }
492                  }
493              }
494              break;
495          }
496          case IMAGE_BPP_RGB565: {
497              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
498  
499              if(!mask) {
500                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
501                      data[i] |= ~((uint16_t *) other)[i];
502                  }
503              } else {
504                  for (int i = 0, j = img->w; i < j; i++) {
505                      if (image_get_mask_pixel(mask, i, line)) {
506                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
507                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
508                               | ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
509                      }
510                  }
511              }
512              break;
513          }
514          default: {
515              break;
516          }
517      }
518  }
519  
520  void imlib_b_nor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
521  {
522      //imlib_image_operation(img, path, other, scalar,imlib_b_nor_line_op,  mask);
523  }
524  
525  static void imlib_b_xor_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
526  {
527      image_t *mask = (image_t *) data;
528  
529      switch(img->bpp) {
530          case IMAGE_BPP_BINARY: {
531              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
532  
533              if(!mask) {
534                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
535                      data[i] ^= ((uint32_t *) other)[i];
536                  }
537              } else {
538                  for (int i = 0, j = img->w; i < j; i++) {
539                      if (image_get_mask_pixel(mask, i, line)) {
540                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
541                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
542                               ^ IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
543                      }
544                  }
545              }
546              break;
547          }
548          case IMAGE_BPP_GRAYSCALE: {
549              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
550  
551              if(!mask) {
552                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
553                      data[i] ^= ((uint8_t *) other)[i];
554                  }
555              } else {
556                  for (int i = 0, j = img->w; i < j; i++) {
557                      if (image_get_mask_pixel(mask, i, line)) {
558                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
559                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
560                               ^ IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
561                      }
562                  }
563              }
564              break;
565          }
566          case IMAGE_BPP_RGB565: {
567              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
568  
569              if(!mask) {
570                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
571                      data[i] ^= ((uint16_t *) other)[i];
572                  }
573              } else {
574                  for (int i = 0, j = img->w; i < j; i++) {
575                      if (image_get_mask_pixel(mask, i, line)) {
576                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
577                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
578                               ^ IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
579                      }
580                  }
581              }
582              break;
583          }
584          default: {
585              break;
586          }
587      }
588  }
589  
590  void imlib_b_xor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
591  {
592      //imlib_image_operation(img, path, other, scalar, imlib_b_xor_line_op, mask);
593  }
594  
595  static void imlib_b_xnor_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
596  {
597      image_t *mask = (image_t *) data;
598  
599      switch(img->bpp) {
600          case IMAGE_BPP_BINARY: {
601              uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
602  
603              if(!mask) {
604                  for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
605                      data[i] ^= ~((uint32_t *) other)[i];
606                  }
607              } else {
608                  for (int i = 0, j = img->w; i < j; i++) {
609                      if (image_get_mask_pixel(mask, i, line)) {
610                          IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
611                              (IMAGE_GET_BINARY_PIXEL_FAST(data, i)
612                               ^ ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
613                      }
614                  }
615              }
616              break;
617          }
618          case IMAGE_BPP_GRAYSCALE: {
619              uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
620  
621              if(!mask) {
622                  for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
623                      data[i] ^= ~((uint8_t *) other)[i];
624                  }
625              } else {
626                  for (int i = 0, j = img->w; i < j; i++) {
627                      if (image_get_mask_pixel(mask, i, line)) {
628                          IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
629                              (IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
630                               ^ ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
631                      }
632                  }
633              }
634              break;
635          }
636          case IMAGE_BPP_RGB565: {
637              uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
638  
639              if(!mask) {
640                  for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
641                      data[i] ^= ~((uint16_t *) other)[i];
642                  }
643              } else {
644                  for (int i = 0, j = img->w; i < j; i++) {
645                      if (image_get_mask_pixel(mask, i, line)) {
646                          IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
647                              (IMAGE_GET_RGB565_PIXEL_FAST(data, i)
648                               ^ ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
649                      }
650                  }
651              }
652              break;
653          }
654          default: {
655              break;
656          }
657      }
658  }
659  
660  void imlib_b_xnor(image_t *img, const char *path, image_t *other, int scalar, image_t *mask)
661  {
662      //imlib_image_operation(img, path, other, scalar, imlib_b_xnor_line_op, mask);
663  }
664  
665  static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d, image_t *mask)
666  {
667      int brows = ksize + 1;
668      image_t buf;
669      buf.w = img->w;
670      buf.h = brows;
671      buf.bpp = img->bpp;
672  
673      switch(img->bpp) {
674          case IMAGE_BPP_BINARY: {
675              buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
676  
677              for (int y = 0, yy = img->h; y < yy; y++) {
678                  uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
679                  uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
680  
681                  for (int x = 0, xx = img->w; x < xx; x++) {
682                      int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x);
683                      IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
684  
685                      if ((mask && (!image_get_mask_pixel(mask, x, y)))
686                      || (pixel == e_or_d)) {
687                          continue; // Short circuit.
688                      }
689  
690                      int acc = e_or_d ? 0 : -1; // Don't count center pixel...
691  
692                      for (int j = -ksize; j <= ksize; j++) {
693                          uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
694                              IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
695  
696                          for (int k = -ksize; k <= ksize; k++) {
697                              acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
698                                  IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
699                          }
700                      }
701  
702                      if (!e_or_d) {
703                          // Preserve original pixel value... or clear it.
704                          if (acc < threshold) IMAGE_CLEAR_BINARY_PIXEL_FAST(buf_row_ptr, x);
705                      } else {
706                          // Preserve original pixel value... or set it.
707                          if (acc > threshold) IMAGE_SET_BINARY_PIXEL_FAST(buf_row_ptr, x);
708                      }
709                  }
710  
711                  if (y >= ksize) { // Transfer buffer lines...
712                      memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
713                             IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
714                             IMAGE_BINARY_LINE_LEN_BYTES(img));
715                  }
716              }
717  
718              // Copy any remaining lines from the buffer image...
719              for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
720                  memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
721                         IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
722                         IMAGE_BINARY_LINE_LEN_BYTES(img));
723              }
724  
725              fb_free();
726              break;
727          }
728          case IMAGE_BPP_GRAYSCALE: {
729              buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows);
730  
731              for (int y = 0, yy = img->h; y < yy; y++) {
732                  uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
733                  uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows));
734  
735                  for (int x = 0, xx = img->w; x < xx; x++) {
736                      int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x);
737                      IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel);
738  
739                      if ((mask && (!image_get_mask_pixel(mask, x, y)))
740                      || (COLOR_GRAYSCALE_TO_BINARY(pixel) == e_or_d)) {
741                          continue; // Short circuit.
742                      }
743  
744                      int acc = e_or_d ? 0 : -1; // Don't count center pixel...
745  
746                      for (int j = -ksize; j <= ksize; j++) {
747                          uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img,
748                              IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
749  
750                          for (int k = -ksize; k <= ksize; k++) {
751                              acc += COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,
752                                  IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
753                          }
754                      }
755  
756                      if (!e_or_d) {
757                          // Preserve original pixel value... or clear it.
758                          if (acc < threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
759                                                                              COLOR_GRAYSCALE_BINARY_MIN);
760                      } else {
761                          // Preserve original pixel value... or set it.
762                          if (acc > threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
763                                                                              COLOR_GRAYSCALE_BINARY_MAX);
764                      }
765                  }
766  
767                  if (y >= ksize) { // Transfer buffer lines...
768                      memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)),
769                             IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
770                             IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
771                  }
772              }
773  
774              // Copy any remaining lines from the buffer image...
775              for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
776                  memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y),
777                         IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)),
778                         IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
779              }
780  
781              fb_free();
782              break;
783          }
784          case IMAGE_BPP_RGB565: {
785              buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows);
786  
787              for (int y = 0, yy = img->h; y < yy; y++) {
788                  uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
789                  uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows));
790  
791                  for (int x = 0, xx = img->w; x < xx; x++) {
792                      int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
793                      IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel);
794  
795                      if ((mask && (!image_get_mask_pixel(mask, x, y)))
796                      || (COLOR_RGB565_TO_BINARY(pixel) == e_or_d)) {
797                          continue; // Short circuit.
798                      }
799  
800                      int acc = e_or_d ? 0 : -1; // Don't count center pixel...
801  
802                      for (int j = -ksize; j <= ksize; j++) {
803                          uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img,
804                              IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
805  
806                          for (int k = -ksize; k <= ksize; k++) {
807                              acc += COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,
808                                  IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
809                          }
810                      }
811  
812                      if (!e_or_d) {
813                          // Preserve original pixel value... or clear it.
814                          if (acc < threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
815                                                                           COLOR_RGB565_BINARY_MIN);
816                      } else {
817                          // Preserve original pixel value... or set it.
818                          if (acc > threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
819                                                                           COLOR_RGB565_BINARY_MAX);
820                      }
821                  }
822  
823                  if (y >= ksize) { // Transfer buffer lines...
824                      memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)),
825                             IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
826                             IMAGE_RGB565_LINE_LEN_BYTES(img));
827                  }
828              }
829  
830              // Copy any remaining lines from the buffer image...
831              for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
832                  memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y),
833                         IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)),
834                         IMAGE_RGB565_LINE_LEN_BYTES(img));
835              }
836  
837              fb_free();
838              break;
839          }
840          default: {
841              break;
842          }
843      }
844  }
845  
846  void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask)
847  {
848      // Threshold should be equal to (((ksize*2)+1)*((ksize*2)+1))-1
849      // for normal operation. E.g. for ksize==3 -> threshold==8
850      // Basically you're adjusting the number of data that
851      // must be set in the kernel (besides the center) for the output to be 1.
852      // Erode normally requires all data to be 1.
853      imlib_erode_dilate(img, ksize, threshold, 0, mask);
854  }
855  
856  void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask)
857  {
858      // Threshold should be equal to 0
859      // for normal operation. E.g. for ksize==3 -> threshold==0
860      // Basically you're adjusting the number of data that
861      // must be set in the kernel (besides the center) for the output to be 1.
862      // Dilate normally requires one pixel to be 1.
863      imlib_erode_dilate(img, ksize, threshold, 1, mask);
864  }
865  
866  void imlib_open(image_t *img, int ksize, int threshold, image_t *mask)
867  {
868      imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask);
869      imlib_dilate(img, ksize, 0 + threshold, mask);
870  }
871  
872  void imlib_close(image_t *img, int ksize, int threshold, image_t *mask)
873  {
874      imlib_dilate(img, ksize, 0 + threshold, mask);
875      imlib_erode(img, ksize, (((ksize*2)+1)*((ksize*2)+1))-1 - threshold, mask);
876  }
877  
878  void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask)
879  {
880      image_t temp;
881      temp.w = img->w;
882      temp.h = img->h;
883      temp.bpp = img->bpp;
884      temp.data = fb_alloc(image_size(img));
885      memcpy(temp.data, img->data, image_size(img));
886      imlib_open(&temp, ksize, threshold, mask);
887      imlib_difference(img, NULL, &temp, 0, mask);
888      fb_free();
889  }
890  
891  void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask)
892  {
893      image_t temp;
894      temp.w = img->w;
895      temp.h = img->h;
896      temp.bpp = img->bpp;
897      temp.data = fb_alloc(image_size(img));
898      memcpy(temp.data, img->data, image_size(img));
899      imlib_close(&temp, ksize, threshold, mask);
900      imlib_difference(img, NULL, &temp, 0, mask);
901      fb_free();
902  }
903  #endif