mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-07-02 13:30:59 +02:00
IDF release/v3.3 (#3672)
ESP-IDF release/v3.3: 66d3783c8 esp-face: 420fc7e esp32-camera: 0107093
This commit is contained in:
344
tools/sdk/include/esp-face/esp_image.hpp
Normal file
344
tools/sdk/include/esp-face/esp_image.hpp
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user