22 #include "trackerdata.pb.h"
24 #include <google/protobuf/util/time_util.h>
32 using google::protobuf::util::TimeUtil;
35 Tracker::Tracker(std::string clipTrackerDataPath)
38 init_effect_details();
41 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
43 trackedData->LoadBoxData(clipTrackerDataPath);
44 ClipBase* parentClip = this->ParentClip();
45 trackedData->ParentClip(parentClip);
46 trackedData->Id(std::to_string(0));
48 trackedObjects.insert({0, trackedData});
55 init_effect_details();
58 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
59 ClipBase* parentClip = this->ParentClip();
60 trackedData->ParentClip(parentClip);
61 trackedData->Id(std::to_string(0));
63 trackedObjects.insert({0, trackedData});
68 void Tracker::init_effect_details()
74 info.class_name =
"Tracker";
75 info.name =
"Tracker";
76 info.description =
"Track the selected bounding box through the video.";
77 info.has_audio =
false;
78 info.has_video =
true;
79 info.has_tracked_object =
true;
81 this->TimeScale = 1.0;
86 std::shared_ptr<Frame> Tracker::GetFrame(std::shared_ptr<Frame> frame, int64_t frame_number)
89 cv::Mat frame_image = frame->GetImageCV();
94 std::shared_ptr<QImage> childClipImage =
nullptr;
97 if(!frame_image.empty() &&
98 trackedData->Contains(frame_number) &&
99 trackedData->visible.GetValue(frame_number) == 1)
102 float fw = frame_image.size().width;
103 float fh = frame_image.size().height;
106 BBox fd = trackedData->GetBox(frame_number);
109 if (trackedData->draw_box.GetValue(frame_number) == 1)
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);
118 cv::RotatedRect box ( cv::Point2f( (
int)(fd.
cx*fw), (
int)(fd.
cy*fh) ),
119 cv::Size2f( (
int)(fd.
width*fw), (
int)(fd.
height*fh) ),
122 DrawRectangleRGBA(frame_image, box, bg_rgba, bg_alpha, 1,
true);
123 DrawRectangleRGBA(frame_image, box, stroke_rgba, stroke_alpha, stroke_width,
false);
127 if (trackedData->ChildClipId() !=
""){
132 Clip* childClip = parentTimeline->
GetClip(trackedData->ChildClipId());
135 std::shared_ptr<Frame> childClipFrame = childClip->
GetFrame(frame_number);
136 childClipImage = childClipFrame->GetImage();
139 boxRect.setRect((
int)((fd.
cx-fd.
width/2)*fw),
151 frame->SetImageCV(frame_image);
156 QImage frameImage = *(frame->GetImage());
159 QPainter painter(&frameImage);
162 painter.drawImage(boxRect, *childClipImage);
165 frame->AddImage(std::make_shared<QImage>(frameImage));
171 void Tracker::DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector<int> color,
float alpha,
int thickness,
bool is_background){
173 cv::Point2f vertices2f[4];
174 box.points(vertices2f);
182 cv::Mat overlayFrame;
183 frame_image.copyTo(overlayFrame);
186 cv::Point vertices[4];
187 for(
int i = 0; i < 4; ++i){
188 vertices[i] = vertices2f[i];}
190 cv::Rect rect = box.boundingRect();
191 cv::fillConvexPoly(overlayFrame, vertices, 4, cv::Scalar(color[2],color[1],color[0]), cv::LINE_AA);
193 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
196 cv::Mat overlayFrame;
197 frame_image.copyTo(overlayFrame);
200 for (
int i = 0; i < 4; i++)
202 cv::line(overlayFrame, vertices2f[i], vertices2f[(i+1)%4], cv::Scalar(color[2],color[1],color[0]),
203 thickness, cv::LINE_AA);
207 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
212 std::string Tracker::GetVisibleObjects(int64_t frame_number)
const{
216 root[
"visible_objects_index"] = Json::Value(Json::arrayValue);
217 root[
"visible_objects_id"] = Json::Value(Json::arrayValue);
220 for (
const auto& trackedObject : trackedObjects){
222 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(frame_number);
223 if (trackedObjectJSON[
"visible"][
"value"].asBool()){
225 root[
"visible_objects_index"].append(trackedObject.first);
226 root[
"visible_objects_id"].append(trackedObject.second->Id());
230 return root.toStyledString();
234 std::string Tracker::Json()
const {
237 return JsonValue().toStyledString();
241 Json::Value Tracker::JsonValue()
const {
244 Json::Value root = EffectBase::JsonValue();
247 root[
"type"] = info.class_name;
248 root[
"protobuf_data_path"] = protobuf_data_path;
249 root[
"BaseFPS"][
"num"] = BaseFPS.num;
250 root[
"BaseFPS"][
"den"] = BaseFPS.den;
251 root[
"TimeScale"] = this->TimeScale;
255 for (
auto const& trackedObject : trackedObjects){
256 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
258 objects[trackedObject.second->Id()] = trackedObjectJSON;
260 root[
"objects"] = objects;
267 void Tracker::SetJson(
const std::string value) {
276 catch (
const std::exception& e)
279 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
285 void Tracker::SetJsonValue(
const Json::Value root) {
288 EffectBase::SetJsonValue(root);
290 if (!root[
"BaseFPS"].isNull() && root[
"BaseFPS"].isObject())
292 if (!root[
"BaseFPS"][
"num"].isNull())
294 BaseFPS.num = (int) root[
"BaseFPS"][
"num"].asInt();
296 if (!root[
"BaseFPS"][
"den"].isNull())
298 BaseFPS.den = (int) root[
"BaseFPS"][
"den"].asInt();
302 if (!root[
"TimeScale"].isNull())
303 TimeScale = (
double) root[
"TimeScale"].asDouble();
306 if (!root[
"protobuf_data_path"].isNull() && protobuf_data_path.size() <= 1)
308 protobuf_data_path = root[
"protobuf_data_path"].asString();
309 if(!trackedData->LoadBoxData(protobuf_data_path))
311 std::clog <<
"Invalid protobuf data path " << protobuf_data_path <<
'\n';
312 protobuf_data_path =
"";
316 if (!root[
"objects"].isNull()){
317 for (
auto const& trackedObject : trackedObjects){
318 std::string obj_id = std::to_string(trackedObject.first);
319 if(!root[
"objects"][obj_id].isNull()){
320 trackedObject.second->SetJsonValue(root[
"objects"][obj_id]);
326 if (!root[
"objects_id"].isNull()){
327 for (
auto const& trackedObject : trackedObjects){
328 Json::Value trackedObjectJSON;
329 trackedObjectJSON[
"box_id"] = root[
"objects_id"][trackedObject.first].asString();
330 trackedObject.second->SetJsonValue(trackedObjectJSON);
338 std::string Tracker::PropertiesJSON(int64_t requested_frame)
const {
345 for (
auto const& trackedObject : trackedObjects){
346 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
348 objects[trackedObject.second->Id()] = trackedObjectJSON;
350 root[
"objects"] = objects;
353 root[
"id"] = add_property_json(
"ID", 0.0,
"string", Id(), NULL, -1, -1,
true, requested_frame);
354 root[
"position"] = add_property_json(
"Position", Position(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
355 root[
"layer"] = add_property_json(
"Track", Layer(),
"int",
"", NULL, 0, 20,
false, requested_frame);
356 root[
"start"] = add_property_json(
"Start", Start(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
357 root[
"end"] = add_property_json(
"End", End(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
358 root[
"duration"] = add_property_json(
"Duration", Duration(),
"float",
"", NULL, 0, 1000 * 60 * 30,
true, requested_frame);
361 return root.toStyledString();
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.
This class represents a clip (used to arrange readers on the timeline)
std::shared_ptr< openshot::Frame > GetFrame(int64_t clip_frame_number) override
Get an openshot::Frame object for a specific frame number of this clip. The image size and number of ...
Exception for invalid JSON.
This class represents a timeline.
openshot::Clip * GetClip(const std::string &id)
Look up a single clip by ID.
This class contains the properties of a tracked object and functions to manipulate it.
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
float angle
bounding box rotation angle [degrees]