41 #include <google/protobuf/util/time_util.h> 49 using google::protobuf::util::TimeUtil;
52 Tracker::Tracker(std::string clipTrackerDataPath)
55 init_effect_details();
58 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
61 ClipBase* parentClip = this->ParentClip();
62 trackedData->ParentClip(parentClip);
63 trackedData->Id(std::to_string(0));
65 trackedObjects.insert({0, trackedData});
72 init_effect_details();
75 trackedData = std::make_shared<TrackedObjectBBox>(trackedDataObject);
76 ClipBase* parentClip = this->ParentClip();
77 trackedData->ParentClip(parentClip);
78 trackedData->Id(std::to_string(0));
80 trackedObjects.insert({0, trackedData});
85 void Tracker::init_effect_details()
91 info.class_name =
"Tracker";
92 info.name =
"Tracker";
93 info.description =
"Track the selected bounding box through the video.";
94 info.has_audio =
false;
95 info.has_video =
true;
96 info.has_tracked_object =
true;
98 this->TimeScale = 1.0;
103 std::shared_ptr<Frame> Tracker::GetFrame(std::shared_ptr<Frame> frame, int64_t frame_number)
106 cv::Mat frame_image = frame->GetImageCV();
111 std::shared_ptr<QImage> childClipImage =
nullptr;
114 if(!frame_image.empty() &&
115 trackedData->Contains(frame_number) &&
116 trackedData->visible.GetValue(frame_number) == 1)
119 float fw = frame_image.size().width;
120 float fh = frame_image.size().height;
123 BBox fd = trackedData->GetBox(frame_number);
126 if (trackedData->draw_box.GetValue(frame_number) == 1)
128 std::vector<int> stroke_rgba = trackedData->stroke.GetColorRGBA(frame_number);
129 int stroke_width = trackedData->stroke_width.GetValue(frame_number);
130 float stroke_alpha = trackedData->stroke_alpha.GetValue(frame_number);
131 std::vector<int> bg_rgba = trackedData->background.GetColorRGBA(frame_number);
132 float bg_alpha = trackedData->background_alpha.GetValue(frame_number);
135 cv::RotatedRect box ( cv::Point2f( (
int)(fd.
cx*fw), (
int)(fd.
cy*fh) ),
136 cv::Size2f( (
int)(fd.
width*fw), (
int)(fd.
height*fh) ),
139 DrawRectangleRGBA(frame_image, box, bg_rgba, bg_alpha, 1,
true);
140 DrawRectangleRGBA(frame_image, box, stroke_rgba, stroke_alpha, stroke_width,
false);
144 if (trackedData->ChildClipId() !=
""){
149 Clip* childClip = parentTimeline->
GetClip(trackedData->ChildClipId());
152 std::shared_ptr<Frame> f(
new Frame(1, frame->GetWidth(), frame->GetHeight(),
"#00000000"));
153 std::shared_ptr<Frame> childClipFrame = childClip->
GetFrame(f, frame_number);
154 childClipImage = childClipFrame->GetImage();
157 boxRect.setRect((
int)((fd.
cx-fd.
width/2)*fw),
169 frame->SetImageCV(frame_image);
174 QImage frameImage = *(frame->GetImage());
177 QPainter painter(&frameImage);
180 painter.drawImage(boxRect, *childClipImage, QRectF(0, 0, frameImage.size().width(), frameImage.size().height()));
183 frame->AddImage(std::make_shared<QImage>(frameImage));
189 void Tracker::DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector<int> color,
float alpha,
int thickness,
bool is_background){
191 cv::Point2f vertices2f[4];
192 box.points(vertices2f);
200 cv::Mat overlayFrame;
201 frame_image.copyTo(overlayFrame);
204 cv::Point vertices[4];
205 for(
int i = 0; i < 4; ++i){
206 vertices[i] = vertices2f[i];}
208 cv::Rect rect = box.boundingRect();
209 cv::fillConvexPoly(overlayFrame, vertices, 4, cv::Scalar(color[2],color[1],color[0]), cv::LINE_AA);
211 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
214 cv::Mat overlayFrame;
215 frame_image.copyTo(overlayFrame);
218 for (
int i = 0; i < 4; i++)
220 cv::line(overlayFrame, vertices2f[i], vertices2f[(i+1)%4], cv::Scalar(color[2],color[1],color[0]),
221 thickness, cv::LINE_AA);
225 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
230 std::string Tracker::GetVisibleObjects(int64_t frame_number)
const{
234 root[
"visible_objects_index"] = Json::Value(Json::arrayValue);
235 root[
"visible_objects_id"] = Json::Value(Json::arrayValue);
238 for (
const auto& trackedObject : trackedObjects){
240 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(frame_number);
241 if (trackedObjectJSON[
"visible"][
"value"].asBool()){
243 root[
"visible_objects_index"].append(trackedObject.first);
244 root[
"visible_objects_id"].append(trackedObject.second->Id());
248 return root.toStyledString();
252 std::string Tracker::Json()
const {
255 return JsonValue().toStyledString();
259 Json::Value Tracker::JsonValue()
const {
262 Json::Value root = EffectBase::JsonValue();
265 root[
"type"] = info.class_name;
266 root[
"protobuf_data_path"] = protobuf_data_path;
267 root[
"BaseFPS"][
"num"] = BaseFPS.num;
268 root[
"BaseFPS"][
"den"] = BaseFPS.den;
269 root[
"TimeScale"] = this->TimeScale;
273 for (
auto const& trackedObject : trackedObjects){
274 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
276 objects[trackedObject.second->Id()] = trackedObjectJSON;
278 root[
"objects"] = objects;
285 void Tracker::SetJson(
const std::string value) {
294 catch (
const std::exception& e)
297 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
303 void Tracker::SetJsonValue(
const Json::Value root) {
306 EffectBase::SetJsonValue(root);
308 if(!root[
"type"].isNull())
309 info.class_name = root[
"type"].asString();
311 if (!root[
"BaseFPS"].isNull() && root[
"BaseFPS"].isObject())
313 if (!root[
"BaseFPS"][
"num"].isNull())
315 BaseFPS.num = (int) root[
"BaseFPS"][
"num"].asInt();
317 if (!root[
"BaseFPS"][
"den"].isNull())
319 BaseFPS.den = (int) root[
"BaseFPS"][
"den"].asInt();
323 if (!root[
"TimeScale"].isNull())
324 TimeScale = (
double) root[
"TimeScale"].asDouble();
327 if (!root[
"protobuf_data_path"].isNull() && protobuf_data_path.size() <= 1)
329 protobuf_data_path = root[
"protobuf_data_path"].asString();
330 if(!trackedData->LoadBoxData(protobuf_data_path))
332 std::clog <<
"Invalid protobuf data path " << protobuf_data_path <<
'\n';
333 protobuf_data_path =
"";
337 if (!root[
"objects"].isNull()){
338 for (
auto const& trackedObject : trackedObjects){
339 std::string obj_id = std::to_string(trackedObject.first);
340 if(!root[
"objects"][obj_id].isNull()){
341 trackedObject.second->SetJsonValue(root[
"objects"][obj_id]);
347 if (!root[
"objects_id"].isNull()){
348 for (
auto const& trackedObject : trackedObjects){
349 Json::Value trackedObjectJSON;
350 trackedObjectJSON[
"box_id"] = root[
"objects_id"][trackedObject.first].asString();
351 trackedObject.second->SetJsonValue(trackedObjectJSON);
359 std::string Tracker::PropertiesJSON(int64_t requested_frame)
const {
366 for (
auto const& trackedObject : trackedObjects){
367 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
369 objects[trackedObject.second->Id()] = trackedObjectJSON;
371 root[
"objects"] = objects;
374 root[
"id"] = add_property_json(
"ID", 0.0,
"string", Id(), NULL, -1, -1,
true, requested_frame);
375 root[
"position"] = add_property_json(
"Position", Position(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
376 root[
"layer"] = add_property_json(
"Track", Layer(),
"int",
"", NULL, 0, 20,
false, requested_frame);
377 root[
"start"] = add_property_json(
"Start", Start(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
378 root[
"end"] = add_property_json(
"End", End(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
379 root[
"duration"] = add_property_json(
"Duration", Duration(),
"float",
"", NULL, 0, 1000 * 60 * 30,
true, requested_frame);
382 return root.toStyledString();
Header file for Tracker effect class.
float cy
y-coordinate of the bounding box center
This class represents a single frame of video (i.e. image & audio data)
float height
bounding box height
openshot::Clip * GetClip(const std::string &id)
Look up a single clip by ID.
const Json::Value stringToJson(const std::string value)
float angle
bounding box rotation angle [degrees]
Header file for Timeline class.
Header file for all Exception classes.
bool LoadBoxData(std::string inputFilePath)
Load the bounding-boxes information from the protobuf file.
This class represents a clip (used to arrange readers on the timeline)
float width
bounding box width
This abstract class is the base class, used by all clips in libopenshot.
This struct holds the information of a bounding-box.
This namespace is the default namespace for all code in the openshot library.
float cx
x-coordinate of the bounding box center
Exception for invalid JSON.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
Get an openshot::Frame object for a specific frame number of this clip. The image size and number of ...
This class contains the properties of a tracked object and functions to manipulate it...
This class represents a timeline.