diff --git a/src/effects/ObjectDetection.cpp b/src/effects/ObjectDetection.cpp index 9c947e911..a85d807aa 100644 --- a/src/effects/ObjectDetection.cpp +++ b/src/effects/ObjectDetection.cpp @@ -39,495 +39,505 @@ using namespace openshot; /// Blank constructor, useful when using Json to load the effect properties ObjectDetection::ObjectDetection(std::string clipObDetectDataPath) { - // Init effect properties - init_effect_details(); + // Init effect properties + init_effect_details(); - // Tries to load the tracker data from protobuf - LoadObjDetectdData(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; + // Initialize the selected object index as the first object index + selectedObjectIndex = trackedObjects.begin()->first; } // Default constructor ObjectDetection::ObjectDetection() { - // Init effect properties - init_effect_details(); + // Init effect properties + init_effect_details(); - // Initialize the selected object index as the first object index - selectedObjectIndex = trackedObjects.begin()->first; + // Initialize the selected object index as the first object index + selectedObjectIndex = trackedObjects.begin()->first; } // Init effect settings void ObjectDetection::init_effect_details() { - /// Initialize the values of the EffectInfo struct. - InitEffectInfo(); - - /// Set the effect info - info.class_name = "Object Detector"; - info.name = "Object Detector"; - info.description = "Detect objects through the video."; - info.has_audio = false; - info.has_video = true; - info.has_tracked_object = true; + /// Initialize the values of the EffectInfo struct. + InitEffectInfo(); + + /// Set the effect info + info.class_name = "Object Detector"; + info.name = "Object Detector"; + info.description = "Detect objects through the video."; + info.has_audio = false; + info.has_video = true; + info.has_tracked_object = true; } // This method is required for all derived classes of EffectBase, and returns a // modified openshot::Frame object std::shared_ptr ObjectDetection::GetFrame(std::shared_ptr frame, int64_t frame_number) { - // Get the frame's image - cv::Mat cv_image = frame->GetImageCV(); - - // Check if frame isn't NULL - if(cv_image.empty()){ - return frame; - } - - // Check if track data exists for the requested frame - if (detectionsData.find(frame_number) != detectionsData.end()) { - float fw = cv_image.size().width; - float fh = cv_image.size().height; - - DetectionData detections = detectionsData[frame_number]; - for(int i = 0; i 0 && - std::find(display_classes.begin(), display_classes.end(), classNames[detections.classIds.at(i)]) == display_classes.end()){ - continue; - } - - // Get the object id - int objectId = detections.objectIds.at(i); - - // Search for the object in the trackedObjects map - auto trackedObject_it = trackedObjects.find(objectId); - - // Cast the object as TrackedObjectBBox - std::shared_ptr trackedObject = std::static_pointer_cast(trackedObject_it->second); - - // Check if the tracked object has data for this frame - if (trackedObject->Contains(frame_number) && - trackedObject->visible.GetValue(frame_number) == 1) - { - // Get the bounding-box of given frame - BBox trackedBox = trackedObject->GetBox(frame_number); - - std::vector stroke_rgba = trackedObject->stroke.GetColorRGBA(frame_number); - int stroke_width = trackedObject->stroke_width.GetValue(frame_number); - float stroke_alpha = trackedObject->stroke_alpha.GetValue(frame_number); - std::vector bg_rgba = trackedObject->background.GetColorRGBA(frame_number); - float bg_alpha = trackedObject->background_alpha.GetValue(frame_number); - - // Create a rotated rectangle object that holds the bounding box - // cv::RotatedRect box ( cv::Point2f( (int)(trackedBox.cx*fw), (int)(trackedBox.cy*fh) ), - // cv::Size2f( (int)(trackedBox.width*fw), (int)(trackedBox.height*fh) ), - // (int) (trackedBox.angle) ); - - // DrawRectangleRGBA(cv_image, box, bg_rgba, bg_alpha, 1, true); - // DrawRectangleRGBA(cv_image, box, stroke_rgba, stroke_alpha, stroke_width, false); - - cv::Rect2d box( - (int)( (trackedBox.cx-trackedBox.width/2)*fw), - (int)( (trackedBox.cy-trackedBox.height/2)*fh), - (int)( trackedBox.width*fw), - (int)( trackedBox.height*fh) - ); - drawPred(detections.classIds.at(i), detections.confidences.at(i), - box, cv_image, detections.objectIds.at(i), bg_rgba, bg_alpha, 1, true); - drawPred(detections.classIds.at(i), detections.confidences.at(i), - box, cv_image, detections.objectIds.at(i), stroke_rgba, stroke_alpha, stroke_width, false); - } - } - } - - // Update Qt image with new Opencv frame - frame->SetImageCV(cv_image); - - return frame; + // Get the frame's image + cv::Mat cv_image = frame->GetImageCV(); + + // Check if frame isn't NULL + if(cv_image.empty()){ + return frame; + } + + // Check if track data exists for the requested frame + if (detectionsData.find(frame_number) != detectionsData.end()) { + float fw = cv_image.size().width; + float fh = cv_image.size().height; + + DetectionData detections = detectionsData[frame_number]; + for(int i = 0; i 0 && + std::find(display_classes.begin(), display_classes.end(), classNames[detections.classIds.at(i)]) == display_classes.end()){ + continue; + } + + // Get the object id + int objectId = detections.objectIds.at(i); + + // Search for the object in the trackedObjects map + auto trackedObject_it = trackedObjects.find(objectId); + + // Cast the object as TrackedObjectBBox + std::shared_ptr trackedObject = std::static_pointer_cast(trackedObject_it->second); + + // Check if the tracked object has data for this frame + if (trackedObject->Contains(frame_number) && + trackedObject->visible.GetValue(frame_number) == 1) + { + // Get the bounding-box of given frame + BBox trackedBox = trackedObject->GetBox(frame_number); + bool draw_text = !display_box_text.GetValue(frame_number); + std::vector stroke_rgba = trackedObject->stroke.GetColorRGBA(frame_number); + int stroke_width = trackedObject->stroke_width.GetValue(frame_number); + float stroke_alpha = trackedObject->stroke_alpha.GetValue(frame_number); + std::vector bg_rgba = trackedObject->background.GetColorRGBA(frame_number); + float bg_alpha = trackedObject->background_alpha.GetValue(frame_number); + + // Create a rotated rectangle object that holds the bounding box + // cv::RotatedRect box ( cv::Point2f( (int)(trackedBox.cx*fw), (int)(trackedBox.cy*fh) ), + // cv::Size2f( (int)(trackedBox.width*fw), (int)(trackedBox.height*fh) ), + // (int) (trackedBox.angle) ); + + // DrawRectangleRGBA(cv_image, box, bg_rgba, bg_alpha, 1, true); + // DrawRectangleRGBA(cv_image, box, stroke_rgba, stroke_alpha, stroke_width, false); + + cv::Rect2d box( + (int)( (trackedBox.cx-trackedBox.width/2)*fw), + (int)( (trackedBox.cy-trackedBox.height/2)*fh), + (int)( trackedBox.width*fw), + (int)( trackedBox.height*fh) + ); + drawPred(detections.classIds.at(i), detections.confidences.at(i), + box, cv_image, detections.objectIds.at(i), bg_rgba, bg_alpha, 1, true, draw_text); + drawPred(detections.classIds.at(i), detections.confidences.at(i), + box, cv_image, detections.objectIds.at(i), stroke_rgba, stroke_alpha, stroke_width, false, draw_text); + } + } + } + + // Update Qt image with new Opencv frame + frame->SetImageCV(cv_image); + + return frame; } void ObjectDetection::DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector color, float alpha, - int thickness, bool is_background){ - // Get the bouding box vertices - cv::Point2f vertices2f[4]; - box.points(vertices2f); - - // TODO: take a rectangle of frame_image by refencence and draw on top of that to improve speed - // select min enclosing rectangle to draw on a small portion of the image - // cv::Rect rect = box.boundingRect(); - // cv::Mat image = frame_image(rect) - - if(is_background){ - cv::Mat overlayFrame; - frame_image.copyTo(overlayFrame); - - // draw bounding box background - cv::Point vertices[4]; - for(int i = 0; i < 4; ++i){ - vertices[i] = vertices2f[i];} - - cv::Rect rect = box.boundingRect(); - cv::fillConvexPoly(overlayFrame, vertices, 4, cv::Scalar(color[2],color[1],color[0]), cv::LINE_AA); - // add opacity - cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image); - } - else{ - cv::Mat overlayFrame; - frame_image.copyTo(overlayFrame); - - // Draw bounding box - for (int i = 0; i < 4; i++) - { - cv::line(overlayFrame, vertices2f[i], vertices2f[(i+1)%4], cv::Scalar(color[2],color[1],color[0]), - thickness, cv::LINE_AA); - } - - // add opacity - cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image); - } + int thickness, bool is_background){ + // Get the bouding box vertices + cv::Point2f vertices2f[4]; + box.points(vertices2f); + + // TODO: take a rectangle of frame_image by refencence and draw on top of that to improve speed + // select min enclosing rectangle to draw on a small portion of the image + // cv::Rect rect = box.boundingRect(); + // cv::Mat image = frame_image(rect) + + if(is_background){ + cv::Mat overlayFrame; + frame_image.copyTo(overlayFrame); + + // draw bounding box background + cv::Point vertices[4]; + for(int i = 0; i < 4; ++i){ + vertices[i] = vertices2f[i];} + + cv::Rect rect = box.boundingRect(); + cv::fillConvexPoly(overlayFrame, vertices, 4, cv::Scalar(color[2],color[1],color[0]), cv::LINE_AA); + // add opacity + cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image); + } + else{ + cv::Mat overlayFrame; + frame_image.copyTo(overlayFrame); + + // Draw bounding box + for (int i = 0; i < 4; i++) + { + cv::line(overlayFrame, vertices2f[i], vertices2f[(i+1)%4], cv::Scalar(color[2],color[1],color[0]), + thickness, cv::LINE_AA); + } + + // add opacity + cv::addWeighted(overlayFrame, 1-alpha, frame_image, alpha, 0, frame_image); + } } void ObjectDetection::drawPred(int classId, float conf, cv::Rect2d box, cv::Mat& frame, int objectNumber, std::vector color, - float alpha, int thickness, bool is_background) + float alpha, int thickness, bool is_background, bool display_text) { - if(is_background){ - cv::Mat overlayFrame; - frame.copyTo(overlayFrame); - - //Draw a rectangle displaying the bounding box - cv::rectangle(overlayFrame, box, cv::Scalar(color[2],color[1],color[0]), cv::FILLED); - - // add opacity - cv::addWeighted(overlayFrame, 1-alpha, frame, alpha, 0, frame); - } - else{ - cv::Mat overlayFrame; - frame.copyTo(overlayFrame); - - //Draw a rectangle displaying the bounding box - cv::rectangle(overlayFrame, box, cv::Scalar(color[2],color[1],color[0]), thickness); - - //Get the label for the class name and its confidence - std::string label = cv::format("%.2f", conf); - if (!classNames.empty()) - { - CV_Assert(classId < (int)classNames.size()); - label = classNames[classId] + ":" + label; - } - - //Display the label at the top of the bounding box - int baseLine; - cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); - - double left = box.x; - double top = std::max((int)box.y, labelSize.height); - - cv::rectangle(overlayFrame, cv::Point(left, top - round(1.025*labelSize.height)), cv::Point(left + round(1.025*labelSize.width), top + baseLine), - cv::Scalar(color[2],color[1],color[0]), cv::FILLED); - putText(overlayFrame, label, cv::Point(left+1, top), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0,0,0),1); - - // add opacity - cv::addWeighted(overlayFrame, 1-alpha, frame, alpha, 0, frame); - } + if(is_background){ + cv::Mat overlayFrame; + frame.copyTo(overlayFrame); + + //Draw a rectangle displaying the bounding box + cv::rectangle(overlayFrame, box, cv::Scalar(color[2],color[1],color[0]), cv::FILLED); + + // add opacity + cv::addWeighted(overlayFrame, 1-alpha, frame, alpha, 0, frame); + } + else{ + cv::Mat overlayFrame; + frame.copyTo(overlayFrame); + + //Draw a rectangle displaying the bounding box + cv::rectangle(overlayFrame, box, cv::Scalar(color[2],color[1],color[0]), thickness); + + if(display_text){ + //Get the label for the class name and its confidence + std::string label = cv::format("%.2f", conf); + if (!classNames.empty()) + { + CV_Assert(classId < (int)classNames.size()); + label = classNames[classId] + ":" + label; + } + + //Display the label at the top of the bounding box + int baseLine; + cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); + + double left = box.x; + double top = std::max((int)box.y, labelSize.height); + + cv::rectangle(overlayFrame, cv::Point(left, top - round(1.025*labelSize.height)), cv::Point(left + round(1.025*labelSize.width), top + baseLine), + cv::Scalar(color[2],color[1],color[0]), cv::FILLED); + putText(overlayFrame, label, cv::Point(left+1, top), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0,0,0),1); + } + // add opacity + cv::addWeighted(overlayFrame, 1-alpha, frame, alpha, 0, frame); + } } // Load protobuf data file bool ObjectDetection::LoadObjDetectdData(std::string inputFilePath){ - // Create tracker message - pb_objdetect::ObjDetect objMessage; - - - // Read the existing tracker message. - fstream input(inputFilePath, ios::in | ios::binary); - if (!objMessage.ParseFromIstream(&input)) { - cerr << "Failed to parse protobuf message." << endl; - return false; - } - - - // Make sure classNames, detectionsData and trackedObjects are empty - classNames.clear(); - detectionsData.clear(); - trackedObjects.clear(); - - // Seed to generate same random numbers - std::srand(1); - // Get all classes names and assign a color to them - for(int i = 0; i < objMessage.classnames_size(); i++) - { - classNames.push_back(objMessage.classnames(i)); - classesColor.push_back(cv::Scalar(std::rand()%205 + 50, std::rand()%205 + 50, std::rand()%205 + 50)); - } - - // Iterate over all frames of the saved message - for (size_t i = 0; i < objMessage.frame_size(); i++) - { - // Create protobuf message reader - const pb_objdetect::Frame& pbFrameData = objMessage.frame(i); - - // Get frame Id - size_t id = pbFrameData.id(); - - // Load bounding box data - const google::protobuf::RepeatedPtrField &pBox = pbFrameData.bounding_box(); - - // Construct data vectors related to detections in the current frame - std::vector classIds; - std::vector confidences; - std::vector> boxes; - std::vector objectIds; - - // Iterate through the detected objects - for(int i = 0; i < pbFrameData.bounding_box_size(); i++) - { - // Get bounding box coordinates - float x = pBox.Get(i).x(); - float y = pBox.Get(i).y(); - float w = pBox.Get(i).w(); - float h = pBox.Get(i).h(); - // Get class Id (which will be assign to a class name) - int classId = pBox.Get(i).classid(); - // Get prediction confidence - float confidence = pBox.Get(i).confidence(); - - // Get the object Id - int objectId = pBox.Get(i).objectid(); - - // Search for the object id on trackedObjects map - auto trackedObject = trackedObjects.find(objectId); - // Check if object already exists on the map - if (trackedObject != trackedObjects.end()) - { - // Add a new BBox to it - trackedObject->second->AddBox(id, x+(w/2), y+(h/2), w, h, 0.0); - } - else - { - // There is no tracked object with that id, so insert a new one - TrackedObjectBBox trackedObj((int)classesColor[classId](0), (int)classesColor[classId](1), (int)classesColor[classId](2), (int)0); - trackedObj.AddBox(id, x+(w/2), y+(h/2), w, h, 0.0); - std::shared_ptr trackedObjPtr = std::make_shared(trackedObj); - trackedObjects.insert({objectId, trackedObjPtr}); - } - - // Create OpenCV rectangle with the bouding box info - cv::Rect_ box(x, y, w, h); - - // Push back data into vectors - boxes.push_back(box); - classIds.push_back(classId); - confidences.push_back(confidence); - objectIds.push_back(objectId); - } - - // Assign data to object detector map - detectionsData[id] = DetectionData(classIds, confidences, boxes, id, objectIds); - } - - // Delete all global objects allocated by libprotobuf. - google::protobuf::ShutdownProtobufLibrary(); - - return true; + // Create tracker message + pb_objdetect::ObjDetect objMessage; + + + // Read the existing tracker message. + fstream input(inputFilePath, ios::in | ios::binary); + if (!objMessage.ParseFromIstream(&input)) { + cerr << "Failed to parse protobuf message." << endl; + return false; + } + + + // Make sure classNames, detectionsData and trackedObjects are empty + classNames.clear(); + detectionsData.clear(); + trackedObjects.clear(); + + // Seed to generate same random numbers + std::srand(1); + // Get all classes names and assign a color to them + for(int i = 0; i < objMessage.classnames_size(); i++) + { + classNames.push_back(objMessage.classnames(i)); + classesColor.push_back(cv::Scalar(std::rand()%205 + 50, std::rand()%205 + 50, std::rand()%205 + 50)); + } + + // Iterate over all frames of the saved message + for (size_t i = 0; i < objMessage.frame_size(); i++) + { + // Create protobuf message reader + const pb_objdetect::Frame& pbFrameData = objMessage.frame(i); + + // Get frame Id + size_t id = pbFrameData.id(); + + // Load bounding box data + const google::protobuf::RepeatedPtrField &pBox = pbFrameData.bounding_box(); + + // Construct data vectors related to detections in the current frame + std::vector classIds; + std::vector confidences; + std::vector> boxes; + std::vector objectIds; + + // Iterate through the detected objects + for(int i = 0; i < pbFrameData.bounding_box_size(); i++) + { + // Get bounding box coordinates + float x = pBox.Get(i).x(); + float y = pBox.Get(i).y(); + float w = pBox.Get(i).w(); + float h = pBox.Get(i).h(); + // Get class Id (which will be assign to a class name) + int classId = pBox.Get(i).classid(); + // Get prediction confidence + float confidence = pBox.Get(i).confidence(); + + // Get the object Id + int objectId = pBox.Get(i).objectid(); + + // Search for the object id on trackedObjects map + auto trackedObject = trackedObjects.find(objectId); + // Check if object already exists on the map + if (trackedObject != trackedObjects.end()) + { + // Add a new BBox to it + trackedObject->second->AddBox(id, x+(w/2), y+(h/2), w, h, 0.0); + } + else + { + // There is no tracked object with that id, so insert a new one + TrackedObjectBBox trackedObj((int)classesColor[classId](0), (int)classesColor[classId](1), (int)classesColor[classId](2), (int)0); + trackedObj.AddBox(id, x+(w/2), y+(h/2), w, h, 0.0); + std::shared_ptr trackedObjPtr = std::make_shared(trackedObj); + trackedObjects.insert({objectId, trackedObjPtr}); + } + + // Create OpenCV rectangle with the bouding box info + cv::Rect_ box(x, y, w, h); + + // Push back data into vectors + boxes.push_back(box); + classIds.push_back(classId); + confidences.push_back(confidence); + objectIds.push_back(objectId); + } + + // Assign data to object detector map + detectionsData[id] = DetectionData(classIds, confidences, boxes, id, objectIds); + } + + // Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + + return true; } // Get tracker info for the desired frame DetectionData ObjectDetection::GetTrackedData(size_t frameId){ - // Check if the tracker info for the requested frame exists - if ( detectionsData.find(frameId) == detectionsData.end() ) { - return DetectionData(); - } else { - return detectionsData[frameId]; - } + // Check if the tracker info for the requested frame exists + if ( detectionsData.find(frameId) == detectionsData.end() ) { + return DetectionData(); + } else { + return detectionsData[frameId]; + } } // Get the indexes and IDs of all visible objects in the given frame std::string ObjectDetection::GetVisibleObjects(int64_t frame_number) const{ - - // Initialize the JSON objects - Json::Value root; - root["visible_objects_index"] = Json::Value(Json::arrayValue); - root["visible_objects_id"] = Json::Value(Json::arrayValue); - - // Check if track data exists for the requested frame - if (detectionsData.find(frame_number) == detectionsData.end()){ - return root.toStyledString(); - } - DetectionData detections = detectionsData.at(frame_number); - - // Iterate through the tracked objects - for(int i = 0; i 0 && - std::find(display_classes.begin(), display_classes.end(), classNames[detections.classIds.at(i)]) == display_classes.end()){ - continue; - } - - int objectId = detections.objectIds.at(i); - // Search for the object in the trackedObjects map - auto trackedObject = trackedObjects.find(objectId); - - // Get the tracked object JSON properties for this frame - Json::Value trackedObjectJSON = trackedObject->second->PropertiesJSON(frame_number); - - if (trackedObjectJSON["visible"]["value"].asBool() && - trackedObject->second->ExactlyContains(frame_number)){ - // Save the object's index and ID if it's visible in this frame - root["visible_objects_index"].append(trackedObject->first); - root["visible_objects_id"].append(trackedObject->second->Id()); - } - } - - return root.toStyledString(); + + // Initialize the JSON objects + Json::Value root; + root["visible_objects_index"] = Json::Value(Json::arrayValue); + root["visible_objects_id"] = Json::Value(Json::arrayValue); + + // Check if track data exists for the requested frame + if (detectionsData.find(frame_number) == detectionsData.end()){ + return root.toStyledString(); + } + DetectionData detections = detectionsData.at(frame_number); + + // Iterate through the tracked objects + for(int i = 0; i 0 && + std::find(display_classes.begin(), display_classes.end(), classNames[detections.classIds.at(i)]) == display_classes.end()){ + continue; + } + + int objectId = detections.objectIds.at(i); + // Search for the object in the trackedObjects map + auto trackedObject = trackedObjects.find(objectId); + + // Get the tracked object JSON properties for this frame + Json::Value trackedObjectJSON = trackedObject->second->PropertiesJSON(frame_number); + + if (trackedObjectJSON["visible"]["value"].asBool() && + trackedObject->second->ExactlyContains(frame_number)){ + // Save the object's index and ID if it's visible in this frame + root["visible_objects_index"].append(trackedObject->first); + root["visible_objects_id"].append(trackedObject->second->Id()); + } + } + + return root.toStyledString(); } // Generate JSON string of this object std::string ObjectDetection::Json() const { - // Return formatted string - return JsonValue().toStyledString(); + // Return formatted string + return JsonValue().toStyledString(); } // Generate Json::Value for this object Json::Value ObjectDetection::JsonValue() const { - // Create root json object - 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; - root["confidence_threshold"] = confidence_threshold; - - // Add tracked object's IDs to root - root["objects_id"] = Json::Value(Json::arrayValue); - for (auto const& trackedObject : trackedObjects){ - Json::Value trackedObjectJSON = trackedObject.second->JsonValue(); - root["objects_id"].append(trackedObject.second->Id()); - } - - // Add the selected object Json to root - if(trackedObjects.count(selectedObjectIndex) != 0){ - auto selectedObject = trackedObjects.at(selectedObjectIndex); - if (selectedObject){ - Json::Value selectedObjectJSON = selectedObject->JsonValue(); - for (auto const& key : selectedObjectJSON.getMemberNames()) - root[key] = selectedObjectJSON[key]; - } - } - - // return JsonValue - return root; + // Create root json object + 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; + root["confidence_threshold"] = confidence_threshold; + root["display_box_text"] = display_box_text.JsonValue(); + + // Add tracked object's IDs to root + root["objects_id"] = Json::Value(Json::arrayValue); + for (auto const& trackedObject : trackedObjects){ + Json::Value trackedObjectJSON = trackedObject.second->JsonValue(); + root["objects_id"].append(trackedObject.second->Id()); + } + + // Add the selected object Json to root + if(trackedObjects.count(selectedObjectIndex) != 0){ + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject){ + Json::Value selectedObjectJSON = selectedObject->JsonValue(); + for (auto const& key : selectedObjectJSON.getMemberNames()) + root[key] = selectedObjectJSON[key]; + } + } + + // return JsonValue + return root; } // Load JSON string into this object void ObjectDetection::SetJson(const std::string value) { - // Parse JSON string into JSON objects - try - { - std::cout<<"entrou no objectDetection SetJson \n"<SetJsonValue(trackedObjectJSON); - } - } - - // Set the selected object's properties - if(trackedObjects.count(selectedObjectIndex) != 0){ - auto selectedObject = trackedObjects.at(selectedObjectIndex); - if (selectedObject) - selectedObject->SetJsonValue(root); - } + std::cout<<"entrou no objectDetection SetJasonValue \n"<SetJsonValue(trackedObjectJSON); + } + } + + // Set the selected object's properties + if(trackedObjects.count(selectedObjectIndex) != 0){ + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject) + selectedObject->SetJsonValue(root); + } } // Get all properties for a specific frame std::string ObjectDetection::PropertiesJSON(int64_t requested_frame) const { - // Generate JSON properties list - Json::Value root; - - // Add the selected object Json to root - if(trackedObjects.count(selectedObjectIndex) != 0){ - auto selectedObject = trackedObjects.at(selectedObjectIndex); - if (selectedObject) - root = selectedObject->PropertiesJSON(requested_frame); - } - - 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); - root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); - root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); - root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame); - root["confidence_threshold"] = add_property_json("Confidence Theshold", confidence_threshold, "float", "", NULL, 0, 1, false, requested_frame); - root["class_filter"] = add_property_json("Class Filter", 0.0, "string", class_filter, NULL, -1, -1, false, requested_frame); - // Return formatted string - return root.toStyledString(); + // Generate JSON properties list + Json::Value root; + + // Add the selected object Json to root + if(trackedObjects.count(selectedObjectIndex) != 0){ + auto selectedObject = trackedObjects.at(selectedObjectIndex); + if (selectedObject) + root = selectedObject->PropertiesJSON(requested_frame); + } + + 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); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame); + root["confidence_threshold"] = add_property_json("Confidence Theshold", confidence_threshold, "float", "", NULL, 0, 1, false, requested_frame); + root["class_filter"] = add_property_json("Class Filter", 0.0, "string", class_filter, NULL, -1, -1, false, requested_frame); + + root["display_box_text"] = add_property_json("Draw Box Text", display_box_text.GetValue(requested_frame), "int", "", &display_box_text, 0, 1.0, false, requested_frame); + root["display_box_text"]["choices"].append(add_property_choice_json("Off", 1, display_box_text.GetValue(requested_frame))); + root["display_box_text"]["choices"].append(add_property_choice_json("On", 0, display_box_text.GetValue(requested_frame))); + + // Return formatted string + return root.toStyledString(); } diff --git a/src/effects/ObjectDetection.h b/src/effects/ObjectDetection.h index fee9382bb..bf7782301 100644 --- a/src/effects/ObjectDetection.h +++ b/src/effects/ObjectDetection.h @@ -46,23 +46,23 @@ struct DetectionData{ DetectionData(){} DetectionData( - std::vector _classIds, - std::vector _confidences, - std::vector> _boxes, - size_t _frameId, - std::vector _objectIds) - { + std::vector _classIds, + std::vector _confidences, + std::vector> _boxes, + size_t _frameId, + std::vector _objectIds) + { classIds = _classIds; confidences = _confidences; boxes = _boxes; frameId = _frameId; - objectIds = _objectIds; + objectIds = _objectIds; } size_t frameId; std::vector classIds; std::vector confidences; std::vector> boxes; - std::vector objectIds; + std::vector objectIds; }; namespace openshot @@ -78,20 +78,22 @@ namespace openshot std::vector classNames; std::vector classesColor; - - /// Minimum confidence value to display the detected objects - float confidence_threshold = 0.5; - /// Contain the user selected classes for visualization - std::vector display_classes; - std::string class_filter; - - /// Init effect settings - void init_effect_details(); - /// Draw bounding box with class and score text - void drawPred(int classId, float conf, cv::Rect2d box, cv::Mat& frame, int objectNumber, std::vector color, float alpha, - int thickness, bool is_background); - /// Draw rotated rectangle with alpha channel - void DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector color, float alpha, int thickness, bool is_background); + + /// Draw class name and confidence score on top of the bounding box + Keyframe display_box_text; + /// Minimum confidence value to display the detected objects + float confidence_threshold = 0.5; + /// Contain the user selected classes for visualization + std::vector display_classes; + std::string class_filter; + + /// Init effect settings + void init_effect_details(); + /// Draw bounding box with class and score text + void drawPred(int classId, float conf, cv::Rect2d box, cv::Mat& frame, int objectNumber, std::vector color, float alpha, + int thickness, bool is_background, bool draw_text); + /// Draw rotated rectangle with alpha channel + void DrawRectangleRGBA(cv::Mat &frame_image, cv::RotatedRect box, std::vector color, float alpha, int thickness, bool is_background); public: