OpenShot Library | libopenshot 0.3.3
Loading...
Searching...
No Matches
Tracker.cpp
Go to the documentation of this file.
1
10// Copyright (c) 2008-2019 OpenShot Studios, LLC
11//
12// SPDX-License-Identifier: LGPL-3.0-or-later
13
14#include <string>
15#include <memory>
16#include <iostream>
17
18#include "effects/Tracker.h"
19#include "Exceptions.h"
20#include "Timeline.h"
21#include "trackerdata.pb.h"
22
23#include <google/protobuf/util/time_util.h>
24
25#include <QImage>
26#include <QPainter>
27#include <QPen>
28#include <QBrush>
29#include <QRectF>
30
31using namespace std;
32using namespace openshot;
33using google::protobuf::util::TimeUtil;
34
36Tracker::Tracker(std::string clipTrackerDataPath)
37{
38 // Init effect properties
39 init_effect_details();
40 // Instantiate a TrackedObjectBBox object and point to it
41 TrackedObjectBBox trackedDataObject;
42 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
43 // Tries to load the tracked object's data from protobuf file
44 trackedData->LoadBoxData(clipTrackerDataPath);
45 ClipBase* parentClip = this->ParentClip();
46 trackedData->ParentClip(parentClip);
47 trackedData->Id(std::to_string(0));
48 // Insert TrackedObject with index 0 to the trackedObjects map
49 trackedObjects.insert({0, trackedData});
50}
51
52// Default constructor
54{
55 // Init effect properties
56 init_effect_details();
57 // Instantiate a TrackedObjectBBox object and point to it
58 TrackedObjectBBox trackedDataObject;
59 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
60 ClipBase* parentClip = this->ParentClip();
61 trackedData->ParentClip(parentClip);
62 trackedData->Id(std::to_string(0));
63 // Insert TrackedObject with index 0 to the trackedObjects map
64 trackedObjects.insert({0, trackedData});
65}
66
67
68// Init effect settings
69void Tracker::init_effect_details()
70{
73
75 info.class_name = "Tracker";
76 info.name = "Tracker";
77 info.description = "Track the selected bounding box through the video.";
78 info.has_audio = false;
79 info.has_video = true;
81
82 this->TimeScale = 1.0;
83}
84
85// This method is required for all derived classes of EffectBase, and returns a
86// modified openshot::Frame object
87std::shared_ptr<Frame> Tracker::GetFrame(std::shared_ptr<Frame> frame, int64_t frame_number) {
88 // Get the frame's QImage
89 std::shared_ptr<QImage> frame_image = frame->GetImage();
90
91 // Check if frame isn't NULL
92 if(frame_image && !frame_image->isNull() &&
93 trackedData->Contains(frame_number) &&
94 trackedData->visible.GetValue(frame_number) == 1) {
95 QPainter painter(frame_image.get());
96
97 // Get the bounding-box of the given frame
98 BBox fd = trackedData->GetBox(frame_number);
99
100 // Create a QRectF for the bounding box
101 QRectF boxRect((fd.cx - fd.width / 2) * frame_image->width(),
102 (fd.cy - fd.height / 2) * frame_image->height(),
103 fd.width * frame_image->width(),
104 fd.height * frame_image->height());
105
106 // Check if track data exists for the requested frame
107 if (trackedData->draw_box.GetValue(frame_number) == 1) {
108 painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
109
110 // Get trackedObjectBox keyframes
111 std::vector<int> stroke_rgba = trackedData->stroke.GetColorRGBA(frame_number);
112 int stroke_width = trackedData->stroke_width.GetValue(frame_number);
113 float stroke_alpha = trackedData->stroke_alpha.GetValue(frame_number);
114 std::vector<int> bg_rgba = trackedData->background.GetColorRGBA(frame_number);
115 float bg_alpha = trackedData->background_alpha.GetValue(frame_number);
116 float bg_corner = trackedData->background_corner.GetValue(frame_number);
117
118 // Set the pen for the border
119 QPen pen(QColor(stroke_rgba[0], stroke_rgba[1], stroke_rgba[2], 255 * stroke_alpha));
120 pen.setWidth(stroke_width);
121 painter.setPen(pen);
122
123 // Set the brush for the background
124 QBrush brush(QColor(bg_rgba[0], bg_rgba[1], bg_rgba[2], 255 * bg_alpha));
125 painter.setBrush(brush);
126
127 // Draw the rounded rectangle
128 painter.drawRoundedRect(boxRect, bg_corner, bg_corner);
129 }
130
131 painter.end();
132 }
133
134 // No need to set the image back to the frame, as we directly modified the frame's QImage
135 return frame;
136}
137
138// Get the indexes and IDs of all visible objects in the given frame
139std::string Tracker::GetVisibleObjects(int64_t frame_number) const{
140
141 // Initialize the JSON objects
142 Json::Value root;
143 root["visible_objects_index"] = Json::Value(Json::arrayValue);
144 root["visible_objects_id"] = Json::Value(Json::arrayValue);
145
146 // Iterate through the tracked objects
147 for (const auto& trackedObject : trackedObjects){
148 // Get the tracked object JSON properties for this frame
149 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(frame_number);
150 if (trackedObjectJSON["visible"]["value"].asBool()){
151 // Save the object's index and ID if it's visible in this frame
152 root["visible_objects_index"].append(trackedObject.first);
153 root["visible_objects_id"].append(trackedObject.second->Id());
154 }
155 }
156
157 return root.toStyledString();
158}
159
160// Generate JSON string of this object
161std::string Tracker::Json() const {
162
163 // Return formatted string
164 return JsonValue().toStyledString();
165}
166
167// Generate Json::Value for this object
168Json::Value Tracker::JsonValue() const {
169
170 // Create root json object
171 Json::Value root = EffectBase::JsonValue(); // get parent properties
172
173 // Save the effect's properties on root
174 root["type"] = info.class_name;
175 root["protobuf_data_path"] = protobuf_data_path;
176 root["BaseFPS"]["num"] = BaseFPS.num;
177 root["BaseFPS"]["den"] = BaseFPS.den;
178 root["TimeScale"] = this->TimeScale;
179
180 // Add trackedObjects IDs to JSON
181 Json::Value objects;
182 for (auto const& trackedObject : trackedObjects){
183 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
184 // add object json
185 objects[trackedObject.second->Id()] = trackedObjectJSON;
186 }
187 root["objects"] = objects;
188
189 // return JsonValue
190 return root;
191}
192
193// Load JSON string into this object
194void Tracker::SetJson(const std::string value) {
195
196 // Parse JSON string into JSON objects
197 try
198 {
199 const Json::Value root = openshot::stringToJson(value);
200 // Set all values that match
201 SetJsonValue(root);
202 }
203 catch (const std::exception& e)
204 {
205 // Error parsing JSON (or missing keys)
206 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
207 }
208 return;
209}
210
211// Load Json::Value into this object
212void Tracker::SetJsonValue(const Json::Value root) {
213
214 // Set parent data
216
217 if (!root["BaseFPS"].isNull() && root["BaseFPS"].isObject())
218 {
219 if (!root["BaseFPS"]["num"].isNull())
220 {
221 BaseFPS.num = (int) root["BaseFPS"]["num"].asInt();
222 }
223 if (!root["BaseFPS"]["den"].isNull())
224 {
225 BaseFPS.den = (int) root["BaseFPS"]["den"].asInt();
226 }
227 }
228
229 if (!root["TimeScale"].isNull())
230 TimeScale = (double) root["TimeScale"].asDouble();
231
232 // Set data from Json (if key is found)
233 if (!root["protobuf_data_path"].isNull() && protobuf_data_path.size() <= 1)
234 {
235 protobuf_data_path = root["protobuf_data_path"].asString();
236 if(!trackedData->LoadBoxData(protobuf_data_path))
237 {
238 std::clog << "Invalid protobuf data path " << protobuf_data_path << '\n';
240 }
241 }
242
243 if (!root["objects"].isNull()){
244 for (auto const& trackedObject : trackedObjects){
245 std::string obj_id = std::to_string(trackedObject.first);
246 if(!root["objects"][obj_id].isNull()){
247 trackedObject.second->SetJsonValue(root["objects"][obj_id]);
248 }
249 }
250 }
251
252 // Set the tracked object's ids
253 if (!root["objects_id"].isNull()){
254 for (auto const& trackedObject : trackedObjects){
255 Json::Value trackedObjectJSON;
256 trackedObjectJSON["box_id"] = root["objects_id"][trackedObject.first].asString();
257 trackedObject.second->SetJsonValue(trackedObjectJSON);
258 }
259 }
260
261 return;
262}
263
264// Get all properties for a specific frame
265std::string Tracker::PropertiesJSON(int64_t requested_frame) const {
266
267 // Generate JSON properties list
268 Json::Value root = BasePropertiesJSON(requested_frame);
269
270 // Add trackedObject properties to JSON
271 Json::Value objects;
272 for (auto const& trackedObject : trackedObjects){
273 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
274 // add object json
275 objects[trackedObject.second->Id()] = trackedObjectJSON;
276 }
277 root["objects"] = objects;
278
279 // Return formatted string
280 return root.toStyledString();
281}
Header file for all Exception classes.
Header file for Timeline class.
Header file for Tracker effect class.
This abstract class is the base class, used by all clips in libopenshot.
Definition ClipBase.h:33
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
openshot::ClipBase * ParentClip()
Parent clip object of this effect (which can be unparented and NULL)
Json::Value BasePropertiesJSON(int64_t requested_frame) const
Generate JSON object of base properties (recommended to be used by all effects)
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
EffectInfoStruct info
Information about the current effect.
Definition EffectBase.h:69
std::map< int, std::shared_ptr< openshot::TrackedObjectBase > > trackedObjects
Map of Tracked Object's by their indices (used by Effects that track objects on clips)
Definition EffectBase.h:66
int num
Numerator for the fraction.
Definition Fraction.h:32
int den
Denominator for the fraction.
Definition Fraction.h:33
Exception for invalid JSON.
Definition Exceptions.h:218
This class contains the properties of a tracked object and functions to manipulate it.
std::string Json() const override
Generate JSON string of this object.
Definition Tracker.cpp:161
std::string GetVisibleObjects(int64_t frame_number) const override
Get the indexes and IDs of all visible objects in the given frame.
Definition Tracker.cpp:139
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition Tracker.cpp:168
void SetJson(const std::string value) override
Load JSON string into this object.
Definition Tracker.cpp:194
std::shared_ptr< Frame > GetFrame(std::shared_ptr< Frame > frame, int64_t frame_number) override
Apply this effect to an openshot::Frame.
Definition Tracker.cpp:87
std::string PropertiesJSON(int64_t requested_frame) const override
Definition Tracker.cpp:265
std::shared_ptr< TrackedObjectBBox > trackedData
Pointer to an object that holds the bounding-box data and it's Keyframes.
Definition Tracker.h:52
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition Tracker.cpp:212
Tracker()
Default constructor.
Definition Tracker.cpp:53
std::string protobuf_data_path
Path to the protobuf file that holds the bounding-box data.
Definition Tracker.h:51
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16
This struct holds the information of a bounding-box.
float cy
y-coordinate of the bounding box center
float height
bounding box height
float cx
x-coordinate of the bounding box center
float width
bounding box width
bool has_video
Determines if this effect manipulates the image of a frame.
Definition EffectBase.h:40
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition EffectBase.h:41
std::string class_name
The class name of the effect.
Definition EffectBase.h:36
std::string name
The name of the effect.
Definition EffectBase.h:37
std::string description
The description of this effect and what it does.
Definition EffectBase.h:38
bool has_tracked_object
Determines if this effect track objects through the clip.
Definition EffectBase.h:42