ESP32-S3-串口-摄像头和电脑通信
#include <Arduino.h>
#include "esp_camera.h"
#include <esp_spiram.h>
// 引脚配置(根据你接线来改)
#define PWDN_GPIO_NUM     -1  // 接地就设为 -1
#define RESET_GPIO_NUM    -1  // 接 3.3V 就设为 -1
#define XCLK_GPIO_NUM     -1
#define SIOD_GPIO_NUM     18
#define SIOC_GPIO_NUM     17

#define Y9_GPIO_NUM       12
#define Y8_GPIO_NUM       11
#define Y7_GPIO_NUM       10
#define Y6_GPIO_NUM       9
#define Y5_GPIO_NUM       8
#define Y4_GPIO_NUM       7
#define Y3_GPIO_NUM       6
#define Y2_GPIO_NUM       5

#define VSYNC_GPIO_NUM    16
#define HREF_GPIO_NUM     14
#define PCLK_GPIO_NUM     13
void setup() {
  Serial.begin(3000000);
  if (psramFound()) {
    Serial.println("PSRAM is available");
    // 启用 PSRAM 分配
    // heap_caps_malloc_extmem_enable(16); // 单位为 KB,最小分配块
  } else {
    Serial.println("PSRAM not found!");
  }
  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_xclk = -1;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda  = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  config.frame_size = FRAMESIZE_HVGA;  // 320x240
  config.jpeg_quality = 10;
  config.fb_count = 1;
  config.fb_location = CAMERA_FB_IN_PSRAM;

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  Serial.println("Camera Ready");
}

void loop() {
  camera_fb_t *fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }

  Serial.println("===IMG_START===");
  Serial.write(fb->buf, fb->len);
  Serial.println("\n===IMG_END===");

  esp_camera_fb_return(fb);
  //
  // delay(2000);  // 每2秒发一张
  // 发送图像内容
  // Serial.write(fb->buf, fb->len);

  // esp_camera_fb_return(fb);
  delay(10); // 控制帧率
}
import serial
import time
import os
import cv2
import numpy as np

SERIAL_PORT = 'COM7'
BAUD_RATE = 3000000
SAVE_DIR = 'images'
IMAGE_PREFIX = 'image'

os.makedirs(SAVE_DIR, exist_ok=True)
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)

cv2.namedWindow("cam", cv2.WINDOW_AUTOSIZE)
print("等待图像...")

buffer = bytearray()
in_frame = False
img_count = 0

while True:
    try:
        # 读一行文本,检测起始和结束标志
        line = ser.readline()
        if b'===IMG_START===' in line:
            print(f"[{time.strftime('%H:%M:%S')}] 捕获图像开始")
            buffer = bytearray()
            in_frame = True
            continue
        elif b'===IMG_END===' in line:
            print(f"[{time.strftime('%H:%M:%S')}] 图像结束,解码显示中...")
            in_frame = False
            print(f"接收的图像数据长度: {len(buffer)}")
            if len(buffer) == 0:
                print("错误:图像数据为空")
                continue

            nparr = np.frombuffer(buffer, np.uint8)
            img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
            if img is not None:
                # 2. 获取屏幕分辨率(假设 1920x1080)
                screen_width, screen_height = 1280, 960  # 可以改成你的屏幕分辨率

                # 3. 缩放图片到全屏(可选择不同的插值方法)
                resized_img = cv2.resize(img, (screen_width, screen_height), interpolation=cv2.INTER_LINEAR)
                cv2.imshow("cam", resized_img)
                cv2.waitKey(1)
                img_path = os.path.join(SAVE_DIR, f"{IMAGE_PREFIX}_{img_count:03d}.jpg")
                cv2.imwrite(img_path, img)
                print(f"图像已保存: {img_path}")
                img_count += 1
            else:
                print("图像解码失败")
            continue

        if in_frame:
            # 用 read(size) 代替 readline() 更安全
            # 但这里先用 readline 观察效果,之后可以改为 ser.read()
            buffer += line

    except KeyboardInterrupt:
        print("中断,退出程序")
        break
    except Exception as e:
        print(f"错误: {e}")
        break

ser.close()
cv2.destroyAllWindows()
上一篇
下一篇