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:
Kwabena W. Agyeman 2018-02-25 00:14:30 -05:00
parent b8298c43cd
commit fb3d0776f0
13 changed files with 1080 additions and 442 deletions

View File

@ -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 \

View File

@ -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
View 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);
}

View File

@ -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, &lt, &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)

View File

@ -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)) {

View File

@ -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);

View File

@ -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

View File

@ -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},

View File

@ -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)

View File

@ -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())

View 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.

View File

@ -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())

View 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.