mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Overhaul Binary Functions
Binary() can noew zero things so you can remove bright lights. All the line ops (and/or/xor/etc) accept masks. Erode and dilate now accept masks. And finally, you can now pass arguments versus keywords for folks who don't read the documentation. Also, the binary image type is now supported for these methods. I'm putting in all this work because I saw the need for it when I was doing shadow removal. Note: Some effort needs to be put into optimizing the py_image.c code soon. This is on the todo list before the next release.
This commit is contained in:
parent
b8298c43cd
commit
fb3d0776f0
@ -144,6 +144,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \
|
||||
)
|
||||
|
||||
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/img/,\
|
||||
binary.o \
|
||||
blob.o \
|
||||
qrcode.o \
|
||||
apriltag.o \
|
||||
|
||||
@ -22,6 +22,7 @@ SRCS += $(addprefix , \
|
||||
)
|
||||
|
||||
SRCS += $(addprefix img/, \
|
||||
binary.c \
|
||||
blob.c \
|
||||
qrcode.c \
|
||||
apriltag.c \
|
||||
|
||||
713
src/omv/img/binary.c
Normal file
713
src/omv/img/binary.c
Normal file
@ -0,0 +1,713 @@
|
||||
/* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "imlib.h"
|
||||
|
||||
void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero)
|
||||
{
|
||||
for (list_lnk_t *it = iterator_start_from_head(thresholds); it; it = iterator_next(it)) {
|
||||
color_thresholds_list_lnk_data_t lnk_data;
|
||||
iterator_get(thresholds, it, &lnk_data);
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
if (!zero) {
|
||||
for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
*start = COLOR_THRESHOLD_GRAYSCALE(*start, &lnk_data, invert)
|
||||
? COLOR_GRAYSCALE_BINARY_MAX : COLOR_GRAYSCALE_BINARY_MIN;
|
||||
}
|
||||
} else {
|
||||
for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
if (COLOR_THRESHOLD_GRAYSCALE(*start, &lnk_data, invert)) *start =
|
||||
COLOR_GRAYSCALE_BINARY_MIN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
if (!zero) {
|
||||
for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
*start = COLOR_THRESHOLD_RGB565(*start, &lnk_data, invert)
|
||||
? COLOR_RGB565_BINARY_MAX : COLOR_RGB565_BINARY_MIN;
|
||||
}
|
||||
} else {
|
||||
for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
if (COLOR_THRESHOLD_RGB565(*start, &lnk_data, invert)) *start =
|
||||
COLOR_RGB565_BINARY_MIN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_invert(image_t *img)
|
||||
{
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
for (uint32_t *start = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
*start = ~*start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
for (uint8_t *start = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
*start = ~*start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
for (uint16_t *start = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, 0),
|
||||
*end = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, img->h);
|
||||
start < end; start++) {
|
||||
*start = ~*start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void imlib_b_and_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
& IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
& IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
& IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_and(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_and_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_b_nand_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ~((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
& ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ~((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
& ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] &= ~((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
& ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_nand(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_nand_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_b_or_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
| IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
| IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
| IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_or(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_or_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_b_nor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ~((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
| ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ~((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
| ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] |= ~((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
| ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_nor(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_nor_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_b_xor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
^ IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
^ IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
^ IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_xor(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_xor_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_b_xnor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
image_t *mask = (image_t *) data;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_BINARY_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ~((uint32_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_BINARY_PIXEL_FAST(data, i)
|
||||
^ ~IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_GRAYSCALE_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ~((uint8_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i)
|
||||
^ ~IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
|
||||
|
||||
if(!mask) {
|
||||
for (int i = 0, j = IMAGE_RGB565_LINE_LEN(img); i < j; i++) {
|
||||
data[i] ^= ~((uint16_t *) other)[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0, j = img->w; i < j; i++) {
|
||||
if (image_get_mask_pixel(mask, i, line)) {
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(data, i,
|
||||
(IMAGE_GET_RGB565_PIXEL_FAST(data, i)
|
||||
^ ~IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_xnor(image_t *img, const char *path, image_t *other, image_t *mask)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_xnor_line_op, mask);
|
||||
}
|
||||
|
||||
static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d, image_t *mask)
|
||||
{
|
||||
int brows = ksize + 1;
|
||||
image_t buf;
|
||||
buf.w = img->w;
|
||||
buf.h = brows;
|
||||
buf.bpp = img->bpp;
|
||||
|
||||
switch(img->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);
|
||||
|
||||
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||
uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||
uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||
|
||||
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||
int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x);
|
||||
IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||
|
||||
if ((mask && (!image_get_mask_pixel(mask, x, y)))
|
||||
|| (pixel == e_or_d)) {
|
||||
continue; // Short circuit.
|
||||
}
|
||||
|
||||
int acc = e_or_d ? 0 : -1; // Don't count center pixel...
|
||||
|
||||
for (int j = -ksize; j <= ksize; j++) {
|
||||
uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
|
||||
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||
|
||||
for (int k = -ksize; k <= ksize; k++) {
|
||||
acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
|
||||
IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!e_or_d) {
|
||||
// Preserve original pixel value... or clear it.
|
||||
if (acc < threshold) IMAGE_CLEAR_BINARY_PIXEL_FAST(buf_row_ptr, x);
|
||||
} else {
|
||||
// Preserve original pixel value... or set it.
|
||||
if (acc > threshold) IMAGE_SET_BINARY_PIXEL_FAST(buf_row_ptr, x);
|
||||
}
|
||||
}
|
||||
|
||||
if (y >= ksize) { // Transfer buffer lines...
|
||||
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining lines from the buffer image...
|
||||
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||
memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
|
||||
IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||
IMAGE_BINARY_LINE_LEN_BYTES(img));
|
||||
}
|
||||
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows);
|
||||
|
||||
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||
uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
|
||||
uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||
|
||||
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||
int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x);
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||
|
||||
if ((mask && (!image_get_mask_pixel(mask, x, y)))
|
||||
|| (COLOR_GRAYSCALE_TO_BINARY(pixel) == e_or_d)) {
|
||||
continue; // Short circuit.
|
||||
}
|
||||
|
||||
int acc = e_or_d ? 0 : -1; // Don't count center pixel...
|
||||
|
||||
for (int j = -ksize; j <= ksize; j++) {
|
||||
uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img,
|
||||
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||
|
||||
for (int k = -ksize; k <= ksize; k++) {
|
||||
acc += COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,
|
||||
IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
|
||||
}
|
||||
}
|
||||
|
||||
if (!e_or_d) {
|
||||
// Preserve original pixel value... or clear it.
|
||||
if (acc < threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
|
||||
COLOR_GRAYSCALE_BINARY_MIN);
|
||||
} else {
|
||||
// Preserve original pixel value... or set it.
|
||||
if (acc > threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
|
||||
COLOR_GRAYSCALE_BINARY_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (y >= ksize) { // Transfer buffer lines...
|
||||
memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||
IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||
IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining lines from the buffer image...
|
||||
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||
memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y),
|
||||
IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||
IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
|
||||
}
|
||||
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows);
|
||||
|
||||
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||
uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
|
||||
uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows));
|
||||
|
||||
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||
int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel);
|
||||
|
||||
if ((mask && (!image_get_mask_pixel(mask, x, y)))
|
||||
|| (COLOR_RGB565_TO_BINARY(pixel) == e_or_d)) {
|
||||
continue; // Short circuit.
|
||||
}
|
||||
|
||||
int acc = e_or_d ? 0 : -1; // Don't count center pixel...
|
||||
|
||||
for (int j = -ksize; j <= ksize; j++) {
|
||||
uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img,
|
||||
IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));
|
||||
|
||||
for (int k = -ksize; k <= ksize; k++) {
|
||||
acc += COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,
|
||||
IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
|
||||
}
|
||||
}
|
||||
|
||||
if (!e_or_d) {
|
||||
// Preserve original pixel value... or clear it.
|
||||
if (acc < threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
|
||||
COLOR_RGB565_BINARY_MIN);
|
||||
} else {
|
||||
// Preserve original pixel value... or set it.
|
||||
if (acc > threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
|
||||
COLOR_RGB565_BINARY_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (y >= ksize) { // Transfer buffer lines...
|
||||
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)),
|
||||
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
|
||||
IMAGE_RGB565_LINE_LEN_BYTES(img));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy any remaining lines from the buffer image...
|
||||
for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
|
||||
memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y),
|
||||
IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)),
|
||||
IMAGE_RGB565_LINE_LEN_BYTES(img));
|
||||
}
|
||||
|
||||
fb_free();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask)
|
||||
{
|
||||
// Threshold should be equal to (((ksize*2)+1)*((ksize*2)+1))-1
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==8
|
||||
// Basically you're adjusting the number of data that
|
||||
// must be set in the kernel (besides the center) for the output to be 1.
|
||||
// Erode normally requires all data to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 0, mask);
|
||||
}
|
||||
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask)
|
||||
{
|
||||
// Threshold should be equal to 0
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==0
|
||||
// Basically you're adjusting the number of data that
|
||||
// must be set in the kernel (besides the center) for the output to be 1.
|
||||
// Dilate normally requires one pixel to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 1, mask);
|
||||
}
|
||||
@ -20,10 +20,15 @@ typedef struct gvec {
|
||||
void imlib_edge_simple(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh)
|
||||
{
|
||||
imlib_morph(src, 1, kernel_high_pass_3, 1.0f, 0.0f);
|
||||
simple_color_t lt = {.G=low_thresh};
|
||||
simple_color_t ht = {.G=high_thresh};
|
||||
imlib_binary(src, 1, <, &ht, false);
|
||||
imlib_erode(src, 1, 2);
|
||||
list_t thresholds;
|
||||
list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t));
|
||||
color_thresholds_list_lnk_data_t lnk_data;
|
||||
lnk_data.LMin=low_thresh;
|
||||
lnk_data.LMax=high_thresh;
|
||||
list_push_back(&thresholds, &lnk_data);
|
||||
imlib_binary(src, &thresholds, false, false);
|
||||
list_free(&thresholds);
|
||||
imlib_erode(src, 1, 2, NULL);
|
||||
}
|
||||
|
||||
void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_thresh)
|
||||
|
||||
@ -171,17 +171,17 @@ void image_copy(image_t *dst, image_t *src)
|
||||
memcpy(dst, src, sizeof(image_t));
|
||||
}
|
||||
|
||||
uint32_t image_size(image_t *ptr)
|
||||
size_t image_size(image_t *ptr)
|
||||
{
|
||||
switch (ptr->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
return ((ptr->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * ptr->h;
|
||||
return IMAGE_BINARY_LINE_LEN_BYTES(ptr) * ptr->h;
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
return (ptr->w * ptr->h) * sizeof(uint8_t);
|
||||
return IMAGE_GRAYSCALE_LINE_LEN_BYTES(ptr) * ptr->h;
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
return (ptr->w * ptr->h) * sizeof(uint16_t);
|
||||
return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h;
|
||||
}
|
||||
case IMAGE_BPP_BAYER: {
|
||||
return ptr->w * ptr->h;
|
||||
@ -192,6 +192,24 @@ uint32_t image_size(image_t *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
bool image_get_mask_pixel(image_t *ptr, int x, int y)
|
||||
{
|
||||
switch (ptr->bpp) {
|
||||
case IMAGE_BPP_BINARY: {
|
||||
return IMAGE_GET_BINARY_PIXEL(ptr, x, y);
|
||||
}
|
||||
case IMAGE_BPP_GRAYSCALE: {
|
||||
return COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL(ptr, x, y));
|
||||
}
|
||||
case IMAGE_BPP_RGB565: {
|
||||
return COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL(ptr, x, y));
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gamma uncompress
|
||||
extern const float xyz_table[256];
|
||||
|
||||
@ -636,292 +654,6 @@ void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void imlib_binary(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert)
|
||||
{
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels;
|
||||
for (int i=0, j=img->w*img->h; i<j; i++) {
|
||||
bool in = false;
|
||||
for (int k=0; k<num_thresholds; k++) {
|
||||
in |= invert ^
|
||||
((l_thresholds[k].G <= pixels[i])
|
||||
&& (pixels[i] <= h_thresholds[k].G));
|
||||
}
|
||||
pixels[i] = in ? 0xFF : 0;
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = (uint16_t *) img->pixels;
|
||||
for (int i=0, j=img->w*img->h; i<j; i++) {
|
||||
const int pixel = pixels[i];
|
||||
const int lab_l = IM_RGB5652L(pixel);
|
||||
const int lab_a = IM_RGB5652A(pixel);
|
||||
const int lab_b = IM_RGB5652B(pixel);
|
||||
bool in = false;
|
||||
for (int k=0; k<num_thresholds; k++) {
|
||||
in |= invert ^
|
||||
(((l_thresholds[k].L <= lab_l)
|
||||
&& (lab_l <= h_thresholds[k].L))
|
||||
&& ((l_thresholds[k].A <= lab_a)
|
||||
&& (lab_a <= h_thresholds[k].A))
|
||||
&& ((l_thresholds[k].B <= lab_b)
|
||||
&& (lab_b <= h_thresholds[k].B)));
|
||||
}
|
||||
pixels[i] = in ? 0xFFFF : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_invert(image_t *img)
|
||||
{
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels;
|
||||
for (int i=0, j=img->w*img->h; i<j; i++) {
|
||||
pixels[i] = ~pixels[i];
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = (uint16_t *) img->pixels;
|
||||
for (int i=0, j=img->w*img->h; i<j; i++) {
|
||||
pixels[i] = ~pixels[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void imlib_b_and_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] &= other[i];
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] &= ((uint16_t *) other)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_and(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_and_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_b_nand_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] & other[i]);
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] & ((uint16_t *) other)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_nand(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_nand_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_b_or_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] |= other[i];
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] |= ((uint16_t *) other)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_or(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_or_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_b_nor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] | other[i]);
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] | ((uint16_t *) other)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_nor(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_nor_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_b_xor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] ^= other[i];
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] ^= ((uint16_t *) other)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_xor(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_xor_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_b_xnor_line_op(image_t *img, int line, uint8_t *other, void *data, bool vflipped)
|
||||
{
|
||||
data = data; vflipped = vflipped;
|
||||
|
||||
if (IM_IS_GS(img)) {
|
||||
uint8_t *pixels = img->pixels + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] ^ other[i]);
|
||||
}
|
||||
} else {
|
||||
uint16_t *pixels = ((uint16_t *) img->pixels) + (img->w * line);
|
||||
for (int i=0; i<img->w; i++) {
|
||||
pixels[i] = ~(pixels[i] ^ ((uint16_t *) other)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void imlib_b_xnor(image_t *img, const char *path, image_t *other)
|
||||
{
|
||||
imlib_image_operation(img, path, other, imlib_b_xnor_line_op, NULL);
|
||||
}
|
||||
|
||||
static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d)
|
||||
{
|
||||
int brows = ksize + 1;
|
||||
uint8_t *buffer = fb_alloc(img->w * brows * img->bpp);
|
||||
if (IM_IS_GS(img)) {
|
||||
for (int y=0; y<img->h; y++) {
|
||||
for (int x=0; x<img->w; x++) {
|
||||
// We're writing into the buffer like if it were a window.
|
||||
int buffer_idx = ((y%brows)*img->w)+x;
|
||||
buffer[buffer_idx] = IM_GET_GS_PIXEL(img, x, y);
|
||||
if ((!!buffer[buffer_idx]) == e_or_d) {
|
||||
continue; // short circuit (makes this very fast - usually)
|
||||
}
|
||||
int acc = e_or_d ? 0 : -1; // don't count center pixel...
|
||||
for (int j=-ksize; j<=ksize; j++) {
|
||||
for (int k=-ksize; k<=ksize; k++) {
|
||||
int x_k = IM_MIN(IM_MAX(x+k, 0), img->w-1);
|
||||
int y_j = IM_MIN(IM_MAX(y+j, 0), img->h-1);
|
||||
acc += !!IM_GET_GS_PIXEL(img, x_k, y_j);
|
||||
}
|
||||
}
|
||||
if (!e_or_d) {
|
||||
// Preserve original pixel value...
|
||||
if (acc < threshold) buffer[buffer_idx] = 0; // clear
|
||||
} else {
|
||||
// Preserve original pixel value...
|
||||
if (acc > threshold) buffer[buffer_idx] = -1; // set
|
||||
}
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(img->pixels+((y-ksize)*img->w),
|
||||
buffer+(((y-ksize)%brows)*img->w),
|
||||
img->w * sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
for (int y=img->h-ksize; y<img->h; y++) {
|
||||
memcpy(img->pixels+(y*img->w),
|
||||
buffer+((y%brows)*img->w),
|
||||
img->w * sizeof(uint8_t));
|
||||
}
|
||||
} else {
|
||||
for (int y=0; y<img->h; y++) {
|
||||
for (int x=0; x<img->w; x++) {
|
||||
// We're writing into the buffer like if it were a window.
|
||||
int buffer_idx = ((y%brows)*img->w)+x;
|
||||
((uint16_t *) buffer)[buffer_idx] = IM_GET_RGB565_PIXEL(img, x, y);
|
||||
if ((!!((uint16_t *) buffer)[buffer_idx]) == e_or_d) {
|
||||
continue; // short circuit (makes this very fast - usually)
|
||||
}
|
||||
int acc = e_or_d ? 0 : -1; // don't count center pixel...
|
||||
for (int j=-ksize; j<=ksize; j++) {
|
||||
for (int k=-ksize; k<=ksize; k++) {
|
||||
int x_k = IM_MIN(IM_MAX(x+k, 0), img->w-1);
|
||||
int y_j = IM_MIN(IM_MAX(y+j, 0), img->h-1);
|
||||
acc += !!IM_GET_RGB565_PIXEL(img, x_k, y_j);
|
||||
}
|
||||
}
|
||||
if (!e_or_d) {
|
||||
// Preserve original pixel value...
|
||||
if (acc < threshold) ((uint16_t *) buffer)[buffer_idx] = 0; // clear
|
||||
} else {
|
||||
// Preserve original pixel value...
|
||||
if (acc > threshold) ((uint16_t *) buffer)[buffer_idx] = -1; // set
|
||||
}
|
||||
}
|
||||
if (y>=ksize) {
|
||||
memcpy(((uint16_t *) img->pixels)+((y-ksize)*img->w),
|
||||
((uint16_t *) buffer)+(((y-ksize)%brows)*img->w),
|
||||
img->w * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
for (int y=img->h-ksize; y<img->h; y++) {
|
||||
memcpy(((uint16_t *) img->pixels)+(y*img->w),
|
||||
((uint16_t *) buffer)+((y%brows)*img->w),
|
||||
img->w * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
fb_free();
|
||||
}
|
||||
|
||||
void imlib_erode(image_t *img, int ksize, int threshold)
|
||||
{
|
||||
// Threshold should be equal to ((ksize*2)+1)*((ksize*2)+1)-1
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==8
|
||||
// Basically you're adjusting the number of pixels that
|
||||
// must be set in the kernel (besides the center) for the output to be 1.
|
||||
// Erode normally requires all pixels to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 0);
|
||||
}
|
||||
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold)
|
||||
{
|
||||
// Threshold should be equal to 0
|
||||
// for normal operation. E.g. for ksize==3 -> threshold==0
|
||||
// Basically you're adjusting the number of pixels that
|
||||
// must be set in the kernel (besides the center) for the output to be 1.
|
||||
// Dilate normally requires one pixel to be 1.
|
||||
imlib_erode_dilate(img, ksize, threshold, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void imlib_negate(image_t *img)
|
||||
{
|
||||
if (IM_IS_GS(img)) {
|
||||
|
||||
@ -145,6 +145,10 @@ color_thresholds_list_lnk_data_t;
|
||||
|
||||
#define COLOR_BINARY_MIN 0
|
||||
#define COLOR_BINARY_MAX 1
|
||||
#define COLOR_GRAYSCALE_BINARY_MIN 0x00
|
||||
#define COLOR_GRAYSCALE_BINARY_MAX 0xFF
|
||||
#define COLOR_RGB565_BINARY_MIN 0x0000
|
||||
#define COLOR_RGB565_BINARY_MAX 0xFFFF
|
||||
|
||||
#define COLOR_GRAYSCALE_MIN 0
|
||||
#define COLOR_GRAYSCALE_MAX 255
|
||||
@ -319,9 +323,9 @@ extern const int8_t yuv_table[196608];
|
||||
|
||||
#define COLOR_BINARY_TO_GRAYSCALE(pixel) ((pixel) * COLOR_GRAYSCALE_MAX)
|
||||
#define COLOR_BINARY_TO_RGB565(pixel) COLOR_YUV_TO_RGB565((pixel) * 127, 0, 0)
|
||||
#define COLOR_RGB565_TO_BINARY(pixel) (COLOR_RGB565_TO_Y(pixel) == 127)
|
||||
#define COLOR_RGB565_TO_BINARY(pixel) (COLOR_RGB565_TO_Y(pixel) > (((COLOR_Y_MAX - COLOR_Y_MIN) / 2) + COLOR_Y_MIN))
|
||||
#define COLOR_RGB565_TO_GRAYSCALE(pixel) (COLOR_RGB565_TO_Y(pixel) + 128)
|
||||
#define COLOR_GRAYSCALE_TO_BINARY(pixel) ((pixel) == COLOR_GRAYSCALE_MAX)
|
||||
#define COLOR_GRAYSCALE_TO_BINARY(pixel) ((pixel) > (((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / 2) + COLOR_GRAYSCALE_MIN))
|
||||
#define COLOR_GRAYSCALE_TO_RGB565(pixel) COLOR_YUV_TO_RGB565((pixel) - 128, 0, 0)
|
||||
|
||||
/////////////////
|
||||
@ -350,7 +354,17 @@ typedef struct image {
|
||||
|
||||
void image_init(image_t *ptr, int w, int h, int bpp, void *data);
|
||||
void image_copy(image_t *dst, image_t *src);
|
||||
uint32_t image_size(image_t *ptr);
|
||||
size_t image_size(image_t *ptr);
|
||||
bool image_get_mask_pixel(image_t *ptr, int x, int y);
|
||||
|
||||
#define IMAGE_BINARY_LINE_LEN(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT)
|
||||
#define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t))
|
||||
|
||||
#define IMAGE_GRAYSCALE_LINE_LEN(image) ((image)->w)
|
||||
#define IMAGE_GRAYSCALE_LINE_LEN_BYTES(image) (IMAGE_GRAYSCALE_LINE_LEN(image) * sizeof(uint8_t))
|
||||
|
||||
#define IMAGE_RGB565_LINE_LEN(image) ((image)->w)
|
||||
#define IMAGE_RGB565_LINE_LEN_BYTES(image) (IMAGE_RGB565_LINE_LEN(image) * sizeof(uint16_t))
|
||||
|
||||
#define IMAGE_GET_BINARY_PIXEL(image, x, y) \
|
||||
({ \
|
||||
@ -1106,20 +1120,6 @@ void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c);
|
||||
void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c);
|
||||
void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c);
|
||||
|
||||
/* Binary functions */
|
||||
void imlib_binary(image_t *img,
|
||||
int num_thresholds, simple_color_t *l_thresholds, simple_color_t *h_thresholds,
|
||||
bool invert);
|
||||
void imlib_invert(image_t *img);
|
||||
void imlib_b_and(image_t *img, const char *path, image_t *other);
|
||||
void imlib_b_nand(image_t *img, const char *path, image_t *other);
|
||||
void imlib_b_or(image_t *img, const char *path, image_t *other);
|
||||
void imlib_b_nor(image_t *img, const char *path, image_t *other);
|
||||
void imlib_b_xor(image_t *img, const char *path, image_t *other);
|
||||
void imlib_b_xnor(image_t *img, const char *path, image_t *other);
|
||||
void imlib_erode(image_t *img, int ksize, int threshold);
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold);
|
||||
|
||||
/* Background Subtraction (Frame Differencing) functions */
|
||||
void imlib_negate(image_t *img);
|
||||
void imlib_difference(image_t *img, const char *path, image_t *other);
|
||||
@ -1213,6 +1213,17 @@ void imlib_edge_canny(image_t *src, rectangle_t *roi, int low_thresh, int high_t
|
||||
// HoG
|
||||
void imlib_find_hog(image_t *src, rectangle_t *roi, int cell_size);
|
||||
|
||||
// Binary Functions
|
||||
void imlib_binary(image_t *img, list_t *thresholds, bool invert, bool zero);
|
||||
void imlib_invert(image_t *img);
|
||||
void imlib_b_and(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_b_nand(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_b_or(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_b_nor(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_b_xor(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_b_xnor(image_t *img, const char *path, image_t *other, image_t *mask);
|
||||
void imlib_erode(image_t *img, int ksize, int threshold, image_t *mask);
|
||||
void imlib_dilate(image_t *img, int ksize, int threshold, image_t *mask);
|
||||
// Image Correction
|
||||
void imlib_logpolar_int(image_t *dst, image_t *src, rectangle_t *roi, bool linear, bool reverse); // helper/internal
|
||||
void imlib_logpolar(image_t *img, bool linear, bool reverse);
|
||||
|
||||
@ -218,17 +218,21 @@ void imlib_remove_shadows(image_t *img, const char *path, image_t *other)
|
||||
threshold_t t;
|
||||
imlib_get_threshold(&t, temp_image.bpp, &h);
|
||||
|
||||
simple_color_t t_l, t_h;
|
||||
t_l.L = COLOR_L_MIN;
|
||||
t_l.A = COLOR_A_MIN;
|
||||
t_l.B = COLOR_B_MIN;
|
||||
t_h.L = t.LValue;
|
||||
t_h.A = COLOR_A_MAX;
|
||||
t_h.B = COLOR_B_MAX;
|
||||
imlib_binary(&temp_image, 1, &t_l, &t_h, false);
|
||||
list_t thresholds;
|
||||
list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t));
|
||||
color_thresholds_list_lnk_data_t lnk_data;
|
||||
lnk_data.LMin = COLOR_L_MIN;
|
||||
lnk_data.AMin = COLOR_A_MIN;
|
||||
lnk_data.BMin = COLOR_B_MIN;
|
||||
lnk_data.LMax = t.LValue;
|
||||
lnk_data.AMax = COLOR_A_MAX;
|
||||
lnk_data.BMax = COLOR_B_MAX;
|
||||
list_push_back(&thresholds, &lnk_data);
|
||||
imlib_binary(&temp_image, &thresholds, false, false);
|
||||
list_free(&thresholds);
|
||||
|
||||
imlib_erode(&temp_image, 3, 30);
|
||||
imlib_dilate(&temp_image, 1, 1);
|
||||
imlib_erode(&temp_image, 3, 30, NULL);
|
||||
imlib_dilate(&temp_image, 1, 1, NULL);
|
||||
|
||||
// Get Shadow Average
|
||||
|
||||
@ -239,7 +243,7 @@ void imlib_remove_shadows(image_t *img, const char *path, image_t *other)
|
||||
temp_image_2.data = fb_alloc(image_size(&temp_image));
|
||||
|
||||
memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image));
|
||||
imlib_erode(&temp_image_2, 3, 48);
|
||||
imlib_erode(&temp_image_2, 3, 48, NULL);
|
||||
|
||||
int shadow_r_sum = 0;
|
||||
int shadow_g_sum = 0;
|
||||
@ -266,10 +270,10 @@ void imlib_remove_shadows(image_t *img, const char *path, image_t *other)
|
||||
|
||||
memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image));
|
||||
imlib_invert(&temp_image_2);
|
||||
imlib_erode(&temp_image_2, 5, 120);
|
||||
imlib_erode(&temp_image_2, 5, 120, NULL);
|
||||
imlib_invert(&temp_image_2);
|
||||
imlib_b_xor(&temp_image_2, NULL, &temp_image);
|
||||
imlib_erode(&temp_image_2, 2, 24);
|
||||
imlib_b_xor(&temp_image_2, NULL, &temp_image, NULL);
|
||||
imlib_erode(&temp_image_2, 2, 24, NULL);
|
||||
|
||||
int not_shadow_r_sum = 0;
|
||||
int not_shadow_g_sum = 0;
|
||||
@ -337,9 +341,9 @@ void imlib_remove_shadows(image_t *img, const char *path, image_t *other)
|
||||
|
||||
memcpy(temp_image.data, temp_image_2.data, image_size(&temp_image_2));
|
||||
|
||||
imlib_erode(&temp_image_2, 1, 8);
|
||||
imlib_b_xor(&temp_image, NULL, &temp_image_2);
|
||||
imlib_dilate(&temp_image, 3, 0);
|
||||
imlib_erode(&temp_image_2, 1, 8, NULL);
|
||||
imlib_b_xor(&temp_image, NULL, &temp_image_2, NULL);
|
||||
imlib_dilate(&temp_image, 3, 0, NULL);
|
||||
imlib_median_filter(img, 2, 12, false, 0, false, &temp_image);
|
||||
|
||||
fb_free(); // temp_image_2
|
||||
|
||||
@ -955,44 +955,19 @@ static mp_obj_t py_image_binary(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
mp_uint_t arg_t_len;
|
||||
mp_obj_t *arg_t;
|
||||
mp_obj_get_array(args[1], &arg_t_len, &arg_t);
|
||||
if (!arg_t_len) return mp_const_none;
|
||||
list_t thresholds;
|
||||
list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t));
|
||||
py_helper_arg_to_thresholds(args[1], &thresholds);
|
||||
|
||||
simple_color_t l_t[arg_t_len], u_t[arg_t_len];
|
||||
if (IM_IS_GS(arg_img)) {
|
||||
for (int i=0; i<arg_t_len; i++) {
|
||||
mp_obj_t *temp;
|
||||
mp_obj_get_array_fixed_n(arg_t[i], 2, &temp);
|
||||
int lo = mp_obj_get_int(temp[0]);
|
||||
int hi = mp_obj_get_int(temp[1]);
|
||||
// Swap ranges if they are wrong.
|
||||
l_t[i].G = IM_MIN(lo, hi);
|
||||
u_t[i].G = IM_MAX(lo, hi);
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<arg_t_len; i++) {
|
||||
mp_obj_t *temp;
|
||||
mp_obj_get_array_fixed_n(arg_t[i], 6, &temp);
|
||||
int l_lo = mp_obj_get_int(temp[0]);
|
||||
int l_hi = mp_obj_get_int(temp[1]);
|
||||
int a_lo = mp_obj_get_int(temp[2]);
|
||||
int a_hi = mp_obj_get_int(temp[3]);
|
||||
int b_lo = mp_obj_get_int(temp[4]);
|
||||
int b_hi = mp_obj_get_int(temp[5]);
|
||||
// Swap ranges if they are wrong.
|
||||
l_t[i].L = IM_MIN(l_lo, l_hi);
|
||||
u_t[i].L = IM_MAX(l_lo, l_hi);
|
||||
l_t[i].A = IM_MIN(a_lo, a_hi);
|
||||
u_t[i].A = IM_MAX(a_lo, a_hi);
|
||||
l_t[i].B = IM_MIN(b_lo, b_hi);
|
||||
u_t[i].B = IM_MAX(b_lo, b_hi);
|
||||
}
|
||||
}
|
||||
bool invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert),
|
||||
(n_args > 2) ? mp_obj_get_int(args[2]) : false);
|
||||
|
||||
bool zero = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_zero),
|
||||
(n_args > 3) ? mp_obj_get_int(args[3]) : false);
|
||||
|
||||
imlib_binary(arg_img, &thresholds, invert, zero);
|
||||
list_free(&thresholds);
|
||||
|
||||
int arg_invert = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_invert), 0);
|
||||
imlib_binary(arg_img, arg_t_len, l_t, u_t, arg_invert ? 1 : 0);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
@ -1005,88 +980,154 @@ static mp_obj_t py_image_invert(mp_obj_t img_obj)
|
||||
return img_obj;
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_and(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_and(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_and(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_and(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_and(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_and(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_nand(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_nand(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_nand(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_nand(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_nand(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_nand(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_or(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_or(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_or(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_or(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_or(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_or(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_nor(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_nor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_nor(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_nor(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_nor(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_nor(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_xor(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_xor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_xor(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_xor(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_xor(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_xor(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_b_xnor(mp_obj_t img_obj, mp_obj_t other_obj)
|
||||
static mp_obj_t py_image_b_xnor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
{
|
||||
image_t *arg_img = py_image_cobj(img_obj);
|
||||
image_t *arg_img = py_image_cobj(args[0]);
|
||||
PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported.");
|
||||
|
||||
if (MP_OBJ_IS_STR(other_obj)) {
|
||||
imlib_b_xnor(arg_img, mp_obj_str_get_str(other_obj), NULL);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
if (MP_OBJ_IS_STR(args[1])) {
|
||||
fb_alloc_mark();
|
||||
imlib_b_xnor(arg_img, mp_obj_str_get_str(args[1]), NULL,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_mark();
|
||||
} else {
|
||||
image_t *arg_other = py_image_cobj(other_obj);
|
||||
imlib_b_xnor(arg_img, NULL, arg_other);
|
||||
image_t *arg_other = py_image_cobj(args[1]);
|
||||
fb_alloc_mark();
|
||||
imlib_b_xnor(arg_img, NULL, arg_other,
|
||||
(kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 2) ? py_image_cobj(args[2]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
}
|
||||
return img_obj;
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
static mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||
@ -1096,9 +1137,16 @@ static mp_obj_t py_image_erode(uint n_args, const mp_obj_t *args, mp_map_t *kw_a
|
||||
|
||||
int arg_ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
imlib_erode(arg_img, arg_ksize,
|
||||
py_helper_lookup_int(kw_args,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_threshold), ((arg_ksize*2)+1)*((arg_ksize*2)+1)-1));
|
||||
|
||||
int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold),
|
||||
(n_args > 2) ? mp_obj_get_int(args[2]) : ((((arg_ksize*2)+1)*((arg_ksize*2)+1))-1));
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
fb_alloc_mark();
|
||||
imlib_erode(arg_img, arg_ksize, threshold, (kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 3) ? py_image_cobj(args[3]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
@ -1109,9 +1157,16 @@ static mp_obj_t py_image_dilate(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
||||
|
||||
int arg_ksize = mp_obj_get_int(args[1]);
|
||||
PY_ASSERT_TRUE_MSG(arg_ksize >= 0, "Kernel Size must be >= 0");
|
||||
imlib_dilate(arg_img, arg_ksize,
|
||||
py_helper_lookup_int(kw_args,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_threshold), 0));
|
||||
|
||||
int threshold = py_helper_lookup_int(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_threshold),
|
||||
(n_args > 2) ? mp_obj_get_int(args[2]) : 0);
|
||||
mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), MP_MAP_LOOKUP);
|
||||
|
||||
fb_alloc_mark();
|
||||
imlib_dilate(arg_img, arg_ksize, threshold, (kw_arg != NULL) ? py_image_cobj(kw_arg->value) :
|
||||
((n_args > 3) ? py_image_cobj(args[3]) : NULL));
|
||||
fb_alloc_free_till_mark();
|
||||
|
||||
return args[0];
|
||||
}
|
||||
|
||||
@ -4293,15 +4348,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_circle_obj, 4, py_image_draw_cir
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_string_obj, 4, py_image_draw_string);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_cross_obj, 3, py_image_draw_cross);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_draw_keypoints_obj, 2, py_image_draw_keypoints);
|
||||
/* Binary functions */
|
||||
/* Binary Methods */
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_binary_obj, 2, py_image_binary);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_invert_obj, py_image_invert);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_and_obj, py_image_b_and);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_nand_obj, py_image_b_nand);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_or_obj, py_image_b_or);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_nor_obj, py_image_b_nor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_xor_obj, py_image_b_xor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_b_xnor_obj, py_image_b_xnor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_and_obj, 2, py_image_b_and);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nand_obj, 2, py_image_b_nand);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_or_obj, 2, py_image_b_or);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_nor_obj, 2, py_image_b_nor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xor_obj, 2, py_image_b_xor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_b_xnor_obj, 2, py_image_b_xnor);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_erode_obj, 2, py_image_erode);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_dilate_obj, 2, py_image_dilate);
|
||||
/* Background Subtraction (Frame Differencing) functions */
|
||||
@ -4418,7 +4473,7 @@ static const mp_map_elem_t locals_dict_table[] = {
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_string), (mp_obj_t)&py_image_draw_string_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_cross), (mp_obj_t)&py_image_draw_cross_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_draw_keypoints), (mp_obj_t)&py_image_draw_keypoints_obj},
|
||||
/* Binary functions */
|
||||
/* Binary Methods */
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_binary), (mp_obj_t)&py_image_binary_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_invert), (mp_obj_t)&py_image_invert_obj},
|
||||
{MP_OBJ_NEW_QSTR(MP_QSTR_and), (mp_obj_t)&py_image_b_and_obj},
|
||||
|
||||
@ -46,22 +46,6 @@ Q(draw_circle)
|
||||
Q(draw_string)
|
||||
Q(draw_cross)
|
||||
Q(draw_keypoints)
|
||||
Q(binary)
|
||||
Q(invert)
|
||||
Q(and)
|
||||
Q(b_and)
|
||||
Q(nand)
|
||||
Q(b_nand)
|
||||
Q(or)
|
||||
Q(b_or)
|
||||
Q(nor)
|
||||
Q(b_nor)
|
||||
Q(xor)
|
||||
Q(b_xor)
|
||||
Q(xnor)
|
||||
Q(b_xnor)
|
||||
Q(erode)
|
||||
Q(dilate)
|
||||
Q(negate)
|
||||
Q(difference)
|
||||
Q(replace)
|
||||
@ -349,6 +333,54 @@ Q(CPUFREQ_216MHZ)
|
||||
Q(get_frequency)
|
||||
Q(set_frequency)
|
||||
|
||||
// Binary
|
||||
Q(binary)
|
||||
Q(invert)
|
||||
Q(zero)
|
||||
|
||||
// Invert
|
||||
// duplicate Q(invert)
|
||||
|
||||
// And
|
||||
Q(and)
|
||||
Q(b_and)
|
||||
Q(mask)
|
||||
|
||||
// Nand
|
||||
Q(nand)
|
||||
Q(b_nand)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Or
|
||||
Q(or)
|
||||
Q(b_or)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Nor
|
||||
Q(nor)
|
||||
Q(b_nor)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Xor
|
||||
Q(xor)
|
||||
Q(b_xor)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Xnor
|
||||
Q(xnor)
|
||||
Q(b_xnor)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Erode
|
||||
Q(erode)
|
||||
// duplicate Q(threshold)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Dilate
|
||||
Q(dilate)
|
||||
// duplicate Q(threshold)
|
||||
// duplicate Q(mask)
|
||||
|
||||
// Max
|
||||
// duplicate Q(max)
|
||||
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
# Color Binary Filter Example
|
||||
#
|
||||
# This script shows off the binary image filter. This script was originally a
|
||||
# test script... but, it can be useful for showing how to use binary.
|
||||
# This script shows off the binary image filter. You may pass binary any
|
||||
# number of thresholds to segment the image by.
|
||||
|
||||
import pyb, sensor, image, math
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset()
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
sensor.set_pixformat(sensor.RGB565)
|
||||
sensor.skip_frames(time = 2000)
|
||||
clock = time.clock()
|
||||
|
||||
# Use the Tools -> Machine Vision -> Threshold Edtor to pick better thresholds.
|
||||
red_threshold = (0,100, 0,127, 0,127) # L A B
|
||||
green_threshold = (0,100, -128,0, 0,127) # L A B
|
||||
blue_threshold = (0,100, -128,127, -128,0) # L A B
|
||||
@ -17,25 +20,42 @@ while(True):
|
||||
|
||||
# Test red threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([red_threshold])
|
||||
print(clock.fps())
|
||||
|
||||
# Test green threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([green_threshold])
|
||||
print(clock.fps())
|
||||
|
||||
# Test blue threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([blue_threshold])
|
||||
print(clock.fps())
|
||||
|
||||
# Test not red threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([red_threshold], invert = 1)
|
||||
print(clock.fps())
|
||||
|
||||
# Test not green threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([green_threshold], invert = 1)
|
||||
print(clock.fps())
|
||||
|
||||
# Test not blue threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([blue_threshold], invert = 1)
|
||||
print(clock.fps())
|
||||
|
||||
25
usr/examples/04-Image-Filters/color_light_removal.py
Normal file
25
usr/examples/04-Image-Filters/color_light_removal.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Color Light Removal
|
||||
#
|
||||
# This example shows off how to remove bright lights from the image.
|
||||
# You can do this using the binary() method with the "zero=" argument.
|
||||
#
|
||||
# Removing bright lights from the image allows you to now use
|
||||
# histeq() on the image without outliers from oversaturated
|
||||
# parts of the image breaking the algorithm...
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
thresholds = (90, 100, -128, 127, -128, 127)
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot().binary([thresholds], invert=False, zero=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
@ -1,31 +1,45 @@
|
||||
# Grayscale Binary Filter Example
|
||||
#
|
||||
# This script shows off the binary image filter. This script was originally a
|
||||
# test script... but, it can be useful for showing how to use binary.
|
||||
# This script shows off the binary image filter. You may pass binary any
|
||||
# number of thresholds to segment the image by.
|
||||
|
||||
import pyb, sensor, image, math
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset()
|
||||
sensor.set_framesize(sensor.QVGA)
|
||||
sensor.set_pixformat(sensor.GRAYSCALE)
|
||||
sensor.skip_frames(time = 2000)
|
||||
clock = time.clock()
|
||||
|
||||
low_threshold = (0, 50)
|
||||
high_threshold = (205, 255)
|
||||
|
||||
while(True):
|
||||
|
||||
# Test low threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([low_threshold])
|
||||
print(clock.fps())
|
||||
|
||||
# Test high threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([high_threshold])
|
||||
print(clock.fps())
|
||||
|
||||
# Test not low threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([low_threshold], invert = 1)
|
||||
print(clock.fps())
|
||||
|
||||
# Test not high threshold
|
||||
for i in range(100):
|
||||
clock.tick()
|
||||
img = sensor.snapshot()
|
||||
img.binary([high_threshold], invert = 1)
|
||||
print(clock.fps())
|
||||
|
||||
25
usr/examples/04-Image-Filters/grayscale_light_removal.py
Normal file
25
usr/examples/04-Image-Filters/grayscale_light_removal.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Grayscale Light Removal
|
||||
#
|
||||
# This example shows off how to remove bright lights from the image.
|
||||
# You can do this using the binary() method with the "zero=" argument.
|
||||
#
|
||||
# Removing bright lights from the image allows you to now use
|
||||
# histeq() on the image without outliers from oversaturated
|
||||
# parts of the image breaking the algorithm...
|
||||
|
||||
import sensor, image, time
|
||||
|
||||
sensor.reset() # Initialize the camera sensor.
|
||||
sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.RGB565
|
||||
sensor.set_framesize(sensor.QQVGA) # or sensor.QVGA (or others)
|
||||
sensor.skip_frames(time = 2000) # Let new settings take affect.
|
||||
clock = time.clock() # Tracks FPS.
|
||||
|
||||
thresholds = (220, 255)
|
||||
|
||||
while(True):
|
||||
clock.tick() # Track elapsed milliseconds between snapshots().
|
||||
img = sensor.snapshot().binary([thresholds], invert=False, zero=True)
|
||||
|
||||
print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
|
||||
# connected to your computer. The FPS should increase once disconnected.
|
||||
Loading…
Reference in New Issue
Block a user