AbstractRecordingStrategy.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package visionx::imrec
17 * @author Christian R. G. Dreher <christian.dreher@student.kit.edu>
18 * @date 2018
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23
24// Metadata version to handle potential breaking changes in the future.
25#define METADATA_VERSION "2.0"
26
27
29
30
31// STD/STL
32#include <filesystem>
33
34// OpenCV 2
35#include <opencv2/opencv.hpp>
36
37// IVT
38#include <Image/ByteImage.h>
39
40// ArmarX
43
45
50
52 const std::filesystem::path& file_path) :
53 m_file_path{file_path}, m_recording{false}
54{
55 // pass
56}
57
65
66bool
68{
69 return m_recording;
70}
71
72void
74{
75 ARMARX_CHECK_EXPRESSION(not m_recording)
76 << "Instance has already been initialised for recording";
77 ARMARX_CHECK_EXPRESSION(not std::filesystem::exists(m_file_path)) << "File already exists";
78
79 std::filesystem::create_directories(m_file_path.parent_path());
80
81 m_recording = true;
82}
83
84void
86 const std::chrono::microseconds time)
87{
88 // Default implementations of recordFrame just convert the parameter and call the other recordFrame method.
89 // This way only one method needs to be overridden in the interface-implementing classes
90
91 // Call cv::Mat variant of recordFrame(...)
92 cv::Mat cv_frame;
93 visionx::imrec::convert(frame, cv_frame);
94 recordFrame(cv_frame, time);
95}
96
97void
99 const std::chrono::microseconds time)
100{
101 // Default implementations of recordFrame just convert the parameter and call the other recordFrame method.
102 // This way only one method needs to be overridden in the interface-implementing classes
103
104 // Call CByteImage variant of recordFrame(...)
105 CByteImage ivt_frame;
106 visionx::imrec::convert(frame, ivt_frame);
107 recordFrame(ivt_frame, time);
108}
109
110void
112{
113 writeMetadataLine("frame_count", "unsigned int", std::to_string(m_sequence_number));
114 m_recording = false;
115 if (m_metadata_file.is_open())
116 {
117 m_metadata_file.close();
118 }
119}
120
121std::filesystem::path
126
127std::filesystem::path
129{
130 return m_file_path.parent_path();
131}
132
133std::filesystem::path
138
139std::filesystem::path
144
145std::filesystem::path
147{
148 std::filesystem::path path = getPath();
149 std::filesystem::path filename = getStem().string() + "_metadata.csv";
150 return std::filesystem::canonical(path) / filename;
151}
152
153std::tuple<unsigned int, std::string>
155 const CByteImage& frame,
156 const std::chrono::microseconds timestamp)
157{
159 "frame_height", "unsigned int", std::to_string(static_cast<unsigned int>(frame.height)));
161 "frame_width", "unsigned int", std::to_string(static_cast<unsigned int>(frame.width)));
162 return writeMetadataFrameFileInfo(timestamp);
163}
164
165std::tuple<unsigned int, std::string>
167 const cv::Mat& frame,
168 const std::chrono::microseconds timestamp)
169{
170 writeMetadataLine("frame_height",
171 "unsigned int",
172 std::to_string(static_cast<unsigned int>(frame.size().height)));
173 writeMetadataLine("frame_width",
174 "unsigned int",
175 std::to_string(static_cast<unsigned int>(frame.size().width)));
176 return writeMetadataFrameFileInfo(timestamp);
177}
178
179std::tuple<unsigned int, std::string>
180visionx::imrec::AbstractRecordingStrategy::writeMetadataFrameFileInfo(
181 const std::chrono::microseconds timestamp)
182{
183 const unsigned int sequence_number = m_sequence_number++;
184
185 // Write local system reference time of not already done.
186 if (m_reference_time.count() == 0)
187 {
188 m_reference_time = timestamp;
189 writeMetadataDatetime("frame_0_system_reference_time", timestamp);
190 }
191
192 // Normalize time to time since frame_0.
193 const std::chrono::microseconds normalized_time = timestamp - m_reference_time;
194 const std::string normalized_time_str = timestamp_to_string(normalized_time);
195
196 // Write frame_<SEQUENCE_NUMBER> = <FRAME_NAME>.
197 writeMetadataLine("frame_" + std::to_string(sequence_number), "string", normalized_time_str);
198
199 return {sequence_number, normalized_time_str};
200}
201
202void
204 const std::string& var_name,
205 const std::chrono::microseconds timestamp)
206{
207 writeMetadataLine(var_name + "_us", "long", std::to_string(timestamp.count()));
208 writeMetadataLine(var_name + "_hr", "string", datetime_to_string(timestamp));
209}
210
211void
213 const std::string_view var_type,
214 const std::string_view var_value)
215{
216 if (not m_metadata_file.is_open())
217 {
218 m_metadata_file.open(getMetadataPath());
219 writeMetadataLine("name", "type", "value");
220 writeMetadataLine("metadata_version", "string", METADATA_VERSION);
221 }
222
223 // If the given variable was already written, do nothing
224 if (m_written_metadata_variables.insert(var_name).second == false)
225 {
226 return;
227 }
228
229 m_metadata_file << var_name << "," << var_type << "," << var_value << "\n";
230 m_metadata_file.flush();
231}
#define METADATA_VERSION
std::string timestamp()
virtual std::filesystem::path getDotExtension() const
Gets the extension plus preceeded dot of the configured file (e.g.
virtual void writeMetadataDatetime(const std::string &var_name, std::chrono::microseconds timestamp)
virtual std::filesystem::path getPath() const
Gets the path to the recording without filename.
virtual std::filesystem::path getMetadataPath() const
virtual bool isRecording() const
Indicates whether this instance is already initialised for recording.
AbstractRecordingStrategy()
Default constructor to start the recording manually.
virtual std::filesystem::path getStem() const
Gets the stem of the configured file (filename without extension)
std::filesystem::path m_file_path
Path to where the recording file should be written to.
virtual void startRecording()
Starts the recording manually if constructed empty.
virtual std::tuple< unsigned int, std::string > writeMetadataFrame(const CByteImage &frame, std::chrono::microseconds timestamp)
virtual void recordFrame(const CByteImage &frame, std::chrono::microseconds timestamp)
Adds the given frame to the recording.
virtual void writeMetadataLine(const std::string &var_name, std::string_view var_type, std::string_view var_value)
virtual std::filesystem::path getFilePath() const
Gets the raw file path for the recording as configured.
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
std::string timestamp_to_string(std::chrono::microseconds ts)
Definition helper.cpp:112
std::string datetime_to_string(std::chrono::microseconds ts)
Definition helper.cpp:77
void convert(const CByteImage &in, cv::Mat &out)
Converts an IVT CByteImage to OpenCV's BGR Mat.
Definition helper.cpp:40