From 4a28654bcce6e77c4bf0c65737d7a71a152d111b Mon Sep 17 00:00:00 2001 From: Brenno Date: Wed, 27 Jan 2021 16:52:15 -0300 Subject: [PATCH] Added support to show the transform handler for the selected object When using the ObjectDetection effect, it's now possible to select one detected object and update it's properties through it's transform handler. --- src/Timeline.cpp | 46 +++++++++----- src/Timeline.h | 4 +- src/effects/ObjectDetection.cpp | 102 +++++++++++++++++++++----------- src/effects/ObjectDetection.h | 3 + 4 files changed, 102 insertions(+), 53 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index dd2c1702e..47b52bdf6 100644 --- a/src/Timeline.cpp +++ b/src/Timeline.cpp @@ -290,7 +290,8 @@ std::list Timeline::GetTrackedObjectsIds() const{ return trackedObjects_ids; } -std::string Timeline::GetTrackedObjectValues(std::string id) const { +// Return the trackedObject's properties as a JSON string +std::string Timeline::GetTrackedObjectValues(std::string id, int64_t frame_number) const { // Initialize the JSON object Json::Value trackedObjectJson; @@ -304,19 +305,34 @@ std::string Timeline::GetTrackedObjectValues(std::string id) const { std::shared_ptr trackedObject = std::static_pointer_cast(iterator->second); // Get the trackedObject values for it's first frame - auto boxes = trackedObject->BoxVec; - auto firstBox = boxes.begin()->second; - float x1 = firstBox.cx - (firstBox.width/2); - float y1 = firstBox.cy - (firstBox.height/2); - float x2 = firstBox.cx + (firstBox.width/2); - float y2 = firstBox.cy + (firstBox.height/2); - float r = firstBox.angle; - - trackedObjectJson["x1"] = x1; - trackedObjectJson["y1"] = y1; - trackedObjectJson["x2"] = x2; - trackedObjectJson["y2"] = y2; - trackedObjectJson["r"] = r; + if (trackedObject->ExactlyContains(frame_number)){ + BBox box = trackedObject->GetBox(frame_number); + float x1 = box.cx - (box.width/2); + float y1 = box.cy - (box.height/2); + float x2 = box.cx + (box.width/2); + float y2 = box.cy + (box.height/2); + float rotation = box.angle; + + trackedObjectJson["x1"] = x1; + trackedObjectJson["y1"] = y1; + trackedObjectJson["x2"] = x2; + trackedObjectJson["y2"] = y2; + trackedObjectJson["rotation"] = rotation; + + } else { + BBox box = trackedObject->BoxVec.begin()->second; + float x1 = box.cx - (box.width/2); + float y1 = box.cy - (box.height/2); + float x2 = box.cx + (box.width/2); + float y2 = box.cy + (box.height/2); + float rotation = box.angle; + + trackedObjectJson["x1"] = x1; + trackedObjectJson["y1"] = y1; + trackedObjectJson["x2"] = x2; + trackedObjectJson["y2"] = y2; + trackedObjectJson["rotation"] = rotation; + } } else { @@ -325,7 +341,7 @@ std::string Timeline::GetTrackedObjectValues(std::string id) const { trackedObjectJson["y1"] = 0; trackedObjectJson["x2"] = 0; trackedObjectJson["y2"] = 0; - trackedObjectJson["r"] = 0; + trackedObjectJson["rotation"] = 0; } return trackedObjectJson.toStyledString(); diff --git a/src/Timeline.h b/src/Timeline.h index e9b201b04..b17d164e1 100644 --- a/src/Timeline.h +++ b/src/Timeline.h @@ -250,8 +250,8 @@ namespace openshot { std::shared_ptr GetTrackedObject(std::string id) const; /// Return the ID's of the tracked objects as a list of strings std::list GetTrackedObjectsIds() const; - /// Return the first trackedObject's properties as a JSON string - std::string GetTrackedObjectValues(std::string id) const; + /// Return the trackedObject's properties as a JSON string + std::string GetTrackedObjectValues(std::string id, int64_t frame_number) const; /// @brief Add an openshot::Clip to the timeline /// @param clip Add an openshot::Clip to the timeline. A clip can contain any type of Reader. diff --git a/src/effects/ObjectDetection.cpp b/src/effects/ObjectDetection.cpp index 621070132..a9ee04114 100644 --- a/src/effects/ObjectDetection.cpp +++ b/src/effects/ObjectDetection.cpp @@ -45,6 +45,9 @@ ObjectDetection::ObjectDetection(std::string clipObDetectDataPath) // Tries to load the tracker data from protobuf LoadObjDetectdData(clipObDetectDataPath); + + // Initialize the selected object index as the first object index + selectedObjectIndex = trackedObjects.begin()->first; } // Default constructor @@ -53,6 +56,8 @@ ObjectDetection::ObjectDetection() // Init effect properties init_effect_details(); + // Initialize the selected object index as the first object index + selectedObjectIndex = trackedObjects.begin()->first; } // Init effect settings @@ -273,18 +278,23 @@ Json::Value ObjectDetection::JsonValue() const { Json::Value root = EffectBase::JsonValue(); // get parent properties root["type"] = info.class_name; root["protobuf_data_path"] = protobuf_data_path; + root["selected_object_index"] = selectedObjectIndex; - // Add trackedObjects IDs to JSON - for (auto const& trackedObject : trackedObjects){ - Json::Value trackedObjectJSON = trackedObject.second->JsonValue(); - // Save the trackedObject JSON on root + for (auto const& trackedObject : trackedObjects){ + Json::Value trackedObjectJSON = trackedObject.second->JsonValue(); root["box_id-"+to_string(trackedObject.first)] = trackedObjectJSON["box_id"]; - root["delta_x-"+to_string(trackedObject.first)] = trackedObjectJSON["delta_x"]; - root["delta_y-"+to_string(trackedObject.first)] = trackedObjectJSON["delta_y"]; - root["scale_x-"+to_string(trackedObject.first)] = trackedObjectJSON["scale_x"]; - root["scale_y-"+to_string(trackedObject.first)] = trackedObjectJSON["scale_y"]; - root["rotation-"+to_string(trackedObject.first)] = trackedObjectJSON["rotation"]; - } + } + + // Add the selected object Json to root + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject){ + Json::Value selectedObjectJSON = selectedObject->JsonValue(); + root["delta_x-"+to_string(selectedObjectIndex)] = selectedObjectJSON["delta_x"]; + root["delta_y-"+to_string(selectedObjectIndex)] = selectedObjectJSON["delta_y"]; + root["scale_x-"+to_string(selectedObjectIndex)] = selectedObjectJSON["scale_x"]; + root["scale_y-"+to_string(selectedObjectIndex)] = selectedObjectJSON["scale_y"]; + root["rotation-"+to_string(selectedObjectIndex)] = selectedObjectJSON["rotation"]; + } // return JsonValue return root; @@ -322,17 +332,31 @@ void ObjectDetection::SetJsonValue(const Json::Value root) { } } + // Set the selected object index + if (!root["selected_object_index"].isNull()) + selectedObjectIndex = root["selected_object_index"].asInt(); + for (auto const& trackedObject : trackedObjects){ Json::Value trackedObjectJSON; trackedObjectJSON["box_id"] = root["box_id-"+to_string(trackedObject.first)]; - trackedObjectJSON["delta_x"] = root["delta_x-"+to_string(trackedObject.first)]; - trackedObjectJSON["delta_y"] = root["delta_y-"+to_string(trackedObject.first)]; - trackedObjectJSON["scale_x"] = root["scale_x-"+to_string(trackedObject.first)]; - trackedObjectJSON["scale_y"] = root["scale_y-"+to_string(trackedObject.first)]; - trackedObjectJSON["rotation"] = root["rotation-"+to_string(trackedObject.first)]; - if (!trackedObjectJSON.isNull()) - trackedObject.second->SetJsonValue(trackedObjectJSON); - } + trackedObject.second->SetJsonValue(trackedObjectJSON); + } + + // Set the selectec object's properties + if (!root["box_id-"+to_string(selectedObjectIndex)].isNull()){ + Json::Value selectedObjectJSON; + selectedObjectJSON["box_id"] = root["box_id-"+to_string(selectedObjectIndex)]; + selectedObjectJSON["delta_x"] = root["delta_x-"+to_string(selectedObjectIndex)]; + selectedObjectJSON["delta_y"] = root["delta_y-"+to_string(selectedObjectIndex)]; + selectedObjectJSON["scale_x"] = root["scale_x-"+to_string(selectedObjectIndex)]; + selectedObjectJSON["scale_y"] = root["scale_y-"+to_string(selectedObjectIndex)]; + selectedObjectJSON["rotation"] = root["rotation-"+to_string(selectedObjectIndex)]; + if (!selectedObjectJSON.isNull()){ + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject) + selectedObject->SetJsonValue(selectedObjectJSON); + } + } } // Get all properties for a specific frame @@ -341,27 +365,33 @@ std::string ObjectDetection::PropertiesJSON(int64_t requested_frame) const { // Generate JSON properties list Json::Value root; - // Add trackedObjects IDs to JSON - for (auto const& trackedObject : trackedObjects){ - // Save the trackedObject Id on root + // root["visible_objects"] = Json::Value(Json::arrayValue); + + for (auto const& trackedObject : trackedObjects){ Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame); - root["box_id-"+to_string(trackedObject.first)] = trackedObjectJSON["box_id"]; root["visible-"+to_string(trackedObject.first)] = trackedObjectJSON["visible"]; - - // Add trackedObject's properties only if it's visible in this frame (performance boost) - if (trackedObjectJSON["visible"]["value"].asBool()){ - root["x1-"+to_string(trackedObject.first)] = trackedObjectJSON["x1"]; - root["y1-"+to_string(trackedObject.first)] = trackedObjectJSON["y1"]; - root["x2-"+to_string(trackedObject.first)] = trackedObjectJSON["x2"]; - root["y2-"+to_string(trackedObject.first)] = trackedObjectJSON["y2"]; - root["delta_x-"+to_string(trackedObject.first)] = trackedObjectJSON["delta_x"]; - root["delta_y-"+to_string(trackedObject.first)] = trackedObjectJSON["delta_y"]; - root["scale_x-"+to_string(trackedObject.first)] = trackedObjectJSON["scale_x"]; - root["scale_y-"+to_string(trackedObject.first)] = trackedObjectJSON["scale_y"]; - root["rotation-"+to_string(trackedObject.first)] = trackedObjectJSON["rotation"]; - } - } + if (trackedObjectJSON["visible"]["value"].asBool()) + root["box_id-"+to_string(trackedObject.first)] = trackedObjectJSON["box_id"]; + } + + // Add the selected object Json to root + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject){ + Json::Value selectedObjectJSON = selectedObject->PropertiesJSON(requested_frame); + root["box_id-"+to_string(selectedObjectIndex)] = selectedObjectJSON["box_id"]; + root["visible-"+to_string(selectedObjectIndex)] = selectedObjectJSON["visible"]; + root["x1-"+to_string(selectedObjectIndex)] = selectedObjectJSON["x1"]; + root["y1-"+to_string(selectedObjectIndex)] = selectedObjectJSON["y1"]; + root["x2-"+to_string(selectedObjectIndex)] = selectedObjectJSON["x2"]; + root["y2-"+to_string(selectedObjectIndex)] = selectedObjectJSON["y2"]; + root["delta_x-"+to_string(selectedObjectIndex)] = selectedObjectJSON["delta_x"]; + root["delta_y-"+to_string(selectedObjectIndex)] = selectedObjectJSON["delta_y"]; + root["scale_x-"+to_string(selectedObjectIndex)] = selectedObjectJSON["scale_x"]; + root["scale_y-"+to_string(selectedObjectIndex)] = selectedObjectJSON["scale_y"]; + root["rotation-"+to_string(selectedObjectIndex)] = selectedObjectJSON["rotation"]; + } + root["selected_object_index"] = add_property_json("Selected Object", selectedObjectIndex, "int", "", NULL, 0, 200, false, requested_frame); root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); diff --git a/src/effects/ObjectDetection.h b/src/effects/ObjectDetection.h index 64df91c3b..39f7f33c0 100644 --- a/src/effects/ObjectDetection.h +++ b/src/effects/ObjectDetection.h @@ -86,6 +86,9 @@ namespace openshot public: + /// Index of the Tracked Object that was selected to modify it's properties + int selectedObjectIndex; + /// Blank constructor, useful when using Json to load the effect properties ObjectDetection(std::string clipTrackerDataPath);