-
Notifications
You must be signed in to change notification settings - Fork 290
/
object_localization.cpp
103 lines (92 loc) · 3.96 KB
/
object_localization.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "opencv2/opencv.hpp"
#define DEG2RAD(v) (v * CV_PI / 180)
#define Rx(rx) (cv::Matx33d(1, 0, 0, 0, cos(rx), -sin(rx), 0, sin(rx), cos(rx)))
#define Ry(ry) (cv::Matx33d(cos(ry), 0, sin(ry), 0, 1, 0, -sin(ry), 0, cos(ry)))
#define Rz(rz) (cv::Matx33d(cos(rz), -sin(rz), 0, sin(rz), cos(rz), 0, 0, 0, 1))
class MouseDrag
{
public:
MouseDrag() : dragged(false) { }
bool dragged;
cv::Point xy_s, xy_e;
};
void MouseEventHandler(int event, int x, int y, int flags, void* param)
{
// Change 'mouse_state' (given as 'param') according to the mouse 'event'
if (param == NULL) return;
MouseDrag* drag = (MouseDrag*)param;
if (event == cv::EVENT_LBUTTONDOWN)
{
drag->dragged = true;
drag->xy_s = cv::Point(x, y);
drag->xy_e = cv::Point(0, 0);
}
else if (event == cv::EVENT_MOUSEMOVE)
{
if (drag->dragged) drag->xy_e = cv::Point(x, y);
}
else if (event == cv::EVENT_LBUTTONUP)
{
if (drag->dragged)
{
drag->dragged = false;
drag->xy_e = cv::Point(x, y);
}
}
}
int main()
{
// The given image and its calibration data
const char* img_file = "../data/daejeon_station.png";
double f = 810.5, cx = 480, cy = 270, L = 3.31; // Unit: [px], [px], [px], [m]
cv::Point3d cam_ori(DEG2RAD(-18.7), DEG2RAD(-8.2), DEG2RAD(2.0)); // Unit: [deg]
cv::Range grid_x(-2, 3), grid_z(5, 36); // Unit: [m]
// Load an images
cv::Mat img = cv::imread(img_file);
if (img.empty()) return -1;
// Register the mouse callback function
MouseDrag drag;
cv::namedWindow("Object Localization and Measurement");
cv::setMouseCallback("Object Localization and Measurement", MouseEventHandler, &drag);
// Prepare the camera projection
cv::Matx33d K(f, 0, cx, 0, f, cy, 0, 0, 1);
cv::Matx33d Rc = Rz(cam_ori.z) * Ry(cam_ori.y) * Rx(cam_ori.x);
cv::Point3d tc = cv::Point3d(0, -L, 0);
cv::Matx33d R = Rc.t();
cv::Point3d t = -Rc.t() * tc;
// Draw X- and Z-grids on the ground
for (int z = grid_z.start; z <= grid_z.end; z++)
{
cv::Point3d p = K * (R * cv::Point3d(grid_x.start, 0, z) + t);
cv::Point3d q = K * (R * cv::Point3d(grid_x.end, 0, z) + t);
cv::line(img, cv::Point2d(p.x / p.z, p.y / p.z), cv::Point2d(q.x / q.z, q.y / q.z), cv::Vec3b(64, 128, 64), 1);
}
for (int x = grid_x.start; x <= grid_x.end; x++)
{
cv::Point3d p = K * (R * cv::Point3d(x, 0, grid_z.start) + t);
cv::Point3d q = K * (R * cv::Point3d(x, 0, grid_z.end) + t);
cv::line(img, cv::Point2d(p.x / p.z, p.y / p.z), cv::Point2d(q.x / q.z, q.y / q.z), cv::Vec3b(64, 128, 64), 1);
}
while (true)
{
cv::Mat img_copy = img.clone();
if (drag.xy_e.x > 0 && drag.xy_e.y > 0)
{
// Calculate object location and height
cv::Point3d c = R.t() * cv::Point3d(drag.xy_s.x - cx, drag.xy_s.y - cy, f);
if (c.y < DBL_EPSILON) continue; // Skip the degenerate case (beyond the horizon)
cv::Point3d h = R.t() * cv::Point3d(drag.xy_e.x - cx, drag.xy_e.y - cy, f);
double Z = c.z / c.y * L, X = c.x / c.y * L, H = (c.y / c.z - h.y / h.z) * Z;
// Draw head/contact points and location/height
cv::line(img_copy, drag.xy_s, drag.xy_e, cv::Vec3b(0, 0, 255), 2);
cv::circle(img_copy, drag.xy_e, 4, cv::Vec3b(255, 0, 0), -1);
cv::circle(img_copy, drag.xy_s, 4, cv::Vec3b(0, 255, 0), -1);
cv::putText(img_copy, cv::format("X:%.2f, Z:%.2f, H:%.2f", X, Z, H), drag.xy_s + cv::Point(-20, 20), cv::FONT_HERSHEY_PLAIN, 1, cv::Vec3b(0, 255, 0));
}
// Show the image
cv::imshow("Object Localization and Measurement", img_copy);
int key = cv::waitKey(1);
if (key == 27) break; // ESC
}
return 0;
}