mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #2293 from kwagyeman/kwabena/pack_unpack_2
modules/py_ml: Make predict output a numpy array.
This commit is contained in:
commit
5df4e84699
@ -43,7 +43,7 @@ while True:
|
||||
# This combines the labels and confidence values into a list of tuples
|
||||
# and then sorts that list by the confidence values.
|
||||
sorted_list = sorted(
|
||||
zip(labels, model.predict([img])[0]), key=lambda x: x[1], reverse=True
|
||||
zip(labels, model.predict([img])[0].flatten().tolist()), key=lambda x: x[1], reverse=True
|
||||
)
|
||||
for i in range(5):
|
||||
print("%s = %f" % (sorted_list[i][0], sorted_list[i][1]))
|
||||
|
||||
@ -23,6 +23,7 @@ threshold_list = [(math.ceil(min_confidence * 255), 255)]
|
||||
|
||||
# Load built-in FOMO face detection model
|
||||
model = ml.Model("fomo_face_detection")
|
||||
print(model)
|
||||
|
||||
# Alternatively, models can be loaded from the filesystem storage.
|
||||
# model = ml.Model('<object_detection_modelwork>.tflite', load_to_fb=True)
|
||||
@ -50,7 +51,7 @@ def fomo_post_process(model, inputs, outputs):
|
||||
n, oh, ow, oc = model.output_shape[0]
|
||||
nms = NMS(ow, oh, inputs[0].roi)
|
||||
for i in range(oc):
|
||||
img = image.Image(outputs[0], shape=(oh, ow, 1), strides=(i, oc), scale=(0, 1))
|
||||
img = image.Image(outputs[0][0, :, :, i] * 255)
|
||||
blobs = img.find_blobs(
|
||||
threshold_list, x_stride=1, area_threshold=1, pixels_threshold=1
|
||||
)
|
||||
@ -81,6 +82,6 @@ while True:
|
||||
center_x = math.floor(x + (w / 2))
|
||||
center_y = math.floor(y + (h / 2))
|
||||
print(f"x {center_x}\ty {center_y}\tscore {score}")
|
||||
img.draw_circle((center_x, center_y, 12), color=colors[i], thickness=2)
|
||||
img.draw_circle((center_x, center_y, 12), color=colors[i])
|
||||
|
||||
print(clock.fps(), "fps", end="\n")
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
|
||||
import image
|
||||
from ulab import numpy as np
|
||||
|
||||
|
||||
class Normalization:
|
||||
@ -34,6 +35,7 @@ class Normalization:
|
||||
return n
|
||||
|
||||
buffer, shape, dtype = args
|
||||
|
||||
# Create an image using the input tensor as buffer.
|
||||
if len(shape) != 4:
|
||||
raise ValueError("Expected input tensor with shape: (1, H, W, C)")
|
||||
@ -42,12 +44,32 @@ class Normalization:
|
||||
raise ValueError("Expected batches to be 1")
|
||||
if c != 1 and c != 3:
|
||||
raise ValueError("Expected channels to be 1 or 3")
|
||||
|
||||
# Place the image buffer at the end of the input buffer so we can convert it in-place.
|
||||
pixfmt = image.GRAYSCALE if c == 1 else image.RGB565
|
||||
img = image.Image(w, h, pixfmt, buffer=buffer)
|
||||
offset = len(buffer) - (w * h * (1 if c == 1 else 2))
|
||||
img = image.Image(w, h, pixfmt, buffer=memoryview(buffer)[offset:])
|
||||
|
||||
# Copy and scale (if needed) the input image to the input buffer.
|
||||
hints = image.BILINEAR | image.CENTER | image.SCALE_ASPECT_EXPAND | image.BLACK_BACKGROUND
|
||||
img.draw_image(self._image, 0, 0, roi=self.roi, hint=hints)
|
||||
|
||||
# Scale and convert the image to input tensor data.
|
||||
img.unpack(buffer, dtype, scale=self.scale, mean=self.mean, stdev=self.stdev)
|
||||
# Convert the image in-place into an ndarray input tensor.
|
||||
array = img.to_ndarray(dtype, buffer=buffer)
|
||||
|
||||
# Normalize the input tensor.
|
||||
if dtype == ord('f'):
|
||||
fscale = (self.scale[1] - self.scale[0]) / 255.0
|
||||
fadd = self.scale[0]
|
||||
|
||||
def grayscale(x):
|
||||
return (x[0] * 0.299) + (x[1] * 0.587) + (x[2] * 0.114)
|
||||
|
||||
if c == 1:
|
||||
fadd = (fadd - grayscale(self.mean)) / grayscale(self.stdev)
|
||||
fscale = fscale / grayscale(self.stdev)
|
||||
else:
|
||||
fadd = (fadd - np.array(self.mean)) / np.array(self.stdev)
|
||||
fscale = fscale / np.array(self.stdev)
|
||||
|
||||
array = (array * fscale) + fadd
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
#define IMLIB_ENABLE_MATH_OPS
|
||||
|
||||
// Enable flood_fill()
|
||||
#define IMLIB_ENABLE_FLOOD_FILL
|
||||
// #define IMLIB_ENABLE_FLOOD_FILL
|
||||
|
||||
// Enable mean()
|
||||
#define IMLIB_ENABLE_MEAN
|
||||
@ -42,10 +42,10 @@
|
||||
#define IMLIB_ENABLE_MEDIAN
|
||||
|
||||
// Enable mode()
|
||||
#define IMLIB_ENABLE_MODE
|
||||
// #define IMLIB_ENABLE_MODE
|
||||
|
||||
// Enable midpoint()
|
||||
#define IMLIB_ENABLE_MIDPOINT
|
||||
// #define IMLIB_ENABLE_MIDPOINT
|
||||
|
||||
// Enable morph()
|
||||
#define IMLIB_ENABLE_MORPH
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define NDARRAY_BINARY_USES_FUN_POINTER (1)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -111,8 +111,8 @@
|
||||
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
#define NDARRAY_BINARY_USES_FUN_POINTER (1)
|
||||
|
||||
@ -111,7 +111,7 @@
|
||||
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define NDARRAY_BINARY_USES_FUN_POINTER (1)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define NDARRAY_BINARY_USES_FUN_POINTER (1)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
// Enable find_features() and built-in Haar cascades. (75KBs)
|
||||
#define IMLIB_ENABLE_FEATURES
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_FACE_CASCADE
|
||||
#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
//#define IMLIB_ENABLE_FEATURES_BUILTIN_EYES_CASCADE
|
||||
|
||||
// Enable Tensor Flow
|
||||
#if !defined(CUBEAI)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#ifndef __ULAB_CONFIG_H__
|
||||
#define __ULAB_CONFIG_H__
|
||||
// Override ulab defaults here.
|
||||
#define ULAB_MAX_DIMS (4)
|
||||
#define ULAB_SUPPORTS_COMPLEX (0)
|
||||
#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1)
|
||||
#define ULAB_SCIPY_HAS_SPECIAL_MODULE (0)
|
||||
|
||||
@ -423,95 +423,6 @@ void imlib_fill_image_from_float(image_t *img, int w, int h, float *data, float
|
||||
}
|
||||
}
|
||||
|
||||
// Unpacks src into dst. dst must be an array of src->w*src->h*dtype*channels bytes, where channels is
|
||||
// 1 for grayscale and 3 for RGB.
|
||||
void imlib_unpack(void *dst, image_t *src, const char dtype, float *scale, float *mean, float *stdev) {
|
||||
// src will be unpacked into dst in reverse order so that we can handle in-place unpacking.
|
||||
int size = (src->w * src->h) - 1; // must be int per countdown loop
|
||||
float fscale = 1.0f, fadd = 0.0f;
|
||||
|
||||
if (scale[0] == 0.0f && scale[1] == 1.0f) {
|
||||
fscale = 1.0f / 255.0f;
|
||||
} else if (scale[0] == -1.0f && scale[1] == 1.0f) {
|
||||
fscale = 2.0f / 255.0f;
|
||||
fadd = -1.0f;
|
||||
} else if (scale[0] == -128.0f && scale[1] == 127.0f) {
|
||||
fadd = -128.0f;
|
||||
}
|
||||
|
||||
float fscale_r = fscale, fadd_r = fadd;
|
||||
float fscale_g = fscale, fadd_g = fadd;
|
||||
float fscale_b = fscale, fadd_b = fadd;
|
||||
|
||||
// To normalize the input image we need to subtract the mean and divide by the standard deviation.
|
||||
// We can do this by applying the normalization to fscale and fadd outside the loop.
|
||||
// Red
|
||||
fadd_r = (fadd_r - mean[0]) / stdev[0];
|
||||
fscale_r /= stdev[0];
|
||||
|
||||
// Green
|
||||
fadd_g = (fadd_g - mean[1]) / stdev[1];
|
||||
fscale_g /= stdev[1];
|
||||
|
||||
// Blue
|
||||
fadd_b = (fadd_b - mean[2]) / stdev[2];
|
||||
fscale_b /= stdev[2];
|
||||
|
||||
// Grayscale -> Y = 0.299R + 0.587G + 0.114B
|
||||
float m = (mean[0] * 0.299f) + (mean[1] * 0.587f) + (mean[2] * 0.114f);
|
||||
float s = (stdev[0] * 0.299f) + (stdev[1] * 0.587f) + (stdev[2] * 0.114f);
|
||||
fadd = (fadd - m) / s;
|
||||
fscale /= s;
|
||||
|
||||
if (src->pixfmt == PIXFORMAT_GRAYSCALE) {
|
||||
uint8_t *input_u8 = (uint8_t *) src->data;
|
||||
if (dtype == 'f') {
|
||||
// convert u8 -> f32
|
||||
float *output_f32 = (float *) dst;
|
||||
for (; size >= 0; size -= 1) {
|
||||
output_f32[size] = (input_u8[size] * fscale) + fadd;
|
||||
}
|
||||
} else {
|
||||
// convert u8 -> s8
|
||||
#if (__ARM_ARCH > 6)
|
||||
uint32_t *input_u32 = (uint32_t *) src->data;
|
||||
uint32_t *output_u32 = (uint32_t *) dst;
|
||||
for (; size >= 3; size -= 4) {
|
||||
output_u32[size / 4] = input_u32[size / 4] ^ 0x80808080;
|
||||
}
|
||||
#endif
|
||||
uint8_t *input_u8 = (uint8_t *) src->data;
|
||||
uint8_t *output_u8 = (uint8_t *) dst;
|
||||
for (; size >= 0; size -= 1) {
|
||||
output_u8[size] = input_u8[size] ^ 128;
|
||||
}
|
||||
}
|
||||
} else if (src->pixfmt == PIXFORMAT_RGB565) {
|
||||
int rgb_size = size * 3; // must be int per countdown loop
|
||||
if (dtype == 'f') {
|
||||
uint16_t *input_u16 = (uint16_t *) src->data;
|
||||
float *output_f32 = (float *) dst;
|
||||
for (; size >= 0; size -= 1, rgb_size -= 3) {
|
||||
int pixel = input_u16[size];
|
||||
output_f32[rgb_size + 0] = (COLOR_RGB565_TO_R8(pixel) * fscale_r) + fadd_r;
|
||||
output_f32[rgb_size + 1] = (COLOR_RGB565_TO_G8(pixel) * fscale_g) + fadd_g;
|
||||
output_f32[rgb_size + 2] = (COLOR_RGB565_TO_B8(pixel) * fscale_b) + fadd_b;
|
||||
}
|
||||
} else {
|
||||
uint16_t *input_u16 = (uint16_t *) src->data;
|
||||
uint8_t *output_u8 = (uint8_t *) dst;
|
||||
for (; size >= 0; size -= 1, rgb_size -= 3) {
|
||||
int pixel = input_u16[size];
|
||||
output_u8[rgb_size + 0] = COLOR_RGB565_TO_R8(pixel) ^ 128;
|
||||
output_u8[rgb_size + 1] = COLOR_RGB565_TO_G8(pixel) ^ 128;
|
||||
output_u8[rgb_size + 2] = COLOR_RGB565_TO_B8(pixel) ^ 128;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected input channels to be 1 or 3"));
|
||||
}
|
||||
}
|
||||
|
||||
int8_t imlib_rgb565_to_l(uint16_t pixel) {
|
||||
float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)];
|
||||
float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)];
|
||||
|
||||
@ -1161,7 +1161,6 @@ void imlib_deinit_all();
|
||||
// Generic Helper Functions
|
||||
void imlib_fill_image_from_float(image_t *img, int w, int h, float *data, float min, float max,
|
||||
bool mirror, bool flip, bool dst_transpose, bool src_transpose);
|
||||
void imlib_unpack(void *dst, image_t *src, const char dtype, float *scale, float *mean, float *stdev);
|
||||
|
||||
// Bayer Image Processing
|
||||
pixformat_t imlib_bayer_shift(pixformat_t pixfmt, int x, int y, bool transpose);
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#if defined(IMLIB_ENABLE_IMAGE_IO)
|
||||
#include "py_imageio.h"
|
||||
#endif
|
||||
#include "ulab/code/ndarray.h"
|
||||
|
||||
const mp_obj_type_t py_image_type;
|
||||
|
||||
@ -724,22 +725,19 @@ static mp_obj_t py_image_bytearray(mp_obj_t img_obj) {
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(py_image_bytearray_obj, py_image_bytearray);
|
||||
|
||||
static mp_obj_t py_image_unpack(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_buffer, ARG_dtype, ARG_scale, ARG_mean, ARG_stdev };
|
||||
#if defined(MODULE_ULAB_ENABLED) && (ULAB_MAX_DIMS == 4)
|
||||
static mp_obj_t py_image_to_ndarray(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_dtype, ARG_buffer };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_dtype, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_scale, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_mean, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_stdev, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
|
||||
image_t *image = py_helper_arg_to_image(pos_args[0], ARG_IMAGE_ANY);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_buffer_info_t bufinfo = {0};
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
int len = image->w * image->h;
|
||||
|
||||
int dtype_code;
|
||||
int dtype_size;
|
||||
@ -752,7 +750,6 @@ static mp_obj_t py_image_unpack(uint n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
}
|
||||
|
||||
switch (dtype_code) {
|
||||
case 'c':
|
||||
case 'b':
|
||||
case 'B': {
|
||||
dtype_size = 1;
|
||||
@ -768,14 +765,24 @@ static mp_obj_t py_image_unpack(uint n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
}
|
||||
}
|
||||
|
||||
size_t shape[ULAB_MAX_DIMS];
|
||||
size_t strides[ULAB_MAX_DIMS];
|
||||
int channels;
|
||||
int ndim;
|
||||
|
||||
switch (image->pixfmt) {
|
||||
case PIXFORMAT_GRAYSCALE: {
|
||||
memcpy(shape, (size_t []) {0, 0, image->h, image->w}, sizeof(shape));
|
||||
memcpy(strides, (size_t []) {0, 0, image->w * dtype_size, dtype_size}, sizeof(strides));
|
||||
channels = 1;
|
||||
ndim = 2;
|
||||
break;
|
||||
}
|
||||
case PIXFORMAT_RGB565: {
|
||||
memcpy(shape, (size_t []) {0, image->h, image->w, 3}, sizeof(shape));
|
||||
memcpy(strides, (size_t []) {0, image->w * dtype_size * 3, dtype_size * 3, dtype_size}, sizeof(strides));
|
||||
channels = 3;
|
||||
ndim = 3;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -784,24 +791,78 @@ static mp_obj_t py_image_unpack(uint n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
}
|
||||
}
|
||||
|
||||
if ((image->w * image->h * dtype_size * channels) > bufinfo.len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Buffer size is too small"));
|
||||
ndarray_obj_t *ndarray;
|
||||
|
||||
if (args[ARG_buffer].u_obj != mp_const_none) {
|
||||
mp_buffer_info_t bufinfo = {0};
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
if ((len * dtype_size * channels) > bufinfo.len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Buffer is too small"));
|
||||
}
|
||||
|
||||
ndarray = m_new_obj(ndarray_obj_t);
|
||||
ndarray->base.type = &ulab_ndarray_type;
|
||||
ndarray->dtype = dtype_code;
|
||||
ndarray->boolean = NDARRAY_NUMERIC;
|
||||
ndarray->ndim = ndim;
|
||||
ndarray->len = len * channels;
|
||||
ndarray->itemsize = dtype_size;
|
||||
memcpy(ndarray->shape, shape, sizeof(shape));
|
||||
memcpy(ndarray->strides, strides, sizeof(strides));
|
||||
ndarray->array = bufinfo.buf;
|
||||
ndarray->origin = bufinfo.buf;
|
||||
} else {
|
||||
ndarray = ndarray_new_dense_ndarray(ndim, shape, dtype_code);
|
||||
}
|
||||
|
||||
// scale, offset
|
||||
float scale[2] = {0.0f, 1.0f};
|
||||
py_helper_arg_to_float_array(args[ARG_scale].u_obj, scale, 2);
|
||||
int shift = (dtype_code == 'b') ? 0x80808080 : 0x00000000;
|
||||
|
||||
float mean[3] = {0.0f, 0.0f, 0.0f};
|
||||
py_helper_arg_to_float_array(args[ARG_mean].u_obj, mean, 3);
|
||||
if (image->pixfmt == PIXFORMAT_GRAYSCALE) {
|
||||
uint8_t *input_u8 = (uint8_t *) image->data;
|
||||
if (dtype_code == 'f') {
|
||||
float *output_f32 = (float *) ndarray->array;
|
||||
for (int i = 0; i < len; i++) {
|
||||
output_f32[i] = input_u8[i];
|
||||
}
|
||||
} else {
|
||||
uint8_t *output_u8 = (uint8_t *) ndarray->array;
|
||||
|
||||
float stdev[3] = {1.0f, 1.0f, 1.0f};
|
||||
py_helper_arg_to_float_array(args[ARG_stdev].u_obj, stdev, 3);
|
||||
int i = 0;
|
||||
|
||||
imlib_unpack(bufinfo.buf, image, dtype_code, scale, mean, stdev);
|
||||
return pos_args[0];
|
||||
for (; i < len; i += 4) {
|
||||
*((uint32_t *) (output_u8 + i)) = *((uint32_t *) (input_u8 + i)) ^ shift;
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
output_u8[i] = input_u8[i] ^ shift;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint16_t *input_u16 = (uint16_t *) image->data;
|
||||
if (dtype_code == 'f') {
|
||||
float *output_f32 = (float *) ndarray->array;
|
||||
for (int i = 0, j = 0; i < len; i++, j += 3) {
|
||||
int pixel = input_u16[i];
|
||||
output_f32[j + 0] = COLOR_RGB565_TO_R8(pixel);
|
||||
output_f32[j + 1] = COLOR_RGB565_TO_G8(pixel);
|
||||
output_f32[j + 2] = COLOR_RGB565_TO_B8(pixel);
|
||||
}
|
||||
} else {
|
||||
uint8_t *output_u8 = (uint8_t *) ndarray->array;
|
||||
for (int i = 0, j = 0; i < len; i++, j += 3) {
|
||||
int pixel = input_u16[i];
|
||||
output_u8[j + 0] = COLOR_RGB565_TO_R8(pixel) ^ shift;
|
||||
output_u8[j + 1] = COLOR_RGB565_TO_G8(pixel) ^ shift;
|
||||
output_u8[j + 2] = COLOR_RGB565_TO_B8(pixel) ^ shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_unpack_obj, 1, py_image_unpack);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(py_image_to_ndarray_obj, 1, py_image_to_ndarray);
|
||||
#endif
|
||||
|
||||
static mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
image_t *arg_img = py_helper_arg_to_image(args[0], ARG_IMAGE_UNCOMPRESSED);
|
||||
@ -6330,9 +6391,6 @@ mp_obj_t py_image_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw
|
||||
{ MP_QSTR_pixformat, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_copy_to_fb, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
|
||||
{ MP_QSTR_shape, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_strides, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_scale, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
@ -6361,97 +6419,68 @@ mp_obj_t py_image_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw
|
||||
#else
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
||||
#endif // IMLIB_ENABLE_IMAGE_FILE_IO
|
||||
} else if (MP_OBJ_IS_TYPE(args[ARG_arg].u_obj, &mp_type_tuple) ||
|
||||
MP_OBJ_IS_TYPE(args[ARG_arg].u_obj, &mp_type_list)) {
|
||||
mp_obj_t *shape;
|
||||
mp_obj_get_array_fixed_n(args[ARG_shape].u_obj, 3, &shape);
|
||||
#if defined(MODULE_ULAB_ENABLED) && (ULAB_MAX_DIMS >= 3)
|
||||
} else if (MP_OBJ_IS_TYPE(args[ARG_arg].u_obj, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *array = MP_OBJ_TO_PTR(args[ARG_arg].u_obj);
|
||||
|
||||
image.h = mp_obj_get_int(shape[0]);
|
||||
PY_ASSERT_TRUE_MSG(image.h > 0, "Image height must be > 0");
|
||||
if (array->dtype != NDARRAY_FLOAT) {
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a ndarray with dtype float"));
|
||||
}
|
||||
|
||||
image.w = mp_obj_get_int(shape[1]);
|
||||
PY_ASSERT_TRUE_MSG(image.w > 0, "Image width must be > 0");
|
||||
if (!((array->ndim == 2) || ((array->ndim == 3) && (array->shape[ULAB_MAX_DIMS - 1] == 3)))) {
|
||||
mp_raise_msg(&mp_type_ValueError,
|
||||
MP_ERROR_TEXT("Expected a ndarray with shape (height, width) or (height, width, 3"));
|
||||
}
|
||||
|
||||
int channels = mp_obj_get_int(shape[2]);
|
||||
|
||||
if (channels == 1) {
|
||||
if (array->ndim == 2) {
|
||||
image.w = array->shape[ULAB_MAX_DIMS - 1];
|
||||
image.h = array->shape[ULAB_MAX_DIMS - 2];
|
||||
image.pixfmt = PIXFORMAT_GRAYSCALE;
|
||||
} else if (channels == 3) {
|
||||
} else {
|
||||
image.w = array->shape[ULAB_MAX_DIMS - 2];
|
||||
image.h = array->shape[ULAB_MAX_DIMS - 3];
|
||||
image.pixfmt = PIXFORMAT_RGB565;
|
||||
} else {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Channels must be 1 or 3"));
|
||||
}
|
||||
|
||||
mp_obj_t *strides;
|
||||
mp_obj_get_array_fixed_n(args[ARG_strides].u_obj, 2, &strides);
|
||||
|
||||
int start = 0;
|
||||
int start_r = 0;
|
||||
int start_g = 0;
|
||||
int start_b = 0;
|
||||
|
||||
if (channels == 1) {
|
||||
start = mp_obj_get_int(strides[0]);
|
||||
PY_ASSERT_TRUE_MSG(start >= 0, "Start must be >= 0");
|
||||
} else {
|
||||
mp_obj_t *rgb_strides;
|
||||
mp_obj_get_array_fixed_n(strides[0], 3, &rgb_strides);
|
||||
|
||||
start_r = mp_obj_get_int(rgb_strides[0]);
|
||||
PY_ASSERT_TRUE_MSG(start_r >= 0, "R Start must be >= 0");
|
||||
|
||||
start_g = mp_obj_get_int(rgb_strides[1]);
|
||||
PY_ASSERT_TRUE_MSG(start_g >= 0, "G Start must be >= 0");
|
||||
|
||||
start_b = mp_obj_get_int(rgb_strides[2]);
|
||||
PY_ASSERT_TRUE_MSG(start_b >= 0, "B Start must be >= 0");
|
||||
}
|
||||
|
||||
int step = mp_obj_get_int(strides[1]);
|
||||
PY_ASSERT_TRUE_MSG(step > 0, "Step must be > 0");
|
||||
|
||||
mp_obj_t *items;
|
||||
size_t items_len;
|
||||
mp_obj_get_array(args[ARG_arg].u_obj, &items_len, &items);
|
||||
|
||||
int size = image.w * image.h;
|
||||
int step_max = (size - 1) * step;
|
||||
|
||||
if (channels == 1) {
|
||||
if (items_len <= (start + step_max)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Array too small"));
|
||||
}
|
||||
} else {
|
||||
if ((items_len <= (start_r + step_max)) ||
|
||||
(items_len <= (start_g + step_max)) ||
|
||||
(items_len <= (start_b + step_max))) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Array too small"));
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t *scale;
|
||||
mp_obj_get_array_fixed_n(args[ARG_scale].u_obj, 2, &scale);
|
||||
float fscale = 255.0f / (mp_obj_get_float(scale[1]) - mp_obj_get_float(scale[0]));
|
||||
float fadd = -mp_obj_get_float(scale[0]) * fscale;
|
||||
|
||||
if (args[ARG_copy_to_fb].u_bool) {
|
||||
py_helper_set_to_framebuffer(&image);
|
||||
} else if (args[ARG_buffer].u_obj != mp_const_none) {
|
||||
mp_buffer_info_t bufinfo = {0};
|
||||
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
|
||||
image.data = bufinfo.buf;
|
||||
if (image_size(&image) > bufinfo.len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Buffer is too small"));
|
||||
}
|
||||
} else {
|
||||
image.data = xalloc(image_size(&image));
|
||||
}
|
||||
|
||||
if (channels == 1) {
|
||||
for (int i = 0; i < size; i++, start += step) {
|
||||
((uint8_t *) image.data)[i] = __USAT(fast_roundf((mp_obj_get_float(items[start]) * fscale) + fadd), 8);
|
||||
mp_float_t *farray = (mp_float_t *) array->array;
|
||||
|
||||
if (image.pixfmt == PIXFORMAT_GRAYSCALE) {
|
||||
int y_stride = array->strides[ULAB_MAX_DIMS - 2] / array->itemsize;
|
||||
int x_stride = array->strides[ULAB_MAX_DIMS - 1] / array->itemsize;
|
||||
for (int y = 0, i = 0; y < image.h; y++, i += y_stride) {
|
||||
uint8_t *row = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&image, y);
|
||||
for (int x = 0, j = i; x < image.w; x++, j += x_stride) {
|
||||
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row, x, __USAT(fast_roundf(farray[j]), 8));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < size; i++, start_r += step, start_g += step, start_b += step) {
|
||||
int r = __USAT(fast_roundf((mp_obj_get_float(items[start_r]) * fscale) + fadd), 8);
|
||||
int g = __USAT(fast_roundf((mp_obj_get_float(items[start_g]) * fscale) + fadd), 8);
|
||||
int b = __USAT(fast_roundf((mp_obj_get_float(items[start_b]) * fscale) + fadd), 8);
|
||||
((uint16_t *) image.data)[i] = COLOR_R8_G8_B8_TO_RGB565(r, g, b);
|
||||
int y_stride = array->strides[ULAB_MAX_DIMS - 3] / array->itemsize;
|
||||
int x_stride = array->strides[ULAB_MAX_DIMS - 2] / array->itemsize;
|
||||
int c_stride = array->strides[ULAB_MAX_DIMS - 1] / array->itemsize;
|
||||
for (int y = 0, i = 0; y < image.h; y++, i += y_stride) {
|
||||
uint16_t *row = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&image, y);
|
||||
for (int x = 0, j = i; x < image.w; x++, j += x_stride) {
|
||||
int r = __USAT(fast_roundf(farray[j]), 8);
|
||||
int g = __USAT(fast_roundf(farray[j + c_stride]), 8);
|
||||
int b = __USAT(fast_roundf(farray[j + (c_stride * 2)]), 8);
|
||||
IMAGE_PUT_RGB565_PIXEL_FAST(row, x, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
image.w = mp_obj_get_int(args[ARG_arg].u_obj);
|
||||
PY_ASSERT_TRUE_MSG(image.w > 0, "Image width must be > 0");
|
||||
@ -6500,7 +6529,9 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
|
||||
{MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&py_image_format_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_image_size_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_bytearray), MP_ROM_PTR(&py_image_bytearray_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&py_image_unpack_obj)},
|
||||
#if defined(MODULE_ULAB_ENABLED) && (ULAB_MAX_DIMS == 4)
|
||||
{MP_ROM_QSTR(MP_QSTR_to_ndarray), MP_ROM_PTR(&py_image_to_ndarray_obj)},
|
||||
#endif
|
||||
{MP_ROM_QSTR(MP_QSTR_get_pixel), MP_ROM_PTR(&py_image_get_pixel_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_set_pixel), MP_ROM_PTR(&py_image_set_pixel_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_to_bitmap), MP_ROM_PTR(&py_image_to_bitmap_obj)},
|
||||
|
||||
@ -121,33 +121,45 @@ static mp_obj_t py_ml_process_output(py_ml_model_obj_t *model) {
|
||||
for (size_t i = 0; i < model->outputs_size; i++) {
|
||||
void *model_output = ml_backend_get_output(model, i);
|
||||
size_t size = py_ml_tuple_sum(MP_OBJ_TO_PTR(model->output_shape->items[i]));
|
||||
mp_obj_tuple_t *output = MP_OBJ_TO_PTR(mp_obj_new_tuple(size, NULL));
|
||||
mp_obj_tuple_t *output_shape = MP_OBJ_TO_PTR(model->output_shape->items[i]);
|
||||
float output_scale = mp_obj_get_float(model->output_scale->items[i]);
|
||||
int output_zero_point = mp_obj_get_int(model->output_zero_point->items[i]);
|
||||
int output_dtype = mp_obj_get_int(model->output_dtype->items[i]);
|
||||
|
||||
size_t shape[ULAB_MAX_DIMS] = {};
|
||||
|
||||
if (ULAB_MAX_DIMS < output_shape->len) {
|
||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Output shape has too many dimensions"));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < output_shape->len; j++) {
|
||||
size_t ulab_offset = ULAB_MAX_DIMS - output_shape->len;
|
||||
shape[ulab_offset + j] = mp_obj_get_int(output_shape->items[j]);
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(output_shape->len, shape, NDARRAY_FLOAT);
|
||||
|
||||
if (output_dtype == 'f') {
|
||||
for (size_t j = 0; j < size; j++) {
|
||||
output->items[j] = mp_obj_new_float(((float *) model_output)[j]);
|
||||
}
|
||||
memcpy(ndarray->array, model_output, size * sizeof(float));
|
||||
} else if (output_dtype == 'b') {
|
||||
for (size_t j = 0; j < size; j++) {
|
||||
float v = (((int8_t *) model_output)[j] - output_zero_point);
|
||||
output->items[j] = mp_obj_new_float(v * output_scale);
|
||||
((float *) ndarray->array)[j] = v * output_scale;
|
||||
}
|
||||
} else if (output_dtype == 'B') {
|
||||
for (size_t j = 0; j < size; j++) {
|
||||
float v = (((uint8_t *) model_output)[j] - output_zero_point);
|
||||
output->items[j] = mp_obj_new_float(v * output_scale);
|
||||
((float *) ndarray->array)[j] = v * output_scale;
|
||||
}
|
||||
} else {
|
||||
for (size_t j = 0; j < size; j++) {
|
||||
float v = (((int8_t *) model_output)[j] - output_zero_point);
|
||||
output->items[j] = mp_obj_new_float(v * output_scale);
|
||||
((float *) ndarray->array)[j] = v * output_scale;
|
||||
}
|
||||
}
|
||||
output_list->items[i] = MP_OBJ_FROM_PTR(output);
|
||||
output_list->items[i] = MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(output_list);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user