diff --git a/conf/modules/cv_georeference.xml b/conf/modules/cv_georeference.xml
new file mode 100644
index 0000000000..8b87d87474
--- /dev/null
+++ b/conf/modules/cv_georeference.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Geo-reference computer vision detections
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/modules/computer_vision/cv_georeference.c b/sw/airborne/modules/computer_vision/cv_georeference.c
new file mode 100644
index 0000000000..97063319bb
--- /dev/null
+++ b/sw/airborne/modules/computer_vision/cv_georeference.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) C. De Wagter
+ *
+ * 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/cv_georeference.c"
+ * @author C. De Wagter
+ * Geo-reference computer vision detections
+ */
+
+#include "modules/computer_vision/cv_georeference.h"
+
+#include "math/pprz_trig_int.h"
+#include "math/pprz_algebra.h"
+#include "math/pprz_algebra_int.h"
+
+#include "state.h"
+#include "generated/flight_plan.h"
+
+struct camera_frame_t {
+ int32_t w; ///< Frame width [px]
+ int32_t h; ///< Frame height [px]
+ int32_t f; ///< Camera Focal length in [px]
+ int32_t px; ///< Target pixel coordinate (left = 0)
+ int32_t py; ///< Target pixel coordinate (top = 0)
+};
+
+struct georeference_filter_t {
+ struct Int32Vect3 x; ///< Target
+ struct Int32Vect3 v; ///< Target Velocity
+ int32_t P; ///< Covariance/Average-count
+};
+
+struct georeference_t {
+ struct Int32Vect3 target_i; ///< Target in pixels, with z being the focal length in pixels, x=up,y=right,out
+ struct Int32Vect3 target_l; ///< Target in meters, relative to the drone in LTP frame
+
+ struct Int32Vect3 x_t; ///< Target coordinates NED
+
+ struct georeference_filter_t filter; ///< Filter waypoint location
+};
+
+struct georeference_t geo;
+
+void georeference_project(struct camera_frame_t *tar, int wp)
+{
+ // Target direction in camera frame: Zero is looking down in body frames
+ // Pixel with x (width) value 0 projects to the left (body-Y-axis)
+ // and y = 0 (height) to the top (body-X-axis)
+ VECT3_ASSIGN(geo.target_i,
+ ((tar->h / 2) - tar->py),
+ (tar->px - (tar->w / 2)),
+ (tar->f)
+ );
+ INT32_VECT3_LSHIFT(geo.target_i, geo.target_i, 4)
+
+ // Camera <-> Body
+ // Looking down in body frame
+ // Bebop has 180deg Z rotation in camera (butt up yields normal webcam)
+ struct Int32RMat body_to_cam_rmat;
+ INT32_MAT33_ZERO(body_to_cam_rmat);
+ MAT33_ELMT(body_to_cam_rmat, 0, 0) = -1 << INT32_TRIG_FRAC;
+ MAT33_ELMT(body_to_cam_rmat, 1, 1) = -1 << INT32_TRIG_FRAC;
+ MAT33_ELMT(body_to_cam_rmat, 2, 2) = 1 << INT32_TRIG_FRAC;
+
+ struct Int32Vect3 target_b;
+ int32_rmat_transp_vmult(&target_b, &body_to_cam_rmat, &geo.target_i);
+
+ // Body <-> LTP
+ struct Int32RMat *ltp_to_body_rmat = stateGetNedToBodyRMat_i();
+ int32_rmat_transp_vmult(&geo.target_l, ltp_to_body_rmat, &target_b);
+
+ // target_l is now a scale-less [pix< no ground projection
+ return;
+ }
+
+ // Multiply with height above ground
+ struct NedCoor_i *pos = stateGetPositionNed_i();
+ int32_t zb = pos->z;
+ geo.target_l.x *= zb;
+ geo.target_l.y *= zb;
+
+ // Divide by z-component
+ geo.target_l.x /= zi;
+ geo.target_l.y /= zi;
+ geo.target_l.z = zb;
+
+ // NED
+ geo.x_t.x = pos->x - geo.target_l.x;
+ geo.x_t.y = pos->y - geo.target_l.y;
+ geo.x_t.z = 0;
+
+ // ENU
+ waypoint_set_xy_i(wp, geo.x_t.y, geo.x_t.x);
+ waypoint_set_alt_i(wp, geo.x_t.z);
+}
+
+void georeference_filter(bool_t kalman, int wp)
+{
+ struct Int32Vect3 err;
+
+ if (kalman)
+ {
+ // Predict
+ VECT3_ADD(geo.filter.x, geo.filter.v);
+
+ // Error = prediction - observation
+ VECT3_COPY(err,geo.filter.x);
+ VECT3_SUB(err, geo.x_t);
+ }
+ else // Average
+ {
+ VECT3_SMUL(geo.filter.x,geo.filter.x,geo.filter.P);
+ VECT3_ADD(geo.filter.x, geo.x_t);
+ geo.filter.P++;
+ VECT3_SDIV(geo.filter.x,geo.filter.x,geo.filter.P);
+ }
+
+ // ENU
+ waypoint_set_xy_i(wp, geo.filter.x.y, geo.filter.x.x);
+ waypoint_set_alt_i(wp, geo.filter.x.z);
+}
+
+int32_t focus_length;
+
+void georeference_run(void)
+{
+ struct camera_frame_t target;
+ target.w = 320;
+ target.h = 240;
+ target.f = focus_length;
+ target.px = 0;
+ target.py = 0;
+ georeference_project(&target,WP_p1);
+ target.px = 320;
+ target.py = 0;
+ georeference_project(&target,WP_p2);
+ target.px = 320;
+ target.py = 240;
+ georeference_project(&target,WP_p3);
+ target.px = 0;
+ target.py = 240;
+ georeference_project(&target,WP_p4);
+
+ target.px = 0;
+ target.py = 120;
+ georeference_project(&target,0);
+ georeference_filter(FALSE, WP_CAM);
+}
+
+void georeference_init(void)
+{
+ INT32_VECT3_ZERO(geo.target_i);
+ INT32_VECT3_ZERO(geo.target_l);
+
+ VECT3_ASSIGN(geo.x_t, 0, 0, 0);
+
+ INT32_VECT3_ZERO(geo.filter.v);
+ INT32_VECT3_ZERO(geo.filter.x);
+ geo.filter.P = 0;
+ focus_length = 400;
+}
+
+
diff --git a/sw/airborne/modules/computer_vision/cv_georeference.h b/sw/airborne/modules/computer_vision/cv_georeference.h
new file mode 100644
index 0000000000..56e134a140
--- /dev/null
+++ b/sw/airborne/modules/computer_vision/cv_georeference.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) C. De Wagter
+ *
+ * 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/cv_georeference.h"
+ * @author C. De Wagter
+ * Geo-reference computer vision detections
+ */
+
+#ifndef CV_GEOREFERENCE_H
+#define CV_GEOREFERENCE_H
+
+#include
+
+extern int32_t focus_length;
+
+extern void georeference_init(void);
+extern void georeference_run(void);
+
+#endif
+