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 | 44 ++++++++----- src/Timeline.h | 4 +- src/effects/ObjectDetection.cpp | 106 ++++++++++++++++++++------------ src/effects/ObjectDetection.h | 3 + 4 files changed, 103 insertions(+), 54 deletions(-) diff --git a/src/Timeline.cpp b/src/Timeline.cpp index dd2c1702..47b52bdf 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; + 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["r"] = r; + 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 e9b201b0..b17d164e 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 62107013..a9ee0411 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 - 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"]; - } - } + // root["visible_objects"] = Json::Value(Json::arrayValue); + for (auto const& trackedObject : trackedObjects){ + Json::Value trackedObjectJSON = trackedObject.second->PropertiesJSON(requested_frame); + root["visible-"+to_string(trackedObject.first)] = trackedObjectJSON["visible"]; + 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 64df91c3..39f7f33c 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);