mirror of
				https://github.com/0xFEEDC0DE64/arduino-esp32.git
				synced 2025-10-31 06:01:39 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			344 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|   * ESPRESSIF MIT License
 | |
|   *
 | |
|   * Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
 | |
|   *
 | |
|   * 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 <stdint.h>
 | |
| #include <math.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| }
 | |
| #endif
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     IMAGE_RESIZE_BILINEAR = 0, /*<! Resize image by taking bilinear of four pixels */
 | |
|     IMAGE_RESIZE_MEAN = 1,     /*<! Resize image by taking mean of four pixels */
 | |
|     IMAGE_RESIZE_NEAREST = 2   /*<! Resize image by taking the nearest pixel */
 | |
| } image_resize_t;
 | |
| 
 | |
| template <class T>
 | |
| 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 <class T>
 | |
| void Image<T>::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<int>::pixel_rgb565_to_rgb888(src_image[src_row_0], temp);
 | |
|                 Image<int>::pixel_rgb565_to_rgb888(src_image[src_row_0 + 1], temp + 3);
 | |
|                 Image<int>::pixel_rgb565_to_rgb888(src_image[src_row_1], temp + 6);
 | |
|                 Image<int>::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<int>::pixel_rgb565_to_rgb888(src_image[src_row_0], temp);
 | |
|                 Image<int>::pixel_rgb565_to_rgb888(src_image[src_row_0 + 1], temp + 3);
 | |
|                 Image<int>::pixel_rgb565_to_rgb888(src_image[src_row_1], temp + 6);
 | |
|                 Image<int>::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<int>::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 <class T>
 | |
| void Image<T>::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;
 | |
|     }
 | |
| } |