diff --git a/conf/airframes/examples/bebop.xml b/conf/airframes/examples/bebop.xml index 85e7b55a96..8cc00a0023 100644 --- a/conf/airframes/examples/bebop.xml +++ b/conf/airframes/examples/bebop.xml @@ -17,9 +17,9 @@ - - - + + + @@ -50,9 +50,6 @@ - - - diff --git a/conf/modules/bebop_front_camera.xml b/conf/modules/bebop_front_camera.xml deleted file mode 100644 index 894dace458..0000000000 --- a/conf/modules/bebop_front_camera.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - Video streaming for the Bebop front camera - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - include $(CFG_SHARED)/udp.makefile - - BEBOP_FRONT_CAMERA_HOST ?= $(MODEM_HOST) - BEBOP_FRONT_CAMERA_PORT_OUT ?= 6000 - BEBOP_FRONT_CAMERA_BROADCAST ?= TRUE - - BEBOPVIEWVID_CFLAGS = -DBEBOP_FRONT_CAMERA_HOST=$(BEBOP_FRONT_CAMERA_HOST) -DBEBOP_FRONT_CAMERA_PORT_OUT=$(BEBOP_FRONT_CAMERA_PORT_OUT) - ifeq ($(BEBOP_FRONT_CAMERA_USE_NETCAT),) - ap.CFLAGS += $(BEBOPVIEWVID_CFLAGS) -DBEBOP_FRONT_CAMERA_BROADCAST=$(BEBOP_FRONT_CAMERA_BROADCAST) - else - ap.CFLAGS += $(BEBOPVIEWVID_CFLAGS) -DBEBOP_FRONT_CAMERA_USE_NETCAT - endif - - - - - - -
- diff --git a/sw/airborne/boards/bebop.h b/sw/airborne/boards/bebop.h index e114d00d2a..4ade6fc957 100644 --- a/sw/airborne/boards/bebop.h +++ b/sw/airborne/boards/bebop.h @@ -29,79 +29,6 @@ #include "peripherals/video_device.h" #include "boards/bebop/mt9f002.h" -/* define required ouput image size */ -#ifndef MT9F002_OUTPUT_HEIGHT -#define MT9F002_OUTPUT_HEIGHT 822 // full resolution 3288 -#endif - -#ifndef MT9F002_OUTPUT_WIDTH -#define MT9F002_OUTPUT_WIDTH 1152 // full resolution 4608 -#endif - -#ifndef MT9F002_INITIAL_OFFSET_X -#define MT9F002_INITIAL_OFFSET_X 0. // signed fractional offset from centre of image of original sensor [-0.5,0.5] -#endif - -#ifndef MT9F002_INITIAL_OFFSET_Y -#define MT9F002_INITIAL_OFFSET_Y 0. // signed fractional offset from centre of image of original sensor [-0.5,0.5] -#endif - -/** Our output is only OUTPUT_SCALER of the pixels we take of the sensor - * It is programmable in 1/16 steps determined by ScaleFactor = 16/scale_m. - * Legal values for scale_m are 16 through 128, giving you the ability to scale from - * 1:1 to 1:8 (with m=128). - * Example: - * output_width = 512 - * output_height = 830 - * output_scaler = 0.25 - * We now get an image of 512 by 830 which contains a "compressed version" - * of what would normally be an image of 2048 by 3320 ISP (4608H x 2592V sensor) - */ -#ifndef MT9F002_OUTPUT_SCALER -#define MT9F002_OUTPUT_SCALER 1. -#endif - -/** Exposure of the front camera of the bebop. Experimental values: - * Outside: 15 - * Inside well lit: 30 - * Inside poorly lit: 60 - */ -#ifndef MT9F002_TARGET_EXPOSURE -#define MT9F002_TARGET_EXPOSURE 30 -#endif - -#ifndef MT9F002_TARGET_FPS -#define MT9F002_TARGET_FPS 10 -#endif - -/* Set the colour balance gains */ -#ifndef MT9F002_GAIN_GREEN1 -#define MT9F002_GAIN_GREEN1 3.0 -#endif - -#ifndef MT9F002_GAIN_GREEN2 -#define MT9F002_GAIN_GREEN2 3.0 -#endif - -#ifndef MT9F002_GAIN_RED -#define MT9F002_GAIN_RED 3.0 -#endif - -#ifndef MT9F002_GAIN_BLUE -#define MT9F002_GAIN_BLUE 4.0 -#endif - -/* Set pixel increment value to implement subsampling */ -/* Supported values for MT9F002_X_ODD_INC_VAL are 3, 7, 15 and 31 */ -#ifndef MT9F002_X_ODD_INC_VAL -#define MT9F002_X_ODD_INC_VAL 1 -#endif - -/* Supported values for MT9F002_Y_ODD_INC_VAL are 1, 3 and 7 */ -#ifndef MT9F002_Y_ODD_INC_VAL -#define MT9F002_Y_ODD_INC_VAL 1 -#endif - /** uart connected to GPS internally */ #define UART1_DEV /dev/ttyPA1 #define GPS_UBX_ENABLE_NMEA_DATA_MASK 0xff diff --git a/sw/airborne/boards/bebop/mt9f002.c b/sw/airborne/boards/bebop/mt9f002.c index f77ca7cd19..ae3f5f7351 100644 --- a/sw/airborne/boards/bebop/mt9f002.c +++ b/sw/airborne/boards/bebop/mt9f002.c @@ -29,6 +29,7 @@ #include "mt9f002_regs.h" #include "math/pprz_algebra_int.h" #include "boards/bebop.h" +#include "modules/computer_vision/lib/isp/libisp.h" #include #include @@ -38,10 +39,10 @@ #include #include -#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#define MT9F002_MAX_WIDTH 4608 +#define MT9F002_MAX_HEIGHT 3288 -#define MAX_WIDTH 4608 -#define MAX_HEIGHT 3288 +extern struct libisp_config isp_config; /* Camera structure */ struct video_config_t front_camera = { @@ -571,16 +572,16 @@ static void mt9f002_set_blanking(struct mt9f002_t *mt) /* Calculate minimum line length */ float subsampling_factor = (float)(1 + x_odd_inc) / 2.0f; // See page 52 - uint16_t min_line_length = MAX(min_line_length_pck, + uint16_t min_line_length = Max(min_line_length_pck, mt->scaled_width / subsampling_factor + min_line_blanking_pck); // EQ 9 - min_line_length = MAX(min_line_length, + min_line_length = Max(min_line_length, (mt->scaled_width - 1 + x_odd_inc) / subsampling_factor / 2 + min_line_blanking_pck); if (mt->interface == MT9F002_MIPI || mt->interface == MT9F002_HiSPi) { - min_line_length = MAX(min_line_length, + min_line_length = Max(min_line_length, ((uint16_t)((float)mt->scaled_width * mt->vt_pix_clk / mt->op_pix_clk) / 2) + 0x005E); // 2 lanes, pll clocks } else { - min_line_length = MAX(min_line_length, + min_line_length = Max(min_line_length, ((uint16_t)((float)mt->scaled_width * mt->vt_pix_clk / mt->op_pix_clk)) + 0x005E); // pll clocks } @@ -648,7 +649,6 @@ static void mt9f002_set_blanking(struct mt9f002_t *mt) } } - printf("line: %d, frame %d\n", mt->line_length, mt->frame_length); /* Actually set the calculated values */ write_reg(mt, MT9F002_LINE_LENGTH_PCK, mt->line_length, 2); write_reg(mt, MT9F002_FRAME_LENGTH_LINES, mt->frame_length, 2); @@ -790,33 +790,34 @@ void mt9f002_set_resolution(struct mt9f002_t *mt) mt->output_scaler = (float)MT9F002_SCALER_N / scaleFactor; int x_skip_factor = (mt->x_odd_inc + 1) / 2; int y_skip_factor = (mt->y_odd_inc + 1) / 2; - mt->scaled_width = mt->output_width * x_skip_factor / mt->output_scaler - mt->x_odd_inc + 1; - mt->scaled_height = mt->output_height * y_skip_factor / mt->output_scaler - mt->y_odd_inc + 1; + mt->scaled_width = mt->output_width * x_skip_factor / mt->output_scaler + mt->x_odd_inc - 1; + mt->scaled_height = mt->output_height * y_skip_factor / mt->output_scaler + mt->y_odd_inc - 1; if (mt->scaled_width % (x_skip_factor * 8) != 0) { - mt->scaled_width = round(mt->scaled_width / (x_skip_factor * 8)) * (x_skip_factor * 8); + mt->scaled_width = floor(mt->scaled_width / (x_skip_factor * 8)) * (x_skip_factor * 8); printf("[MT9F002] Warning, scaled_width not a multiple of %i, changing to %i\n", 8 * x_skip_factor, mt->scaled_width); } if (mt->scaled_height % (y_skip_factor * 8) != 0) { - mt->scaled_height = round(mt->scaled_height / (y_skip_factor * 8)) * (y_skip_factor * 8); + mt->scaled_height = floor(mt->scaled_height / (y_skip_factor * 8)) * (y_skip_factor * 8); printf("[MT9F002] Warning, scaled_height not a multiple of %i, changing to %i\n", 8 * y_skip_factor, mt->scaled_height); } if (mt->output_scaler < 1.0) { write_reg(mt, MT9F002_SCALING_MODE, 2, 2); // Vertical and horizontal scaling write_reg(mt, MT9F002_SCALE_M, scaleFactor, 2); } - printf("OUTPUT_SIZE: (%i, %i)\tSCALED_SIZE: (%i, %i)\n", mt->output_width, mt->output_height, mt->scaled_width, + printf("[MT9F002] OUTPUT_SIZE: (%i, %i)\tSCALED_SIZE: (%i, %i)\n", mt->output_width, mt->output_height, + mt->scaled_width, mt->scaled_height); /* bound offsets */ - if (mt->offset_x * MAX_WIDTH + mt->scaled_width / 2 > MAX_WIDTH){mt->offset_x = 1 - (float)mt->scaled_width / 2 / MAX_WIDTH;} - if (-mt->offset_x * MAX_WIDTH > mt->scaled_width){mt->offset_x = -(float)mt->scaled_width/ 2 / MAX_WIDTH;} + if (mt->offset_x * MT9F002_MAX_WIDTH + mt->scaled_width / 2 > MT9F002_MAX_WIDTH) {mt->offset_x = 1 - (float)mt->scaled_width / 2 / MT9F002_MAX_WIDTH;} + if (-mt->offset_x * MT9F002_MAX_WIDTH > mt->scaled_width) {mt->offset_x = -(float)mt->scaled_width / 2 / MT9F002_MAX_WIDTH;} - if (mt->offset_y * MAX_HEIGHT + mt->scaled_height / 2 > MAX_HEIGHT){mt->offset_y = 1 - (float)mt->scaled_height/ 2 / MAX_HEIGHT;} - if (-mt->offset_y * MAX_HEIGHT > mt->scaled_height / 2){mt->offset_y = -(float)mt->scaled_height/ 2 / MAX_HEIGHT;} + if (mt->offset_y * MT9F002_MAX_HEIGHT + mt->scaled_height / 2 > MT9F002_MAX_HEIGHT) {mt->offset_y = 1 - (float)mt->scaled_height / 2 / MT9F002_MAX_HEIGHT;} + if (-mt->offset_y * MT9F002_MAX_HEIGHT > mt->scaled_height / 2) {mt->offset_y = -(float)mt->scaled_height / 2 / MT9F002_MAX_HEIGHT;} /* Set position (based on offset and subsample increment) */ - uint16_t start_addr_x = (uint16_t)((MAX_WIDTH - mt->scaled_width) / 2 + mt->offset_x * MAX_WIDTH); - uint16_t start_addr_y = (uint16_t)((MAX_HEIGHT - mt->scaled_height) / 2 + mt->offset_y * MAX_HEIGHT); + uint16_t start_addr_x = (uint16_t)((MT9F002_MAX_WIDTH - mt->scaled_width) / 2 + mt->offset_x * MT9F002_MAX_WIDTH); + uint16_t start_addr_y = (uint16_t)((MT9F002_MAX_HEIGHT - mt->scaled_height) / 2 + mt->offset_y * MT9F002_MAX_HEIGHT); if (start_addr_x < 24) { start_addr_x = 24; @@ -837,6 +838,17 @@ void mt9f002_set_resolution(struct mt9f002_t *mt) uint16_t end_addr_y = start_addr_y + mt->scaled_height - 1; write_reg(mt, MT9F002_X_ADDR_END, end_addr_x, 2); write_reg(mt, MT9F002_Y_ADDR_END, end_addr_y, 2); + + // set statistics to correct values + isp_config.statistics_bayer.window_x.x_offset = mt->scaled_width - (mt->scaled_width / BAYERSTATS_STATX) / 2; + isp_config.statistics_bayer.window_y.y_offset = mt->scaled_height - (mt->scaled_height / BAYERSTATS_STATY) / 2; + isp_config.statistics_bayer.window_x.x_width = mt->scaled_width / BAYERSTATS_STATX; + isp_config.statistics_bayer.window_y.y_width = mt->scaled_height / BAYERSTATS_STATY; + + isp_config.statistics_yuv.window_pos_x.window_x_end = mt->scaled_width - 1; + isp_config.statistics_yuv.window_pos_y.window_y_end = mt->scaled_height - 1; + isp_config.statistics_yuv.increments_log2.x_log2_inc = log2(x_skip_factor); + isp_config.statistics_yuv.increments_log2.x_log2_inc = log2(y_skip_factor); } /** diff --git a/sw/airborne/boards/bebop/mt9f002.h b/sw/airborne/boards/bebop/mt9f002.h index b8c1ce0f4f..64fbad1cd7 100644 --- a/sw/airborne/boards/bebop/mt9f002.h +++ b/sw/airborne/boards/bebop/mt9f002.h @@ -30,6 +30,79 @@ #include "std.h" #include "mcu_periph/i2c.h" +/* define required ouput image size */ +#ifndef MT9F002_OUTPUT_HEIGHT +#define MT9F002_OUTPUT_HEIGHT 822 // full resolution 3288 +#endif + +#ifndef MT9F002_OUTPUT_WIDTH +#define MT9F002_OUTPUT_WIDTH 1152 // full resolution 4608 +#endif + +#ifndef MT9F002_INITIAL_OFFSET_X +#define MT9F002_INITIAL_OFFSET_X 0. // signed fractional offset from centre of image of original sensor [-0.5,0.5] +#endif + +#ifndef MT9F002_INITIAL_OFFSET_Y +#define MT9F002_INITIAL_OFFSET_Y 0. // signed fractional offset from centre of image of original sensor [-0.5,0.5] +#endif + +/** Our output is only OUTPUT_SCALER of the pixels we take of the sensor + * It is programmable in 1/16 steps determined by ScaleFactor = 16/scale_m. + * Legal values for scale_m are 16 through 128, giving you the ability to scale from + * 1:1 to 1:8 (with m=128). + * Example: + * output_width = 512 + * output_height = 830 + * output_scaler = 0.25 + * We now get an image of 512 by 830 which contains a "compressed version" + * of what would normally be an image of 2048 by 3320 ISP (4608H x 2592V sensor) + */ +#ifndef MT9F002_OUTPUT_SCALER +#define MT9F002_OUTPUT_SCALER 1. +#endif + +/** Exposure of the front camera of the bebop. Experimental values: + * Outside: 15 + * Inside well lit: 30 + * Inside poorly lit: 60 + */ +#ifndef MT9F002_TARGET_EXPOSURE +#define MT9F002_TARGET_EXPOSURE 30 +#endif + +#ifndef MT9F002_TARGET_FPS +#define MT9F002_TARGET_FPS 15 +#endif + +/* Set the colour balance gains */ +#ifndef MT9F002_GAIN_GREEN1 +#define MT9F002_GAIN_GREEN1 3.0 +#endif + +#ifndef MT9F002_GAIN_GREEN2 +#define MT9F002_GAIN_GREEN2 3.0 +#endif + +#ifndef MT9F002_GAIN_RED +#define MT9F002_GAIN_RED 3.0 +#endif + +#ifndef MT9F002_GAIN_BLUE +#define MT9F002_GAIN_BLUE 4.0 +#endif + +/* Set pixel increment value to implement subsampling */ +/* Supported values for MT9F002_X_ODD_INC_VAL are 3, 7, 15 and 31 */ +#ifndef MT9F002_X_ODD_INC_VAL +#define MT9F002_X_ODD_INC_VAL 1 +#endif + +/* Supported values for MT9F002_Y_ODD_INC_VAL are 1, 3 and 7 */ +#ifndef MT9F002_Y_ODD_INC_VAL +#define MT9F002_Y_ODD_INC_VAL 1 +#endif + /* Interface types for the MT9F002 connection */ enum mt9f002_interface { MT9F002_MIPI, ///< MIPI type connection diff --git a/sw/airborne/modules/computer_vision/bebop_front_camera.c b/sw/airborne/modules/computer_vision/bebop_front_camera.c deleted file mode 100644 index cd4636af8a..0000000000 --- a/sw/airborne/modules/computer_vision/bebop_front_camera.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2012-2014 The Paparazzi Community - * 2015 Freek van Tienen - * - * This file is part of Paparazzi. - * - * Paparazzi 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, or (at your option) - * any later version. - * - * Paparazzi 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 paparazzi; see the file COPYING. If not, see - * . - * - */ - -/** - * @file modules/computer_vision/bebop_front_camera.c - */ - -// Own header -#include "modules/computer_vision/bebop_front_camera.h" - -#include -#include -#include -#include -#include -#include - -// Video -#include "lib/v4l/v4l2.h" -#include "lib/vision/image.h" -#include "lib/vision/bayer.h" -#include "lib/encoding/jpeg.h" -#include "lib/encoding/rtp.h" -#include "udp_socket.h" - -// Threaded computer vision -#include - -#define MT9F002_WIDTH 1408 -#define MT9F002_HEIGHT 2112 -#define BEBOP_FRONT_CAMERA_WIDTH 272 -#define BEBOP_FRONT_CAMERA_HEIGHT 272 - -// The place where the shots are saved (without slash on the end) -#ifndef BEBOP_FRONT_CAMERA_SHOT_PATH -#define BEBOP_FRONT_CAMERA_SHOT_PATH /data/ftp/internal_000/images -#endif -PRINT_CONFIG_VAR(BEBOP_FRONT_CAMERA_SHOT_PATH) - -// Main thread -static void *bebop_front_camera_thread(void *data); -static void bebop_front_camera_save_shot(struct image_t *img_color, struct image_t *img_jpeg, struct image_t *raw_img); -void bebop_front_camera_periodic(void) { } - -// Initialize the bebop_front_camera structure with the defaults -struct bebopfrontcamera_t bebop_front_camera = { - .is_streaming = FALSE, - .take_shot = FALSE, - .shot_number = 0, - .take_shot = FALSE, - .shot_number = 0 -}; - -void bebop_front_camera_take_shot(bool take) -{ - bebop_front_camera.take_shot = true; -} -/** - * Handles all the video streaming and saving of the image shots - * This is a sepereate thread, so it needs to be thread safe! - */ -static void *bebop_front_camera_thread(void *data __attribute__((unused))) -{ - struct UdpSocket video_sock; - udp_socket_create(&video_sock, STRINGIFY(BEBOP_FRONT_CAMERA_HOST), BEBOP_FRONT_CAMERA_PORT_OUT, -1, - BEBOP_FRONT_CAMERA_BROADCAST); - - // Create the JPEG encoded image - struct image_t img_jpeg; - image_create(&img_jpeg, BEBOP_FRONT_CAMERA_WIDTH, BEBOP_FRONT_CAMERA_HEIGHT, IMAGE_JPEG); - - // Create the Color image - struct image_t img_color; - image_create(&img_color, BEBOP_FRONT_CAMERA_WIDTH, BEBOP_FRONT_CAMERA_HEIGHT, IMAGE_YUV422); - - // Start the streaming of the V4L2 device - if (!v4l2_start_capture(bebop_front_camera.dev)) { - printf("[bebop_front_camera-thread] Could not start capture of %s.\n", bebop_front_camera.dev->name); - return 0; - } - - // Start streaming - bebop_front_camera.is_streaming = true; - while (bebop_front_camera.is_streaming) { - // Wait for a new frame (blocking) - struct image_t img; - v4l2_image_get(bebop_front_camera.dev, &img); - - BayerToYUV(&img, &img_color, 0, 0); - - if (bebop_front_camera.take_shot) { - // Save the image - bebop_front_camera_save_shot(&img_color, &img_jpeg, &img); - bebop_front_camera.take_shot = false; - } - - jpeg_encode_image(&img_color, &img_jpeg, 80, 0); - - // Send image with RTP - rtp_frame_send( - &video_sock, // UDP socket - &img_jpeg, - 0, // Format 422 - 80, // Jpeg-Quality - 0, // DRI Header - 0 // 90kHz time increment - ); - - - // Free the image - v4l2_image_free(bebop_front_camera.dev, &img); - } - - return 0; -} - -/** - * Initialize the view video - */ -void bebop_front_camera_init(void) -{ - // Initialize the V4L2 subdevice (TODO: fix hardcoded path, which and code) - if (!v4l2_init_subdev("/dev/v4l-subdev1", 0, 0, V4L2_MBUS_FMT_SGBRG10_1X10, MT9F002_WIDTH, MT9F002_HEIGHT)) { - printf("[bebop_front_camera] Could not initialize the v4l-subdev1 subdevice.\n"); - return; - } - - // Initialize the V4L2 device - bebop_front_camera.dev = v4l2_init("/dev/video1", MT9F002_WIDTH, MT9F002_HEIGHT, 10, V4L2_PIX_FMT_SGBRG10); - if (bebop_front_camera.dev == NULL) { - printf("[bebop_front_camera] Could not initialize the /dev/video1 V4L2 device.\n"); - return; - } - - // Create the shot directory - char save_name[128]; - sprintf(save_name, "mkdir -p %s", STRINGIFY(BEBOP_FRONT_CAMERA_SHOT_PATH)); - if (system(save_name) != 0) { - printf("[bebop_front_camera] Could not create shot directory %s.\n", STRINGIFY(BEBOP_FRONT_CAMERA_SHOT_PATH)); - return; - } -} - -/** - * Start with streaming - */ -void bebop_front_camera_start(void) -{ - // Check if we are already running - if (bebop_front_camera.is_streaming) { - return; - } - - // Start the streaming thread - pthread_t tid; - if (pthread_create(&tid, NULL, bebop_front_camera_thread, NULL) != 0) { - printf("[vievideo] Could not create streaming thread.\n"); - return; - } -} - -/** - * Stops the streaming - * This could take some time, because the thread is stopped asynchronous. - */ -void bebop_front_camera_stop(void) -{ - // Check if not already stopped streaming - if (!bebop_front_camera.is_streaming) { - return; - } - - // Stop the streaming thread - bebop_front_camera.is_streaming = false; - - // Stop the capturing - if (!v4l2_stop_capture(bebop_front_camera.dev)) { - printf("[bebop_front_camera] Could not stop capture of %s.\n", bebop_front_camera.dev->name); - return; - } - - // TODO: wait for the thread to finish to be able to start the thread again! -} - -static void bebop_front_camera_save_shot(struct image_t *img, struct image_t *img_jpeg, struct image_t *raw_img) -{ - - // Search for a file where we can write to - char save_name[128]; - for (; bebop_front_camera.shot_number < 99999; bebop_front_camera.shot_number++) { - sprintf(save_name, "%s/img_%05d.pgm", STRINGIFY(BEBOP_FRONT_CAMERA_SHOT_PATH), bebop_front_camera.shot_number); - // Check if file exists or not - if (access(save_name, F_OK) == -1) { - FILE *fp = fopen(save_name, "w"); - if (fp == NULL) { - printf("[bebop_front_camera-thread] Could not write shot %s.\n", save_name); - } else { - // Save it to the file and close it - char pgm_header[] = "P5\n272 272\n255\n"; - fwrite(pgm_header, sizeof(char), 15, fp); - fwrite(img->buf, sizeof(uint8_t), img->buf_size, fp); - fclose(fp); - - // JPEG - jpeg_encode_image(img, img_jpeg, 99, 1); - sprintf(save_name, "%s/img_%05d.jpg", STRINGIFY(BEBOP_FRONT_CAMERA_SHOT_PATH), bebop_front_camera.shot_number); - fp = fopen(save_name, "w"); - fwrite(img_jpeg->buf, sizeof(uint8_t), img_jpeg->buf_size, fp); - fclose(fp); - - sprintf(save_name, "%s/img_%05d.raw", STRINGIFY(BEBOP_FRONT_CAMERA_SHOT_PATH), bebop_front_camera.shot_number); - fp = fopen(save_name, "w"); - fwrite(raw_img->buf, sizeof(uint8_t), raw_img->buf_size, fp); - fclose(fp); - - } - - // We don't need to seek for a next index anymore - break; - } - } -} diff --git a/sw/airborne/modules/computer_vision/bebop_front_camera.h b/sw/airborne/modules/computer_vision/bebop_front_camera.h deleted file mode 100644 index afaf5255af..0000000000 --- a/sw/airborne/modules/computer_vision/bebop_front_camera.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012-2014 The Paparazzi Community - * 2015 Freek van Tienen - * - * This file is part of Paparazzi. - * - * Paparazzi 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, or (at your option) - * any later version. - * - * Paparazzi 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 paparazzi; see the file COPYING. If not, see - * . - * - */ - -/** - * @file modules/computer_vision/bebop_front_camera.h - * - * Get live images from a RTP/UDP stream - * and save pictures on internal memory - * - * Works on Bebop platforms - */ - -#ifndef BEBOP_FRONT_CAMERA_H -#define BEBOP_FRONT_CAMERA_H - -#include "std.h" - -// Main viewvideo structure -struct bebopfrontcamera_t { - struct v4l2_device *dev; ///< The V4L2 device that is used for the video stream - uint8_t fps; ///< The amount of frames per second - volatile bool take_shot; ///< Wether to take an image - uint16_t shot_number; ///< The last shot number - volatile bool is_streaming; ///< When the device is streaming - uint8_t downsize_factor; ///< Downsize factor during the stream - uint8_t quality_factor; ///< Quality factor during the stream - bool use_rtp; ///< Stream over RTP -}; -extern struct bebopfrontcamera_t bebop_front_camera; - -// Module functions -extern void bebop_front_camera_init(void); -extern void bebop_front_camera_periodic(void); ///< A dummy for now -extern void bebop_front_camera_start(void); -extern void bebop_front_camera_stop(void); -extern void bebop_front_camera_take_shot(bool take); - -#endif /* BEBOP_FRONT_CAMERA_H */ - diff --git a/sw/airborne/modules/computer_vision/cv_ae_awb.c b/sw/airborne/modules/computer_vision/cv_ae_awb.c index 295fc8283f..79040ff538 100644 --- a/sw/airborne/modules/computer_vision/cv_ae_awb.c +++ b/sw/airborne/modules/computer_vision/cv_ae_awb.c @@ -65,10 +65,13 @@ void cv_ae_awb_periodic(void) uint32_t max_saturated_pixels = yuv_stats.nb_valid_Y / 400; // 0.25% float adjustment = 1.0f; + printf("%d %d\n", bright_pixels, target_bright_pixels); + // Fix saturated pixels if (saturated_pixels > max_saturated_pixels) { adjustment = 1.0f - ((float)(saturated_pixels - max_saturated_pixels)) / yuv_stats.nb_valid_Y; - } else if (bright_pixels + target_bright_pixels / 10 < target_bright_pixels) { // Fix bright pixels if outside of 10% of target + } else if (bright_pixels + target_bright_pixels / 10 < + target_bright_pixels) { // Fix bright pixels if outside of 10% of target // increase brightness to try and hit the desired number of well exposed pixels int l = MAX_HIST_Y - 11; while (bright_pixels < target_bright_pixels && l > 0) { @@ -78,7 +81,8 @@ void cv_ae_awb_periodic(void) } adjustment = (float)(MAX_HIST_Y - 11 + 1) / (l + 1); - } else if (bright_pixels - target_bright_pixels / 10 > target_bright_pixels) { // Fix bright pixels if outside of 10% of target + } else if (bright_pixels - target_bright_pixels / 10 > + target_bright_pixels) { // Fix bright pixels if outside of 10% of target // decrease brightness to try and hit the desired number of well exposed pixels int l = MAX_HIST_Y - 20; while (bright_pixels > target_bright_pixels && l < MAX_HIST_Y) { @@ -105,16 +109,16 @@ void cv_ae_awb_periodic(void) float gain = 1.; bool changed = false; - if (fabs(avgU) > threshold){ + if (fabs(avgU) > threshold) { mt9f002.gain_blue -= gain * avgU; changed = true; } - if (fabs(avgV) > threshold){ + if (fabs(avgV) > threshold) { mt9f002.gain_red -= gain * avgV; changed = true; } - if (changed){ + if (changed) { Bound(mt9f002.gain_blue, 2, 75); Bound(mt9f002.gain_red, 2, 75); mt9f002_set_gains(&mt9f002); diff --git a/sw/airborne/modules/computer_vision/lib/encoding/rtp.c b/sw/airborne/modules/computer_vision/lib/encoding/rtp.c index d1f4c9c46a..b011bec61e 100644 --- a/sw/airborne/modules/computer_vision/lib/encoding/rtp.c +++ b/sw/airborne/modules/computer_vision/lib/encoding/rtp.c @@ -92,24 +92,21 @@ void rtp_frame_test(struct UdpSocket *udp) * @param[in] format_code 0 for YUV422 and 1 for YUV421 * @param[in] quality_code The JPEG encoding quality * @param[in] has_dri_header Whether we have an DRI header or not - * @param[in] delta_t Time between images (if set to 0 or less it is calculated) + * @param[in] delta_t Time between images in usec (if set to 0 or less it is calculated) */ void rtp_frame_send(struct UdpSocket *udp, struct image_t *img, uint8_t format_code, - uint8_t quality_code, uint8_t has_dri_header, uint32_t delta_t) + uint8_t quality_code, uint8_t has_dri_header, uint32_t frame_time, uint32_t *packet_number) { - static uint32_t packetcounter = 0; - static uint32_t timecounter = 0; uint32_t offset = 0; uint32_t jpeg_size = img->buf_size; uint8_t *jpeg_ptr = img->buf; #define MAX_PACKET_SIZE 1400 - if (delta_t <= 0) { + if (frame_time <= 0) { struct timeval tv; gettimeofday(&tv, 0); - uint32_t t = (tv.tv_sec % (256 * 256)) * 90000 + tv.tv_usec * 9 / 100; - timecounter = t; + frame_time = (tv.tv_sec % (256 * 256)) + tv.tv_usec; } // Split frame into packets @@ -122,31 +119,29 @@ void rtp_frame_send(struct UdpSocket *udp, struct image_t *img, uint8_t format_c len = jpeg_size; } - rtp_packet_send(udp, jpeg_ptr, len, packetcounter, timecounter, offset, lastpacket, img->w, img->h, format_code, + rtp_packet_send(udp, jpeg_ptr, len, (*packet_number)++, frame_time, offset, lastpacket, img->w, img->h, format_code, quality_code, has_dri_header); jpeg_size -= len; jpeg_ptr += len; offset += len; - packetcounter++; - } - - - if (delta_t > 0) { - // timestamp = 1 / 90 000 seconds - timecounter += delta_t; } } /* - * The RTP timestamp is in units of 90000Hz. The same timestamp MUST - appear in each fragment of a given frame. The RTP marker bit MUST be - set in the last packet of a frame. + * The same timestamp MUST appear in each fragment of a given frame. + * The RTP marker bit MUST be set in the last packet of a frame. + * Extra note: When the time difference between frames is non-constant, + there seems to introduce some lag or jitter in the video streaming. + One way to solve this is to send the timestamp in units of 90000Hz + rather than 100000 (when the frame is received the timestamp is always + "late" so the frame is displayed immediately). (1 = 1/90000 s) which + is probably stupid but is actually working. * @param[in] *udp The UDP socket to send the RTP packet over * @param[in] *Jpeg JPEG encoded image byte buffer * @param[in] JpegLen The length of the byte buffer * @param[in] m_SequenceNumber RTP sequence number - * @param[in] m_Timestamp Timestamp of the image + * @param[in] m_Timestamp Timestamp of the image in usec * @param[in] m_offset 3 byte fragmentation offset for fragmented images * @param[in] marker_bit RTP marker bit * @param[in] w The width of the JPEG image @@ -190,6 +185,7 @@ static void rtp_packet_send( +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ + m_Timestamp *= 9 / 100; // convert timestamp to units of 1 / 90000 Hz // Prepare the 12 byte RTP header RtpBuf[0] = 0x80; // RTP version RtpBuf[1] = 0x1a + (marker_bit << 7); // JPEG payload (26) and marker bit diff --git a/sw/airborne/modules/computer_vision/lib/encoding/rtp.h b/sw/airborne/modules/computer_vision/lib/encoding/rtp.h index 88a8075522..2616ebeefa 100644 --- a/sw/airborne/modules/computer_vision/lib/encoding/rtp.h +++ b/sw/airborne/modules/computer_vision/lib/encoding/rtp.h @@ -33,7 +33,7 @@ #include "udp_socket.h" void rtp_frame_send(struct UdpSocket *udp, struct image_t *img, uint8_t format_code, uint8_t quality_code, - uint8_t has_dri_header, uint32_t delta_t); + uint8_t has_dri_header, uint32_t frame_time, uint32_t *packet_number); void rtp_frame_test(struct UdpSocket *udp); #endif /* _CV_ENCODING_RTP_H */ diff --git a/sw/airborne/modules/computer_vision/lib/isp/libisp.c b/sw/airborne/modules/computer_vision/lib/isp/libisp.c index 646592fd09..7997bf1f8e 100644 --- a/sw/airborne/modules/computer_vision/lib/isp/libisp.c +++ b/sw/airborne/modules/computer_vision/lib/isp/libisp.c @@ -8,7 +8,7 @@ #include #include -#include "libisp.h" +//#include "libisp.h" #include "libisp_config.h" #define AVI_BASE 0x400000 @@ -194,10 +194,6 @@ int configure_isp(struct v4l2_device *dev) avi_isp_gamma_corrector_gu_lut_set_registers(&isp_ctx, &isp_config.gc_gu_lut); avi_isp_gamma_corrector_bv_lut_set_registers(&isp_ctx, &isp_config.gc_bv_lut); avi_isp_chroma_set_registers(&isp_ctx, &isp_config.chroma); - - isp_config.statistics_yuv.increments_log2.x_log2_inc = log2(MT9F002_X_ODD_INC_VAL); - isp_config.statistics_yuv.increments_log2.x_log2_inc = log2(MT9F002_Y_ODD_INC_VAL); - avi_isp_statistics_yuv_set_registers(&isp_ctx, &isp_config.statistics_yuv); avi_isp_edge_enhancement_color_reduction_filter_set_registers(&isp_ctx, &isp_config.eecrf); avi_isp_edge_enhancement_color_reduction_filter_ee_lut_set_registers(&isp_ctx, &isp_config.eecrf_lut); diff --git a/sw/airborne/modules/computer_vision/lib/isp/libisp_config.h b/sw/airborne/modules/computer_vision/lib/isp/libisp_config.h index a1ec2e07b3..07d5e39109 100644 --- a/sw/airborne/modules/computer_vision/lib/isp/libisp_config.h +++ b/sw/airborne/modules/computer_vision/lib/isp/libisp_config.h @@ -1,7 +1,7 @@ #ifndef _LIBISP_CONFIG_H #define _LIBISP_CONFIG_H -#include "boards/bebop.h" +#include "boards/bebop/mt9f002.h" #include "libisp.h" struct libisp_config isp_config = { @@ -433,8 +433,8 @@ struct libisp_config isp_config = { .statistics_yuv = { .measure_req = {{1, 1}}, .measure_status = {{0, 0}}, - .window_pos_x = {{ .window_x_start = 0, .window_x_end = MT9F002_OUTPUT_WIDTH }}, - .window_pos_y = {{ .window_y_start = 0, .window_y_end = MT9F002_OUTPUT_HEIGHT }}, + .window_pos_x = {{ .window_x_start = 0, .window_x_end = MT9F002_OUTPUT_WIDTH - 1 }}, + .window_pos_y = {{ .window_y_start = 0, .window_y_end = MT9F002_OUTPUT_HEIGHT - 1 }}, .circle_pos_x_center = {{ 1088 }}, .circle_pos_x_squared = {{ 1183744 }}, .circle_pos_y_center = {{ 1078 }}, diff --git a/sw/airborne/modules/computer_vision/viewvideo.c b/sw/airborne/modules/computer_vision/viewvideo.c index d3a48e15cb..2a233c58e5 100644 --- a/sw/airborne/modules/computer_vision/viewvideo.c +++ b/sw/airborne/modules/computer_vision/viewvideo.c @@ -68,7 +68,7 @@ PRINT_CONFIG_VAR(VIEWVIDEO_RTP_TIME_INC) // Define stream framerate #ifndef VIEWVIDEO_FPS -#define VIEWVIDEO_FPS 10 +#define VIEWVIDEO_FPS 5 #endif PRINT_CONFIG_VAR(VIEWVIDEO_FPS) @@ -112,16 +112,11 @@ struct viewvideo_t viewvideo = { #endif }; -#if defined(VIEWVIDEO_CAMERA) && defined(VIEWVIDEO_CAMERA2) && VIEWVIDEO_BROADCAST == true -#warning Broadcasting dual video stream causes too much udp overhead resulting in unstable streaming -#warning We recomment using a static VIEWVIDEO_HOST address and VIEWVIDEO_BROADCAST to false -#endif - /** * Handles all the video streaming and saving of the image shots * This is a separate thread, so it needs to be thread safe! */ -static struct image_t *viewvideo_function(struct UdpSocket *socket, struct image_t *img) +static struct image_t *viewvideo_function(struct UdpSocket *socket, struct image_t *img, uint32_t *rtp_frame_nr) { // Resize image if needed struct image_t img_small; @@ -180,19 +175,11 @@ static struct image_t *viewvideo_function(struct UdpSocket *socket, struct image 0, // Format 422 VIEWVIDEO_QUALITY_FACTOR, // Jpeg-Quality 0, // DRI Header - VIEWVIDEO_RTP_TIME_INC // 90kHz time increment + (img->ts.tv_sec * 1000000 + img->ts.tv_usec), + rtp_frame_nr ); - // Extra note: when the time increment is set to 0, - // it is automaticaly calculated by the send_rtp_frame function - // based on gettimeofday value. This seems to introduce some lag or jitter. - // An other way is to compute the time increment and set the correct value. - // It seems that a lower value is also working (when the frame is received - // the timestamp is always "late" so the frame is displayed immediately). - // Here, we set the time increment to the lowest possible value - // (1 = 1/90000 s) which is probably stupid but is actually working. } #endif - } // Free all buffers @@ -204,14 +191,16 @@ static struct image_t *viewvideo_function(struct UdpSocket *socket, struct image #ifdef VIEWVIDEO_CAMERA static struct image_t *viewvideo_function1(struct image_t *img) { - return viewvideo_function(&video_sock1, img); + static uint32_t rtp_frame_nr = 0; + return viewvideo_function(&video_sock1, img, &rtp_frame_nr); } #endif #ifdef VIEWVIDEO_CAMERA2 static struct image_t *viewvideo_function2(struct image_t *img) { - return viewvideo_function(&video_sock2, img); + static uint32_t rtp_frame_nr = 0; + return viewvideo_function(&video_sock2, img, &rtp_frame_nr); } #endif