22 #include "trackerdata.pb.h"
24 #include <google/protobuf/util/time_util.h>
34 using google::protobuf::util::TimeUtil;
41 init_effect_details();
44 trackedData = std::make_shared<TrackedObjectBBox>();
45 trackedData->ParentClip(this->ParentClip());
48 trackedObjects.clear();
49 trackedObjects.emplace(0, trackedData);
53 trackedData->Id(Id() +
"-0");
57 void Tracker::init_effect_details()
63 info.class_name =
"Tracker";
64 info.name =
"Tracker";
65 info.description =
"Track the selected bounding box through the video.";
66 info.has_audio =
false;
67 info.has_video =
true;
68 info.has_tracked_object =
true;
70 this->TimeScale = 1.0;
75 std::shared_ptr<Frame> Tracker::GetFrame(std::shared_ptr<Frame> frame, int64_t frame_number)
78 if (!frame)
return frame;
79 auto frame_image = frame->GetImage();
80 if (!frame_image || frame_image->isNull())
return frame;
81 if (!trackedData)
return frame;
84 if (!trackedData->Contains(frame_number) ||
85 trackedData->visible.GetValue(frame_number) != 1)
88 QPainter painter(frame_image.get());
89 painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
92 BBox fd = trackedData->GetBox(frame_number);
94 (fd.
cx - fd.
width/2) * frame_image->width(),
95 (fd.
cy - fd.
height/2) * frame_image->height(),
96 fd.
width * frame_image->width(),
97 fd.
height * frame_image->height()
100 if (trackedData->draw_box.GetValue(frame_number) == 1)
102 auto stroke_rgba = trackedData->stroke.GetColorRGBA(frame_number);
103 int stroke_width = trackedData->stroke_width.GetValue(frame_number);
104 float stroke_alpha = trackedData->stroke_alpha.GetValue(frame_number);
105 auto bg_rgba = trackedData->background.GetColorRGBA(frame_number);
106 float bg_alpha = trackedData->background_alpha.GetValue(frame_number);
107 float bg_corner = trackedData->background_corner.GetValue(frame_number);
110 stroke_rgba[0], stroke_rgba[1], stroke_rgba[2],
111 int(255 * stroke_alpha)
113 pen.setWidth(stroke_width);
117 bg_rgba[0], bg_rgba[1], bg_rgba[2],
120 painter.setBrush(brush);
122 painter.drawRoundedRect(boxRect, bg_corner, bg_corner);
130 std::string Tracker::GetVisibleObjects(int64_t frame_number)
const
133 root[
"visible_objects_index"] = Json::Value(Json::arrayValue);
134 root[
"visible_objects_id"] = Json::Value(Json::arrayValue);
136 if (trackedObjects.empty())
137 return root.toStyledString();
139 for (
auto const& kv : trackedObjects) {
140 auto ptr = kv.second;
144 Json::Value propsJson = ptr->PropertiesJSON(frame_number);
146 if (propsJson[
"visible"][
"value"].asBool()) {
147 root[
"visible_objects_index"].append(kv.first);
148 root[
"visible_objects_id"].append(ptr->Id());
152 return root.toStyledString();
156 std::string Tracker::Json()
const {
159 return JsonValue().toStyledString();
163 Json::Value Tracker::JsonValue()
const {
166 Json::Value root = EffectBase::JsonValue();
169 root[
"type"] = info.class_name;
170 root[
"protobuf_data_path"] = protobuf_data_path;
171 root[
"BaseFPS"][
"num"] = BaseFPS.num;
172 root[
"BaseFPS"][
"den"] = BaseFPS.den;
173 root[
"TimeScale"] = this->TimeScale;
177 for (
auto const& trackedObject : trackedObjects){
178 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
180 objects[trackedObject.second->Id()] = trackedObjectJSON;
182 root[
"objects"] = objects;
189 void Tracker::SetJson(
const std::string value) {
198 catch (
const std::exception& e)
201 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
207 void Tracker::SetJsonValue(
const Json::Value root) {
210 EffectBase::SetJsonValue(root);
212 if (!root[
"BaseFPS"].isNull()) {
213 if (!root[
"BaseFPS"][
"num"].isNull())
214 BaseFPS.num = root[
"BaseFPS"][
"num"].asInt();
215 if (!root[
"BaseFPS"][
"den"].isNull())
216 BaseFPS.den = root[
"BaseFPS"][
"den"].asInt();
219 if (!root[
"TimeScale"].isNull()) {
220 TimeScale = root[
"TimeScale"].asDouble();
223 if (!root[
"protobuf_data_path"].isNull()) {
224 std::string new_path = root[
"protobuf_data_path"].asString();
225 if (protobuf_data_path != new_path || trackedData->GetLength() == 0) {
226 protobuf_data_path = new_path;
227 if (!trackedData->LoadBoxData(protobuf_data_path)) {
228 std::clog <<
"Invalid protobuf data path " << protobuf_data_path <<
'\n';
229 protobuf_data_path.clear();
233 for (
auto& kv : trackedObjects) {
235 auto ptr = kv.second;
237 std::string prefix = this->Id();
240 ptr->Id(prefix + std::to_string(idx));
248 if (!root[
"objects"].isNull()) {
250 const auto memberNames = root[
"objects"].getMemberNames();
251 for (
const auto& name : memberNames)
255 bool numeric_key = std::all_of(name.begin(), name.end(), ::isdigit);
257 index = std::stoi(name);
261 size_t pos = name.find_last_of(
'-');
262 if (pos != std::string::npos) {
264 index = std::stoi(name.substr(pos + 1));
271 auto obj_it = trackedObjects.find(index);
272 if (obj_it != trackedObjects.end() && obj_it->second) {
275 obj_it->second->Id(name);
276 obj_it->second->SetJsonValue(root[
"objects"][name]);
282 if (!root[
"objects_id"].isNull()) {
283 for (
auto& kv : trackedObjects) {
284 if (!root[
"objects_id"][kv.first].isNull())
285 kv.second->Id(root[
"objects_id"][kv.first].asString());
291 std::string Tracker::PropertiesJSON(int64_t requested_frame)
const {
294 Json::Value root = BasePropertiesJSON(requested_frame);
298 for (
auto const& trackedObject : trackedObjects){
299 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
301 objects[trackedObject.second->Id()] = trackedObjectJSON;
303 root[
"objects"] = objects;
306 return root.toStyledString();
Header file for all Exception classes.
Header file for Timeline class.
Header file for Tracker effect class.
Exception for invalid JSON.
This namespace is the default namespace for all code in the openshot library.
const Json::Value stringToJson(const std::string value)
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