/* * ESPRESSIF MIT License * * Copyright (c) 2018 * * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, * it is free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef __cplusplus } #endif typedef enum { IMAGE_RESIZE_BILINEAR = 0, /* class Image { public: /** * @brief Convert a RGB565 pixel to RGB888 * * @param input Pixel value in RGB565 * @param output Pixel value in RGB888 */ static inline void pixel_rgb565_to_rgb888(uint16_t input, T *output) { output[2] = (input & 0x1F00) >> 5; //blue output[1] = ((input & 0x7) << 5) | ((input & 0xE000) >> 11); //green output[0] = input & 0xF8; //red }; /** * @brief Resize a RGB565 image to a RGB88 image * * @param dst_image The destination image * @param y_start The start y index of where resized image located * @param y_end The end y index of where resized image located * @param x_start The start x index of where resized image located * @param x_end The end x index of where resized image located * @param channel The channel number of image * @param src_image The source image * @param src_h The height of source image * @param src_w The width of source image * @param dst_w The width of destination image * @param shift_left The bit number of left shifting * @param type The resize type */ static void resize_to_rgb888(T *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint16_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type); /** * @brief Resize a RGB888 image to a RGB88 image * * @param dst_image The destination image * @param y_start The start y index of where resized image located * @param y_end The end y index of where resized image located * @param x_start The start x index of where resized image located * @param x_end The end x index of where resized image located * @param channel The channel number of image * @param src_image The source image * @param src_h The height of source image * @param src_w The width of source image * @param dst_w The width of destination image * @param shift_left The bit number of left shifting * @param type The resize type */ static void resize_to_rgb888(T *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint8_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type); // static void resize_to_rgb565(uint16_t *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint16_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type); // static void resize_to_rgb565(uint16_t *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint8_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type); }; template void Image::resize_to_rgb888(T *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint16_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type) { assert(channel == 3); float scale_y = (float)src_h / (y_end - y_start); float scale_x = (float)src_w / (x_end - x_start); int temp[13]; switch (type) { case IMAGE_RESIZE_BILINEAR: for (size_t y = y_start; y < y_end; y++) { float ratio_y[2]; ratio_y[0] = (float)((y + 0.5) * scale_y - 0.5); // y int src_y = (int)ratio_y[0]; // y1 ratio_y[0] -= src_y; // y - y1 if (src_y < 0) { ratio_y[0] = 0; src_y = 0; } if (src_y > src_h - 2) { ratio_y[0] = 0; src_y = src_h - 2; } ratio_y[1] = 1 - ratio_y[0]; // y2 - y int _dst_i = y * dst_w; int _src_row_0 = src_y * src_w; int _src_row_1 = _src_row_0 + src_w; for (size_t x = x_start; x < x_end; x++) { float ratio_x[2]; ratio_x[0] = (float)((x + 0.5) * scale_x - 0.5); // x int src_x = (int)ratio_x[0]; // x1 ratio_x[0] -= src_x; // x - x1 if (src_x < 0) { ratio_x[0] = 0; src_x = 0; } if (src_x > src_w - 2) { ratio_x[0] = 0; src_x = src_w - 2; } ratio_x[1] = 1 - ratio_x[0]; // x2 - x int dst_i = (_dst_i + x) * channel; int src_row_0 = _src_row_0 + src_x; int src_row_1 = _src_row_1 + src_x; Image::pixel_rgb565_to_rgb888(src_image[src_row_0], temp); Image::pixel_rgb565_to_rgb888(src_image[src_row_0 + 1], temp + 3); Image::pixel_rgb565_to_rgb888(src_image[src_row_1], temp + 6); Image::pixel_rgb565_to_rgb888(src_image[src_row_1 + 1], temp + 9); for (int c = 0; c < channel; c++) { temp[12] = round(temp[c] * ratio_x[1] * ratio_y[1] + temp[channel + c] * ratio_x[0] * ratio_y[1] + temp[channel + channel + c] * ratio_x[1] * ratio_y[0] + src_image[channel + channel + channel + c] * ratio_x[0] * ratio_y[0]); dst_image[dst_i + c] = (shift_left > 0) ? (temp[12] << shift_left) : (temp[12] >> -shift_left); } } } break; case IMAGE_RESIZE_MEAN: shift_left -= 2; for (int y = y_start; y < y_end; y++) { int _dst_i = y * dst_w; float _src_row_0 = rintf(y * scale_y) * src_w; float _src_row_1 = _src_row_0 + src_w; for (int x = x_start; x < x_end; x++) { int dst_i = (_dst_i + x) * channel; int src_row_0 = (_src_row_0 + rintf(x * scale_x)); int src_row_1 = (_src_row_1 + rintf(x * scale_x)); Image::pixel_rgb565_to_rgb888(src_image[src_row_0], temp); Image::pixel_rgb565_to_rgb888(src_image[src_row_0 + 1], temp + 3); Image::pixel_rgb565_to_rgb888(src_image[src_row_1], temp + 6); Image::pixel_rgb565_to_rgb888(src_image[src_row_1 + 1], temp + 9); dst_image[dst_i] = (shift_left > 0) ? ((temp[0] + temp[3] + temp[6] + temp[9]) << shift_left) : ((temp[0] + temp[3] + temp[6] + temp[9]) >> -shift_left); dst_image[dst_i + 1] = (shift_left > 0) ? ((temp[1] + temp[4] + temp[7] + temp[10]) << shift_left) : ((temp[1] + temp[4] + temp[7] + temp[10]) >> -shift_left); dst_image[dst_i + 2] = (shift_left > 0) ? ((temp[2] + temp[5] + temp[8] + temp[11]) << shift_left) : ((temp[1] + temp[4] + temp[7] + temp[10]) >> -shift_left); } } break; case IMAGE_RESIZE_NEAREST: for (size_t y = y_start; y < y_end; y++) { int _dst_i = y * dst_w; float _src_i = rintf(y * scale_y) * src_w; for (size_t x = x_start; x < x_end; x++) { int dst_i = (_dst_i + x) * channel; int src_i = _src_i + rintf(x * scale_x); Image::pixel_rgb565_to_rgb888(src_image[src_i], temp); dst_image[dst_i] = (shift_left > 0) ? (temp[0] << shift_left) : (temp[0] >> -shift_left); dst_image[dst_i + 1] = (shift_left > 0) ? (temp[1] << shift_left) : (temp[1] >> -shift_left); dst_image[dst_i + 2] = (shift_left > 0) ? (temp[2] << shift_left) : (temp[2] >> -shift_left); } } break; default: break; } } template void Image::resize_to_rgb888(T *dst_image, int y_start, int y_end, int x_start, int x_end, int channel, uint8_t *src_image, int src_h, int src_w, int dst_w, int shift_left, image_resize_t type) { float scale_y = (float)src_h / (y_end - y_start); float scale_x = (float)src_w / (x_end - x_start); int temp; switch (type) { case IMAGE_RESIZE_BILINEAR: for (size_t y = y_start; y < y_end; y++) { float ratio_y[2]; ratio_y[0] = (float)((y + 0.5) * scale_y - 0.5); // y int src_y = (int)ratio_y[0]; // y1 ratio_y[0] -= src_y; // y - y1 if (src_y < 0) { ratio_y[0] = 0; src_y = 0; } if (src_y > src_h - 2) { ratio_y[0] = 0; src_y = src_h - 2; } ratio_y[1] = 1 - ratio_y[0]; // y2 - y int _dst_i = y * dst_w; int _src_row_0 = src_y * src_w; int _src_row_1 = _src_row_0 + src_w; for (size_t x = x_start; x < x_end; x++) { float ratio_x[2]; ratio_x[0] = (float)((x + 0.5) * scale_x - 0.5); // x int src_x = (int)ratio_x[0]; // x1 ratio_x[0] -= src_x; // x - x1 if (src_x < 0) { ratio_x[0] = 0; src_x = 0; } if (src_x > src_w - 2) { ratio_x[0] = 0; src_x = src_w - 2; } ratio_x[1] = 1 - ratio_x[0]; // x2 - x int dst_i = (_dst_i + x) * channel; int src_row_0 = (_src_row_0 + src_x) * channel; int src_row_1 = (_src_row_1 + src_x) * channel; for (int c = 0; c < channel; c++) { temp = round(src_image[src_row_0 + c] * ratio_x[1] * ratio_y[1] + src_image[src_row_0 + channel + c] * ratio_x[0] * ratio_y[1] + src_image[src_row_1 + c] * ratio_x[1] * ratio_y[0] + src_image[src_row_1 + channel + c] * ratio_x[0] * ratio_y[0]); dst_image[dst_i + c] = (shift_left > 0) ? (temp << shift_left) : (temp >> -shift_left); } } } break; case IMAGE_RESIZE_MEAN: shift_left -= 2; for (size_t y = y_start; y < y_end; y++) { int _dst_i = y * dst_w; float _src_row_0 = rintf(y * scale_y) * src_w; float _src_row_1 = _src_row_0 + src_w; for (size_t x = x_start; x < x_end; x++) { int dst_i = (_dst_i + x) * channel; int src_row_0 = (_src_row_0 + rintf(x * scale_x)) * channel; int src_row_1 = (_src_row_1 + rintf(x * scale_x)) * channel; for (size_t c = 0; c < channel; c++) { temp = (int)src_image[src_row_0 + c] + (int)src_image[src_row_0 + channel + c] + (int)src_image[src_row_1 + c] + (int)src_image[src_row_1 + channel + c]; dst_image[dst_i + c] = (shift_left > 0) ? (temp << shift_left) : (temp >> -shift_left); } } } break; case IMAGE_RESIZE_NEAREST: for (size_t y = y_start; y < y_end; y++) { int _dst_i = y * dst_w; float _src_i = rintf(y * scale_y) * src_w; for (size_t x = x_start; x < x_end; x++) { int dst_i = (_dst_i + x) * channel; int src_i = (_src_i + rintf(x * scale_x)) * channel; for (size_t c = 0; c < channel; c++) { dst_image[dst_i + c] = (shift_left > 0) ? ((T)src_image[src_i + c] << shift_left) : ((T)src_image[src_i + c] >> -shift_left); } } } break; default: break; } }