From 1121a6f7df9da0d0cc2ae1789c606d6e964f5c9b Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Fri, 26 Feb 2016 22:00:04 -0500 Subject: [PATCH] Fixed save image. It now figures out the file type from the file extension. If no file extension is given it just saves the file as BMP if its not a JPEG image or JPEG if it's a JPEG image. If you specify an extension and the file is not of that type then it will give you an error. The new test_save.py should run until you reach the JPEG image part where it quits due to lack of JPEG support natively on OV7725 boards. Maybe JPEG mode should be supoorted by just compressing pictures? --- src/omv/img/imlib.c | 112 +++++++++++++++++++++++++++++++++-------- src/omv/img/imlib.h | 8 +-- src/omv/mdefs.h | 4 ++ src/omv/py/py_image.c | 6 +-- src/omv/usbdbg.c | 2 +- usr/tests/test_save.py | 111 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+), 30 deletions(-) create mode 100644 usr/tests/test_save.py diff --git a/src/omv/img/imlib.c b/src/omv/img/imlib.c index 4398fbf8b..723848301 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -28,36 +28,101 @@ extern const uint16_t rainbow_table[256]; //////////////////////////////////////////////////////////////////////////////// -bool imlib_read_geometry(FIL *fp, image_t *image, const char *path, img_read_settings_t *rs) +static save_image_format_t imblib_parse_extension(image_t *img, const char *path) +{ + size_t l = strlen(path); + const char *p = path + l; + if (l >= 5) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'e') || (p[-2] == 'E')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == 'j') || (p[-4] == 'J')) + && ((p[-5] == '.') || (p[-5] == '.'))) { + if (!IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not JPEG!")); + } + return FORMAT_JPG; + } + } + if (l >= 4) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'j') || (p[-3] == 'J')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not JPG!")); + } + return FORMAT_JPG; + } else if (((p[-1] == 'p') || (p[-1] == 'P')) + && ((p[-2] == 'm') || (p[-2] == 'M')) + && ((p[-3] == 'b') || (p[-3] == 'B')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not BMP!")); + } + return FORMAT_BMP; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_RGB565(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not PPM!")); + } + return FORMAT_PNM; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'g') || (p[-2] == 'G')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_GS(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not PGM!")); + } + return FORMAT_PNM; + } + } + return FORMAT_DONT_CARE; +} + +bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) { file_read_open(fp, path); char magic[2]; read_data(fp, &magic, 2); file_close(fp); + bool vflipped = false; if ((magic[0]=='P') && ((magic[1]=='2') || (magic[1]=='3') || (magic[1]=='5') || (magic[1]=='6'))) { // PPM rs->format = FORMAT_PNM; - ppm_read_geometry(fp, image, path, &rs->ppm_rs); + ppm_read_geometry(fp, img, path, &rs->ppm_rs); } else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP rs->format = FORMAT_BMP; - return bmp_read_geometry(fp, image, path, &rs->bmp_rs); + vflipped = bmp_read_geometry(fp, img, path, &rs->bmp_rs); } else { ff_unsupported_format(NULL); } - return false; + imblib_parse_extension(img, path); // Enforce extension! + return vflipped; } void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs) { switch (rs->format) { + case FORMAT_DONT_CARE: // won't happen + break; case FORMAT_BMP: bmp_read_pixels(fp, img, line_start, line_end, &rs->bmp_rs); break; case FORMAT_PNM: ppm_read_pixels(fp, img, line_start, line_end, &rs->ppm_rs); break; + case FORMAT_JPG: // won't happen + break; } } @@ -80,25 +145,32 @@ void imlib_load_image(image_t *img, const char *path) } else { ff_unsupported_format(NULL); } + imblib_parse_extension(img, path); // Enforce extension! } -void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format) +void imlib_save_image(image_t *img, const char *path, rectangle_t *roi) { - if (IM_IS_JPEG(img)) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg"); - jpeg_write(img, new_path); - fb_free(); - } else if (format == FORMAT_BMP) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp"); - bmp_write_subimg(img, new_path, roi); - fb_free(); - } else if (format == FORMAT_PNM) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), - IM_IS_GS(img) ? ".pgm" : ".ppm"); - ppm_write_subimg(img, new_path, roi); - fb_free(); - } else { - ff_unsupported_format(NULL); + switch (imblib_parse_extension(img, path)) { + case FORMAT_DONT_CARE: + if (IM_IS_JPEG(img)) { + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg"); + jpeg_write(img, new_path); + fb_free(); + } else { + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp"); + bmp_write_subimg(img, new_path, roi); + fb_free(); + } + break; + case FORMAT_BMP: + bmp_write_subimg(img, path, roi); + break; + case FORMAT_PNM: + ppm_write_subimg(img, path, roi); + break; + case FORMAT_JPG: + jpeg_write(img, path); + break; } } diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index fa6366df5..e44f7b2bb 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -296,8 +296,10 @@ typedef struct ppm_read_settings { } ppm_read_settings_t; typedef enum save_image_format { + FORMAT_DONT_CARE, FORMAT_BMP, - FORMAT_PNM + FORMAT_PNM, + FORMAT_JPG } save_image_format_t; typedef struct img_read_settings { @@ -322,10 +324,8 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path); void jpeg_read_pixels(FIL *fp, image_t *img); void jpeg_read(image_t *img, const char *path); void jpeg_write(image_t *img, const char *path); -bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs); -void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs); void imlib_load_image(image_t *img, const char *path); -void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format); +void imlib_save_image(image_t *img, const char *path, rectangle_t *roi); /* Basic image functions */ int imlib_get_pixel(image_t *img, int x, int y); diff --git a/src/omv/mdefs.h b/src/omv/mdefs.h index a090ea13d..6153e6871 100644 --- a/src/omv/mdefs.h +++ b/src/omv/mdefs.h @@ -17,3 +17,7 @@ #ifndef DISABLE_OPT #define DISABLE_OPT __attribute__((optimize("O0"))) #endif + +#ifndef PRINT_LINE +#define PRINT_LINE printf("%s:%d\n", __FILE__, __LINE__) +#endif diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index ccd64ffd7..768b1a814 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -164,9 +164,7 @@ static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar rectangle_t roi; py_helper_lookup_rectangle(kw_args, arg_img, &roi); - imlib_save_image(arg_img, path, &roi, - py_helper_lookup_int(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_format), FORMAT_BMP)); + imlib_save_image(arg_img, path, &roi); return mp_const_true; } @@ -1202,8 +1200,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_match_keypoints_obj, 4, 4, p STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_lbp_obj, 2, py_image_match_lbp); static const mp_map_elem_t locals_dict_table[] = { - {MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_BMP), MP_OBJ_NEW_SMALL_INT(FORMAT_BMP)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_PNM), MP_OBJ_NEW_SMALL_INT(FORMAT_PNM)}, /* Image file functions */ {MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj}, /* Basic image functions */ diff --git a/src/omv/usbdbg.c b/src/omv/usbdbg.c index e4936440c..0cf7e5485 100644 --- a/src/omv/usbdbg.c +++ b/src/omv/usbdbg.c @@ -168,7 +168,7 @@ void usbdbg_data_out(void *buffer, int length) rectangle_t *roi = (rectangle_t*)buffer; char *path = (char*)buffer+sizeof(rectangle_t); - imlib_save_image(&image, path, roi, FORMAT_PNM); + imlib_save_image(&image, path, roi); // raise a flash IRQ to flush image //NVIC->STIR = FLASH_IRQn; break; diff --git a/usr/tests/test_save.py b/usr/tests/test_save.py new file mode 100644 index 000000000..691ee9d97 --- /dev/null +++ b/usr/tests/test_save.py @@ -0,0 +1,111 @@ +import pyb, sensor, image, os, time +sensor.reset() +sensor.set_framesize(sensor.QVGA) +if not "test" in os.listdir(): os.mkdir("test") +while(True): + sensor.set_pixformat(sensor.GRAYSCALE) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.pgm" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.pgm" % num) + # + sensor.set_pixformat(sensor.RGB565) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.ppm" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.ppm" % num) + # + sensor.set_pixformat(sensor.JPEG) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.jpg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.jpeg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.jpg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.jpeg" % num) + # + print("Sleeping 5...") + time.sleep(1000) + print("Sleeping 4...") + time.sleep(1000) + print("Sleeping 3...") + time.sleep(1000) + print("Sleeping 2...") + time.sleep(1000) + print("Sleeping 1...") + time.sleep(1000)