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);
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> f(
new Frame(1, frame->GetWidth(), frame->GetHeight(),
"#00000000"));
136 std::shared_ptr<Frame> childClipFrame = childClip->
GetFrame(f, frame_number);
137 childClipImage = childClipFrame->GetImage();
140 boxRect.setRect((
int)((fd.
cx-fd.
width/2)*fw),
152 frame->SetImageCV(frame_image);
157 QImage frameImage = *(frame->GetImage());
160 QPainter painter(&frameImage);
163 painter.drawImage(boxRect, *childClipImage, QRectF(0, 0, frameImage.size().width(), frameImage.size().height()));
166 frame->AddImage(std::make_shared<QImage>(frameImage));
172 void Tracker::DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector<int> color,
float alpha,
int thickness,
bool is_background){
174 cv::Point2f vertices2f[4];
175 box.points(vertices2f);
183 cv::Mat overlayFrame;
184 frame_image.copyTo(overlayFrame);
187 cv::Point vertices[4];
188 for(
int i = 0; i < 4; ++i){
189 vertices[i] = vertices2f[i];}
191 cv::Rect rect = box.boundingRect();
192 cv::fillConvexPoly(overlayFrame, vertices, 4, cv::Scalar(color[2],color[1],color[0]), cv::LINE_AA);
194 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
197 cv::Mat overlayFrame;
198 frame_image.copyTo(overlayFrame);
201 for (
int i = 0; i < 4; i++)
203 cv::line(overlayFrame, vertices2f[i], vertices2f[(i+1)%4], cv::Scalar(color[2],color[1],color[0]),
204 thickness, cv::LINE_AA);
208 cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image);
213 std::string Tracker::GetVisibleObjects(int64_t frame_number)
const{
217 root[
"visible_objects_index"] = Json::Value(Json::arrayValue);
218 root[
"visible_objects_id"] = Json::Value(Json::arrayValue);
221 for (
const auto& trackedObject : trackedObjects){
223 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(frame_number);
224 if (trackedObjectJSON[
"visible"][
"value"].asBool()){
226 root[
"visible_objects_index"].append(trackedObject.first);
227 root[
"visible_objects_id"].append(trackedObject.second->Id());
231 return root.toStyledString();
235 std::string Tracker::Json()
const {
238 return JsonValue().toStyledString();
242 Json::Value Tracker::JsonValue()
const {
245 Json::Value root = EffectBase::JsonValue();
248 root[
"type"] = info.class_name;
249 root[
"protobuf_data_path"] = protobuf_data_path;
250 root[
"BaseFPS"][
"num"] = BaseFPS.num;
251 root[
"BaseFPS"][
"den"] = BaseFPS.den;
252 root[
"TimeScale"] = this->TimeScale;
256 for (
auto const& trackedObject : trackedObjects){
257 Json::Value trackedObjectJSON = trackedObject.second->JsonValue();
259 objects[trackedObject.second->Id()] = trackedObjectJSON;
261 root[
"objects"] = objects;
268 void Tracker::SetJson(
const std::string value) {
277 catch (
const std::exception& e)
280 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
286 void Tracker::SetJsonValue(
const Json::Value root) {
289 EffectBase::SetJsonValue(root);
291 if (!root[
"BaseFPS"].isNull() && root[
"BaseFPS"].isObject())
293 if (!root[
"BaseFPS"][
"num"].isNull())
295 BaseFPS.num = (int) root[
"BaseFPS"][
"num"].asInt();
297 if (!root[
"BaseFPS"][
"den"].isNull())
299 BaseFPS.den = (int) root[
"BaseFPS"][
"den"].asInt();
303 if (!root[
"TimeScale"].isNull())
304 TimeScale = (
double) root[
"TimeScale"].asDouble();
307 if (!root[
"protobuf_data_path"].isNull() && protobuf_data_path.size() <= 1)
309 protobuf_data_path = root[
"protobuf_data_path"].asString();
310 if(!trackedData->LoadBoxData(protobuf_data_path))
312 std::clog <<
"Invalid protobuf data path " << protobuf_data_path <<
'\n';
313 protobuf_data_path =
"";
317 if (!root[
"objects"].isNull()){
318 for (
auto const& trackedObject : trackedObjects){
319 std::string obj_id = std::to_string(trackedObject.first);
320 if(!root[
"objects"][obj_id].isNull()){
321 trackedObject.second->SetJsonValue(root[
"objects"][obj_id]);
327 if (!root[
"objects_id"].isNull()){
328 for (
auto const& trackedObject : trackedObjects){
329 Json::Value trackedObjectJSON;
330 trackedObjectJSON[
"box_id"] = root[
"objects_id"][trackedObject.first].asString();
331 trackedObject.second->SetJsonValue(trackedObjectJSON);
339 std::string Tracker::PropertiesJSON(int64_t requested_frame)
const {
346 for (
auto const& trackedObject : trackedObjects){
347 Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame);
349 objects[trackedObject.second->Id()] = trackedObjectJSON;
351 root[
"objects"] = objects;
354 root[
"id"] = add_property_json(
"ID", 0.0,
"string", Id(), NULL, -1, -1,
true, requested_frame);
355 root[
"position"] = add_property_json(
"Position", Position(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
356 root[
"layer"] = add_property_json(
"Track", Layer(),
"int",
"", NULL, 0, 20,
false, requested_frame);
357 root[
"start"] = add_property_json(
"Start", Start(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
358 root[
"end"] = add_property_json(
"End", End(),
"float",
"", NULL, 0, 1000 * 60 * 30,
false, requested_frame);
359 root[
"duration"] = add_property_json(
"Duration", Duration(),
"float",
"", NULL, 0, 1000 * 60 * 30,
true, requested_frame);
362 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
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 ...
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.
This class contains the properties of a tracked object and functions to manipulate it...
This class represents a timeline.