Skip to content
This repository was archived by the owner on May 25, 2023. It is now read-only.

Commit e21e905

Browse files
author
Benjamin Winger
committed
Added geolocation code (adapted from Chris's PR #79)
1 parent 67bcdb9 commit e21e905

File tree

8 files changed

+234
-7
lines changed

8 files changed

+234
-7
lines changed

modules/core/include/frame.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ class Frame{
106106
*/
107107
cv::Mat* undistort(Camera &camera);
108108

109+
/**
110+
* @brief Camera associated with the frame
111+
*
112+
* @return Camera associated with the frame
113+
*/
114+
Camera & get_camera();
115+
109116
private:
110117

111118
/**

modules/core/src/camera.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,18 @@ Mat * Camera::undistort(Mat & img) {
3636

3737
Camera Camera::TestCamera() {
3838
double cameraMatrix[] = {
39-
2.4052826789763981e+03, 0, 2000,
40-
0, 2.4052826789763981e+03, 1500,
39+
2410, 0, 3000,
40+
0, 2410, 2000,
4141
0, 0, 1
4242
};
4343

4444
double distMatrix[] = {
45-
6.0190515380007324e-02, -1.8618345553370965e+00, 0, 0,
46-
2.9590336363673964e+00
45+
0, 0, 0, 0, 0
4746
};
4847

4948
return Camera(
50-
Size(4000, 3000),
51-
Size2d(120, 90),
49+
Size(6000, 4000),
50+
Size2d(73.74, 53.13),
5251
Mat(
5352
Size(3, 3),
5453
CV_8UC1,

modules/core/src/frame.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ void Frame::save(std::string dir) {
8787
exifData["Exif.Photo.UserComment"] = ss.str();
8888
image->writeMetadata();
8989
}
90+
91+
Camera & Frame::get_camera() {
92+
return camera;
93+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include_directories(include ../core/include)
22
ADD_DEFINITIONS("-DBOOST_LOG_DYN_LINK")
3-
add_library(TargetAnalysis src/area_analyzer.cpp src/target_analyzer.cpp src/target_loader.cpp)
3+
add_library(TargetAnalysis src/area_analyzer.cpp src/target_analyzer.cpp src/target_loader.cpp src/gps.cpp)
44
target_link_libraries(TargetAnalysis ${Boost_LIBRARIES} Core)
55
target_compile_features(TargetAnalysis PRIVATE)
66
add_subdirectory("test")
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @file gps.cpp
3+
* @author WARG
4+
*
5+
* @section LICENSE
6+
*
7+
* Copyright (c) 2015-2017, Waterloo Aerial Robotics Group (WARG)
8+
* All rights reserved.
9+
*
10+
* This software is licensed under a modified version of the BSD 3 clause license
11+
* that should have been included with this software in a file called COPYING.txt
12+
* Otherwise it is available at:
13+
* https://raw.githubusercontent.com/UWARG/computer-vision/master/COPYING.txt
14+
*/
15+
16+
#ifndef GPS_H
17+
#define GPS_H
18+
19+
#include "frame.h"
20+
21+
static const double GPS_TOLERANCE = 0.0000001;
22+
23+
/**
24+
* @brief Determines GPS location of a point in an image
25+
* @param point Location in the image (pixels)
26+
* @param f Image
27+
* @param returnResult Resulting location in the image (in latitude and longitude)
28+
*
29+
* @return true on success, false on failure
30+
*/
31+
int get_gps(cv::Point2d point, Frame *f, cv::Point2d *returnResult);
32+
33+
/**
34+
* @brief Calculates the distance (in metres) between two sets of GPS co-ordinates
35+
*
36+
* Calculates distance in metres between two sets of GPS co-ordinates.
37+
* Inaccurate for long distances since it calculates the direct distance rather than the distance along the surface of the earth.
38+
*/
39+
double gps_dist(cv::Point2d p1, cv::Point2d p2);
40+
41+
#endif // GPS_H

modules/targetanalysis/src/gps.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @file gps.cpp
3+
* @author WARG
4+
*
5+
* @section LICENSE
6+
*
7+
* Copyright (c) 2015-2017, Waterloo Aerial Robotics Group (WARG)
8+
* All rights reserved.
9+
*
10+
* This software is licensed under a modified version of the BSD 3 clause license
11+
* that should have been included with this software in a file called COPYING.txt
12+
* Otherwise it is available at:
13+
* https://raw.githubusercontent.com/UWARG/computer-vision/master/COPYING.txt
14+
*/
15+
16+
#include <iomanip>
17+
#include <boost/log/trivial.hpp>
18+
#include "frame.h"
19+
20+
#define RAD2DEG(rad) ((rad)*180.0/M_PI)
21+
#define DEG2RAD(deg) ((deg)*M_PI/180.0)
22+
#define EARTH_RADIUS 6371000
23+
24+
//Based on the GPS location of the image, calculates the
25+
//GPS location of a certain pixel in the image.
26+
bool get_gps(cv::Point2d point, Frame* f, cv::Point2d* returnResult){
27+
if (f == NULL) {
28+
BOOST_LOG_TRIVIAL(error) << "Frame is null";
29+
return false;
30+
}
31+
BOOST_LOG_TRIVIAL(trace) << "get_gps(" << point << ", " << f->get_id() << ")";
32+
33+
const Metadata* m = f->get_metadata();
34+
cv::Mat img = f->get_img();
35+
int h = img.cols;
36+
int w = img.rows;
37+
38+
if (w <= 0 || h <= 0){
39+
BOOST_LOG_TRIVIAL(error) << "Invalid frame size w:" << w << " h:" << h;
40+
return false;
41+
}
42+
43+
cv::Point2d imgCenter(w/2, h/2);
44+
45+
//(0,0) is in the center of the image
46+
cv::Point2d biasedPoint = point - imgCenter;
47+
48+
double altitude = m->altitude;
49+
double heading = m->heading;
50+
double latitude = m->lat;
51+
double longitude = m->lon;
52+
53+
BOOST_LOG_TRIVIAL(trace) << "Camera FOV: " << f->get_camera().get_fov();
54+
55+
BOOST_LOG_TRIVIAL(trace) << "Dist from Center (pixels: " << biasedPoint;
56+
57+
double cameraXEdge = altitude * tan(DEG2RAD(f->get_camera().get_fov().width/2)); //meters from center of photo to edge
58+
double cameraYEdge = altitude * tan(DEG2RAD(f->get_camera().get_fov().height/2)); //meters from center of photo to edge
59+
60+
BOOST_LOG_TRIVIAL(trace) << "X Edge: " << cameraXEdge << " Y Edge: " << cameraYEdge;
61+
62+
//Rotation Matrix - Heading
63+
//Note: The '-heading' compensates for the fact that directional heading is
64+
//a clockwise quantity, but cos(theta) assumes theta is a counterclockwise
65+
//quantity.
66+
double realX = cos(DEG2RAD(-heading)) * biasedPoint.x/(w/2)*cameraXEdge - sin(DEG2RAD(-heading)) * biasedPoint.y/(h/2)*cameraYEdge;
67+
double realY = sin(DEG2RAD(-heading)) * biasedPoint.x/(w/2)*cameraXEdge + cos(DEG2RAD(-heading)) * biasedPoint.y/(h/2)*cameraYEdge;
68+
69+
BOOST_LOG_TRIVIAL(trace) << "Real X: " << realX << " Real Y: " << realY;
70+
71+
double lon = RAD2DEG(realX/EARTH_RADIUS)/cos(DEG2RAD(latitude)) + longitude;
72+
double lat = RAD2DEG(realY/EARTH_RADIUS) + latitude;
73+
74+
BOOST_LOG_TRIVIAL(trace) << "Distance from centre: " << RAD2DEG(realY/EARTH_RADIUS) << " " << RAD2DEG(realX/EARTH_RADIUS)/cos(DEG2RAD(latitude));
75+
76+
BOOST_LOG_TRIVIAL(trace) << std::setprecision(10) << "Result: " << lat << " " << lon;
77+
78+
*returnResult = cv::Point2d(lat,lon);
79+
return true;
80+
}
81+
82+
double gps_dist(cv::Point2d p1, cv::Point2d p2) {
83+
double dLat = DEG2RAD(p2.x-p1.x);
84+
double dLon = DEG2RAD(p2.y-p1.y);
85+
86+
double rLat1 = DEG2RAD(p1.x);
87+
double rLat2 = DEG2RAD(p2.x);
88+
89+
double a = sin(dLat/2) * sin(dLat/2) +
90+
sin(dLon/2) * sin(dLon/2) * cos(rLat1) * cos(rLat2);
91+
double c = 2 * atan2(sqrt(a), sqrt(1-a));
92+
return EARTH_RADIUS * c;
93+
}

modules/targetanalysis/test/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ enable_testing()
33
if(Boost_FOUND AND OpenCV_FOUND)
44
ADD_DEFINITIONS("-DBOOST_LOG_DYN_LINK")
55
add_executable(target_loader_test test.cpp)
6+
add_executable(gps_test gps_test.cpp)
7+
68
target_link_libraries(target_loader_test ${OpenCV_LIBS} ${Boost_LIBRARIES} Core TargetAnalysis)
9+
target_link_libraries(gps_test ${OpenCV_LIBS} ${Boost_LIBRARIES} Core TargetAnalysis)
710

811
# Tests
912
add_test("SimpleLoad" target_loader_test "${TESTDATA_DIR}/sample.json" "Simple Load" --log_format=XML --log_sink=TEST_LOADER.xml --log_level=all --report_level=no)
13+
14+
add_test("GpsTest" gps_test --log_format=XML --log_sink=TEST_GPS.xml
15+
--log_level=all --report_level=no)
1016
endif()
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @file gps_test.cpp
3+
* @author WARG
4+
*
5+
* @section LICENSE
6+
*
7+
* Copyright (c) 2015-2017, Waterloo Aerial Robotics Group (WARG)
8+
* All rights reserved.
9+
*
10+
* This software is licensed under a modified version of the BSD 3 clause license
11+
* that should have been included with this software in a file called COPYING.txt
12+
* Otherwise it is available at:
13+
* https://raw.githubusercontent.com/UWARG/computer-vision/master/COPYING.txt
14+
*/
15+
16+
#define BOOST_TEST_DYN_LINK
17+
#define BOOST_TEST_MODULE TargetAnalysis
18+
19+
#include <boost/test/unit_test.hpp>
20+
#include <boost/log/core.hpp>
21+
#include <boost/log/trivial.hpp>
22+
#include <boost/log/expressions.hpp>
23+
#include "gps.h"
24+
25+
using namespace std;
26+
using namespace boost;
27+
28+
namespace logging = boost::log;
29+
30+
void gps_check(cv::Point2d point, cv::Point2d expected, Frame *f) {
31+
cv::Point2d result;
32+
if (get_gps(point, f, &result)) {
33+
BOOST_TEST_MESSAGE("Result: " << result);
34+
BOOST_TEST_MESSAGE("Expected: " << expected);
35+
BOOST_TEST_MESSAGE("Error distance: " << gps_dist(result, expected));
36+
BOOST_CHECK(norm(result - expected) < GPS_TOLERANCE);
37+
} else {
38+
BOOST_TEST_FAIL("get_gps returned failure");
39+
}
40+
}
41+
42+
BOOST_AUTO_TEST_CASE(GpsTest){
43+
Metadata m;
44+
m.lat = 43.47181;
45+
m.lon = -80.54366;
46+
m.altitude = 100;
47+
m.heading = 0;
48+
Camera testcamera = Camera::TestCamera();
49+
Frame f(
50+
new cv::Mat(6000, 4000, CV_32F),
51+
"test_image",
52+
m,
53+
testcamera
54+
);
55+
56+
gps_check(cv::Point2d(3000, 2000), cv::Point2d(43.47181, -80.54366), &f);
57+
58+
gps_check(cv::Point2d(1500, 1000), cv::Point2d(43.47158517, -80.54412471), &f);
59+
60+
m.heading = 180;
61+
Frame f2(
62+
new cv::Mat(6000, 4000, CV_32F),
63+
"test_image",
64+
m,
65+
testcamera
66+
);
67+
gps_check(cv::Point2d(4500, 3000), cv::Point2d(43.47158517, -80.54412471), &f2);
68+
69+
m.heading = 90;
70+
Frame f3(
71+
new cv::Mat(6000, 4000, CV_32F),
72+
"test_image",
73+
m,
74+
testcamera
75+
);
76+
gps_check(cv::Point2d(4000, 500), cv::Point2d(43.47158517, -80.54412471), &f3);
77+
}

0 commit comments

Comments
 (0)