CameraStream.ino 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // from: https://github.com/Z4urce/flipperzero-camera/blob/main/esp32_firmware/esp32_cam_uart_stream/esp32_cam_uart_stream.ino
  2. void cam_stream_setup() {
  3. // camera init
  4. camera_config_t config;
  5. config.ledc_channel = LEDC_CHANNEL_0;
  6. config.ledc_timer = LEDC_TIMER_0;
  7. config.pin_d0 = Y2_GPIO_NUM;
  8. config.pin_d1 = Y3_GPIO_NUM;
  9. config.pin_d2 = Y4_GPIO_NUM;
  10. config.pin_d3 = Y5_GPIO_NUM;
  11. config.pin_d4 = Y6_GPIO_NUM;
  12. config.pin_d5 = Y7_GPIO_NUM;
  13. config.pin_d6 = Y8_GPIO_NUM;
  14. config.pin_d7 = Y9_GPIO_NUM;
  15. config.pin_xclk = XCLK_GPIO_NUM;
  16. config.pin_pclk = PCLK_GPIO_NUM;
  17. config.pin_vsync = VSYNC_GPIO_NUM;
  18. config.pin_href = HREF_GPIO_NUM;
  19. config.pin_sscb_sda = SIOD_GPIO_NUM;
  20. config.pin_sscb_scl = SIOC_GPIO_NUM;
  21. config.pin_pwdn = PWDN_GPIO_NUM;
  22. config.pin_reset = RESET_GPIO_NUM;
  23. config.xclk_freq_hz = 20000000;
  24. config.pixel_format = PIXFORMAT_GRAYSCALE;
  25. // We don't need a big frame
  26. config.frame_size = FRAMESIZE_QCIF;
  27. config.fb_count = 1;
  28. esp_err_t err = esp_camera_init(&config);
  29. if (err != ESP_OK) {
  30. Serial.printf("Camera init failed with error 0x%x", err);
  31. return;
  32. }
  33. // Setting high contrast to make easier to dither
  34. sensor_t* s = esp_camera_sensor_get();
  35. s->set_contrast(s, 2);
  36. }
  37. bool disable_dithering = false;
  38. bool invert = false;
  39. bool rotate90 = true;
  40. void cam_stream_loop() {
  41. bool stop_stream = false;
  42. // Reading serial
  43. if (Serial.available() > 0) {
  44. char r = Serial.read();
  45. sensor_t* s = esp_camera_sensor_get();
  46. switch (r) {
  47. case 'S':
  48. //stop_stream = false;
  49. break;
  50. case 's':
  51. /*stop_stream = true;
  52. preferences.putBool("streaming", false);
  53. preferences.end();
  54. ESP.restart();*/
  55. break;
  56. case 'D':
  57. disable_dithering = false;
  58. break;
  59. case 'd':
  60. disable_dithering = true;
  61. break;
  62. case 'C':
  63. s->set_contrast(s, s->status.contrast + 1);
  64. s->set_contrast(s, s->status.brightness + 1);
  65. break;
  66. case 'c':
  67. s->set_contrast(s, s->status.contrast - 1);
  68. s->set_contrast(s, s->status.brightness - 1);
  69. break;
  70. /*case 'B':
  71. s->set_contrast(s, s->status.brightness + 1);
  72. break;
  73. case 'b':
  74. s->set_contrast(s, s->status.brightness - 1);
  75. break;
  76. // Toggle cases
  77. case 'M': // Toggle Mirror
  78. s->set_hmirror(s, !s->status.hmirror);
  79. break;
  80. case '>':
  81. disable_dithering = !disable_dithering;
  82. break;
  83. case '<':
  84. invert = !invert;
  85. break;
  86. */
  87. // Toggle cases
  88. case '>': // Toggle Mirror
  89. s->set_hmirror(s, !s->status.hmirror);
  90. if (s->status.hmirror) {
  91. s->set_vflip(s, !s->status.vflip);
  92. /*if (s->status.vflip)
  93. rotate90 = !rotate90;*/
  94. }
  95. break;
  96. case '<':
  97. invert = !invert;
  98. if (invert)
  99. disable_dithering = !disable_dithering;
  100. break;
  101. default:
  102. break;
  103. }
  104. }
  105. camera_fb_t* fb = esp_camera_fb_get();
  106. if (!fb) {
  107. return;
  108. }
  109. //Length: 19200
  110. //Width: 160
  111. //Height: 120
  112. //Format: 2
  113. //Target: 128x64
  114. if (!disable_dithering) {
  115. DitherImage(fb);
  116. }
  117. uint8_t flipper_y = 0;
  118. for (uint8_t y = 28; y < 92; ++y) {
  119. Serial.print("Y:");
  120. Serial.print((char)flipper_y);
  121. size_t true_y = y * fb->width;
  122. for (uint8_t x = (rotate90 ? 0 : 16); x < (rotate90 ? 128 : 144); x += 8) {
  123. char c = 0;
  124. for (uint8_t j = 0; j < 8; ++j)
  125. c |= IsDarkBit(rotate90 ? fb->buf[(x + (7 - j)) * fb->width + y] : fb->buf[true_y + x + (7 - j)]) << j;
  126. Serial.print(c);
  127. }
  128. ++flipper_y;
  129. Serial.flush();
  130. }
  131. esp_camera_fb_return(fb);
  132. fb = NULL;
  133. delay(50);
  134. }
  135. inline bool IsDarkBit(const uint8_t bit) {
  136. return (invert ^ (bit < 128));
  137. }
  138. void DitherImage(camera_fb_t* fb) {
  139. for (uint8_t y = 0; y < fb->height; ++y) {
  140. for (uint8_t x = 0; x < fb->width; ++x) {
  141. size_t current = (y * fb->width) + x;
  142. uint8_t oldpixel = fb->buf[current];
  143. uint8_t newpixel = oldpixel >= 128 ? 255 : 0;
  144. fb->buf[current] = newpixel;
  145. uint8_t quant_error = oldpixel - newpixel;
  146. fb->buf[(y * fb->width) + x + 1] = fb->buf[(y * fb->width) + x + 1] + quant_error * 7 / 16;
  147. fb->buf[(y + 1 * fb->width) + x - 1] = fb->buf[(y + 1 * fb->width) + x - 1] + quant_error * 3 / 16;
  148. fb->buf[(y + 1 * fb->width) + x] = fb->buf[(y + 1 * fb->width) + x] + quant_error * 5 / 16;
  149. fb->buf[(y + 1 * fb->width) + x + 1] = fb->buf[(y + 1 * fb->width) + x + 1] + quant_error * 1 / 16;
  150. }
  151. }
  152. }