esp32_cam_uart_stream.ino 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include "esp_camera.h"
  2. // Define Pin numbers used by the camera
  3. #define FLASH_GPIO_NUM 4
  4. #define HREF_GPIO_NUM 23
  5. #define PCLK_GPIO_NUM 22
  6. #define PWDN_GPIO_NUM 32
  7. #define RESET_GPIO_NUM -1
  8. #define SIOC_GPIO_NUM 27
  9. #define SIOD_GPIO_NUM 26
  10. #define XCLK_GPIO_NUM 0
  11. #define VSYNC_GPIO_NUM 25
  12. #define Y2_GPIO_NUM 5
  13. #define Y3_GPIO_NUM 18
  14. #define Y4_GPIO_NUM 19
  15. #define Y5_GPIO_NUM 21
  16. #define Y6_GPIO_NUM 36
  17. #define Y7_GPIO_NUM 39
  18. #define Y8_GPIO_NUM 34
  19. #define Y9_GPIO_NUM 35
  20. // Structure to hold the camera configuration parameters
  21. camera_config_t config;
  22. // Function prototypes
  23. void handleSerialInput();
  24. void initializeCamera();
  25. void processImage(camera_fb_t* fb);
  26. void ditherImage(camera_fb_t* fb);
  27. // Enumeration to represent the available dithering algorithms
  28. enum DitheringAlgorithm {
  29. FLOYD_STEINBERG,
  30. JARVIS_JUDICE_NINKE,
  31. STUCKI
  32. };
  33. // Variables to hold state and configurations
  34. DitheringAlgorithm ditherAlgorithm = FLOYD_STEINBERG; // Holds the currently selected dithering algorithm
  35. bool disableDithering = false; // Flag to enable or disable dithering
  36. bool invert = false; // Flag to invert pixel colors
  37. bool isFlashOn = false; // Flag to represent the flash state
  38. bool rotated = false; // Flag to represent whether the image is rotated
  39. bool stopStream = false; // Flag to stop or start the stream
  40. void setup() {
  41. // Start serial communication at 230400 baud rate
  42. Serial.begin(230400);
  43. initializeCamera();
  44. }
  45. void loop() {
  46. if (!stopStream) {
  47. // Capture and process the frame buffer if streaming is enabled
  48. camera_fb_t* fb = esp_camera_fb_get(); // Get the frame buffer from the camera
  49. if (fb) {
  50. processImage(fb);
  51. // Return the frame buffer back to the camera driver
  52. esp_camera_fb_return(fb);
  53. }
  54. delay(50); // Delay for 50ms between each frame
  55. }
  56. handleSerialInput(); // Handle any available serial input commands
  57. }
  58. // Function to handle the serial input commands and perform the associated actions
  59. void handleSerialInput() {
  60. if (Serial.available() > 0) {
  61. char input = Serial.read();
  62. sensor_t* cameraSensor = esp_camera_sensor_get();
  63. switch (input) {
  64. case '>': // Toggle dithering
  65. disableDithering = !disableDithering;
  66. break;
  67. case '<': // Toggle invert
  68. invert = !invert;
  69. break;
  70. case 'B': // Add brightness
  71. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness + 1);
  72. break;
  73. case 'b': // Remove brightness
  74. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.brightness - 1);
  75. break;
  76. case 'C': // Add contrast
  77. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast + 1);
  78. break;
  79. case 'c': // Remove contrast
  80. cameraSensor->set_contrast(cameraSensor, cameraSensor->status.contrast - 1);
  81. break;
  82. case 'P': // Picture sequence.
  83. if (!isFlashOn) {
  84. isFlashOn = true;
  85. pinMode(FLASH_GPIO_NUM, OUTPUT);
  86. // Turn on torch.
  87. digitalWrite(FLASH_GPIO_NUM, HIGH);
  88. delay(2000);
  89. // Turn off torch.
  90. digitalWrite(FLASH_GPIO_NUM, LOW);
  91. delay(50);
  92. isFlashOn = false;
  93. }
  94. break;
  95. case 'M': // Toggle Mirror
  96. cameraSensor->set_hmirror(cameraSensor, !cameraSensor->status.hmirror);
  97. break;
  98. case 'S': // Start stream
  99. stopStream = false;
  100. break;
  101. case 's': // Stop stream
  102. stopStream = true;
  103. break;
  104. case '0': // Use Floyd Steinberg dithering.
  105. ditherAlgorithm = FLOYD_STEINBERG;
  106. break;
  107. case '1': // Use Jarvis Judice dithering.
  108. ditherAlgorithm = JARVIS_JUDICE_NINKE;
  109. break;
  110. case '2': // Use Stucki dithering.
  111. ditherAlgorithm = STUCKI;
  112. break;
  113. default:
  114. // Do nothing.
  115. break;
  116. }
  117. }
  118. }
  119. void initializeCamera() {
  120. // Set camera configurations
  121. config.ledc_channel = LEDC_CHANNEL_0;
  122. config.ledc_timer = LEDC_TIMER_0;
  123. config.pin_d0 = Y2_GPIO_NUM;
  124. config.pin_d1 = Y3_GPIO_NUM;
  125. config.pin_d2 = Y4_GPIO_NUM;
  126. config.pin_d3 = Y5_GPIO_NUM;
  127. config.pin_d4 = Y6_GPIO_NUM;
  128. config.pin_d5 = Y7_GPIO_NUM;
  129. config.pin_d6 = Y8_GPIO_NUM;
  130. config.pin_d7 = Y9_GPIO_NUM;
  131. config.pin_xclk = XCLK_GPIO_NUM;
  132. config.pin_pclk = PCLK_GPIO_NUM;
  133. config.pin_vsync = VSYNC_GPIO_NUM;
  134. config.pin_href = HREF_GPIO_NUM;
  135. config.pin_sscb_sda = SIOD_GPIO_NUM;
  136. config.pin_sscb_scl = SIOC_GPIO_NUM;
  137. config.pin_pwdn = PWDN_GPIO_NUM;
  138. config.pin_reset = RESET_GPIO_NUM;
  139. config.xclk_freq_hz = 20000000;
  140. config.pixel_format = PIXFORMAT_GRAYSCALE;
  141. config.frame_size = FRAMESIZE_QQVGA;
  142. config.fb_count = 1;
  143. if (isFlashOn) {
  144. pinMode(FLASH_GPIO_NUM, OUTPUT);
  145. // Turn off torch.
  146. digitalWrite(FLASH_GPIO_NUM, LOW);
  147. isFlashOn = false;
  148. }
  149. // Initialize camera
  150. esp_err_t err = esp_camera_init(&config);
  151. if (err != ESP_OK) {
  152. Serial.printf("Camera init failed with error 0x%x", err);
  153. return;
  154. }
  155. // Set initial contrast.
  156. sensor_t* s = esp_camera_sensor_get();
  157. s->set_contrast(s, 0);
  158. // Set rotation
  159. s->set_vflip(s, true); // Vertical flip
  160. s->set_hmirror(s, true); // Horizontal mirror
  161. }
  162. void processImage(camera_fb_t* frameBuffer) {
  163. // If dithering is not disabled, perform dithering on the image. Dithering is the
  164. // process of approximating the look of a high-resolution grayscale image in a
  165. // lower resolution by binary values (black & white), thereby representing
  166. // different shades of gray.
  167. if (!disableDithering) {
  168. ditherImage(frameBuffer); // Invokes the dithering process on the frame buffer
  169. }
  170. uint8_t flipper_y = 0;
  171. // Iterating over specific rows of the frame buffer.
  172. for (uint8_t y = 28; y < 92; ++y) {
  173. Serial.print("Y:"); // Print "Y:" for every new row.
  174. Serial.write(flipper_y); // Send the row identifier as a byte.
  175. // Calculate the actual y index in the frame buffer 1D array by multiplying the
  176. // y value with the width of the frame buffer. This gives the starting index
  177. // of the row in the 1D array.
  178. size_t true_y = y * frameBuffer->width;
  179. // Iterating over specific columns of each row in the frame buffer.
  180. for (uint8_t x = 16; x < 144; x += 8) { // step by 8 as we're packing 8 pixels per byte
  181. uint8_t packed_pixels = 0;
  182. // Packing 8 pixel values into one byte.
  183. for(uint8_t bit = 0; bit < 8; ++bit) {
  184. // Check the invert flag and pack the pixels accordingly.
  185. if(invert) {
  186. // If invert is true, consider pixel as 1 if it's less than 127.
  187. if(frameBuffer->buf[true_y + x + bit] < 127) {
  188. packed_pixels |= (1 << (7 - bit));
  189. }
  190. } else {
  191. // If invert is false, consider pixel as 1 if it's more than 127.
  192. if(frameBuffer->buf[true_y + x + bit] > 127) {
  193. packed_pixels |= (1 << (7 - bit));
  194. }
  195. }
  196. }
  197. Serial.write(packed_pixels); // Sending packed pixel byte.
  198. }
  199. ++flipper_y; // Move to the next row.
  200. Serial.flush(); // Ensure all data in the Serial buffer is sent before moving to the next iteration.
  201. }
  202. }
  203. void ditherImage(camera_fb_t* fb) {
  204. for (uint8_t y = 0; y < fb->height; ++y) {
  205. for (uint8_t x = 0; x < fb->width; ++x) {
  206. size_t current = (y * fb->width) + x;
  207. uint8_t oldpixel = fb->buf[current];
  208. uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
  209. fb->buf[current] = newpixel;
  210. int8_t quant_error = oldpixel - newpixel;
  211. // Apply error diffusion based on the selected algorithm
  212. switch (ditherAlgorithm) {
  213. case JARVIS_JUDICE_NINKE:
  214. fb->buf[(y * fb->width) + x + 1] += quant_error * 7 / 48;
  215. fb->buf[(y * fb->width) + x + 2] += quant_error * 5 / 48;
  216. fb->buf[(y + 1) * fb->width + x - 2] += quant_error * 3 / 48;
  217. fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 5 / 48;
  218. fb->buf[(y + 1) * fb->width + x] += quant_error * 7 / 48;
  219. fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 5 / 48;
  220. fb->buf[(y + 1) * fb->width + x + 2] += quant_error * 3 / 48;
  221. fb->buf[(y + 2) * fb->width + x - 2] += quant_error * 1 / 48;
  222. fb->buf[(y + 2) * fb->width + x - 1] += quant_error * 3 / 48;
  223. fb->buf[(y + 2) * fb->width + x] += quant_error * 5 / 48;
  224. fb->buf[(y + 2) * fb->width + x + 1] += quant_error * 3 / 48;
  225. fb->buf[(y + 2) * fb->width + x + 2] += quant_error * 1 / 48;
  226. break;
  227. case STUCKI:
  228. fb->buf[(y * fb->width) + x + 1] += quant_error * 8 / 42;
  229. fb->buf[(y * fb->width) + x + 2] += quant_error * 4 / 42;
  230. fb->buf[(y + 1) * fb->width + x - 2] += quant_error * 2 / 42;
  231. fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 4 / 42;
  232. fb->buf[(y + 1) * fb->width + x] += quant_error * 8 / 42;
  233. fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 4 / 42;
  234. fb->buf[(y + 1) * fb->width + x + 2] += quant_error * 2 / 42;
  235. fb->buf[(y + 2) * fb->width + x - 2] += quant_error * 1 / 42;
  236. fb->buf[(y + 2) * fb->width + x - 1] += quant_error * 2 / 42;
  237. fb->buf[(y + 2) * fb->width + x] += quant_error * 4 / 42;
  238. fb->buf[(y + 2) * fb->width + x + 1] += quant_error * 2 / 42;
  239. fb->buf[(y + 2) * fb->width + x + 2] += quant_error * 1 / 42;
  240. break;
  241. case FLOYD_STEINBERG:
  242. default:
  243. // Default to Floyd-Steinberg dithering if an invalid algorithm is selected
  244. fb->buf[(y * fb->width) + x + 1] += quant_error * 7 / 16;
  245. fb->buf[(y + 1) * fb->width + x - 1] += quant_error * 3 / 16;
  246. fb->buf[(y + 1) * fb->width + x] += quant_error * 5 / 16;
  247. fb->buf[(y + 1) * fb->width + x + 1] += quant_error * 1 / 16;
  248. break;
  249. }
  250. }
  251. }
  252. }