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.setWidthF(trackedData->ScaledStrokeWidth(
114 frame_number, frame_image->width(), frame_image->height()));
118 bg_rgba[0], bg_rgba[1], bg_rgba[2],
121 painter.setBrush(brush);
123 painter.drawRoundedRect(boxRect, bg_corner, bg_corner);
131 std::string Tracker::GetVisibleObjects(int64_t frame_number)
const
134 root[
"visible_objects_index"] = Json::Value(Json::arrayValue);
135 root[
"visible_objects_id"] = Json::Value(Json::arrayValue);
137 if (trackedObjects.empty())
138 return root.toStyledString();
140 for (
auto const& kv : trackedObjects) {
141 auto ptr = kv.second;
145 Json::Value propsJson = ptr->PropertiesJSON(frame_number);
147 if (propsJson[
"visible"][
"value"].asBool()) {
148 root[
"visible_objects_index"].append(kv.first);
149 root[
"visible_objects_id"].append(ptr->Id());
153 return root.toStyledString();
157 std::string Tracker::Json()
const {
160 return JsonValue().toStyledString();
164 Json::Value Tracker::JsonValue()
const {
167 Json::Value root = EffectBase::JsonValue();
170 root[
"type"] = info.class_name;
171 root[
"protobuf_data_path"] = protobuf_data_path;
172 root[
"BaseFPS"][
"num"] = BaseFPS.num;
173 root[
"BaseFPS"][
"den"] = BaseFPS.den;
174 root[
"TimeScale"] = this->TimeScale;
178 for (
auto const& trackedObject : trackedObjects){
179 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
181 objects[trackedObject.second->Id()] = trackedObjectJSON;
183 root[
"objects"] = objects;
190 void Tracker::SetJson(
const std::string value) {
199 catch (
const std::exception& e)
202 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
208 void Tracker::SetJsonValue(
const Json::Value root) {
211 EffectBase::SetJsonValue(root);
213 if (!root[
"BaseFPS"].isNull()) {
214 if (!root[
"BaseFPS"][
"num"].isNull())
215 BaseFPS.num = root[
"BaseFPS"][
"num"].asInt();
216 if (!root[
"BaseFPS"][
"den"].isNull())
217 BaseFPS.den = root[
"BaseFPS"][
"den"].asInt();
220 if (!root[
"TimeScale"].isNull()) {
221 TimeScale = root[
"TimeScale"].asDouble();
224 if (!root[
"protobuf_data_path"].isNull()) {
225 std::string new_path = root[
"protobuf_data_path"].asString();
226 if (protobuf_data_path != new_path || trackedData->GetLength() == 0) {
227 protobuf_data_path = new_path;
228 if (!trackedData->LoadBoxData(protobuf_data_path)) {
229 std::clog <<
"Invalid protobuf data path " << protobuf_data_path <<
'\n';
230 protobuf_data_path.clear();
234 for (
auto& kv : trackedObjects) {
236 auto ptr = kv.second;
238 std::string prefix = this->Id();
241 ptr->Id(prefix + std::to_string(idx));
249 if (!root[
"objects"].isNull()) {
251 const auto memberNames = root[
"objects"].getMemberNames();
252 for (
const auto& name : memberNames)
256 bool numeric_key = std::all_of(name.begin(), name.end(), ::isdigit);
258 index = std::stoi(name);
262 size_t pos = name.find_last_of(
'-');
263 if (pos != std::string::npos) {
265 index = std::stoi(name.substr(pos + 1));
272 auto obj_it = trackedObjects.find(index);
273 if (obj_it != trackedObjects.end() && obj_it->second) {
276 obj_it->second->Id(name);
277 obj_it->second->SetJsonValue(root[
"objects"][name]);
283 if (!root[
"objects_id"].isNull()) {
284 for (
auto& kv : trackedObjects) {
285 if (!root[
"objects_id"][kv.first].isNull())
286 kv.second->Id(root[
"objects_id"][kv.first].asString());
292 std::string Tracker::PropertiesJSON(int64_t requested_frame)
const {
295 Json::Value root = BasePropertiesJSON(requested_frame);
299 for (
auto const& trackedObject : trackedObjects){
300 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
302 objects[trackedObject.second->Id()] = trackedObjectJSON;
304 root[
"objects"] = objects;
307 return root.toStyledString();