diff --git a/docs/images/face_detection.png b/docs/images/face_detection.png new file mode 100644 index 00000000..fd3c4fe8 Binary files /dev/null and b/docs/images/face_detection.png differ diff --git a/docs/img-proc-examples/face-detection.md b/docs/img-proc-examples/face-detection.md index d892163d..e618fda9 100644 --- a/docs/img-proc-examples/face-detection.md +++ b/docs/img-proc-examples/face-detection.md @@ -5,9 +5,41 @@ page_id: face-detection This is the face detection application based on the example as developed by Greenwaves technologies. It is a bit more tailor made towards the AI-deck and uses the wifi streamer to stream the output to your computer. -This was tested on **GAP_SDK version 3.8.1**. Make sure that next to `make SDK`, you also do `make gap_tools`. +This was tested on **GAP_SDK version 4.8.0.2**, which at the moment of writing was the newest we had a docker container for. -> Working directory: AIdeck_examples/GAP8/image_processing_examples/FaceDetection +# Docker GAP-SDK + +Make sure to follow the [getting started with the AI deck tutorial](https://www.bitcraze.io/documentation/tutorials/getting-started-with-aideck/) before continuing. + +To clean, compile and flash the FaceDetection example you have to be in the aideck-gap8-examples directory and execute: + + docker run --rm -v ${PWD}:/module --privileged aideck-with-autotiler tools/build/make-example examples/image_processing/FaceDetection clean all flash + +(if you did not modify the Makefile it should be possible to skip the _clean_). + +If you configured your Crazyflie firmware such that the AIdeck will act as access point (as described in the [wifi-streamer example](/docs/test-functions/wifi-streamer.md)) you can now just connect to it. If you configured it to connect to an existing network you should make sure your computer is in the same network and you need to check the IP address of the AIdeck - for example connect to it through the cfclient and check the console prints. + +Now you can run the image viewer: + + python3 opencv-viewer.py -n "AI_DECK_IP" + +where "AI_DECK_IP" should be replaced with for example 192.168.4.1 (which is the default value and the value used if the AIdeck acts as access point, so in this case it can be omitted). + +Now you should see something like this: + +![image streamer](/docs/images/face_detection.png) + +Note that the face detection does not work great under all conditions - try with a white background and dark hair... + +In the makefile you can comment the following line if you would like to disable the streamer: + + APP_CFLAGS += -DUSE_STREAMER + +Or - what is way more fun to play with - you can set the resolution of the streamed image with _STREAM\_W_ and _STREAM\_H_. Note that you cannot set values higher than 324x244 and that unproportional changes will result in distorted images. Note also that you need to adapt the resolution in the _opencv-viewer.py_ as well. + +# Local GAP-SDK installation + +> Working directory: aideck-gap8-examples/examples/image_processing/FaceDetection To make the face detection application @@ -24,9 +56,8 @@ To flash the code fully on the ai deck: make flash -In the makefile you can uncomment the following lines if you would like to use the himax camera or the streamer: +In the makefile you can comment the following line if you would like to disable the streamer: - # APP_CFLAGS += -DUSE_CAMERA - # APP_CFLAGS += -DUSE_STREAMER + APP_CFLAGS += -DUSE_STREAMER -After that, you can also use `viewer.py` to see the image stream. The rectangle generated around your face is implemented by the firmware. +After that, you can also use `opencv-viewer.py` to see the image stream. The rectangle generated around your face is implemented by the firmware. diff --git a/docs/test-functions/test-camera.md b/docs/test-functions/test-camera.md index 14c873eb..e410b58c 100644 --- a/docs/test-functions/test-camera.md +++ b/docs/test-functions/test-camera.md @@ -3,7 +3,10 @@ title: Testing the Himax Camera page_id: test-camera --- -This concerns the example in folder *AIdeck_examples/GAP8/test_functionalities/test_camera/*. This was tested on **GAP_SDK version 3.8.1**. +# Testing the Himax camera on the AIdeck + + +This concerns the example in folder *AIdeck_examples/GAP8/test_functionalities/test_camera/*. This was tested on **GAP_SDK version 4.8.0.2**, which at the moment of writing was the newest we had a docker container for. In the makefile enable `APP_CFLAGS += -DASYNC_CAPTURE` if you want to test the asynchronous camera capture and remove it if you want to test the normal one. To save a color image enable `APP_CFLAGS += -DCOLOR_IMAGE`. And, to capture a `324x324` image enable `APP_CFLAGS += -DQVGA_MODE`. *Please note though that capturing an image in non-QVGA mode might not always work correctly.* @@ -16,5 +19,5 @@ for directly running the code from L2 (second level internal memory) with your p ## Run in Docker To build and execute in the docker we need to place the `demosaicking`-files in the `common`-folder inside the docker. ``` -docker run --rm -it -v $PWD:/module/data/ --device /dev/ttyUSB0 --privileged -P gapsdk:3.7 /bin/bash -c 'export GAPY_OPENOCD_CABLE=interface/ftdi/olimex-arm-usb-tiny-h.cfg; source /gap_sdk/configs/ai_deck.sh; cd /module/data/; make clean all run' +docker run --rm -it -v $PWD:/module/data/ --device /dev/ttyUSB0 --privileged -P bitcraze/aideck:4.8.0.2 /bin/bash -c 'export GAPY_OPENOCD_CABLE=interface/ftdi/olimex-arm-usb-tiny-h.cfg; source /gap_sdk/configs/ai_deck.sh; cd /module/data/; make clean all run' ``` diff --git a/examples/image_processing/FaceDetection/FaceDetModel.c b/examples/image_processing/FaceDetection/FaceDetModel.c index aee680ab..1fe6cc48 100644 --- a/examples/image_processing/FaceDetection/FaceDetModel.c +++ b/examples/image_processing/FaceDetection/FaceDetModel.c @@ -74,7 +74,7 @@ int main(int argc, char **argv) GenerateCascadeClassifier("Cascade_3",Wout,Hout,24,24); - GenerateResize("final_resize", W, H, 160, 120); + GenerateResize("final_resize", W, H, STREAM_W, STREAM_H); // Now that we are done with model parsing we generate the code GenerateTilingCode(); diff --git a/examples/image_processing/FaceDetection/Makefile b/examples/image_processing/FaceDetection/Makefile index aa3fa19c..47868d9d 100644 --- a/examples/image_processing/FaceDetection/Makefile +++ b/examples/image_processing/FaceDetection/Makefile @@ -18,6 +18,9 @@ APP = face_detection NB_FRAMES ?= -1 +STREAM_W = 160 +STREAM_H = 120 + FACE_DET_MODEL_SRC = FaceDetGenerator.c FaceDetModel.c FACE_DET_MODEL_GEN = FaceDetKernels FACE_DET_MODEL_GEN_C = $(addsuffix .c, $(FACE_DET_MODEL_GEN)) @@ -25,18 +28,22 @@ FACE_DET_MODEL_GEN_CLEAN = $(FACE_DET_MODEL_GEN_C) $(addsuffix .h, $(FACE_DET_MO FACE_DET_SRCS += main.c faceDet.c FaceDetBasicKernels.c ImageDraw.c $(FACE_DET_MODEL_GEN_C) APP_SRCS += $(FACE_DET_SRCS) +APP_SRCS += ../../../lib/cpx/src/com.c ../../../lib/cpx/src/cpx.c APP_INC += $(TILER_INC) APP_CFLAGS += -O3 -g -D__PMSIS__ -DNB_FRAMES=$(NB_FRAMES) -# APP_CFLAGS += -DUSE_CAMERA -# APP_CFLAGS += -DUSE_STREAMER +APP_CFLAGS += -DUSE_STREAMER +APP_CFLAGS += -DSTREAM_W=$(STREAM_W) +APP_CFLAGS += -DSTREAM_H=$(STREAM_H) +APP_INC += ../../../lib/cpx/inc +APP_CFLAGS += -DconfigUSE_TIMERS=1 -DINCLUDE_xTimerPendFunctionCall=1 BOARD_NAME ?= ai_deck -PMSIS_OS ?= pulp_os USE_PMSIS_BSP = 1 -APP_LDFLAGS += -lgaptools -lgaplib export GAP_USE_OPENOCD=1 io=host +# io=uart +PMSIS_OS = freertos # This needs to be defined or else some other IO functionalities or cluster things will break... APP_CFLAGS += -DHIMAX diff --git a/examples/image_processing/FaceDetection/main.c b/examples/image_processing/FaceDetection/main.c index 627c964d..88d3ac27 100644 --- a/examples/image_processing/FaceDetection/main.c +++ b/examples/image_processing/FaceDetection/main.c @@ -22,15 +22,17 @@ #include "bsp/buffer.h" /* PMSIS BSP includes */ +#include "bsp/bsp.h" +#include "bsp/buffer.h" #include "bsp/ai_deck.h" #include "bsp/camera/himax.h" /* Gaplib includes */ -#include "gaplib/ImgIO.h" +// #include "gaplib/ImgIO.h" #if defined(USE_STREAMER) -#include "bsp/transport/nina_w10.h" -#include "tools/frame_streamer.h" +#include "cpx.h" +#include "wifi.h" #endif /* USE_STREAMER */ // All includes for facedetector application @@ -41,10 +43,135 @@ #define CAM_WIDTH 324 #define CAM_HEIGHT 244 +#define IMG_ORIENTATION 0x0101 #define IMAGE_OUT_WIDTH 64 #define IMAGE_OUT_HEIGHT 48 +static EventGroupHandle_t evGroup; +#define CAPTURE_DONE_BIT (1 << 0) + +// Performance menasuring variables +static uint32_t start = 0; +static uint32_t captureTime = 0; +static uint32_t transferTime = 0; +static uint32_t encodingTime = 0; +// #define OUTPUT_PROFILING_DATA + +static int wifiConnected = 0; +static int wifiClientConnected = 0; + +static pi_task_t task1; + +static CPXPacket_t rxp; +void rx_task(void *parameters) +{ + while (1) + { + cpxReceivePacketBlocking(CPX_F_WIFI_CTRL, &rxp); + + WiFiCTRLPacket_t * wifiCtrl = (WiFiCTRLPacket_t*) rxp.data; + + switch (wifiCtrl->cmd) + { + case WIFI_CTRL_STATUS_WIFI_CONNECTED: + cpxPrintToConsole(LOG_TO_CRTP, "Wifi connected (%u.%u.%u.%u)\n", + wifiCtrl->data[0], wifiCtrl->data[1], + wifiCtrl->data[2], wifiCtrl->data[3]); + wifiConnected = 1; + break; + case WIFI_CTRL_STATUS_CLIENT_CONNECTED: + cpxPrintToConsole(LOG_TO_CRTP, "Wifi client connection status: %u\n", wifiCtrl->data[0]); + wifiClientConnected = wifiCtrl->data[0]; + break; + default: + break; + } + } +} + +static void capture_done_cb(void *arg) +{ + xEventGroupSetBits(evGroup, CAPTURE_DONE_BIT); +} + +typedef struct +{ + uint8_t magic; + uint16_t width; + uint16_t height; + uint8_t depth; + uint8_t type; + uint32_t size; +} __attribute__((packed)) img_header_t; + + +typedef enum +{ + RAW_ENCODING = 0, + JPEG_ENCODING = 1 +} __attribute__((packed)) StreamerMode_t; + +pi_buffer_t header; +uint32_t headerSize; +pi_buffer_t footer; +uint32_t footerSize; +pi_buffer_t jpeg_data; +uint32_t jpegSize; + +static StreamerMode_t streamerMode = RAW_ENCODING; + +static CPXPacket_t txp; + +void createImageHeaderPacket(CPXPacket_t * packet, uint32_t imgSize, StreamerMode_t imgType) { + img_header_t *imgHeader = (img_header_t *) packet->data; + imgHeader->magic = 0xBC; + imgHeader->width = CAM_WIDTH; + imgHeader->height = CAM_HEIGHT; + imgHeader->depth = 1; + imgHeader->type = imgType; + imgHeader->size = imgSize; + packet->dataLength = sizeof(img_header_t); +} + +void sendBufferViaCPX(CPXPacket_t * packet, uint8_t * buffer, uint32_t bufferSize) { + uint32_t offset = 0; + uint32_t size = 0; + do { + size = sizeof(packet->data); + if (offset + size > bufferSize) + { + size = bufferSize - offset; + } + memcpy(packet->data, &buffer[offset], sizeof(packet->data)); + packet->dataLength = size; + cpxSendPacketBlocking(packet); + offset += size; + } while (size == sizeof(packet->data)); +} + +#ifdef SETUP_WIFI_AP +void setupWiFi(void) { + static char ssid[] = "WiFi streaming example"; + cpxPrintToConsole(LOG_TO_CRTP, "Setting up WiFi AP\n"); + // Set up the routing for the WiFi CTRL packets + txp.route.destination = CPX_T_ESP32; + rxp.route.source = CPX_T_GAP8; + txp.route.function = CPX_F_WIFI_CTRL; + WiFiCTRLPacket_t * wifiCtrl = (WiFiCTRLPacket_t*) txp.data; + + wifiCtrl->cmd = WIFI_CTRL_SET_SSID; + memcpy(wifiCtrl->data, ssid, sizeof(ssid)); + txp.dataLength = sizeof(ssid); + cpxSendPacketBlocking(&txp); + + wifiCtrl->cmd = WIFI_CTRL_WIFI_CONNECT; + wifiCtrl->data[0] = 0x01; + txp.dataLength = 2; + cpxSendPacketBlocking(&txp); +} +#endif + // Intializing buffers for camera images static unsigned char *imgBuff0; static struct pi_device ili; @@ -64,7 +191,6 @@ struct pi_cluster_task *task; struct pi_cluster_conf conf; ArgCluster_T ClusterCall; -#if defined(USE_CAMERA) // Open himax camera funciton static int open_camera_himax(struct pi_device *device) { @@ -87,23 +213,19 @@ static int open_camera_himax(struct pi_device *device) pi_camera_reg_get(device, IMG_ORIENTATION, ®_value); if (set_value!=reg_value) { - printf("Failed to rotate camera image\n"); + cpxPrintToConsole(LOG_TO_CRTP, "Failed to rotate camera image\n"); return -1; } - + pi_camera_control(device, PI_CAMERA_CMD_STOP, 0); pi_camera_control(device, PI_CAMERA_CMD_AEG_INIT, 0); return 0; } -#endif /* USE_CAMERA */ + static int open_camera(struct pi_device *device) { -#if defined(USE_CAMERA) return open_camera_himax(device); -#else - return 0; -#endif /* USE_CAMERA */ } //UART init param @@ -111,56 +233,6 @@ L2_MEM struct pi_uart_conf uart_conf; L2_MEM struct pi_device uart; L2_MEM uint8_t rec_digit = -1; -#if defined(USE_STREAMER) -// Initialize structs and function for streamer through wifi -static pi_task_t task1; -static struct pi_device wifi; -static frame_streamer_t *streamer1; -static volatile int stream1_done; - -static void streamer_handler(void *arg) -{ - *(int *)arg = 1; - if (stream1_done) - { - } -} - -static int open_wifi(struct pi_device *device) -{ - struct pi_nina_w10_conf nina_conf; - - pi_nina_w10_conf_init(&nina_conf); - - nina_conf.ssid = ""; - nina_conf.passwd = ""; - nina_conf.ip_addr = "192.168.0.0"; - nina_conf.port = 5555; - pi_open_from_conf(device, &nina_conf); - if (pi_transport_open(device)) - return -1; - - return 0; -} - -static frame_streamer_t *open_streamer(char *name) -{ - struct frame_streamer_conf frame_streamer_conf; - - frame_streamer_conf_init(&frame_streamer_conf); - - frame_streamer_conf.transport = &wifi; - frame_streamer_conf.format = FRAME_STREAMER_FORMAT_JPEG; - frame_streamer_conf.width = CAM_WIDTH; - frame_streamer_conf.height = CAM_HEIGHT; - frame_streamer_conf.depth = 1; - frame_streamer_conf.name = name; - - return frame_streamer_open(&frame_streamer_conf); -} /* USE_STREAMER */ - -#endif - // Functions and init for LED toggle static pi_task_t led_task; @@ -175,11 +247,17 @@ static void led_handle(void *arg) -void test_facedetection(void) +void facedetection_task(void) { + vTaskDelay(2000); + cpxInitRoute(CPX_T_GAP8, CPX_T_WIFI_HOST, CPX_F_APP, &txp.route); + cpxPrintToConsole(LOG_TO_CRTP, "Starting face detection task...\n"); - printf("Entering main controller...\n"); +#ifdef SETUP_WIFI_AP + setupWiFi(); +#endif + unsigned int W = CAM_WIDTH, H = CAM_HEIGHT; unsigned int Wout = 64, Hout = 48; unsigned int ImgSize = W * H; @@ -190,7 +268,7 @@ void test_facedetection(void) imgBuff0 = (unsigned char *)pmsis_l2_malloc((CAM_WIDTH * CAM_HEIGHT) * sizeof(unsigned char)); if (imgBuff0 == NULL) { - printf("Failed to allocate Memory for Image \n"); + cpxPrintToConsole(LOG_TO_CRTP, "Failed to allocate Memory for Image \n"); pmsis_exit(-1); } @@ -200,39 +278,21 @@ void test_facedetection(void) SquaredImageIntegral = (unsigned int *)pmsis_l2_malloc((Wout * Hout) * sizeof(unsigned int)); if (ImageOut == 0) { - printf("Failed to allocate Memory for Image (%d bytes)\n", ImgSize * sizeof(unsigned char)); + cpxPrintToConsole(LOG_TO_CRTP, "Failed to allocate Memory for Image (%d bytes)\n", ImgSize * sizeof(unsigned char)); pmsis_exit(-2); } if ((ImageIntegral == 0) || (SquaredImageIntegral == 0)) { - printf("Failed to allocate Memory for one or both Integral Images (%d bytes)\n", ImgSize * sizeof(unsigned int)); + cpxPrintToConsole(LOG_TO_CRTP, "Failed to allocate Memory for one or both Integral Images (%d bytes)\n", ImgSize * sizeof(unsigned int)); pmsis_exit(-3); } - printf("malloc done\n"); + // printf("malloc done\n"); -#if defined(USE_CAMERA) if (open_camera(&cam)) { - printf("Failed to open camera\n"); + cpxPrintToConsole(LOG_TO_CRTP, "Failed to open camera\n"); pmsis_exit(-5); } -#endif - -#if defined(USE_STREAMER) - - if (open_wifi(&wifi)) - { - printf("Failed to open wifi\n"); - return -1; - } - printf("WIFI connected\n"); // check this with NINA printout - - streamer1 = open_streamer("cam"); - if (streamer1 == NULL) - return -1; - printf("Streamer set up\n"); - -#endif // UART init with Crazyflie and configure pi_uart_conf_init(&uart_conf); @@ -241,10 +301,10 @@ void test_facedetection(void) pi_open_from_conf(&uart, &uart_conf); if (pi_uart_open(&uart)) { - printf("[UART] open failed !\n"); + cpxPrintToConsole(LOG_TO_CRTP, "[UART] open failed !\n"); pmsis_exit(-1); } - printf("[UART] Open\n"); + cpxPrintToConsole(LOG_TO_CRTP, "[UART] Open\n"); // Setup buffer for images buffer.data = imgBuff0 + CAM_WIDTH * 2 + 2; @@ -275,8 +335,8 @@ void test_facedetection(void) pi_open_from_conf(&cluster_dev, (void *)&conf); pi_cluster_open(&cluster_dev); - //Set Cluster Frequency to max - pi_freq_set(PI_FREQ_DOMAIN_CL, 175000000); + //Set Cluster Frequency to 75MHz - max (175000000) leads to more camera failures (unknown why) + pi_freq_set(PI_FREQ_DOMAIN_CL, 75000000); // Send intializer function to cluster task = (struct pi_cluster_task *)pmsis_l2_malloc(sizeof(struct pi_cluster_task)); @@ -289,50 +349,123 @@ void test_facedetection(void) task->entry = (void *)faceDet_cluster_main; task->arg = &ClusterCall; - printf("main loop start\n"); + // printf("main loop start\n"); // Start looping through images int nb_frames = 0; + EventBits_t evBits; + pi_camera_control(&cam, PI_CAMERA_CMD_STOP, 0); + while (1 && (NB_FRAMES == -1 || nb_frames < NB_FRAMES)) { -#if defined(USE_CAMERA) // Capture image + pi_camera_capture_async(&cam, imgBuff0, CAM_WIDTH * CAM_HEIGHT, pi_task_callback(&task1, capture_done_cb, NULL)); pi_camera_control(&cam, PI_CAMERA_CMD_START, 0); - pi_camera_capture(&cam, imgBuff0, CAM_WIDTH * CAM_HEIGHT); + // it should really not take longer than 500ms to acquire an image, maybe we could even time out earlier + evBits = xEventGroupWaitBits(evGroup, CAPTURE_DONE_BIT, pdTRUE, pdFALSE, (TickType_t)(500/portTICK_PERIOD_MS)); pi_camera_control(&cam, PI_CAMERA_CMD_STOP, 0); -#else - // Read in image to check if NN is still working - // TODO: this breaks after the second read.... - char imageName[64]; - sprintf(imageName, "../../../imgTest%d.pgm", nb_frames); - printf("Loading %s ...\n", imageName); - if (ReadImageFromFile(imageName, CAM_WIDTH, CAM_HEIGHT, 1, imgBuff0, CAM_WIDTH * CAM_HEIGHT * sizeof(char), IMGIO_OUTPUT_CHAR, 0)) + // if we didn't succeed in capturing the image (which, especially with high cluster frequencies and dark images can happen) we want to retry + while((evBits & CAPTURE_DONE_BIT) != CAPTURE_DONE_BIT) { - printf("Failed to load image %s\n", imageName); - return 1; + cpxPrintToConsole(LOG_TO_CRTP, "Failed camera acquisition\n"); + pi_camera_control(&cam, PI_CAMERA_CMD_START, 0); + evBits = xEventGroupWaitBits(evGroup, CAPTURE_DONE_BIT, pdTRUE, pdFALSE, (TickType_t)(500/portTICK_PERIOD_MS)); + pi_camera_control(&cam, PI_CAMERA_CMD_STOP, 0); } -#endif /* USE_CAMERA */ // Send task to the cluster and print response pi_cluster_send_task_to_cl(&cluster_dev, task); - printf("end of face detection, faces detected: %d\n", ClusterCall.num_reponse); - //WriteImageToFile("../../../img_out.ppm", IMAGE_OUT_WIDTH, IMAGE_OUT_HEIGHT, 1, ImageOut, GRAY_SCALE_IO); + // cpxPrintToConsole(LOG_TO_CRTP, "end of face detection, faces detected: %d\n", ClusterCall.num_reponse); #if defined(USE_STREAMER) - // Send image to the streamer to see the result - frame_streamer_send_async(streamer1, &buffer, pi_task_callback(&task1, streamer_handler, (void *)&stream1_done)); + if (wifiClientConnected == 1) + { + // First send information about the image + createImageHeaderPacket(&txp, STREAM_W*STREAM_H, RAW_ENCODING); + cpxSendPacketBlocking(&txp); + // Send image + sendBufferViaCPX(&txp, ImageOut, STREAM_W*STREAM_H); + } #endif // Send result through the uart to the crazyflie as single characters pi_uart_write(&uart, &ClusterCall.num_reponse, 1); nb_frames++; } - printf("Test face detection done.\n"); + cpxPrintToConsole(LOG_TO_CRTP, "Test face detection done.\n"); pmsis_exit(0); } +#define LED_PIN 2 +static pi_device_t led_gpio_dev; +void hb_task(void *parameters) +{ + (void)parameters; + char *taskname = pcTaskGetName(NULL); + + // Initialize the LED pin + pi_gpio_pin_configure(&led_gpio_dev, LED_PIN, PI_GPIO_OUTPUT); + + const TickType_t xDelay = 500 / portTICK_PERIOD_MS; + + while (1) + { + pi_gpio_pin_write(&led_gpio_dev, LED_PIN, 1); + vTaskDelay(xDelay); + pi_gpio_pin_write(&led_gpio_dev, LED_PIN, 0); + vTaskDelay(xDelay); + } +} + +void start_example(void) +{ + cpxInit(); + cpxEnableFunction(CPX_F_WIFI_CTRL); + + cpxPrintToConsole(LOG_TO_CRTP, "-- WiFi image streamer example --\n"); + + evGroup = xEventGroupCreate(); + + BaseType_t xTask; + + xTask = xTaskCreate(hb_task, "hb_task", configMINIMAL_STACK_SIZE * 2, + NULL, tskIDLE_PRIORITY + 1, NULL); + if (xTask != pdPASS) + { + cpxPrintToConsole(LOG_TO_CRTP, "HB task did not start !\n"); + pmsis_exit(-1); + } + + xTask = xTaskCreate(facedetection_task, "facedetection_task", configMINIMAL_STACK_SIZE * 4, + NULL, tskIDLE_PRIORITY + 1, NULL); + + if (xTask != pdPASS) + { + cpxPrintToConsole(LOG_TO_CRTP, "Camera task did not start !\n"); + pmsis_exit(-1); + } + + xTask = xTaskCreate(rx_task, "rx_task", configMINIMAL_STACK_SIZE * 2, + NULL, tskIDLE_PRIORITY + 1, NULL); + + if (xTask != pdPASS) + { + cpxPrintToConsole(LOG_TO_CRTP, "RX task did not start !\n"); + pmsis_exit(-1); + } + + while (1) + { + pi_yield(); + } +} + int main(void) { - printf("\n\t*** PMSIS FaceDetection Test ***\n\n"); - return pmsis_kickoff((void *)test_facedetection); + pi_bsp_init(); + + // Increase the FC freq to 250 MHz + pi_freq_set(PI_FREQ_DOMAIN_FC, 250000000); + pi_pmu_voltage_set(PI_PMU_DOMAIN_FC, 1200); + return pmsis_kickoff((void *)start_example); } diff --git a/examples/image_processing/FaceDetection/opencv-viewer.py b/examples/image_processing/FaceDetection/opencv-viewer.py new file mode 100644 index 00000000..374b737c --- /dev/null +++ b/examples/image_processing/FaceDetection/opencv-viewer.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# || ____ _ __ +# +------+ / __ )(_) /_______________ _____ ___ +# | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \ +# +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/ +# || || /_____/_/\__/\___/_/ \__,_/ /___/\___/ +# +# Copyright (C) 2021 Bitcraze AB +# +# AI-deck demo +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Demo for showing streamed JPEG images from the AI-deck example. +# +# By default this demo connects to the IP of the AI-deck example when in +# Access point mode. +# +# The demo works by opening a socket to the AI-deck, downloads a stream of +# JPEG images and looks for start/end-of-frame for the streamed JPEG images. +# Once an image has been fully downloaded it's rendered in the UI. +# +# Note that the demo firmware is continously streaming JPEG files so a single +# JPEG image is taken from the stream using the JPEG start-of-frame (0xFF 0xD8) +# and the end-of-frame (0xFF 0xD9). + +import argparse +import time +import socket,os,struct, time +import numpy as np + +# Args for setting IP/port of AI-deck. Default settings are for when +# AI-deck is in AP mode. +parser = argparse.ArgumentParser(description='Connect to AI-deck JPEG streamer example') +parser.add_argument("-n", default="192.168.4.1", metavar="ip", help="AI-deck IP") +parser.add_argument("-p", type=int, default='5000', metavar="port", help="AI-deck port") +parser.add_argument('--save', action='store_true', help="Save streamed images") +args = parser.parse_args() + +deck_port = args.p +deck_ip = args.n + +print("Connecting to socket on {}:{}...".format(deck_ip, deck_port)) +client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +client_socket.connect((deck_ip, deck_port)) +print("Socket connected") + +imgdata = None +data_buffer = bytearray() + +def rx_bytes(size): + data = bytearray() + while len(data) < size: + data.extend(client_socket.recv(size-len(data))) + return data + +import cv2 + +stream_w = 160 +stream_h = 120 + +start = time.time() +count = 0 + +while(1): + # First get the info + packetInfoRaw = rx_bytes(4) + #print(packetInfoRaw) + [length, routing, function] = struct.unpack('0x{:02X}".format(routing & 0xF, routing >> 4)) + #print("Function is 0x{:02X}".format(function)) + + imgHeader = rx_bytes(length - 2) + #print(imgHeader) + #print("Length of data is {}".format(len(imgHeader))) + [magic, width, height, depth, format, size] = struct.unpack('{:02X})".format(length, src, dst)) + chunk = rx_bytes(length - 2) + imgStream.extend(chunk) + + count = count + 1 + meanTimePerImage = (time.time()-start) / count + print("{}".format(meanTimePerImage)) + print("{}".format(1/meanTimePerImage)) + + if format == 0: + bayer_img = np.frombuffer(imgStream, dtype=np.uint8) + bayer_img.shape = (stream_h, stream_w) + cv2.namedWindow('Raw', cv2.WINDOW_NORMAL) + cv2.resizeWindow('Raw', 600,600) + cv2.imshow('Raw', bayer_img) + if args.save: + cv2.imwrite(f"stream_out/raw/img_{count:06d}.png", bayer_img) + cv2.waitKey(1) + else: + with open("img.jpeg", "wb") as f: + f.write(imgStream) + nparr = np.frombuffer(imgStream, np.uint8) + decoded = cv2.imdecode(nparr,cv2.IMREAD_UNCHANGED) + cv2.imshow('JPEG', decoded) + cv2.waitKey(1) + diff --git a/examples/image_processing/FaceDetection/wifi.h b/examples/image_processing/FaceDetection/wifi.h new file mode 100644 index 00000000..8e44996a --- /dev/null +++ b/examples/image_processing/FaceDetection/wifi.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +typedef enum { + WIFI_CTRL_SET_SSID = 0x10, + WIFI_CTRL_SET_KEY = 0x11, + + WIFI_CTRL_WIFI_CONNECT = 0x20, + + WIFI_CTRL_STATUS_WIFI_CONNECTED = 0x31, + WIFI_CTRL_STATUS_CLIENT_CONNECTED = 0x32, +} __attribute__((packed)) WiFiCTRLType; + +typedef struct { + WiFiCTRLType cmd; + uint8_t data[50]; +} __attribute__((packed)) WiFiCTRLPacket_t; \ No newline at end of file diff --git a/examples/other/test_functionalities/test_camera/test.c b/examples/other/test_functionalities/test_camera/test.c index b94c5eea..bcf944d4 100644 --- a/examples/other/test_functionalities/test_camera/test.c +++ b/examples/other/test_functionalities/test_camera/test.c @@ -168,6 +168,6 @@ int test_camera() int main(void) { - printf("\n\t*** PMSIS Camera with LCD Example ***\n\n"); + printf("\n\t*** PMSIS Camera ***\n\n"); return pmsis_kickoff((void *) test_camera); } diff --git a/examples/other/wifi-img-streamer/wifi-img-streamer.c b/examples/other/wifi-img-streamer/wifi-img-streamer.c index 03d015bd..bfdc8b2b 100644 --- a/examples/other/wifi-img-streamer/wifi-img-streamer.c +++ b/examples/other/wifi-img-streamer/wifi-img-streamer.c @@ -66,19 +66,18 @@ static int open_pi_camera_himax(struct pi_device *device) return -1; // rotate image - pi_camera_control(&camera, PI_CAMERA_CMD_START, 0); + pi_camera_control(device, PI_CAMERA_CMD_START, 0); uint8_t set_value = 3; uint8_t reg_value; - pi_camera_reg_set(&camera, IMG_ORIENTATION, &set_value); + pi_camera_reg_set(device, IMG_ORIENTATION, &set_value); pi_time_wait_us(1000000); - pi_camera_reg_get(&camera, IMG_ORIENTATION, ®_value); + pi_camera_reg_get(device, IMG_ORIENTATION, ®_value); if (set_value != reg_value) { cpxPrintToConsole(LOG_TO_CRTP, "Failed to rotate camera image\n"); return -1; } - pi_camera_control(&camera, PI_CAMERA_CMD_STOP, 0); - + pi_camera_control(device, PI_CAMERA_CMD_STOP, 0); pi_camera_control(device, PI_CAMERA_CMD_AEG_INIT, 0); return 0;