esp32_cam_uart_stream.ino 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "esp_camera.h"
  2. // Pin definitions
  3. #define PWDN_GPIO_NUM 32
  4. #define RESET_GPIO_NUM -1
  5. #define XCLK_GPIO_NUM 0
  6. #define SIOD_GPIO_NUM 26
  7. #define SIOC_GPIO_NUM 27
  8. #define Y9_GPIO_NUM 35
  9. #define Y8_GPIO_NUM 34
  10. #define Y7_GPIO_NUM 39
  11. #define Y6_GPIO_NUM 36
  12. #define Y5_GPIO_NUM 21
  13. #define Y4_GPIO_NUM 19
  14. #define Y3_GPIO_NUM 18
  15. #define Y2_GPIO_NUM 5
  16. #define VSYNC_GPIO_NUM 25
  17. #define HREF_GPIO_NUM 23
  18. #define PCLK_GPIO_NUM 22
  19. // Camera configuration
  20. camera_config_t config;
  21. // Function prototypes
  22. void handleSerialInput();
  23. void initializeCamera();
  24. void processImage(camera_fb_t* fb);
  25. void ditherImage(camera_fb_t* fb);
  26. bool isDarkBit(uint8_t bit);
  27. // Serial input flags
  28. bool disableDithering = false;
  29. bool invert = false;
  30. bool rotated = false;
  31. bool stopStream = false;
  32. void setup() {
  33. Serial.begin(230400);
  34. initializeCamera();
  35. }
  36. void loop() {
  37. handleSerialInput();
  38. if (stopStream) {
  39. return;
  40. }
  41. camera_fb_t* fb = esp_camera_fb_get();
  42. if (!fb) {
  43. return;
  44. }
  45. processImage(fb);
  46. esp_camera_fb_return(fb);
  47. fb = NULL;
  48. delay(50);
  49. }
  50. void handleSerialInput() {
  51. if (Serial.available() > 0) {
  52. char input = Serial.read();
  53. sensor_t* cameraSensor = esp_camera_sensor_get();
  54. switch (input) {
  55. case '>': // Toggle dithering.
  56. disableDithering = !disableDithering;
  57. break;
  58. case '<': // Toggle invert.
  59. invert = !invert;
  60. break;
  61. case 'B': // Add brightness.
  62. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness + 1);
  63. break;
  64. case 'b': // Remove brightness.
  65. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness - 1);
  66. break;
  67. case 'C': // Add contrast.
  68. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast + 1);
  69. break;
  70. case 'c': // Remove contrast.
  71. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast - 1);
  72. break;
  73. case 'D': // Enable dithering.
  74. disableDithering = false;
  75. break;
  76. case 'd': // Disable dithering.
  77. disableDithering = true;
  78. break;
  79. case 'M': // Toggle Mirror
  80. cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
  81. break;
  82. case 'S': // Start stream.
  83. stopStream = false;
  84. break;
  85. case 's': // Stop stream.
  86. stopStream = true;
  87. break;
  88. default:
  89. break;
  90. }
  91. }
  92. }
  93. void initializeCamera() {
  94. // Set camera configuration
  95. config.ledc_channel = LEDC_CHANNEL_0;
  96. config.ledc_timer = LEDC_TIMER_0;
  97. config.pin_d0 = Y2_GPIO_NUM;
  98. config.pin_d1 = Y3_GPIO_NUM;
  99. config.pin_d2 = Y4_GPIO_NUM;
  100. config.pin_d3 = Y5_GPIO_NUM;
  101. config.pin_d4 = Y6_GPIO_NUM;
  102. config.pin_d5 = Y7_GPIO_NUM;
  103. config.pin_d6 = Y8_GPIO_NUM;
  104. config.pin_d7 = Y9_GPIO_NUM;
  105. config.pin_xclk = XCLK_GPIO_NUM;
  106. config.pin_pclk = PCLK_GPIO_NUM;
  107. config.pin_vsync = VSYNC_GPIO_NUM;
  108. config.pin_href = HREF_GPIO_NUM;
  109. config.pin_sscb_sda = SIOD_GPIO_NUM;
  110. config.pin_sscb_scl = SIOC_GPIO_NUM;
  111. config.pin_pwdn = PWDN_GPIO_NUM;
  112. config.pin_reset = RESET_GPIO_NUM;
  113. config.xclk_freq_hz = 20000000;
  114. config.pixel_format = PIXFORMAT_GRAYSCALE;
  115. config.frame_size = FRAMESIZE_QQVGA;
  116. config.fb_count = 1;
  117. // Initialize camera
  118. esp_err_t err = esp_camera_init(&config);
  119. if (err != ESP_OK) {
  120. Serial.printf("Camera init failed with error 0x%x", err);
  121. return;
  122. }
  123. // Set high contrast to make dithering easier
  124. sensor_t* s = esp_camera_sensor_get();
  125. s->set_contrast(s, 2);
  126. // Set rotation (added lines)
  127. s->set_vflip(s, true); // Vertical flip
  128. s->set_hmirror(s, true); // Horizontal mirror
  129. }
  130. void processImage(camera_fb_t* frameBuffer) {
  131. if (!disableDithering) {
  132. ditherImage(frameBuffer);
  133. }
  134. uint8_t flipper_y = 0;
  135. for (uint8_t y = 28; y < 92; ++y) {
  136. // Print the Y coordinate.
  137. Serial.print("Y:");
  138. Serial.print((char)flipper_y);
  139. // Print the character.
  140. // The y value to use in the frame buffer array.
  141. size_t true_y = y * frameBuffer->width;
  142. // For each column of 8 pixels in the current row.
  143. for (uint8_t x = 16; x < 144; x += 8) {
  144. // The current character being constructed.
  145. char c = 0;
  146. // For each pixel in the current column of 8.
  147. for (uint8_t j = 0; j < 8; ++j) {
  148. if (isDarkBit(frameBuffer->buf[true_y + x + (7 - j)])) {
  149. // Shift the bit into the right position
  150. c |= (uint8_t)1 << (uint8_t)j;
  151. }
  152. }
  153. // Output the character.
  154. Serial.print(c);
  155. }
  156. // Move to the next line.
  157. ++flipper_y;
  158. Serial.flush();
  159. }
  160. }
  161. // Dither image.
  162. void ditherImage(camera_fb_t* fb) {
  163. for (int y = 0; y < fb->height - 1; ++y) {
  164. for (int x = 1; x < fb->width - 1; ++x) {
  165. int current = y * fb->width + x;
  166. // Convert to black or white
  167. uint8_t oldpixel = fb->buf[current];
  168. uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
  169. fb->buf[current] = newpixel;
  170. // Compute quantization error
  171. int quant_error = oldpixel - newpixel;
  172. // Propagate the error
  173. fb->buf[current + 1] += quant_error * 7 / 16;
  174. fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 3 / 16;
  175. fb->buf[(y + 1) * fb->width + x] += quant_error * 5 / 16;
  176. fb->buf[(y + 1) * fb->width + x + 1] += quant_error / 16;
  177. }
  178. }
  179. }
  180. // Returns true if the bit is "dark".
  181. bool isDarkBit(uint8_t bit) {
  182. if (invert) {
  183. return bit >= 128;
  184. } else {
  185. return bit < 128;
  186. }
  187. }