1 /*******************************************************************************
2 * Copyright 2013-2014 EPFL *
3 * Copyright 2013-2014 Quentin Bonnard *
4 * *
5 * This file is part of chilitags. *
6 * *
7 * Chilitags is free software: you can redistribute it and/or modify *
8 * it under the terms of the Lesser GNU General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * Chilitags is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public License *
18 * along with Chilitags. If not, see <http://www.gnu.org/licenses/>. *
19 *******************************************************************************/
20
21 // This file serves as an illustration of how to use Chilitags
22
23
24 // The Chilitags header
25 #include <chilitags.hpp>
26
27 #ifdef OPENCV3
28 #include <opencv2/core/utility.hpp> // getTickCount...
29 #include <opencv2/imgproc/imgproc.hpp>
30 #endif
31
32 #include <opencv2/core/core_c.h> // CV_AA
33 #include <opencv2/core/core.hpp>
34
35 // OpenCV goodness for I/O
36 #include <opencv2/highgui/highgui.hpp>
37
38 #include <iostream>
39 #include <csignal>
40
41
42 bool sRunning = true;
43 cv::VideoCapture capture;
44
quitFunction(int sig)45 void quitFunction(int sig) {
46 std::cout << "Caught interrupt. Closing" << std::endl;
47 capture.release();
48 sRunning = false;
49 }
50
main(int argc,char * argv[])51 int main(int argc, char* argv[])
52 {
53 signal(SIGINT, quitFunction);
54
55 // Simple parsing of the parameters related to the image acquisition
56 int xRes = 640;
57 int yRes = 480;
58 int cameraIndex = 0;
59 if (argc > 2) {
60 xRes = std::atoi(argv[1]);
61 yRes = std::atoi(argv[2]);
62 }
63 if (argc > 3) {
64 cameraIndex = std::atoi(argv[3]);
65 }
66
67 // The source of input images
68 capture.open(cameraIndex);
69 if (!capture.isOpened())
70 {
71 std::cerr << "Unable to initialise video capture." << std::endl;
72 return 1;
73 }
74 #ifdef OPENCV3
75 capture.set(cv::CAP_PROP_FRAME_WIDTH, xRes);
76 capture.set(cv::CAP_PROP_FRAME_HEIGHT, yRes);
77 #else
78 capture.set(CV_CAP_PROP_FRAME_WIDTH, xRes);
79 capture.set(CV_CAP_PROP_FRAME_HEIGHT, yRes);
80 #endif
81 cv::Mat inputImage;
82
83 // The tag detection happens in the Chilitags class.
84 chilitags::Chilitags chilitags;
85
86 // The detection is not perfect, so if a tag is not detected during one frame,
87 // the tag will shortly disappears, which results in flickering.
88 // To address this, Chilitags "cheats" by keeping tags for n frames
89 // at the same position. When tags disappear for more than 5 frames,
90 // Chilitags actually removes it.
91 // Here, we cancel this to show the raw detection results.
92 chilitags.setFilter(0, 0.0f);
93
94 cv::namedWindow("DisplayChilitags");
95 // Main loop, exiting when 'q is pressed'
96 for (; 'q' != (char) cv::waitKey(1) && sRunning; ) {
97
98 // Capture a new image.
99 capture.read(inputImage);
100
101 // Start measuring the time needed for the detection
102 int64 startTime = cv::getTickCount();
103
104 // Detect tags on the current image (and time the detection);
105 // The resulting map associates tag ids (between 0 and 1023)
106 // to four 2D points corresponding to the corners positions
107 // in the picture.
108 chilitags::TagCornerMap tags = chilitags.find(inputImage);
109
110 // Measure the processing time needed for the detection
111 int64 endTime = cv::getTickCount();
112 float processingTime = 1000.0f*((float) endTime - startTime)/cv::getTickFrequency();
113
114
115 // Now we start using the result of the detection.
116
117 // First, we set up some constants related to the information overlaid
118 // on the captured image
119 const static cv::Scalar COLOR(255, 0, 255);
120 // OpenCv can draw with sub-pixel precision with fixed point coordinates
121 static const int SHIFT = 16;
122 static const float PRECISION = 1<<SHIFT;
123
124 // We dont want to draw directly on the input image, so we clone it
125 cv::Mat outputImage = inputImage.clone();
126
127 for (const std::pair<int, chilitags::Quad> & tag : tags) {
128
129 int id = tag.first;
130 // We wrap the corner matrix into a datastructure that allows an
131 // easy access to the coordinates
132 const cv::Mat_<cv::Point2f> corners(tag.second);
133
134 // We start by drawing the borders of the tag
135 for (size_t i = 0; i < 4; ++i) {
136 cv::line(
137 outputImage,
138 PRECISION*corners(i),
139 PRECISION*corners((i+1)%4),
140 #ifdef OPENCV3
141 COLOR, 1, cv::LINE_AA, SHIFT);
142 #else
143 COLOR, 1, CV_AA, SHIFT);
144 #endif
145 }
146
147 // Other points can be computed from the four corners of the Quad.
148 // Chilitags are oriented. It means that the points 0,1,2,3 of
149 // the Quad coordinates are consistently the top-left, top-right,
150 // bottom-right and bottom-left corners.
151 // (i.e. clockwise, starting from top-left)
152 // Using this, we can compute (an approximation of) the center of
153 // tag.
154 cv::Point2f center = 0.5f*(corners(0) + corners(2));
155 cv::putText(outputImage, cv::format("%d", id), center,
156 cv::FONT_HERSHEY_SIMPLEX, 0.5f, COLOR);
157 }
158
159 // Some stats on the current frame (resolution and processing time)
160 cv::putText(outputImage,
161 cv::format("%dx%d %4.0f ms (press q to quit)",
162 outputImage.cols, outputImage.rows,
163 processingTime),
164 cv::Point(32,32),
165 cv::FONT_HERSHEY_SIMPLEX, 0.5f, COLOR);
166
167 // Finally...
168 cv::imshow("DisplayChilitags", outputImage);
169 }
170
171 cv::destroyWindow("DisplayChilitags");
172 capture.release();
173
174 return 0;
175 }
176