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();