From 5aa5363672af614b8bc7823b7121981b87e7691e Mon Sep 17 00:00:00 2001 From: Joachim Date: Thu, 27 Aug 2020 16:56:46 +0200 Subject: [PATCH] First working version of the OpenCV demo - Getting the camera image - Creating an OpenCV Mat object with it - Creating an lv_img_dsc_t LVGL object - Displaying it on the screen --- esp32/examples/ttgo_demo/main/main.cpp | 151 ++++++++++++++++++------- 1 file changed, 112 insertions(+), 39 deletions(-) diff --git a/esp32/examples/ttgo_demo/main/main.cpp b/esp32/examples/ttgo_demo/main/main.cpp index fcb5acc..a0f6091 100644 --- a/esp32/examples/ttgo_demo/main/main.cpp +++ b/esp32/examples/ttgo_demo/main/main.cpp @@ -30,6 +30,67 @@ void app_main(void); extern CEspLcd *tft; +static lv_obj_t *lvCameraImage; // Camera image object + +void gui_boot_screen() { + lv_obj_t *scr = lv_disp_get_scr_act(nullptr); + + lv_obj_t *label1 = lv_label_create(scr, nullptr); + lv_label_set_text(label1, "Hello World!"); + lv_obj_align(label1, nullptr, LV_ALIGN_CENTER, 0, 0); + +} + +void gui_init() { + // Create screen + lv_obj_t *scr = lv_obj_create(nullptr, nullptr); + lv_scr_load(scr); + + // Init camera image Lvgl object + lvCameraImage = lv_img_create(lv_disp_get_scr_act(nullptr), nullptr); + lv_obj_set_hidden(lvCameraImage, true); + lv_obj_move_foreground(lvCameraImage); +} + +esp_err_t updateCameraImage(const cv::Mat &img) { + // static variables because they must still be available when lv_task_handler() is called + static Mat imgCopy; + static lv_img_dsc_t my_img_dsc; + + if(img.empty()) { + ESP_LOGW(TAG, "Can't display empty image"); + return ESP_ERR_INVALID_ARG; + } + + // convert image to bgr565 if needed + if(img.type() == CV_8UC1) { // grayscale image + cvtColor(img, imgCopy, COLOR_GRAY2BGR565, 1); + } + else if(img.type() == CV_8UC3) { // BGR888 image + cvtColor(img, imgCopy, COLOR_BGR2BGR565, 1); + } + else if(img.type() == CV_8UC2) { // BGR565 image + img.copyTo(imgCopy); + } + + my_img_dsc.header.always_zero = 0; + my_img_dsc.header.w = imgCopy.cols; + my_img_dsc.header.h = imgCopy.rows; + my_img_dsc.header.cf = LV_IMG_CF_TRUE_COLOR; + my_img_dsc.data_size = imgCopy.size().width * imgCopy.size().height; + my_img_dsc.data = imgCopy.ptr(0); + + if(lv_obj_get_hidden(lvCameraImage)) + lv_obj_set_hidden(lvCameraImage, false); + lv_obj_move_foreground(lvCameraImage); + + lv_img_set_src(lvCameraImage, &my_img_dsc); /* Set the created file as image */ + lv_obj_set_pos(lvCameraImage, -40, 0); + + return ESP_OK; +} +//#endif + /** * Task doing the demo: Getting image from camera, processing it with opencv depending on the displayMode and * displaying it on the lcd @@ -40,6 +101,9 @@ void demo_task(void *arg) { // Display memory infos disp_infos(); + tft->setRotation(2); // rotation needed if camera is on the back of the device + sensor_t *s = esp_camera_sensor_get(); + while(true) { auto start = esp_timer_get_time(); @@ -48,50 +112,54 @@ void demo_task(void *arg) { if (!fb) { ESP_LOGE(TAG, "Camera capture failed"); } else { - TFT_jpg_image(CENTER, CENTER, 0, -1, NULL, fb->buf, fb->len); - esp_camera_fb_return(fb); - fb = NULL; + if(s->pixformat == PIXFORMAT_JPEG) { + TFT_jpg_image(CENTER, CENTER, 0, -1, NULL, fb->buf, fb->len); + esp_camera_fb_return(fb); + fb = NULL; + } + else { // RGB565 pixformat + Mat inputImage(fb->height, fb->width, CV_8UC2, fb->buf); // rgb565 is 2 channels of 8-bit unsigned + updateCameraImage(inputImage); + +#if 0 // TODO: next step.. + Mat outputImage; + + if(currentDisplayMode == DisplayMode::RGB) { + } + else if(currentDisplayMode == DisplayMode::GRAYSCALE) { + cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); + } + else if(currentDisplayMode == DisplayMode::BINARIZED) { + cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); + threshold(inputImage, inputImage, 128, 255, THRESH_BINARY); + } + else if(currentDisplayMode == DisplayMode::EDGES) { + cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); + // Reduce noise with a kernel 3x3 + blur(inputImage, inputImage, Size(3, 3)); + /** Apply the canny edges detector with: + * - low threshold = 50 + * - high threshold = 4x low + * - sobel kernel size = 3x3 + */ + int lowThresh = 40; + int kernSize = 3; + Canny(inputImage, inputImage, lowThresh, 4 * lowThresh, kernSize); + } + else { + ESP_LOGE(TAG, "Wrong display mode: %d", (int)currentDisplayMode); + } + + // Diplay image on LCD + setImage(inputImage); +#endif + } } ESP_LOGI(TAG, "time taken: %lld ms", (esp_timer_get_time() - start) / 1000); -#if 0 // TODO: next step.. - Mat inputImage(fb->height, fb->width, CV_8UC2, fb->buf); // rgb565 is 2 channels of 8-bit unsigned - Mat outputImage; - - - if(currentDisplayMode == DisplayMode::RGB) { - } - else if(currentDisplayMode == DisplayMode::GRAYSCALE) { - cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); - } - else if(currentDisplayMode == DisplayMode::BINARIZED) { - cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); - threshold(inputImage, inputImage, 128, 255, THRESH_BINARY); - } - else if(currentDisplayMode == DisplayMode::EDGES) { - cvtColor(inputImage, inputImage, COLOR_BGR5652GRAY); - // Reduce noise with a kernel 3x3 - blur(inputImage, inputImage, Size(3, 3)); - /** Apply the canny edges detector with: - * - low threshold = 50 - * - high threshold = 4x low - * - sobel kernel size = 3x3 - */ - int lowThresh = 40; - int kernSize = 3; - Canny(inputImage, inputImage, lowThresh, 4 * lowThresh, kernSize); - } - else { - ESP_LOGE(TAG, "Wrong display mode: %d", (int)currentDisplayMode); - } - - // Diplay image on LCD - setImage(inputImage); - -#endif - wait_msec(25); + lv_task_handler(); // tells LVGL to handle its tasks } } @@ -102,6 +170,11 @@ void app_main() /* initializations */ app_camera_init(); lvgl_init(); + gui_init(); + + /* display boot screen */ + gui_boot_screen(); + wait_msec(1500); /* Display memory infos */ disp_infos();