Сжатие изображения в оттенках серого с помощью ESP32-S3-WROOM Freenove

esp32 sd-card esp32-cam esp32-s3

У меня есть модуль ESP32-S3-WROOM от Freenove, в котором есть камера и модуль карты micro SD. Я могу сделать снимок в формате PIXELFORMAT_JPEG.

Однако, когда я меняю формат пикселей на «PIXELFORMAT_GRAYSCALE», модуль захватывает необработанные данные (1 байт для каждого пикселя), что составляет константу 480 КБ для SVGA (600x800).

Как сжать эти необработанные данные в формат jpg? Я также попробовал сохранить фотографию в формате «.jpg». файл, однако это не сработало.

Это мой код захвата:

/********************************* *************************************
Имя файла: Камера и SD-карта.
Описание: Используйте встроенные кнопки, чтобы сделать фотографии и сохранить их на SD-карту.
Автор: freenove.com.
Модификация: 2022/11/02
**************************************************** ********************/
#include "esp_camera.h"
#define CAMERA_MODEL_ESP32S3_EYE
#include "camera_pins.h"
#include "ws2812.h"
#include "sd_read_write.h"

#define BUTTON_PIN  0

void setup() {
  Serial.begin(500000);
  Serial.setDebugOutput(false);
  Serial.println();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  ws2812Init();
  sdmmcInit();
  //removeDir(SD_MMC, "/camera");
  createDir(SD_MMC, "/camera");
  listDir(SD_MMC, "/camera", 0);
  if(cameraSetup()==1){
    ws2812SetColor(2);
  }
  else{
    ws2812SetColor(1);
    return;
  }
}

void loop() {
  if (digitalRead(BUTTON_PIN)==LOW) {
    delay(20);
    if (digitalRead(BUTTON_PIN)==LOW) {
      ws2812SetColor(3);
      while (digitalRead(BUTTON_PIN)==LOW);
      camera_fb_t * fb = NULL;
      fb = esp_camera_fb_get();
      if (fb != NULL) {
        int photo_index = readFileNum(SD_MMC, "/camera");
        if (photo_index!=-1) {
          String path = "/camera/" + String(photo_index) +".jpg";
          Serial.println(fb->len);
          writejpg(SD_MMC, path.c_str(), fb->buf, fb->len);
        }
        esp_camera_fb_return(fb);
      }
      else {
        Serial.println("Camera capture failed.");
      }
      ws2812SetColor(2);
    }
  }
}

int cameraSetup(void) {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.frame_size = FRAMESIZE_SVGA;
  config.pixel_format = PIXFORMAT_GRAYSCALE; // для потоковой передачи
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
  config.fb_location = CAMERA_FB_IN_PSRAM;
  config.jpeg_quality = 20;
  config.fb_count = 1;
  
  // если присутствует микросхема PSRAM, инициализация с разрешением UXGA и более высоким качеством JPEG
  // для большего заранее выделенного буфера кадра.
  if (psramFound()) {
    config.jpeg_quality = 10;
    config.fb_count = 2;
    config.grab_mode = CAMERA_GRAB_LATEST;
  } else {
    // Ограничиваем размер кадра, когда PSRAM недоступен
    config.frame_size = FRAMESIZE_SVGA;
    config.fb_location = CAMERA_FB_IN_DRAM;
  }

  // инициализация камеры
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return 0;
  }

  sensor_t * s = esp_camera_sensor_get();
  // начальные датчики перевернуты вертикально, а цвета немного насыщены
  s->set_vflip(s, 1); // переворачиваем его обратно
  s->set_brightness(s, 1); // немного увеличить яркость
  s->set_saturation(s, 0); // уменьшаем насыщенность

  Serial.println("Camera configuration complete!");
  return 1;
}

Это функция writejpg(), использованная во фрагменте кода:

void writejpg(fs::FS &fs, const char * path, const uint8_t *buf, size_t size){
    File file = fs.open(path, FILE_WRITE);
    if (!file) {
        Serial.println("Failed to open file for writing");
        ws2812SetColor(1);
        delay(100);
        return;
    }
    file.write(buf, size);

    // Define the chunk size
    const size_t chunkSize = 2048;

    // Write to serial in chunks
    for (size_t i = 0; i < size; i += chunkSize) {
        // Calculate the size of the current chunk
        size_t currentChunkSize = ((i + chunkSize) <= size) ? chunkSize : (size - i);

        // Write the current chunk in hex format to serial
        for (size_t j = 0; j < currentChunkSize; ++j) {
            Serial.printf("%02X ", buf[i + j]);
//            if ((j + 1) % 128 == 0) { // Print a new line every 16 bytes for better readability
//                Serial.println();
//            }
        }
    }
    Serial.println();
    Serial.printf("Saved file to path: %s\r\n", path);
}

Эта функция также распечатывает шестнадцатеричные значения изображения для отладки.

Итак, есть ли у вас идеи, как сжать это изображение в файл jpg?

, 👍0


1 ответ


0

Мне только что удалось решить эту проблему с помощью функции frame2jpg().

Надеюсь, это поможет!

,

Возможно, вы хотели бы расширить этот ответ, включив в него немного больше деталей?, @sempaiscuba

Конечно! Существует код [to_jpg()](https://github.com/espressif/esp32-camera/blob/master/conversions/to_jpg.cpp), который находится в репозитории esp32 github. В нем вы можете найти функцию «frame2jpg()». Также использование будет похоже на «frame2jpg(fb,quality, &jpg_buf, &jpg_buf_len)», оно вернет логическое значение, указывающее на успешную ситуацию. Если вы не понимаете, я здесь, чтобы помочь!, @BehicMV