Project import generated by Copybara.
GitOrigin-RevId: d073f8e21be2fcc0e503cb97c6695078b6b75310
This commit is contained in:
@@ -36,12 +36,15 @@ android_binary(
|
||||
name = "faceeffect",
|
||||
srcs = glob(["*.java"]),
|
||||
assets = [
|
||||
"//mediapipe/graphs/face_effect/data:axis.binarypb",
|
||||
"//mediapipe/graphs/face_effect/data:axis.pngblob",
|
||||
"//mediapipe/graphs/face_effect/data:facepaint.pngblob",
|
||||
"//mediapipe/graphs/face_effect/data:glasses.binarypb",
|
||||
"//mediapipe/graphs/face_effect/data:glasses.pngblob",
|
||||
"//mediapipe/graphs/face_effect:face_effect_gpu.binarypb",
|
||||
"//mediapipe/modules/face_detection:face_detection_front.tflite",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata.binarypb",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata_detection.binarypb",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata_landmarks.binarypb",
|
||||
"//mediapipe/modules/face_landmark:face_landmark.tflite",
|
||||
],
|
||||
assets_dir = "",
|
||||
|
||||
+68
-28
@@ -29,23 +29,31 @@ import com.google.mediapipe.framework.Packet;
|
||||
import com.google.mediapipe.framework.PacketGetter;
|
||||
import com.google.mediapipe.modules.facegeometry.FaceGeometryProto.FaceGeometry;
|
||||
import com.google.mediapipe.formats.proto.MatrixDataProto.MatrixData;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** Main activity of MediaPipe face mesh app. */
|
||||
public class MainActivity extends com.google.mediapipe.apps.basic.MainActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
// Stream names.
|
||||
private static final String IS_FACEPAINT_EFFECT_SELECTED_INPUT_STREAM_NAME =
|
||||
"is_facepaint_effect_selected";
|
||||
// Side packet / stream names.
|
||||
private static final String USE_FACE_DETECTION_INPUT_SOURCE_INPUT_SIDE_PACKET_NAME =
|
||||
"use_face_detection_input_source";
|
||||
private static final String SELECTED_EFFECT_ID_INPUT_STREAM_NAME = "selected_effect_id";
|
||||
private static final String OUTPUT_FACE_GEOMETRY_STREAM_NAME = "multi_face_geometry";
|
||||
|
||||
private static final String EFFECT_SWITCHING_HINT_TEXT = "Tap to switch between effects!";
|
||||
|
||||
private static final boolean USE_FACE_DETECTION_INPUT_SOURCE = false;
|
||||
private static final int MATRIX_TRANSLATION_Z_INDEX = 14;
|
||||
|
||||
private final Object isFacepaintEffectSelectedLock = new Object();
|
||||
private boolean isFacepaintEffectSelected;
|
||||
private static final int SELECTED_EFFECT_ID_AXIS = 0;
|
||||
private static final int SELECTED_EFFECT_ID_FACEPAINT = 1;
|
||||
private static final int SELECTED_EFFECT_ID_GLASSES = 2;
|
||||
|
||||
private final Object effectSelectionLock = new Object();
|
||||
private int selectedEffectId;
|
||||
|
||||
private View effectSwitchingHintView;
|
||||
private GestureDetector tapGestureDetector;
|
||||
@@ -60,8 +68,20 @@ public class MainActivity extends com.google.mediapipe.apps.basic.MainActivity {
|
||||
ViewGroup viewGroup = findViewById(R.id.preview_display_layout);
|
||||
viewGroup.addView(effectSwitchingHintView);
|
||||
|
||||
// By default, render the glasses effect.
|
||||
isFacepaintEffectSelected = false;
|
||||
// By default, render the axis effect for the face detection input source and the glasses effect
|
||||
// for the face landmark input source.
|
||||
if (USE_FACE_DETECTION_INPUT_SOURCE) {
|
||||
selectedEffectId = SELECTED_EFFECT_ID_AXIS;
|
||||
} else {
|
||||
selectedEffectId = SELECTED_EFFECT_ID_GLASSES;
|
||||
}
|
||||
|
||||
// Pass the USE_FACE_DETECTION_INPUT_SOURCE flag value as an input side packet into the graph.
|
||||
Map<String, Packet> inputSidePackets = new HashMap<>();
|
||||
inputSidePackets.put(
|
||||
USE_FACE_DETECTION_INPUT_SOURCE_INPUT_SIDE_PACKET_NAME,
|
||||
processor.getPacketCreator().createBool(USE_FACE_DETECTION_INPUT_SOURCE));
|
||||
processor.setInputSidePackets(inputSidePackets);
|
||||
|
||||
// This callback demonstrates how the output face geometry packet can be obtained and used
|
||||
// in an Android app. As an example, the Z-translation component of the face pose transform
|
||||
@@ -71,12 +91,9 @@ public class MainActivity extends com.google.mediapipe.apps.basic.MainActivity {
|
||||
OUTPUT_FACE_GEOMETRY_STREAM_NAME,
|
||||
(packet) -> {
|
||||
effectSwitchingHintView.post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
effectSwitchingHintView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
() ->
|
||||
effectSwitchingHintView.setVisibility(
|
||||
USE_FACE_DETECTION_INPUT_SOURCE ? View.INVISIBLE : View.VISIBLE));
|
||||
|
||||
Log.d(TAG, "Received a multi face geometry packet.");
|
||||
List<FaceGeometry> multiFaceGeometry =
|
||||
@@ -103,30 +120,26 @@ public class MainActivity extends com.google.mediapipe.apps.basic.MainActivity {
|
||||
+ "]");
|
||||
});
|
||||
|
||||
// Alongside the input camera frame, we also send the `is_facepaint_effect_selected` boolean
|
||||
// packet to indicate which effect should be rendered on this frame.
|
||||
// Alongside the input camera frame, we also send the `selected_effect_id` int32 packet to
|
||||
// indicate which effect should be rendered on this frame.
|
||||
processor.setOnWillAddFrameListener(
|
||||
(timestamp) -> {
|
||||
Packet isFacepaintEffectSelectedPacket = null;
|
||||
Packet selectedEffectIdPacket = null;
|
||||
try {
|
||||
synchronized (isFacepaintEffectSelectedLock) {
|
||||
isFacepaintEffectSelectedPacket =
|
||||
processor.getPacketCreator().createBool(isFacepaintEffectSelected);
|
||||
synchronized (effectSelectionLock) {
|
||||
selectedEffectIdPacket = processor.getPacketCreator().createInt32(selectedEffectId);
|
||||
}
|
||||
|
||||
processor
|
||||
.getGraph()
|
||||
.addPacketToInputStream(
|
||||
IS_FACEPAINT_EFFECT_SELECTED_INPUT_STREAM_NAME,
|
||||
isFacepaintEffectSelectedPacket,
|
||||
timestamp);
|
||||
SELECTED_EFFECT_ID_INPUT_STREAM_NAME, selectedEffectIdPacket, timestamp);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Exception while adding packet to input stream while switching effects: " + e);
|
||||
TAG, "Exception while adding packet to input stream while switching effects: " + e);
|
||||
} finally {
|
||||
if (isFacepaintEffectSelectedPacket != null) {
|
||||
isFacepaintEffectSelectedPacket.release();
|
||||
if (selectedEffectIdPacket != null) {
|
||||
selectedEffectIdPacket.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -149,8 +162,35 @@ public class MainActivity extends com.google.mediapipe.apps.basic.MainActivity {
|
||||
}
|
||||
|
||||
private void switchEffect() {
|
||||
synchronized (isFacepaintEffectSelectedLock) {
|
||||
isFacepaintEffectSelected = !isFacepaintEffectSelected;
|
||||
// Avoid switching the Axis effect for the face detection input source.
|
||||
if (USE_FACE_DETECTION_INPUT_SOURCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Looped effect order: glasses -> facepaint -> axis -> glasses -> ...
|
||||
synchronized (effectSelectionLock) {
|
||||
switch (selectedEffectId) {
|
||||
case SELECTED_EFFECT_ID_AXIS:
|
||||
{
|
||||
selectedEffectId = SELECTED_EFFECT_ID_GLASSES;
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTED_EFFECT_ID_FACEPAINT:
|
||||
{
|
||||
selectedEffectId = SELECTED_EFFECT_ID_AXIS;
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTED_EFFECT_ID_GLASSES:
|
||||
{
|
||||
selectedEffectId = SELECTED_EFFECT_ID_FACEPAINT;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -60,5 +60,6 @@ android_binary(
|
||||
"//mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic:basic_lib",
|
||||
"//mediapipe/framework/formats:landmark_java_proto_lite",
|
||||
"//mediapipe/java/com/google/mediapipe/framework:android_framework",
|
||||
"@com_google_protobuf//:protobuf_javalite",
|
||||
],
|
||||
)
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ genrule(
|
||||
cmd = "cp $< $@",
|
||||
)
|
||||
|
||||
MODELS_DIR = "//mediapipe/models"
|
||||
MODELS_DIR = "//mediapipe/modules/objectron"
|
||||
|
||||
genrule(
|
||||
name = "model",
|
||||
@@ -165,7 +165,7 @@ android_binary(
|
||||
":mesh",
|
||||
":texture",
|
||||
MODELS_DIR + ":object_detection_ssd_mobilenetv2_oidv4_fp16.tflite",
|
||||
MODELS_DIR + ":object_detection_oidv4_labelmap.pbtxt",
|
||||
MODELS_DIR + ":object_detection_oidv4_labelmap.txt",
|
||||
ASSETS_DIR + ":box.obj.uuu",
|
||||
ASSETS_DIR + ":classic_colors.png",
|
||||
],
|
||||
|
||||
@@ -59,5 +59,6 @@ android_binary(
|
||||
"//mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic:basic_lib",
|
||||
"//mediapipe/framework/formats:landmark_java_proto_lite",
|
||||
"//mediapipe/java/com/google/mediapipe/framework:android_framework",
|
||||
"@com_google_protobuf//:protobuf_javalite",
|
||||
],
|
||||
)
|
||||
|
||||
+1
@@ -59,5 +59,6 @@ android_binary(
|
||||
"//mediapipe/examples/android/src/java/com/google/mediapipe/apps/basic:basic_lib",
|
||||
"//mediapipe/framework/formats:landmark_java_proto_lite",
|
||||
"//mediapipe/java/com/google/mediapipe/framework:android_framework",
|
||||
"@com_google_protobuf//:protobuf_javalite",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -40,10 +40,11 @@ DEFINE_string(output_video_path, "",
|
||||
"Full path of where to save result (.mp4 only). "
|
||||
"If not provided, show result in a window.");
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
@@ -56,22 +57,22 @@ mediapipe::Status RunMPPGraph() {
|
||||
|
||||
LOG(INFO) << "Initialize the camera or load the video.";
|
||||
cv::VideoCapture capture;
|
||||
const bool load_video = !FLAGS_input_video_path.empty();
|
||||
const bool load_video = !absl::GetFlag(FLAGS_input_video_path).empty();
|
||||
if (load_video) {
|
||||
capture.open(FLAGS_input_video_path);
|
||||
capture.open(absl::GetFlag(FLAGS_input_video_path));
|
||||
} else {
|
||||
capture.open(0);
|
||||
}
|
||||
RET_CHECK(capture.isOpened());
|
||||
|
||||
cv::VideoWriter writer;
|
||||
const bool save_video = !FLAGS_output_video_path.empty();
|
||||
const bool save_video = !absl::GetFlag(FLAGS_output_video_path).empty();
|
||||
if (save_video) {
|
||||
LOG(INFO) << "Prepare video writer.";
|
||||
cv::Mat test_frame;
|
||||
capture.read(test_frame); // Consume first frame.
|
||||
capture.set(cv::CAP_PROP_POS_AVI_RATIO, 0); // Rewind to beginning.
|
||||
writer.open(FLAGS_output_video_path,
|
||||
writer.open(absl::GetFlag(FLAGS_output_video_path),
|
||||
mediapipe::fourcc('a', 'v', 'c', '1'), // .mp4
|
||||
capture.get(cv::CAP_PROP_FPS), test_frame.size());
|
||||
RET_CHECK(writer.isOpened());
|
||||
@@ -143,7 +144,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -368,6 +368,7 @@ cc_test(
|
||||
"//mediapipe/framework/deps:file_path",
|
||||
"//mediapipe/framework/formats:image_frame",
|
||||
"//mediapipe/framework/formats:image_frame_opencv",
|
||||
"//mediapipe/framework/port:commandlineflags",
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
"//mediapipe/framework/port:opencv_core",
|
||||
"//mediapipe/framework/port:opencv_imgcodecs",
|
||||
|
||||
@@ -68,9 +68,9 @@ class BorderDetectionCalculator : public CalculatorBase {
|
||||
BorderDetectionCalculator& operator=(const BorderDetectionCalculator&) =
|
||||
delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
// Given a color and image direction, check to see if a border of that color
|
||||
@@ -83,7 +83,7 @@ class BorderDetectionCalculator : public CalculatorBase {
|
||||
double ColorCount(const Color& mask_color, const cv::Mat& image) const;
|
||||
|
||||
// Set member vars (image size) and confirm no changes frame-to-frame.
|
||||
mediapipe::Status SetAndCheckInputs(const cv::Mat& frame);
|
||||
absl::Status SetAndCheckInputs(const cv::Mat& frame);
|
||||
|
||||
// Find the dominant color for a input image.
|
||||
double FindDominantColor(const cv::Mat& image, Color* dominant_color);
|
||||
@@ -97,15 +97,14 @@ class BorderDetectionCalculator : public CalculatorBase {
|
||||
};
|
||||
REGISTER_CALCULATOR(BorderDetectionCalculator);
|
||||
|
||||
mediapipe::Status BorderDetectionCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status BorderDetectionCalculator::Open(mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<BorderDetectionCalculatorOptions>();
|
||||
RET_CHECK_LT(options_.vertical_search_distance(), 0.5)
|
||||
<< "Search distance must be less than half the full image.";
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status BorderDetectionCalculator::SetAndCheckInputs(
|
||||
absl::Status BorderDetectionCalculator::SetAndCheckInputs(
|
||||
const cv::Mat& frame) {
|
||||
if (frame_width_ < 0) {
|
||||
frame_width_ = frame.cols;
|
||||
@@ -118,10 +117,10 @@ mediapipe::Status BorderDetectionCalculator::SetAndCheckInputs(
|
||||
RET_CHECK_EQ(frame.rows, frame_height_)
|
||||
<< "Input frame dimensions must remain constant throughout the video.";
|
||||
RET_CHECK_EQ(frame.channels(), 3) << "Input video type must be 3-channel";
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status BorderDetectionCalculator::Process(
|
||||
absl::Status BorderDetectionCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
if (!cc->Inputs().HasTag(kVideoInputTag) ||
|
||||
cc->Inputs().Tag(kVideoInputTag).Value().IsEmpty()) {
|
||||
@@ -173,7 +172,7 @@ mediapipe::Status BorderDetectionCalculator::Process(
|
||||
.Tag(kDetectedBorders)
|
||||
.AddPacket(Adopt(features.release()).At(cc->InputTimestamp()));
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Find the dominant color within an image.
|
||||
@@ -291,11 +290,11 @@ void BorderDetectionCalculator::DetectBorder(
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status BorderDetectionCalculator::GetContract(
|
||||
absl::Status BorderDetectionCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
cc->Inputs().Tag(kVideoInputTag).Set<ImageFrame>();
|
||||
cc->Outputs().Tag(kDetectedBorders).Set<StaticFeatures>();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -55,23 +55,25 @@ class ContentZoomingCalculator : public CalculatorBase {
|
||||
ContentZoomingCalculator(const ContentZoomingCalculator&) = delete;
|
||||
ContentZoomingCalculator& operator=(const ContentZoomingCalculator&) = delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
// Converts bounds to tilt offset, pan offset and height.
|
||||
mediapipe::Status ConvertToPanTiltZoom(float xmin, float xmax, float ymin,
|
||||
float ymax, int* tilt_offset,
|
||||
int* pan_offset, int* height);
|
||||
absl::Status ConvertToPanTiltZoom(float xmin, float xmax, float ymin,
|
||||
float ymax, int* tilt_offset,
|
||||
int* pan_offset, int* height);
|
||||
// Sets max_frame_value_ and target_aspect_
|
||||
absl::Status UpdateAspectAndMax();
|
||||
ContentZoomingCalculatorOptions options_;
|
||||
// Detection frame width/height.
|
||||
int frame_height_;
|
||||
int frame_width_;
|
||||
// Path solver used to smooth top/bottom border crop values.
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_height_;
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_width_;
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_offset_;
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_zoom_;
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_pan_;
|
||||
std::unique_ptr<KinematicPathSolver> path_solver_tilt_;
|
||||
// Are parameters initialized.
|
||||
bool initialized_;
|
||||
// Stores the time of the last "only_required" input.
|
||||
@@ -89,7 +91,7 @@ class ContentZoomingCalculator : public CalculatorBase {
|
||||
};
|
||||
REGISTER_CALCULATOR(ContentZoomingCalculator);
|
||||
|
||||
mediapipe::Status ContentZoomingCalculator::GetContract(
|
||||
absl::Status ContentZoomingCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
RET_CHECK(
|
||||
!(cc->Inputs().HasTag(kVideoFrame) && cc->Inputs().HasTag(kVideoSize)))
|
||||
@@ -114,11 +116,10 @@ mediapipe::Status ContentZoomingCalculator::GetContract(
|
||||
if (cc->Outputs().HasTag(kCropRect)) {
|
||||
cc->Outputs().Tag(kCropRect).Set<mediapipe::Rect>();
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status ContentZoomingCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status ContentZoomingCalculator::Open(mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<ContentZoomingCalculatorOptions>();
|
||||
if (options_.has_kinematic_options()) {
|
||||
return mediapipe::UnknownErrorBuilder(MEDIAPIPE_LOC)
|
||||
@@ -131,10 +132,10 @@ mediapipe::Status ContentZoomingCalculator::Open(
|
||||
"in kinematic_options_zoom and kinematic_options_tilt "
|
||||
"directly.";
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status ContentZoomingCalculator::ConvertToPanTiltZoom(
|
||||
absl::Status ContentZoomingCalculator::ConvertToPanTiltZoom(
|
||||
float xmin, float xmax, float ymin, float ymax, int* tilt_offset,
|
||||
int* pan_offset, int* height) {
|
||||
// Find center of the y-axis offset (for tilt control).
|
||||
@@ -142,10 +143,11 @@ mediapipe::Status ContentZoomingCalculator::ConvertToPanTiltZoom(
|
||||
// Find center of the x-axis offset (for pan control).
|
||||
float x_center = xmin + (xmax - xmin) / 2;
|
||||
// Find size and apply scale factor to y-axis.
|
||||
float fit_size = fmax((ymax - ymin) / options_.scale_factor(), xmax - xmin);
|
||||
float fit_size_raw =
|
||||
fmax((ymax - ymin) / options_.scale_factor(), xmax - xmin);
|
||||
// Apply max frame for cases where the target size is different than input
|
||||
// frame size.
|
||||
fit_size = fmin(max_frame_value_, fit_size);
|
||||
float fit_size = fmin(max_frame_value_, fit_size_raw);
|
||||
// Prevent box from extending beyond the image.
|
||||
if (y_center - fit_size / 2 < 0) {
|
||||
y_center = fit_size / 2;
|
||||
@@ -160,8 +162,8 @@ mediapipe::Status ContentZoomingCalculator::ConvertToPanTiltZoom(
|
||||
// Scale to pixel coordinates.
|
||||
*tilt_offset = frame_height_ * y_center;
|
||||
*pan_offset = frame_width_ * x_center;
|
||||
*height = frame_height_ * fit_size;
|
||||
return mediapipe::OkStatus();
|
||||
*height = frame_height_ * fit_size_raw;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -185,10 +187,10 @@ mediapipe::autoflip::RectF ShiftDetection(
|
||||
relative_bounding_box.width() * x_offset_percent);
|
||||
return shifted_bb;
|
||||
}
|
||||
mediapipe::Status UpdateRanges(const SalientRegion& region,
|
||||
const float shift_vertical,
|
||||
const float shift_horizontal, float* xmin,
|
||||
float* xmax, float* ymin, float* ymax) {
|
||||
absl::Status UpdateRanges(const SalientRegion& region,
|
||||
const float shift_vertical,
|
||||
const float shift_horizontal, float* xmin,
|
||||
float* xmax, float* ymin, float* ymax) {
|
||||
if (!region.has_location_normalized()) {
|
||||
return mediapipe::UnknownErrorBuilder(MEDIAPIPE_LOC)
|
||||
<< "SalientRegion did not have location normalized set.";
|
||||
@@ -200,12 +202,12 @@ mediapipe::Status UpdateRanges(const SalientRegion& region,
|
||||
*ymin = fmin(*ymin, location.y());
|
||||
*ymax = fmax(*ymax, location.y() + location.height());
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
mediapipe::Status UpdateRanges(const mediapipe::Detection& detection,
|
||||
const float shift_vertical,
|
||||
const float shift_horizontal, float* xmin,
|
||||
float* xmax, float* ymin, float* ymax) {
|
||||
absl::Status UpdateRanges(const mediapipe::Detection& detection,
|
||||
const float shift_vertical,
|
||||
const float shift_horizontal, float* xmin,
|
||||
float* xmax, float* ymin, float* ymax) {
|
||||
RET_CHECK(detection.location_data().format() ==
|
||||
mediapipe::LocationData::RELATIVE_BOUNDING_BOX)
|
||||
<< "Face detection input is lacking required relative_bounding_box()";
|
||||
@@ -217,7 +219,7 @@ mediapipe::Status UpdateRanges(const mediapipe::Detection& detection,
|
||||
*ymin = fmin(*ymin, location.ymin());
|
||||
*ymax = fmax(*ymax, location.ymin() + location.height());
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
void MakeStaticFeatures(const int top_border, const int bottom_border,
|
||||
const int frame_width, const int frame_height,
|
||||
@@ -236,57 +238,97 @@ void MakeStaticFeatures(const int top_border, const int bottom_border,
|
||||
border_bottom->mutable_border_position()->set_width(frame_width);
|
||||
border_bottom->mutable_border_position()->set_height(bottom_border);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
mediapipe::Status ContentZoomingCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status GetVideoResolution(mediapipe::CalculatorContext* cc,
|
||||
int* frame_width, int* frame_height) {
|
||||
if (cc->Inputs().HasTag(kVideoFrame)) {
|
||||
frame_width_ = cc->Inputs().Tag(kVideoFrame).Get<ImageFrame>().Width();
|
||||
frame_height_ = cc->Inputs().Tag(kVideoFrame).Get<ImageFrame>().Height();
|
||||
*frame_width = cc->Inputs().Tag(kVideoFrame).Get<ImageFrame>().Width();
|
||||
*frame_height = cc->Inputs().Tag(kVideoFrame).Get<ImageFrame>().Height();
|
||||
} else if (cc->Inputs().HasTag(kVideoSize)) {
|
||||
if (cc->Inputs().Tag(kVideoSize).IsEmpty()) {
|
||||
return mediapipe::OkStatus();
|
||||
}
|
||||
frame_width_ =
|
||||
*frame_width =
|
||||
cc->Inputs().Tag(kVideoSize).Get<std::pair<int, int>>().first;
|
||||
frame_height_ =
|
||||
*frame_height =
|
||||
cc->Inputs().Tag(kVideoSize).Get<std::pair<int, int>>().second;
|
||||
} else {
|
||||
return mediapipe::UnknownErrorBuilder(MEDIAPIPE_LOC)
|
||||
<< "Input VIDEO or VIDEO_SIZE must be provided.";
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
absl::Status ContentZoomingCalculator::UpdateAspectAndMax() {
|
||||
max_frame_value_ = 1.0;
|
||||
target_aspect_ = frame_width_ / static_cast<float>(frame_height_);
|
||||
// If target size is set and wider than input aspect, make sure to always
|
||||
// crop the min required amount.
|
||||
if (options_.has_target_size()) {
|
||||
RET_CHECK_GT(options_.target_size().width(), 0)
|
||||
<< "Provided target width not valid.";
|
||||
RET_CHECK_GT(options_.target_size().height(), 0)
|
||||
<< "Provided target height not valid.";
|
||||
float input_aspect = frame_width_ / static_cast<float>(frame_height_);
|
||||
target_aspect_ = options_.target_size().width() /
|
||||
static_cast<float>(options_.target_size().height());
|
||||
max_frame_value_ =
|
||||
std::min(input_aspect / target_aspect_, target_aspect_ / input_aspect);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ContentZoomingCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
// For async subgraph support, return on empty video size packets.
|
||||
if (cc->Inputs().HasTag(kVideoSize) &&
|
||||
cc->Inputs().Tag(kVideoSize).IsEmpty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
int frame_width, frame_height;
|
||||
MP_RETURN_IF_ERROR(GetVideoResolution(cc, &frame_width, &frame_height));
|
||||
|
||||
// Init on first call.
|
||||
if (!initialized_) {
|
||||
path_solver_height_ = std::make_unique<KinematicPathSolver>(
|
||||
options_.kinematic_options_zoom(), 0, frame_height_,
|
||||
static_cast<float>(frame_height_) / kFieldOfView);
|
||||
path_solver_width_ = std::make_unique<KinematicPathSolver>(
|
||||
frame_width_ = frame_width;
|
||||
frame_height_ = frame_height;
|
||||
path_solver_pan_ = std::make_unique<KinematicPathSolver>(
|
||||
options_.kinematic_options_pan(), 0, frame_width_,
|
||||
static_cast<float>(frame_width_) / kFieldOfView);
|
||||
path_solver_offset_ = std::make_unique<KinematicPathSolver>(
|
||||
path_solver_tilt_ = std::make_unique<KinematicPathSolver>(
|
||||
options_.kinematic_options_tilt(), 0, frame_height_,
|
||||
static_cast<float>(frame_height_) / kFieldOfView);
|
||||
max_frame_value_ = 1.0;
|
||||
target_aspect_ = frame_width_ / static_cast<float>(frame_height_);
|
||||
// If target size is set and wider than input aspect, make sure to always
|
||||
// crop the min required amount.
|
||||
if (options_.has_target_size()) {
|
||||
RET_CHECK_GT(options_.target_size().width(), 0)
|
||||
<< "Provided target width not valid.";
|
||||
RET_CHECK_GT(options_.target_size().height(), 0)
|
||||
<< "Provided target height not valid.";
|
||||
float input_aspect = frame_width_ / static_cast<float>(frame_height_);
|
||||
target_aspect_ = options_.target_size().width() /
|
||||
static_cast<float>(options_.target_size().height());
|
||||
max_frame_value_ = std::min(input_aspect / target_aspect_,
|
||||
target_aspect_ / input_aspect);
|
||||
}
|
||||
MP_RETURN_IF_ERROR(UpdateAspectAndMax());
|
||||
int min_zoom_size = frame_height_ * (options_.max_zoom_value_deg() /
|
||||
static_cast<double>(kFieldOfView));
|
||||
path_solver_zoom_ = std::make_unique<KinematicPathSolver>(
|
||||
options_.kinematic_options_zoom(), min_zoom_size,
|
||||
max_frame_value_ * frame_height_,
|
||||
static_cast<float>(frame_height_) / kFieldOfView);
|
||||
last_measured_height_ = max_frame_value_ * frame_height_;
|
||||
last_measured_x_offset_ = target_aspect_ * frame_width_;
|
||||
last_measured_y_offset_ = frame_width_ / 2;
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
// Update state for change in input resolution.
|
||||
if (frame_width_ != frame_width || frame_height_ != frame_height) {
|
||||
double width_scale = frame_width / static_cast<double>(frame_width_);
|
||||
double height_scale = frame_height / static_cast<double>(frame_height_);
|
||||
last_measured_height_ = last_measured_height_ * height_scale;
|
||||
last_measured_y_offset_ = last_measured_y_offset_ * height_scale;
|
||||
last_measured_x_offset_ = last_measured_x_offset_ * width_scale;
|
||||
frame_width_ = frame_width;
|
||||
frame_height_ = frame_height;
|
||||
MP_RETURN_IF_ERROR(UpdateAspectAndMax());
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->UpdateMinMaxLocation(0, frame_width_));
|
||||
MP_RETURN_IF_ERROR(
|
||||
path_solver_tilt_->UpdateMinMaxLocation(0, frame_height_));
|
||||
int min_zoom_size = frame_height_ * (options_.max_zoom_value_deg() /
|
||||
static_cast<double>(kFieldOfView));
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->UpdateMinMaxLocation(
|
||||
min_zoom_size, max_frame_value_ * frame_height_));
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->UpdatePixelsPerDegree(
|
||||
static_cast<float>(frame_height_) / kFieldOfView));
|
||||
}
|
||||
|
||||
bool only_required_found = false;
|
||||
|
||||
// Compute the box that contains all "is_required" detections.
|
||||
@@ -307,11 +349,13 @@ mediapipe::Status ContentZoomingCalculator::Process(
|
||||
if (cc->Inputs().HasTag(kDetections)) {
|
||||
if (cc->Inputs().Tag(kDetections).IsEmpty()) {
|
||||
auto default_rect = absl::make_unique<mediapipe::Rect>();
|
||||
default_rect->set_x_center(frame_width_ / 2);
|
||||
default_rect->set_y_center(frame_height_ / 2);
|
||||
default_rect->set_width(frame_width_);
|
||||
default_rect->set_height(frame_height_);
|
||||
cc->Outputs().Tag(kCropRect).Add(default_rect.release(),
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
auto raw_detections =
|
||||
cc->Inputs().Tag(kDetections).Get<std::vector<mediapipe::Detection>>();
|
||||
@@ -350,31 +394,46 @@ mediapipe::Status ContentZoomingCalculator::Process(
|
||||
offset_y = last_measured_y_offset_;
|
||||
}
|
||||
|
||||
// Check if the camera is changing in pan, tilt or zoom. If the camera is in
|
||||
// motion disable temporal filtering.
|
||||
bool pan_state, tilt_state, zoom_state;
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->PredictMotionState(
|
||||
offset_x, cc->InputTimestamp().Microseconds(), &pan_state));
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->PredictMotionState(
|
||||
offset_y, cc->InputTimestamp().Microseconds(), &tilt_state));
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->PredictMotionState(
|
||||
height, cc->InputTimestamp().Microseconds(), &zoom_state));
|
||||
if (pan_state || tilt_state || zoom_state) {
|
||||
path_solver_pan_->ClearHistory();
|
||||
path_solver_tilt_->ClearHistory();
|
||||
path_solver_zoom_->ClearHistory();
|
||||
}
|
||||
|
||||
// Compute smoothed zoom camera path.
|
||||
MP_RETURN_IF_ERROR(path_solver_height_->AddObservation(
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->AddObservation(
|
||||
height, cc->InputTimestamp().Microseconds()));
|
||||
int path_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_height_->GetState(&path_height));
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetState(&path_height));
|
||||
int path_width = path_height * target_aspect_;
|
||||
|
||||
// Update pixel-per-degree value for pan/tilt.
|
||||
int target_height;
|
||||
MP_RETURN_IF_ERROR(path_solver_height_->GetTargetPosition(&target_height));
|
||||
MP_RETURN_IF_ERROR(path_solver_zoom_->GetTargetPosition(&target_height));
|
||||
int target_width = target_height * target_aspect_;
|
||||
MP_RETURN_IF_ERROR(path_solver_width_->UpdatePixelsPerDegree(
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->UpdatePixelsPerDegree(
|
||||
static_cast<float>(target_width) / kFieldOfView));
|
||||
MP_RETURN_IF_ERROR(path_solver_offset_->UpdatePixelsPerDegree(
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->UpdatePixelsPerDegree(
|
||||
static_cast<float>(target_height) / kFieldOfView));
|
||||
|
||||
// Compute smoothed pan/tilt paths.
|
||||
MP_RETURN_IF_ERROR(path_solver_width_->AddObservation(
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->AddObservation(
|
||||
offset_x, cc->InputTimestamp().Microseconds()));
|
||||
MP_RETURN_IF_ERROR(path_solver_offset_->AddObservation(
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->AddObservation(
|
||||
offset_y, cc->InputTimestamp().Microseconds()));
|
||||
int path_offset_x;
|
||||
MP_RETURN_IF_ERROR(path_solver_width_->GetState(&path_offset_x));
|
||||
MP_RETURN_IF_ERROR(path_solver_pan_->GetState(&path_offset_x));
|
||||
int path_offset_y;
|
||||
MP_RETURN_IF_ERROR(path_solver_offset_->GetState(&path_offset_y));
|
||||
MP_RETURN_IF_ERROR(path_solver_tilt_->GetState(&path_offset_y));
|
||||
|
||||
// Prevent box from extending beyond the image after camera smoothing.
|
||||
if (path_offset_y - ceil(path_height / 2.0) < 0) {
|
||||
@@ -415,7 +474,7 @@ mediapipe::Status ContentZoomingCalculator::Process(
|
||||
Timestamp(cc->InputTimestamp()));
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -19,7 +19,7 @@ package mediapipe.autoflip;
|
||||
import "mediapipe/examples/desktop/autoflip/quality/kinematic_path_solver.proto";
|
||||
import "mediapipe/framework/calculator.proto";
|
||||
|
||||
// NextTag: 13
|
||||
// NextTag: 14
|
||||
message ContentZoomingCalculatorOptions {
|
||||
extend mediapipe.CalculatorOptions {
|
||||
optional ContentZoomingCalculatorOptions ext = 313091992;
|
||||
@@ -52,6 +52,9 @@ message ContentZoomingCalculatorOptions {
|
||||
optional float detection_shift_vertical = 11 [default = 0.0];
|
||||
optional float detection_shift_horizontal = 12 [default = 0.0];
|
||||
|
||||
// Defines the smallest value in degrees the camera is permitted to zoom.
|
||||
optional float max_zoom_value_deg = 13 [default = 35];
|
||||
|
||||
// Deprecated parameters
|
||||
optional KinematicOptions kinematic_options = 2 [deprecated = true];
|
||||
optional int64 min_motion_to_reframe = 4 [deprecated = true];
|
||||
|
||||
+108
-4
@@ -42,6 +42,20 @@ const char kConfigA[] = R"(
|
||||
input_stream: "VIDEO:camera_frames"
|
||||
input_stream: "SALIENT_REGIONS:detection_set"
|
||||
output_stream: "BORDERS:borders"
|
||||
options: {
|
||||
[mediapipe.autoflip.ContentZoomingCalculatorOptions.ext]: {
|
||||
max_zoom_value_deg: 0
|
||||
kinematic_options_zoom {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_tilt {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_pan {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
const char kConfigB[] = R"(
|
||||
@@ -55,6 +69,16 @@ const char kConfigB[] = R"(
|
||||
width: 1000
|
||||
height: 500
|
||||
}
|
||||
max_zoom_value_deg: 0
|
||||
kinematic_options_zoom {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_tilt {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_pan {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
@@ -64,6 +88,20 @@ const char kConfigC[] = R"(
|
||||
input_stream: "VIDEO_SIZE:size"
|
||||
input_stream: "SALIENT_REGIONS:detection_set"
|
||||
output_stream: "BORDERS:borders"
|
||||
options: {
|
||||
[mediapipe.autoflip.ContentZoomingCalculatorOptions.ext]: {
|
||||
max_zoom_value_deg: 0
|
||||
kinematic_options_zoom {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_tilt {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_pan {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
const char kConfigD[] = R"(
|
||||
@@ -71,6 +109,20 @@ const char kConfigD[] = R"(
|
||||
input_stream: "VIDEO_SIZE:size"
|
||||
input_stream: "DETECTIONS:detections"
|
||||
output_stream: "CROP_RECT:rect"
|
||||
options: {
|
||||
[mediapipe.autoflip.ContentZoomingCalculatorOptions.ext]: {
|
||||
max_zoom_value_deg: 0
|
||||
kinematic_options_zoom {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_tilt {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
kinematic_options_pan {
|
||||
min_motion_to_reframe: 1.2
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
void CheckBorder(const StaticFeatures& static_features, int width, int height,
|
||||
@@ -91,8 +143,9 @@ void CheckBorder(const StaticFeatures& static_features, int width, int height,
|
||||
EXPECT_EQ(Border::BOTTOM, part.relative_position());
|
||||
}
|
||||
|
||||
void AddDetection(const cv::Rect_<float>& position, const int64 time,
|
||||
CalculatorRunner* runner) {
|
||||
void AddDetectionFrameSize(const cv::Rect_<float>& position, const int64 time,
|
||||
const int width, const int height,
|
||||
CalculatorRunner* runner) {
|
||||
auto detections = std::make_unique<std::vector<mediapipe::Detection>>();
|
||||
mediapipe::Detection detection;
|
||||
detection.mutable_location_data()->set_format(
|
||||
@@ -111,12 +164,17 @@ void AddDetection(const cv::Rect_<float>& position, const int64 time,
|
||||
->Tag("DETECTIONS")
|
||||
.packets.push_back(Adopt(detections.release()).At(Timestamp(time)));
|
||||
|
||||
auto input_size = ::absl::make_unique<std::pair<int, int>>(1000, 1000);
|
||||
auto input_size = ::absl::make_unique<std::pair<int, int>>(width, height);
|
||||
runner->MutableInputs()
|
||||
->Tag("VIDEO_SIZE")
|
||||
.packets.push_back(Adopt(input_size.release()).At(Timestamp(time)));
|
||||
}
|
||||
|
||||
void AddDetection(const cv::Rect_<float>& position, const int64 time,
|
||||
CalculatorRunner* runner) {
|
||||
AddDetectionFrameSize(position, time, 1000, 1000, runner);
|
||||
}
|
||||
|
||||
void CheckCropRect(const int x_center, const int y_center, const int width,
|
||||
const int height, const int frame_number,
|
||||
const std::vector<Packet>& output_packets) {
|
||||
@@ -433,7 +491,53 @@ TEST(ContentZoomingCalculatorTest, EmptyDetections) {
|
||||
->Tag("VIDEO_SIZE")
|
||||
.packets.push_back(Adopt(input_size.release()).At(Timestamp(0)));
|
||||
MP_ASSERT_OK(runner->Run());
|
||||
CheckCropRect(0, 0, 1000, 1000, 0,
|
||||
CheckCropRect(500, 500, 1000, 1000, 0,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
}
|
||||
|
||||
TEST(ContentZoomingCalculatorTest, ResolutionChangeStationary) {
|
||||
auto config = ParseTextProtoOrDie<CalculatorGraphConfig::Node>(kConfigD);
|
||||
auto runner = ::absl::make_unique<CalculatorRunner>(config);
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.4, .4, .2, .2), 0, 1000, 1000,
|
||||
runner.get());
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.4, .4, .2, .2), 1, 500, 500,
|
||||
runner.get());
|
||||
MP_ASSERT_OK(runner->Run());
|
||||
CheckCropRect(500, 500, 222, 222, 0,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
CheckCropRect(500 * 0.5, 500 * 0.5, 222 * 0.5, 222 * 0.5, 1,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
}
|
||||
|
||||
TEST(ContentZoomingCalculatorTest, ResolutionChangeZooming) {
|
||||
auto config = ParseTextProtoOrDie<CalculatorGraphConfig::Node>(kConfigD);
|
||||
auto runner = ::absl::make_unique<CalculatorRunner>(config);
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.1, .1, .8, .8), 0, 1000, 1000,
|
||||
runner.get());
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.4, .4, .2, .2), 1000000, 1000, 1000,
|
||||
runner.get());
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.4, .4, .2, .2), 2000000, 500, 500,
|
||||
runner.get());
|
||||
MP_ASSERT_OK(runner->Run());
|
||||
CheckCropRect(500, 500, 888, 888, 0,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
CheckCropRect(500, 500, 588, 588, 1,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
CheckCropRect(500 * 0.5, 500 * 0.5, 288 * 0.5, 288 * 0.5, 2,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
}
|
||||
|
||||
TEST(ContentZoomingCalculatorTest, MaxZoomValue) {
|
||||
auto config = ParseTextProtoOrDie<CalculatorGraphConfig::Node>(kConfigD);
|
||||
auto* options = config.mutable_options()->MutableExtension(
|
||||
ContentZoomingCalculatorOptions::ext);
|
||||
options->set_max_zoom_value_deg(55);
|
||||
auto runner = ::absl::make_unique<CalculatorRunner>(config);
|
||||
AddDetectionFrameSize(cv::Rect_<float>(.4, .4, .2, .2), 0, 1000, 1000,
|
||||
runner.get());
|
||||
MP_ASSERT_OK(runner->Run());
|
||||
// 55/60 * 1000 = 916
|
||||
CheckCropRect(500, 500, 916, 916, 0,
|
||||
runner->Outputs().Tag("CROP_RECT").packets);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2019 The MediaPipe Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package mediapipe.autoflip;
|
||||
|
||||
import "mediapipe/framework/calculator.proto";
|
||||
|
||||
message FaceBoxAdjusterCalculatorOptions {
|
||||
extend mediapipe.CalculatorOptions {
|
||||
optional FaceBoxAdjusterCalculatorOptions ext = 347462240;
|
||||
}
|
||||
|
||||
// When faces are detected in a given frame, we check these number of frames
|
||||
// in the past. We include only those faces in auto framing that have been
|
||||
// seen in this past history. This helps reduce False Positives and also
|
||||
// handles some of the edge cases. Setting the value to 0 disables the
|
||||
// feature.
|
||||
optional int32 num_frame_history = 1 [default = 0];
|
||||
|
||||
// IOU threshold for matching detected faces with the faces in the frame
|
||||
// history buffer.
|
||||
optional float iou_threshold = 2 [default = 0.2];
|
||||
|
||||
// If true, the face boxes are adjusted based on their face pose. This is done
|
||||
// to correct for extreme poses that can cause the detected face boxes to be
|
||||
// either too big or too small.
|
||||
optional bool adjust_for_pose = 3 [default = true];
|
||||
|
||||
// There are DEPRECATED fields. Do not use.
|
||||
optional float box_area_change_per_up_tilt_degree = 4 [deprecated = true];
|
||||
optional float box_area_change_per_down_tilt_degree = 5 [deprecated = true];
|
||||
|
||||
// The ratios of the face-pose corrected IPD to the face bounding box's width
|
||||
// and height respectively.
|
||||
optional float ipd_face_box_width_ratio = 6 [default = 0.5566];
|
||||
optional float ipd_face_box_height_ratio = 7 [default = 0.3131];
|
||||
}
|
||||
@@ -55,9 +55,9 @@ class FaceToRegionCalculator : public CalculatorBase {
|
||||
FaceToRegionCalculator(const FaceToRegionCalculator&) = delete;
|
||||
FaceToRegionCalculator& operator=(const FaceToRegionCalculator&) = delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
double NormalizeX(const int pixel);
|
||||
@@ -78,18 +78,17 @@ REGISTER_CALCULATOR(FaceToRegionCalculator);
|
||||
|
||||
FaceToRegionCalculator::FaceToRegionCalculator() {}
|
||||
|
||||
mediapipe::Status FaceToRegionCalculator::GetContract(
|
||||
absl::Status FaceToRegionCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
if (cc->Inputs().HasTag("VIDEO")) {
|
||||
cc->Inputs().Tag("VIDEO").Set<ImageFrame>();
|
||||
}
|
||||
cc->Inputs().Tag("FACES").Set<std::vector<mediapipe::Detection>>();
|
||||
cc->Outputs().Tag("REGIONS").Set<DetectionSet>();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status FaceToRegionCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status FaceToRegionCalculator::Open(mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<FaceToRegionCalculatorOptions>();
|
||||
if (!cc->Inputs().HasTag("VIDEO")) {
|
||||
RET_CHECK(!options_.use_visual_scorer())
|
||||
@@ -105,7 +104,7 @@ mediapipe::Status FaceToRegionCalculator::Open(
|
||||
scorer_ = absl::make_unique<VisualScorer>(options_.scorer_options());
|
||||
frame_width_ = -1;
|
||||
frame_height_ = -1;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
inline double FaceToRegionCalculator::NormalizeX(const int pixel) {
|
||||
@@ -146,8 +145,7 @@ void FaceToRegionCalculator::ExtendSalientRegionWithPoint(
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status FaceToRegionCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status FaceToRegionCalculator::Process(mediapipe::CalculatorContext* cc) {
|
||||
if (cc->Inputs().HasTag("VIDEO") &&
|
||||
cc->Inputs().Tag("VIDEO").Value().IsEmpty()) {
|
||||
return mediapipe::UnknownErrorBuilder(MEDIAPIPE_LOC)
|
||||
@@ -280,7 +278,7 @@ mediapipe::Status FaceToRegionCalculator::Process(
|
||||
}
|
||||
cc->Outputs().Tag("REGIONS").Add(region_set.release(), cc->InputTimestamp());
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
+9
-9
@@ -38,9 +38,9 @@ class LocalizationToRegionCalculator : public mediapipe::CalculatorBase {
|
||||
LocalizationToRegionCalculator& operator=(
|
||||
const LocalizationToRegionCalculator&) = delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
// Calculator options.
|
||||
@@ -84,21 +84,21 @@ void FillSalientRegion(const mediapipe::Detection& detection,
|
||||
|
||||
} // namespace
|
||||
|
||||
mediapipe::Status LocalizationToRegionCalculator::GetContract(
|
||||
absl::Status LocalizationToRegionCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
cc->Inputs().Tag("DETECTIONS").Set<std::vector<mediapipe::Detection>>();
|
||||
cc->Outputs().Tag("REGIONS").Set<DetectionSet>();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status LocalizationToRegionCalculator::Open(
|
||||
absl::Status LocalizationToRegionCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<LocalizationToRegionCalculatorOptions>();
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status LocalizationToRegionCalculator::Process(
|
||||
absl::Status LocalizationToRegionCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
const auto& annotations =
|
||||
cc->Inputs().Tag("DETECTIONS").Get<std::vector<mediapipe::Detection>>();
|
||||
@@ -119,7 +119,7 @@ mediapipe::Status LocalizationToRegionCalculator::Process(
|
||||
}
|
||||
|
||||
cc->Outputs().Tag("REGIONS").Add(regions.release(), cc->InputTimestamp());
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -68,7 +68,7 @@ constexpr char kOutputSummary[] = "CROPPING_SUMMARY";
|
||||
constexpr char kExternalRenderingPerFrame[] = "EXTERNAL_RENDERING_PER_FRAME";
|
||||
constexpr char kExternalRenderingFullVid[] = "EXTERNAL_RENDERING_FULL_VID";
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::GetContract(
|
||||
absl::Status SceneCroppingCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
if (cc->InputSidePackets().HasTag(kInputExternalSettings)) {
|
||||
cc->InputSidePackets().Tag(kInputExternalSettings).Set<std::string>();
|
||||
@@ -136,10 +136,10 @@ mediapipe::Status SceneCroppingCalculator::GetContract(
|
||||
cc->Outputs().HasTag(kExternalRenderingFullVid) ||
|
||||
cc->Outputs().HasTag(kOutputCroppedFrames))
|
||||
<< "At leaset one output stream must be specified";
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::Open(CalculatorContext* cc) {
|
||||
absl::Status SceneCroppingCalculator::Open(CalculatorContext* cc) {
|
||||
options_ = cc->Options<SceneCroppingCalculatorOptions>();
|
||||
RET_CHECK_GT(options_.max_scene_size(), 0)
|
||||
<< "Maximum scene size is non-positive.";
|
||||
@@ -175,17 +175,17 @@ mediapipe::Status SceneCroppingCalculator::Open(CalculatorContext* cc) {
|
||||
should_perform_frame_cropping_ = cc->Outputs().HasTag(kOutputCroppedFrames);
|
||||
scene_camera_motion_analyzer_ = absl::make_unique<SceneCameraMotionAnalyzer>(
|
||||
options_.scene_camera_motion_analyzer_options());
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
namespace {
|
||||
mediapipe::Status ParseAspectRatioString(const std::string& aspect_ratio_string,
|
||||
double* aspect_ratio) {
|
||||
absl::Status ParseAspectRatioString(const std::string& aspect_ratio_string,
|
||||
double* aspect_ratio) {
|
||||
std::string error_msg =
|
||||
"Aspect ratio std::string must be in the format of 'width:height', e.g. "
|
||||
"'1:1' or '5:4', your input was " +
|
||||
aspect_ratio_string;
|
||||
auto pos = aspect_ratio_string.find(":");
|
||||
auto pos = aspect_ratio_string.find(':');
|
||||
RET_CHECK(pos != std::string::npos) << error_msg;
|
||||
double width_ratio;
|
||||
RET_CHECK(absl::SimpleAtod(aspect_ratio_string.substr(0, pos), &width_ratio))
|
||||
@@ -196,7 +196,7 @@ mediapipe::Status ParseAspectRatioString(const std::string& aspect_ratio_string,
|
||||
&height_ratio))
|
||||
<< error_msg;
|
||||
*aspect_ratio = width_ratio / height_ratio;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
void ConstructExternalRenderMessage(
|
||||
const cv::Rect& crop_from_location, const cv::Rect& render_to_location,
|
||||
@@ -235,7 +235,7 @@ int RoundToEven(float value) {
|
||||
|
||||
} // namespace
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::InitializeSceneCroppingCalculator(
|
||||
absl::Status SceneCroppingCalculator::InitializeSceneCroppingCalculator(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
if (cc->Inputs().HasTag(kInputVideoFrames)) {
|
||||
const auto& frame = cc->Inputs().Tag(kInputVideoFrames).Get<ImageFrame>();
|
||||
@@ -302,8 +302,7 @@ mediapipe::Status SceneCroppingCalculator::InitializeSceneCroppingCalculator(
|
||||
target_height_ = frame_height_;
|
||||
break;
|
||||
case SceneCroppingCalculatorOptions::UNKNOWN:
|
||||
return mediapipe::InvalidArgumentError(
|
||||
"target_size_type not set properly.");
|
||||
return absl::InvalidArgumentError("target_size_type not set properly.");
|
||||
}
|
||||
target_aspect_ratio_ = GetRatio(target_width_, target_height_);
|
||||
|
||||
@@ -337,7 +336,7 @@ mediapipe::Status SceneCroppingCalculator::InitializeSceneCroppingCalculator(
|
||||
scene_cropper_ = absl::make_unique<SceneCropper>(
|
||||
options_.camera_motion_options(), frame_width_, frame_height_);
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
bool HasFrameSignal(mediapipe::CalculatorContext* cc) {
|
||||
@@ -347,7 +346,7 @@ bool HasFrameSignal(mediapipe::CalculatorContext* cc) {
|
||||
return !cc->Inputs().Tag(kInputVideoSize).Value().IsEmpty();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::Process(
|
||||
absl::Status SceneCroppingCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
// Sets frame dimension and initializes scenecroppingcalculator on first video
|
||||
// frame.
|
||||
@@ -417,11 +416,10 @@ mediapipe::Status SceneCroppingCalculator::Process(
|
||||
continue_last_scene_ = true;
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::Close(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status SceneCroppingCalculator::Close(mediapipe::CalculatorContext* cc) {
|
||||
if (!scene_frame_timestamps_.empty()) {
|
||||
MP_RETURN_IF_ERROR(ProcessScene(/* is_end_of_scene = */ true, cc));
|
||||
}
|
||||
@@ -435,12 +433,12 @@ mediapipe::Status SceneCroppingCalculator::Close(
|
||||
.Tag(kExternalRenderingFullVid)
|
||||
.Add(external_render_list_.release(), Timestamp::PostStream());
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// TODO: split this function into two, one for calculating the border
|
||||
// sizes, the other for the actual removal of borders from the frames.
|
||||
mediapipe::Status SceneCroppingCalculator::RemoveStaticBorders(
|
||||
absl::Status SceneCroppingCalculator::RemoveStaticBorders(
|
||||
CalculatorContext* cc, int* top_border_size, int* bottom_border_size) {
|
||||
*top_border_size = 0;
|
||||
*bottom_border_size = 0;
|
||||
@@ -492,10 +490,10 @@ mediapipe::Status SceneCroppingCalculator::RemoveStaticBorders(
|
||||
*key_frame_infos_[i].mutable_detections() = adjusted_detections;
|
||||
}
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::InitializeFrameCropRegionComputer() {
|
||||
absl::Status SceneCroppingCalculator::InitializeFrameCropRegionComputer() {
|
||||
key_frame_crop_options_ = options_.key_frame_crop_options();
|
||||
MP_RETURN_IF_ERROR(
|
||||
SetKeyFrameCropTarget(frame_width_, effective_frame_height_,
|
||||
@@ -504,7 +502,7 @@ mediapipe::Status SceneCroppingCalculator::InitializeFrameCropRegionComputer() {
|
||||
VLOG(1) << "Target height " << key_frame_crop_options_.target_height();
|
||||
frame_crop_region_computer_ =
|
||||
absl::make_unique<FrameCropRegionComputer>(key_frame_crop_options_);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void SceneCroppingCalculator::FilterKeyFrameInfo() {
|
||||
@@ -530,8 +528,8 @@ void SceneCroppingCalculator::FilterKeyFrameInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::ProcessScene(
|
||||
const bool is_end_of_scene, CalculatorContext* cc) {
|
||||
absl::Status SceneCroppingCalculator::ProcessScene(const bool is_end_of_scene,
|
||||
CalculatorContext* cc) {
|
||||
// Removes detections under special circumstances.
|
||||
FilterKeyFrameInfo();
|
||||
|
||||
@@ -653,10 +651,10 @@ mediapipe::Status SceneCroppingCalculator::ProcessScene(
|
||||
is_key_frames_.clear();
|
||||
static_features_.clear();
|
||||
static_features_timestamps_.clear();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::FormatAndOutputCroppedFrames(
|
||||
absl::Status SceneCroppingCalculator::FormatAndOutputCroppedFrames(
|
||||
const int crop_width, const int crop_height, const int num_frames,
|
||||
std::vector<cv::Rect>* render_to_locations, bool* apply_padding,
|
||||
std::vector<cv::Scalar>* padding_colors, float* vertical_fill_percent,
|
||||
@@ -729,7 +727,7 @@ mediapipe::Status SceneCroppingCalculator::FormatAndOutputCroppedFrames(
|
||||
padding_colors->push_back(padding_color_to_add);
|
||||
}
|
||||
if (!cropped_frames_ptr) {
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Resizes cropped frames, pads frames, and output frames.
|
||||
@@ -772,10 +770,10 @@ mediapipe::Status SceneCroppingCalculator::FormatAndOutputCroppedFrames(
|
||||
.Add(scaled_frame.release(), timestamp);
|
||||
}
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCroppingCalculator::OutputVizFrames(
|
||||
absl::Status SceneCroppingCalculator::OutputVizFrames(
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const std::vector<cv::Rect>& crop_from_locations,
|
||||
@@ -815,7 +813,7 @@ mediapipe::Status SceneCroppingCalculator::OutputVizFrames(
|
||||
.Add(viz_frames[i].release(), Timestamp(scene_frame_timestamps_[i]));
|
||||
}
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
REGISTER_CALCULATOR(SceneCroppingCalculator);
|
||||
|
||||
@@ -125,35 +125,34 @@ namespace autoflip {
|
||||
// fields are optional with default settings.
|
||||
class SceneCroppingCalculator : public CalculatorBase {
|
||||
public:
|
||||
static mediapipe::Status GetContract(CalculatorContract* cc);
|
||||
static absl::Status GetContract(CalculatorContract* cc);
|
||||
|
||||
// Validates calculator options and initializes SceneCameraMotionAnalyzer and
|
||||
// SceneCropper.
|
||||
mediapipe::Status Open(CalculatorContext* cc) override;
|
||||
absl::Status Open(CalculatorContext* cc) override;
|
||||
|
||||
// Buffers each scene frame and its timestamp. Packs and stores KeyFrameInfo
|
||||
// for key frames (a.k.a. frames with detection features). When a shot
|
||||
// boundary is encountered or when the buffer is full, calls ProcessScene()
|
||||
// to process the scene at once, and clears buffers.
|
||||
mediapipe::Status Process(CalculatorContext* cc) override;
|
||||
absl::Status Process(CalculatorContext* cc) override;
|
||||
|
||||
// Calls ProcessScene() on remaining buffered frames. Optionally outputs a
|
||||
// VideoCroppingSummary if the output stream CROPPING_SUMMARY is present.
|
||||
mediapipe::Status Close(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Close(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
// Removes any static borders from the scene frames before cropping. The
|
||||
// arguments |top_border_size| and |bottom_border_size| report the size of the
|
||||
// removed borders.
|
||||
mediapipe::Status RemoveStaticBorders(CalculatorContext* cc,
|
||||
int* top_border_size,
|
||||
int* bottom_border_size);
|
||||
absl::Status RemoveStaticBorders(CalculatorContext* cc, int* top_border_size,
|
||||
int* bottom_border_size);
|
||||
|
||||
// Sets up autoflip after first frame is received and input size is known.
|
||||
mediapipe::Status InitializeSceneCroppingCalculator(
|
||||
absl::Status InitializeSceneCroppingCalculator(
|
||||
mediapipe::CalculatorContext* cc);
|
||||
// Initializes a FrameCropRegionComputer given input and target frame sizes.
|
||||
mediapipe::Status InitializeFrameCropRegionComputer();
|
||||
absl::Status InitializeFrameCropRegionComputer();
|
||||
|
||||
// Processes a scene using buffered scene frames and KeyFrameInfos:
|
||||
// 1. Computes key frame crop regions using a FrameCropRegionComputer.
|
||||
@@ -165,8 +164,7 @@ class SceneCroppingCalculator : public CalculatorBase {
|
||||
// to force flush).
|
||||
// 6. Optionally outputs visualization frames.
|
||||
// 7. Optionally updates cropping summary.
|
||||
mediapipe::Status ProcessScene(const bool is_end_of_scene,
|
||||
CalculatorContext* cc);
|
||||
absl::Status ProcessScene(const bool is_end_of_scene, CalculatorContext* cc);
|
||||
|
||||
// Formats and outputs the cropped frames passed in through
|
||||
// |cropped_frames_ptr|. Scales them to be at least as big as the target
|
||||
@@ -177,14 +175,14 @@ class SceneCroppingCalculator : public CalculatorBase {
|
||||
// cropped frames. This is useful when the calculator is only used for
|
||||
// computing the cropping metadata rather than doing the actual cropping
|
||||
// operation.
|
||||
mediapipe::Status FormatAndOutputCroppedFrames(
|
||||
absl::Status FormatAndOutputCroppedFrames(
|
||||
const int crop_width, const int crop_height, const int num_frames,
|
||||
std::vector<cv::Rect>* render_to_locations, bool* apply_padding,
|
||||
std::vector<cv::Scalar>* padding_colors, float* vertical_fill_percent,
|
||||
const std::vector<cv::Mat>* cropped_frames_ptr, CalculatorContext* cc);
|
||||
|
||||
// Draws and outputs visualization frames if those streams are present.
|
||||
mediapipe::Status OutputVizFrames(
|
||||
absl::Status OutputVizFrames(
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const std::vector<cv::Rect>& crop_from_locations,
|
||||
|
||||
@@ -803,6 +803,7 @@ TEST(SceneCroppingCalculatorTest, OutputsCropMessageKinematicPath) {
|
||||
SceneCroppingCalculatorOptions::ext);
|
||||
auto* kinematic_options =
|
||||
options->mutable_camera_motion_options()->mutable_kinematic_options();
|
||||
kinematic_options->set_min_motion_to_reframe(1.2);
|
||||
kinematic_options->set_max_velocity(200);
|
||||
|
||||
auto runner = absl::make_unique<CalculatorRunner>(config);
|
||||
@@ -875,6 +876,7 @@ TEST(SceneCroppingCalculatorTest, OutputsCropMessageKinematicPathNoVideo) {
|
||||
SceneCroppingCalculatorOptions::ext);
|
||||
auto* kinematic_options =
|
||||
options->mutable_camera_motion_options()->mutable_kinematic_options();
|
||||
kinematic_options->set_min_motion_to_reframe(1.2);
|
||||
kinematic_options->set_max_velocity(2.0);
|
||||
|
||||
auto runner = absl::make_unique<CalculatorRunner>(config);
|
||||
|
||||
@@ -60,9 +60,9 @@ class ShotBoundaryCalculator : public mediapipe::CalculatorBase {
|
||||
ShotBoundaryCalculator(const ShotBoundaryCalculator&) = delete;
|
||||
ShotBoundaryCalculator& operator=(const ShotBoundaryCalculator&) = delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
// Computes the histogram of an image.
|
||||
@@ -98,12 +98,11 @@ void ShotBoundaryCalculator::ComputeHistogram(const cv::Mat& image,
|
||||
kHistogramBinNum, kHistogramRange, true, false);
|
||||
}
|
||||
|
||||
mediapipe::Status ShotBoundaryCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status ShotBoundaryCalculator::Open(mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<ShotBoundaryCalculatorOptions>();
|
||||
last_shot_timestamp_ = Timestamp(0);
|
||||
init_ = false;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void ShotBoundaryCalculator::Transmit(mediapipe::CalculatorContext* cc,
|
||||
@@ -127,8 +126,7 @@ void ShotBoundaryCalculator::Transmit(mediapipe::CalculatorContext* cc,
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status ShotBoundaryCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status ShotBoundaryCalculator::Process(mediapipe::CalculatorContext* cc) {
|
||||
// Connect to input frame and make a mutable copy.
|
||||
cv::Mat frame_org = mediapipe::formats::MatView(
|
||||
&cc->Inputs().Tag(kVideoInputTag).Get<ImageFrame>());
|
||||
@@ -142,7 +140,7 @@ mediapipe::Status ShotBoundaryCalculator::Process(
|
||||
last_histogram_ = current_histogram;
|
||||
init_ = true;
|
||||
Transmit(cc, false);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
double current_motion_estimate =
|
||||
@@ -152,7 +150,7 @@ mediapipe::Status ShotBoundaryCalculator::Process(
|
||||
|
||||
if (motion_history_.size() != options_.window_size()) {
|
||||
Transmit(cc, false);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Shot detection algorithm is a mixture of adaptive (controlled with
|
||||
@@ -176,14 +174,14 @@ mediapipe::Status ShotBoundaryCalculator::Process(
|
||||
// Store histogram for next frame.
|
||||
last_histogram_ = current_histogram;
|
||||
motion_history_.pop_back();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status ShotBoundaryCalculator::GetContract(
|
||||
absl::Status ShotBoundaryCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
cc->Inputs().Tag(kVideoInputTag).Set<ImageFrame>();
|
||||
cc->Outputs().Tag(kShotChangeTag).Set<bool>();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "mediapipe/framework/deps/file_path.h"
|
||||
#include "mediapipe/framework/formats/image_frame.h"
|
||||
#include "mediapipe/framework/formats/image_frame_opencv.h"
|
||||
#include "mediapipe/framework/port/commandlineflags.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
#include "mediapipe/framework/port/gtest.h"
|
||||
#include "mediapipe/framework/port/opencv_core_inc.h"
|
||||
|
||||
@@ -105,13 +105,13 @@ class SignalFusingCalculator : public mediapipe::CalculatorBase {
|
||||
SignalFusingCalculator(const SignalFusingCalculator&) = delete;
|
||||
SignalFusingCalculator& operator=(const SignalFusingCalculator&) = delete;
|
||||
|
||||
static mediapipe::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
mediapipe::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
mediapipe::Status Close(mediapipe::CalculatorContext* cc) override;
|
||||
static absl::Status GetContract(mediapipe::CalculatorContract* cc);
|
||||
absl::Status Open(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Process(mediapipe::CalculatorContext* cc) override;
|
||||
absl::Status Close(mediapipe::CalculatorContext* cc) override;
|
||||
|
||||
private:
|
||||
mediapipe::Status ProcessScene(mediapipe::CalculatorContext* cc);
|
||||
absl::Status ProcessScene(mediapipe::CalculatorContext* cc);
|
||||
std::vector<Packet> GetSignalPackets(mediapipe::CalculatorContext* cc);
|
||||
SignalFusingCalculatorOptions options_;
|
||||
std::map<std::string, SignalSettings> settings_by_type_;
|
||||
@@ -154,8 +154,7 @@ void SetupOrderedInput(mediapipe::CalculatorContract* cc) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
mediapipe::Status SignalFusingCalculator::Open(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status SignalFusingCalculator::Open(mediapipe::CalculatorContext* cc) {
|
||||
options_ = cc->Options<SignalFusingCalculatorOptions>();
|
||||
for (const auto& setting : options_.signal_settings()) {
|
||||
settings_by_type_[CreateSettingsKey(setting.type())] = setting;
|
||||
@@ -166,19 +165,18 @@ mediapipe::Status SignalFusingCalculator::Open(
|
||||
process_by_scene_ = false;
|
||||
}
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SignalFusingCalculator::Close(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status SignalFusingCalculator::Close(mediapipe::CalculatorContext* cc) {
|
||||
if (!scene_frames_.empty()) {
|
||||
MP_RETURN_IF_ERROR(ProcessScene(cc));
|
||||
scene_frames_.clear();
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SignalFusingCalculator::ProcessScene(
|
||||
absl::Status SignalFusingCalculator::ProcessScene(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
std::map<std::string, int> detection_count;
|
||||
std::map<std::string, float> multiframe_score;
|
||||
@@ -240,7 +238,7 @@ mediapipe::Status SignalFusingCalculator::ProcessScene(
|
||||
}
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
std::vector<Packet> SignalFusingCalculator::GetSignalPackets(
|
||||
@@ -260,8 +258,7 @@ std::vector<Packet> SignalFusingCalculator::GetSignalPackets(
|
||||
return signal_packets;
|
||||
}
|
||||
|
||||
mediapipe::Status SignalFusingCalculator::Process(
|
||||
mediapipe::CalculatorContext* cc) {
|
||||
absl::Status SignalFusingCalculator::Process(mediapipe::CalculatorContext* cc) {
|
||||
bool is_boundary = false;
|
||||
if (process_by_scene_) {
|
||||
const auto& shot_tag = (tag_input_interface_)
|
||||
@@ -302,17 +299,17 @@ mediapipe::Status SignalFusingCalculator::Process(
|
||||
scene_frames_.clear();
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SignalFusingCalculator::GetContract(
|
||||
absl::Status SignalFusingCalculator::GetContract(
|
||||
mediapipe::CalculatorContract* cc) {
|
||||
if (cc->Inputs().NumEntries(kSignalInputsTag) > 0) {
|
||||
SetupTagInput(cc);
|
||||
} else {
|
||||
SetupOrderedInput(cc);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -57,20 +57,19 @@ class VideoFilteringCalculator : public CalculatorBase {
|
||||
VideoFilteringCalculator() = default;
|
||||
~VideoFilteringCalculator() override = default;
|
||||
|
||||
static mediapipe::Status GetContract(CalculatorContract* cc);
|
||||
static absl::Status GetContract(CalculatorContract* cc);
|
||||
|
||||
mediapipe::Status Process(CalculatorContext* cc) override;
|
||||
absl::Status Process(CalculatorContext* cc) override;
|
||||
};
|
||||
REGISTER_CALCULATOR(VideoFilteringCalculator);
|
||||
|
||||
mediapipe::Status VideoFilteringCalculator::GetContract(
|
||||
CalculatorContract* cc) {
|
||||
absl::Status VideoFilteringCalculator::GetContract(CalculatorContract* cc) {
|
||||
cc->Inputs().Tag(kInputFrameTag).Set<ImageFrame>();
|
||||
cc->Outputs().Tag(kOutputFrameTag).Set<ImageFrame>();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status VideoFilteringCalculator::Process(CalculatorContext* cc) {
|
||||
absl::Status VideoFilteringCalculator::Process(CalculatorContext* cc) {
|
||||
const auto& options = cc->Options<VideoFilteringCalculatorOptions>();
|
||||
|
||||
const Packet& input_packet = cc->Inputs().Tag(kInputFrameTag).Value();
|
||||
@@ -84,7 +83,7 @@ mediapipe::Status VideoFilteringCalculator::Process(CalculatorContext* cc) {
|
||||
if (filter_type ==
|
||||
VideoFilteringCalculatorOptions::AspectRatioFilter::NO_FILTERING) {
|
||||
cc->Outputs().Tag(kOutputFrameTag).AddPacket(input_packet);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
const int target_width = options.aspect_ratio_filter().target_width();
|
||||
const int target_height = options.aspect_ratio_filter().target_height();
|
||||
@@ -106,7 +105,7 @@ mediapipe::Status VideoFilteringCalculator::Process(CalculatorContext* cc) {
|
||||
}
|
||||
if (should_pass) {
|
||||
cc->Outputs().Tag(kOutputFrameTag).AddPacket(input_packet);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
if (options.fail_if_any()) {
|
||||
return mediapipe::UnknownErrorBuilder(MEDIAPIPE_LOC) << absl::Substitute(
|
||||
@@ -115,7 +114,7 @@ mediapipe::Status VideoFilteringCalculator::Process(CalculatorContext* cc) {
|
||||
target_ratio, frame.Width(), frame.Height());
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} // namespace autoflip
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -166,8 +166,8 @@ TEST(VerticalFrameRemovalCalculatorTest, OutputError) {
|
||||
runner->MutableInputs()
|
||||
->Tag("INPUT_FRAMES")
|
||||
.packets.push_back(Adopt(input_frame.release()).At(Timestamp(1000)));
|
||||
mediapipe::Status status = runner->Run();
|
||||
EXPECT_EQ(status.code(), mediapipe::StatusCode::kUnknown);
|
||||
absl::Status status = runner->Run();
|
||||
EXPECT_EQ(status.code(), absl::StatusCode::kUnknown);
|
||||
EXPECT_THAT(status.ToString(),
|
||||
::testing::HasSubstr("Failing due to aspect ratio"));
|
||||
}
|
||||
|
||||
@@ -249,6 +249,7 @@ cc_test(
|
||||
":scene_camera_motion_analyzer",
|
||||
"//mediapipe/examples/desktop/autoflip:autoflip_messages_cc_proto",
|
||||
"//mediapipe/framework/deps:file_path",
|
||||
"//mediapipe/framework/port:commandlineflags",
|
||||
"//mediapipe/framework/port:file_helpers",
|
||||
"//mediapipe/framework/port:gtest_main",
|
||||
"//mediapipe/framework/port:status",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
namespace mediapipe {
|
||||
namespace autoflip {
|
||||
|
||||
mediapipe::Status FrameCropRegionComputer::ExpandSegmentUnderConstraint(
|
||||
absl::Status FrameCropRegionComputer::ExpandSegmentUnderConstraint(
|
||||
const Segment& segment_to_add, const Segment& base_segment,
|
||||
const int max_length, Segment* combined_segment,
|
||||
CoverType* cover_type) const {
|
||||
@@ -75,10 +75,10 @@ mediapipe::Status FrameCropRegionComputer::ExpandSegmentUnderConstraint(
|
||||
|
||||
*combined_segment =
|
||||
std::make_pair(combined_segment_left, combined_segment_right);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status FrameCropRegionComputer::ExpandRectUnderConstraints(
|
||||
absl::Status FrameCropRegionComputer::ExpandRectUnderConstraints(
|
||||
const Rect& rect_to_add, const int max_width, const int max_height,
|
||||
Rect* base_rect, CoverType* cover_type) const {
|
||||
RET_CHECK(base_rect != nullptr) << "Base rect is null.";
|
||||
@@ -129,7 +129,7 @@ mediapipe::Status FrameCropRegionComputer::ExpandRectUnderConstraints(
|
||||
}
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void FrameCropRegionComputer::UpdateCropRegionScore(
|
||||
@@ -167,7 +167,7 @@ void FrameCropRegionComputer::UpdateCropRegionScore(
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status FrameCropRegionComputer::ComputeFrameCropRegion(
|
||||
absl::Status FrameCropRegionComputer::ComputeFrameCropRegion(
|
||||
const KeyFrameInfo& frame_info, KeyFrameCropResult* crop_result) const {
|
||||
RET_CHECK(crop_result != nullptr) << "KeyFrameCropResult is null.";
|
||||
|
||||
@@ -254,7 +254,7 @@ mediapipe::Status FrameCropRegionComputer::ComputeFrameCropRegion(
|
||||
|
||||
crop_result->set_region_is_empty(crop_region_is_empty);
|
||||
crop_result->set_region_score(crop_region_score);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -43,8 +43,8 @@ class FrameCropRegionComputer {
|
||||
// consider static features, and simply tries to fit the detected features
|
||||
// within the target frame size. The score of the crop region is aggregated
|
||||
// from individual feature scores given the score aggregation type.
|
||||
mediapipe::Status ComputeFrameCropRegion(
|
||||
const KeyFrameInfo& frame_info, KeyFrameCropResult* crop_result) const;
|
||||
absl::Status ComputeFrameCropRegion(const KeyFrameInfo& frame_info,
|
||||
KeyFrameCropResult* crop_result) const;
|
||||
|
||||
protected:
|
||||
// A segment is a 1-d object defined by its left and right point.
|
||||
@@ -75,11 +75,11 @@ class FrameCropRegionComputer {
|
||||
// fraction of the new segment exceeds the maximum length.
|
||||
// In this case the combined segment is the base segment, and cover
|
||||
// type is NOT_COVERED.
|
||||
mediapipe::Status ExpandSegmentUnderConstraint(const Segment& segment_to_add,
|
||||
const Segment& base_segment,
|
||||
const int max_length,
|
||||
Segment* combined_segment,
|
||||
CoverType* cover_type) const;
|
||||
absl::Status ExpandSegmentUnderConstraint(const Segment& segment_to_add,
|
||||
const Segment& base_segment,
|
||||
const int max_length,
|
||||
Segment* combined_segment,
|
||||
CoverType* cover_type) const;
|
||||
|
||||
// Expands a base rectangle to cover a new rectangle to be added under width
|
||||
// and height constraints. The operation is best-effort. It considers
|
||||
@@ -88,11 +88,10 @@ class FrameCropRegionComputer {
|
||||
// FULLY_COVERED if the new rectangle is fully covered in both directions,
|
||||
// PARTIALLY_COVERED if it is at least partially covered in both directions,
|
||||
// and NOT_COVERED if it is not covered in either direction.
|
||||
mediapipe::Status ExpandRectUnderConstraints(const Rect& rect_to_add,
|
||||
const int max_width,
|
||||
const int max_height,
|
||||
Rect* base_rect,
|
||||
CoverType* cover_type) const;
|
||||
absl::Status ExpandRectUnderConstraints(const Rect& rect_to_add,
|
||||
const int max_width,
|
||||
const int max_height, Rect* base_rect,
|
||||
CoverType* cover_type) const;
|
||||
|
||||
// Updates crop region score given current feature score, whether the feature
|
||||
// is required, and the score aggregation type. Ignores negative scores.
|
||||
|
||||
@@ -14,10 +14,66 @@ int Median(const std::deque<std::pair<uint64, int>>& positions_raw) {
|
||||
return positions[n];
|
||||
}
|
||||
} // namespace
|
||||
mediapipe::Status KinematicPathSolver::AddObservation(int position,
|
||||
const uint64 time_us) {
|
||||
bool KinematicPathSolver::IsMotionTooSmall(double delta_degs) {
|
||||
if (options_.has_min_motion_to_reframe()) {
|
||||
return abs(delta_degs) < options_.min_motion_to_reframe();
|
||||
} else if (delta_degs > 0) {
|
||||
return delta_degs < options_.min_motion_to_reframe_upper();
|
||||
} else {
|
||||
return abs(delta_degs) < options_.min_motion_to_reframe_lower();
|
||||
}
|
||||
}
|
||||
void KinematicPathSolver::ClearHistory() { raw_positions_at_time_.clear(); }
|
||||
absl::Status KinematicPathSolver::PredictMotionState(int position,
|
||||
const uint64 time_us,
|
||||
bool* state) {
|
||||
if (!initialized_) {
|
||||
current_position_px_ = position;
|
||||
*state = false;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
auto raw_positions_at_time_copy = raw_positions_at_time_;
|
||||
|
||||
raw_positions_at_time_copy.push_front(
|
||||
std::pair<uint64, int>(time_us, position));
|
||||
while (raw_positions_at_time_copy.size() > 1) {
|
||||
if (static_cast<int64>(raw_positions_at_time_copy.back().first) <
|
||||
static_cast<int64>(time_us) - options_.filtering_time_window_us()) {
|
||||
raw_positions_at_time_copy.pop_back();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int filtered_position = Median(raw_positions_at_time_copy);
|
||||
double delta_degs =
|
||||
(filtered_position - current_position_px_) / pixels_per_degree_;
|
||||
|
||||
// If the motion is smaller than the min_motion_to_reframe and camera is
|
||||
// stationary, don't use the update.
|
||||
if (IsMotionTooSmall(delta_degs) && !motion_state_) {
|
||||
*state = false;
|
||||
} else if (abs(delta_degs) < options_.reframe_window() && motion_state_) {
|
||||
// If the motion is smaller than the reframe_window and camera is moving,
|
||||
// don't use the update.
|
||||
*state = false;
|
||||
} else {
|
||||
// Apply new position, plus the reframe window size.
|
||||
*state = true;
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
absl::Status KinematicPathSolver::AddObservation(int position,
|
||||
const uint64 time_us) {
|
||||
if (!initialized_) {
|
||||
if (position < min_location_) {
|
||||
current_position_px_ = min_location_;
|
||||
} else if (position > max_location_) {
|
||||
current_position_px_ = max_location_;
|
||||
} else {
|
||||
current_position_px_ = position;
|
||||
}
|
||||
target_position_px_ = position;
|
||||
motion_state_ = false;
|
||||
mean_delta_t_ = -1;
|
||||
@@ -30,13 +86,27 @@ mediapipe::Status KinematicPathSolver::AddObservation(int position,
|
||||
<< "pixels_per_degree must be larger than 0.";
|
||||
RET_CHECK_GE(options_.update_rate_seconds(), 0)
|
||||
<< "update_rate_seconds must be greater than 0.";
|
||||
RET_CHECK_GE(options_.min_motion_to_reframe(), options_.reframe_window())
|
||||
<< "Reframe window cannot exceed min_motion_to_reframe.";
|
||||
RET_CHECK_GE(options_.filtering_time_window_us(), 0)
|
||||
<< "update_rate_seconds must be greater than 0.";
|
||||
RET_CHECK_GE(options_.mean_period_update_rate(), 0)
|
||||
<< "mean_period_update_rate must be greater than 0.";
|
||||
return mediapipe::OkStatus();
|
||||
RET_CHECK(options_.has_min_motion_to_reframe() ^
|
||||
(options_.has_min_motion_to_reframe_upper() &&
|
||||
options_.has_min_motion_to_reframe_lower()))
|
||||
<< "Must set min_motion_to_reframe or min_motion_to_reframe_upper and "
|
||||
"min_motion_to_reframe_lower.";
|
||||
if (options_.has_min_motion_to_reframe()) {
|
||||
RET_CHECK_GE(options_.min_motion_to_reframe(), options_.reframe_window())
|
||||
<< "Reframe window cannot exceed min_motion_to_reframe.";
|
||||
} else {
|
||||
RET_CHECK_GE(options_.min_motion_to_reframe_upper(),
|
||||
options_.reframe_window())
|
||||
<< "Reframe window cannot exceed min_motion_to_reframe.";
|
||||
RET_CHECK_GE(options_.min_motion_to_reframe_lower(),
|
||||
options_.reframe_window())
|
||||
<< "Reframe window cannot exceed min_motion_to_reframe.";
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
RET_CHECK(current_time_ < time_us)
|
||||
@@ -58,7 +128,7 @@ mediapipe::Status KinematicPathSolver::AddObservation(int position,
|
||||
|
||||
// If the motion is smaller than the min_motion_to_reframe and camera is
|
||||
// stationary, don't use the update.
|
||||
if (abs(delta_degs) < options_.min_motion_to_reframe() && !motion_state_) {
|
||||
if (IsMotionTooSmall(delta_degs) && !motion_state_) {
|
||||
delta_degs = 0;
|
||||
motion_state_ = false;
|
||||
} else if (abs(delta_degs) < options_.reframe_window() && motion_state_) {
|
||||
@@ -100,7 +170,7 @@ mediapipe::Status KinematicPathSolver::AddObservation(int position,
|
||||
return UpdatePrediction(time_us);
|
||||
}
|
||||
|
||||
mediapipe::Status KinematicPathSolver::UpdatePrediction(const int64 time_us) {
|
||||
absl::Status KinematicPathSolver::UpdatePrediction(const int64 time_us) {
|
||||
RET_CHECK(current_time_ < time_us)
|
||||
<< "Prediction time added before a prior observation or prediction.";
|
||||
|
||||
@@ -122,36 +192,58 @@ mediapipe::Status KinematicPathSolver::UpdatePrediction(const int64 time_us) {
|
||||
if (update_position_px < min_location_) {
|
||||
current_position_px_ = min_location_;
|
||||
current_velocity_deg_per_s_ = 0;
|
||||
motion_state_ = false;
|
||||
} else if (update_position_px > max_location_) {
|
||||
current_position_px_ = max_location_;
|
||||
current_velocity_deg_per_s_ = 0;
|
||||
motion_state_ = false;
|
||||
} else {
|
||||
current_position_px_ = update_position_px;
|
||||
}
|
||||
current_time_ = time_us;
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status KinematicPathSolver::GetState(int* position) {
|
||||
absl::Status KinematicPathSolver::GetState(int* position) {
|
||||
RET_CHECK(initialized_) << "GetState called before first observation added.";
|
||||
*position = round(current_position_px_);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status KinematicPathSolver::GetTargetPosition(int* target_position) {
|
||||
absl::Status KinematicPathSolver::GetTargetPosition(int* target_position) {
|
||||
RET_CHECK(initialized_)
|
||||
<< "GetTargetPosition called before first observation added.";
|
||||
*target_position = round(target_position_px_);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status KinematicPathSolver::UpdatePixelsPerDegree(
|
||||
absl::Status KinematicPathSolver::UpdatePixelsPerDegree(
|
||||
const float pixels_per_degree) {
|
||||
RET_CHECK_GT(pixels_per_degree_, 0)
|
||||
<< "pixels_per_degree must be larger than 0.";
|
||||
pixels_per_degree_ = pixels_per_degree;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status KinematicPathSolver::UpdateMinMaxLocation(const int min_location,
|
||||
const int max_location) {
|
||||
RET_CHECK(initialized_)
|
||||
<< "UpdateMinMaxLocation called before first observation added.";
|
||||
double prior_distance = max_location_ - min_location_;
|
||||
double updated_distance = max_location - min_location;
|
||||
double scale_change = updated_distance / prior_distance;
|
||||
current_position_px_ = current_position_px_ * scale_change;
|
||||
target_position_px_ = target_position_px_ * scale_change;
|
||||
max_location_ = max_location;
|
||||
min_location_ = min_location;
|
||||
auto original_positions_at_time = raw_positions_at_time_;
|
||||
raw_positions_at_time_.clear();
|
||||
for (auto position_at_time : original_positions_at_time) {
|
||||
position_at_time.second = position_at_time.second * scale_change;
|
||||
raw_positions_at_time_.push_front(position_at_time);
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -43,22 +43,34 @@ class KinematicPathSolver {
|
||||
initialized_(false),
|
||||
pixels_per_degree_(pixels_per_degree) {}
|
||||
// Add an observation (detection) at a position and time.
|
||||
mediapipe::Status AddObservation(int position, const uint64 time_us);
|
||||
absl::Status AddObservation(int position, const uint64 time_us);
|
||||
// Get the predicted position at a time.
|
||||
mediapipe::Status UpdatePrediction(const int64 time_us);
|
||||
absl::Status UpdatePrediction(const int64 time_us);
|
||||
// Get the state at a time.
|
||||
mediapipe::Status GetState(int* position);
|
||||
absl::Status GetState(int* position);
|
||||
// Update PixelPerDegree value.
|
||||
mediapipe::Status UpdatePixelsPerDegree(const float pixels_per_degree);
|
||||
absl::Status UpdatePixelsPerDegree(const float pixels_per_degree);
|
||||
// Provide the current target position of the reframe action.
|
||||
mediapipe::Status GetTargetPosition(int* target_position);
|
||||
absl::Status GetTargetPosition(int* target_position);
|
||||
// Change min/max location and update state based on new scaling.
|
||||
absl::Status UpdateMinMaxLocation(const int min_location,
|
||||
const int max_location);
|
||||
// Check if motion is within the reframe window, return false if not.
|
||||
bool IsMotionTooSmall(double delta_degs);
|
||||
// Check if a position measurement will cause the camera to be in motion
|
||||
// without updating the internal state.
|
||||
absl::Status PredictMotionState(int position, const uint64 time_us,
|
||||
bool* state);
|
||||
// Clear any history buffer of positions that are used when
|
||||
// filtering_time_window_us is set to a non-zero value.
|
||||
void ClearHistory();
|
||||
|
||||
private:
|
||||
// Tuning options.
|
||||
KinematicOptions options_;
|
||||
// Min and max value the state can be.
|
||||
const int min_location_;
|
||||
const int max_location_;
|
||||
int min_location_;
|
||||
int max_location_;
|
||||
bool initialized_;
|
||||
float pixels_per_degree_;
|
||||
// Current state values.
|
||||
|
||||
@@ -8,8 +8,14 @@ message KinematicOptions {
|
||||
optional double update_rate = 1 [default = 0.5, deprecated = true];
|
||||
// Max velocity (degrees per second) that the camera can move.
|
||||
optional double max_velocity = 2 [default = 18];
|
||||
// Min motion (in degrees) to react in pixels.
|
||||
optional float min_motion_to_reframe = 3 [default = 1.8];
|
||||
// Min motion (in degrees) to react for both upper and lower directions. Must
|
||||
// not be set if using min_motion_to_reframe_lower and
|
||||
// min_motion_to_reframe_upper.
|
||||
optional float min_motion_to_reframe = 3;
|
||||
// Min motion (in degrees) for upper and lower direction to react. Both must
|
||||
// be set and min_motion_to_reframe cannot be set if these are specified.
|
||||
optional float min_motion_to_reframe_lower = 9;
|
||||
optional float min_motion_to_reframe_upper = 10;
|
||||
// When motion exceeds min_motion_to_reframe, move within this distance of the
|
||||
// camera from the starting direction. Setting this value non-zero reduces
|
||||
// total reframe distance on average. Value cannot exceed
|
||||
|
||||
@@ -190,6 +190,50 @@ TEST(KinematicPathSolverTest, PassReframeWindow) {
|
||||
EXPECT_EQ(state, 508);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassReframeWindowLowerUpper) {
|
||||
KinematicOptions options;
|
||||
// Set min motion to 1deg
|
||||
options.set_min_motion_to_reframe_upper(1.3);
|
||||
options.set_min_motion_to_reframe_lower(1.0);
|
||||
options.set_update_rate_seconds(.0000001);
|
||||
options.set_max_update_rate(1.0);
|
||||
options.set_max_velocity(1000);
|
||||
// Set reframe window size to .75 for test.
|
||||
options.set_reframe_window(0.75);
|
||||
// Set degrees / pixel to 16.6
|
||||
KinematicPathSolver solver(options, 0, 1000, 1000.0 / kWidthFieldOfView);
|
||||
int state;
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 0));
|
||||
// Move target by 20px / 16.6 = 1.2deg
|
||||
MP_ASSERT_OK(solver.AddObservation(520, kMicroSecInSec * 1));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
// Expect cam to not move
|
||||
EXPECT_EQ(state, 500);
|
||||
MP_ASSERT_OK(solver.AddObservation(480, kMicroSecInSec * 2));
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
// Expect cam to move
|
||||
EXPECT_EQ(state, 493);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassCheckState) {
|
||||
KinematicOptions options;
|
||||
// Set min motion to 1deg
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
options.set_update_rate_seconds(.0000001);
|
||||
options.set_max_update_rate(1.0);
|
||||
options.set_max_velocity(1000);
|
||||
// Set reframe window size to .75 for test.
|
||||
options.set_reframe_window(0.75);
|
||||
// Set degrees / pixel to 16.6
|
||||
KinematicPathSolver solver(options, 0, 1000, 1000.0 / kWidthFieldOfView);
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 0));
|
||||
// Move target by 20px / 16.6 = 1.2deg
|
||||
bool motion_state;
|
||||
MP_ASSERT_OK(
|
||||
solver.PredictMotionState(520, kMicroSecInSec * 1, &motion_state));
|
||||
EXPECT_TRUE(motion_state);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassUpdateRate30FPS) {
|
||||
KinematicOptions options;
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
@@ -238,6 +282,26 @@ TEST(KinematicPathSolverTest, PassUpdateRate) {
|
||||
EXPECT_EQ(state, 505);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassUpdateRateResolutionChange) {
|
||||
KinematicOptions options;
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
options.set_update_rate_seconds(4);
|
||||
options.set_max_update_rate(1.0);
|
||||
options.set_max_velocity(18);
|
||||
KinematicPathSolver solver(options, 0, 1000, 1000.0 / kWidthFieldOfView);
|
||||
int state, target_position;
|
||||
MP_ASSERT_OK(solver.AddObservation(500, kMicroSecInSec * 0));
|
||||
MP_ASSERT_OK(solver.GetTargetPosition(&target_position));
|
||||
EXPECT_EQ(target_position, 500);
|
||||
MP_ASSERT_OK(solver.UpdateMinMaxLocation(0, 500));
|
||||
MP_ASSERT_OK(solver.UpdatePixelsPerDegree(500.0 / kWidthFieldOfView));
|
||||
MP_ASSERT_OK(solver.AddObservation(520 * 0.5, kMicroSecInSec * 1));
|
||||
MP_ASSERT_OK(solver.GetTargetPosition(&target_position));
|
||||
EXPECT_EQ(target_position, 520 * 0.5);
|
||||
MP_ASSERT_OK(solver.GetState(&state));
|
||||
EXPECT_EQ(state, 253);
|
||||
}
|
||||
|
||||
TEST(KinematicPathSolverTest, PassMaxVelocity) {
|
||||
KinematicOptions options;
|
||||
options.set_min_motion_to_reframe(1.0);
|
||||
|
||||
@@ -45,7 +45,7 @@ PaddingEffectGenerator::PaddingEffectGenerator(const int input_width,
|
||||
}
|
||||
}
|
||||
|
||||
mediapipe::Status PaddingEffectGenerator::Process(
|
||||
absl::Status PaddingEffectGenerator::Process(
|
||||
const ImageFrame& input_frame, const float background_contrast,
|
||||
const int blur_cv_size, const float overlay_opacity,
|
||||
ImageFrame* output_frame, const cv::Scalar* background_color_in_rgb) {
|
||||
@@ -170,7 +170,7 @@ mediapipe::Status PaddingEffectGenerator::Process(
|
||||
output_frame->CopyPixelData(input_frame.Format(), canvas.cols, canvas.rows,
|
||||
canvas.data,
|
||||
ImageFrame::kDefaultAlignmentBoundary);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
cv::Rect PaddingEffectGenerator::ComputeOutputLocation() {
|
||||
|
||||
@@ -49,11 +49,10 @@ class PaddingEffectGenerator {
|
||||
// the opacity of the black layer.
|
||||
// - background_color_in_rgb: If not null, uses this solid color as background
|
||||
// instead of blurring the image, and does not adjust contrast or opacity.
|
||||
mediapipe::Status Process(
|
||||
const ImageFrame& input_frame, const float background_contrast,
|
||||
const int blur_cv_size, const float overlay_opacity,
|
||||
ImageFrame* output_frame,
|
||||
const cv::Scalar* background_color_in_rgb = nullptr);
|
||||
absl::Status Process(const ImageFrame& input_frame,
|
||||
const float background_contrast, const int blur_cv_size,
|
||||
const float overlay_opacity, ImageFrame* output_frame,
|
||||
const cv::Scalar* background_color_in_rgb = nullptr);
|
||||
|
||||
// Compute the "render location" on the output frame where the "crop from"
|
||||
// location is to be placed. For use with external rendering soutions.
|
||||
|
||||
@@ -48,12 +48,14 @@ const cv::Scalar kRed = cv::Scalar(255, 0, 0);
|
||||
void TestWithAspectRatio(const double aspect_ratio,
|
||||
const cv::Scalar* background_color_in_rgb = nullptr) {
|
||||
std::string test_image;
|
||||
const bool process_arbitrary_image = !FLAGS_input_image.empty();
|
||||
const bool process_arbitrary_image =
|
||||
!absl::GetFlag(FLAGS_input_image).empty();
|
||||
if (!process_arbitrary_image) {
|
||||
std::string test_image_path = mediapipe::file::JoinPath("./", kTestImage);
|
||||
MP_ASSERT_OK(mediapipe::file::GetContents(test_image_path, &test_image));
|
||||
} else {
|
||||
MP_ASSERT_OK(mediapipe::file::GetContents(FLAGS_input_image, &test_image));
|
||||
MP_ASSERT_OK(mediapipe::file::GetContents(absl::GetFlag(FLAGS_input_image),
|
||||
&test_image));
|
||||
}
|
||||
|
||||
const std::vector<char> contents_vector(test_image.begin(), test_image.end());
|
||||
@@ -138,7 +140,7 @@ void TestWithAspectRatio(const double aspect_ratio,
|
||||
EXPECT_EQ(result_image, output_string);
|
||||
} else {
|
||||
std::string output_string_path = mediapipe::file::JoinPath(
|
||||
FLAGS_output_folder,
|
||||
absl::GetFlag(FLAGS_output_folder),
|
||||
absl::StrCat("result_", aspect_ratio,
|
||||
background_color_in_rgb ? "_solid_background" : "",
|
||||
".jpg"));
|
||||
|
||||
@@ -91,7 +91,7 @@ void PolynomialRegressionPathSolver::AddCostFunctionToProblem(
|
||||
problem->AddResidualBlock(cost_function, new CauchyLoss(0.5), a, b, c, d, k);
|
||||
}
|
||||
|
||||
mediapipe::Status PolynomialRegressionPathSolver::ComputeCameraPath(
|
||||
absl::Status PolynomialRegressionPathSolver::ComputeCameraPath(
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const std::vector<FocusPointFrame>& prior_focus_point_frames,
|
||||
const int original_width, const int original_height, const int output_width,
|
||||
@@ -163,7 +163,7 @@ mediapipe::Status PolynomialRegressionPathSolver::ComputeCameraPath(
|
||||
}
|
||||
all_transforms->push_back(transform);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -42,7 +42,7 @@ class PolynomialRegressionPathSolver {
|
||||
// y-axis, such that focus points can be preserved as much as possible. The
|
||||
// returned |all_transforms| hold the camera location at each timestamp
|
||||
// corresponding to each input frame.
|
||||
mediapipe::Status ComputeCameraPath(
|
||||
absl::Status ComputeCameraPath(
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const std::vector<FocusPointFrame>& prior_focus_point_frames,
|
||||
const int original_width, const int original_height,
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
namespace mediapipe {
|
||||
namespace autoflip {
|
||||
|
||||
mediapipe::Status
|
||||
SceneCameraMotionAnalyzer::AnalyzeSceneAndPopulateFocusPointFrames(
|
||||
absl::Status SceneCameraMotionAnalyzer::AnalyzeSceneAndPopulateFocusPointFrames(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const int scene_frame_width, const int scene_frame_height,
|
||||
@@ -67,7 +66,7 @@ SceneCameraMotionAnalyzer::AnalyzeSceneAndPopulateFocusPointFrames(
|
||||
scene_frame_timestamps, focus_point_frames);
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCameraMotionAnalyzer::ToUseSteadyMotion(
|
||||
absl::Status SceneCameraMotionAnalyzer::ToUseSteadyMotion(
|
||||
const float look_at_center_x, const float look_at_center_y,
|
||||
const int crop_window_width, const int crop_window_height,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
@@ -77,10 +76,10 @@ mediapipe::Status SceneCameraMotionAnalyzer::ToUseSteadyMotion(
|
||||
auto* steady_motion = scene_camera_motion->mutable_steady_motion();
|
||||
steady_motion->set_steady_look_at_center_x(look_at_center_x);
|
||||
steady_motion->set_steady_look_at_center_y(look_at_center_y);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCameraMotionAnalyzer::ToUseSweepingMotion(
|
||||
absl::Status SceneCameraMotionAnalyzer::ToUseSweepingMotion(
|
||||
const float start_x, const float start_y, const float end_x,
|
||||
const float end_y, const int crop_window_width,
|
||||
const int crop_window_height, const double time_duration_in_sec,
|
||||
@@ -99,10 +98,10 @@ mediapipe::Status SceneCameraMotionAnalyzer::ToUseSweepingMotion(
|
||||
scene_summary->frame_success_rate(), start_x, start_y, end_x, end_y,
|
||||
time_duration_in_sec);
|
||||
VLOG(1) << sweeping_log;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCameraMotionAnalyzer::DecideCameraMotionType(
|
||||
absl::Status SceneCameraMotionAnalyzer::DecideCameraMotionType(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const double scene_span_sec, const int64 end_time_us,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
@@ -131,7 +130,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::DecideCameraMotionType(
|
||||
no_salient_position_x, no_salient_position_y,
|
||||
scene_summary->crop_window_width(), scene_summary->crop_window_height(),
|
||||
scene_summary, scene_camera_motion));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Sweep across the scene when 1) success rate is too low, AND 2) the current
|
||||
@@ -164,7 +163,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::DecideCameraMotionType(
|
||||
start_x, start_y, end_x, end_y, key_frame_crop_options.target_width(),
|
||||
key_frame_crop_options.target_height(), scene_span_sec, scene_summary,
|
||||
scene_camera_motion));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// If scene motion is small, then look at a steady point in the scene.
|
||||
@@ -179,14 +178,14 @@ mediapipe::Status SceneCameraMotionAnalyzer::DecideCameraMotionType(
|
||||
|
||||
// Otherwise, tracks the focus regions.
|
||||
scene_camera_motion->mutable_tracking_motion();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// If there is no required focus region, looks at the middle of the center
|
||||
// range, and snaps to the scene center if close. Otherwise, look at the center
|
||||
// of the union of the required focus regions, and ensures the crop region
|
||||
// covers this union.
|
||||
mediapipe::Status SceneCameraMotionAnalyzer::DecideSteadyLookAtRegion(
|
||||
absl::Status SceneCameraMotionAnalyzer::DecideSteadyLookAtRegion(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
SceneCameraMotion* scene_camera_motion) const {
|
||||
@@ -252,11 +251,10 @@ mediapipe::Status SceneCameraMotionAnalyzer::DecideSteadyLookAtRegion(
|
||||
MP_RETURN_IF_ERROR(ToUseSteadyMotion(center_x, center_y, crop_width,
|
||||
crop_height, scene_summary,
|
||||
scene_camera_motion));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status
|
||||
SceneCameraMotionAnalyzer::AddFocusPointsFromCenterTypeAndWeight(
|
||||
absl::Status SceneCameraMotionAnalyzer::AddFocusPointsFromCenterTypeAndWeight(
|
||||
const float center_x, const float center_y, const int frame_width,
|
||||
const int frame_height, const FocusPointFrameType type, const float weight,
|
||||
const float bound, FocusPointFrame* focus_point_frame) const {
|
||||
@@ -294,10 +292,10 @@ SceneCameraMotionAnalyzer::AddFocusPointsFromCenterTypeAndWeight(
|
||||
} else {
|
||||
RET_CHECK_FAIL() << absl::StrCat("Invalid FocusPointFrameType ", type);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
absl::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const SceneCameraMotion& scene_camera_motion,
|
||||
const std::vector<int64>& scene_frame_timestamps,
|
||||
@@ -340,7 +338,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
options_.salient_point_bound(), &focus_point_frame));
|
||||
focus_point_frames->push_back(focus_point_frame);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
} else if (scene_camera_motion.has_sweeping_motion()) {
|
||||
// Camera sweeps across the frame.
|
||||
const auto& sweeping_motion = scene_camera_motion.sweeping_motion();
|
||||
@@ -361,7 +359,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
options_.salient_point_bound(), &focus_point_frame));
|
||||
focus_point_frames->push_back(focus_point_frame);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
} else if (scene_camera_motion.has_tracking_motion()) {
|
||||
// Camera tracks crop regions.
|
||||
RET_CHECK_GT(scene_summary.num_key_frames(), 0) << "No key frames.";
|
||||
@@ -369,8 +367,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
scene_summary, focus_point_frame_type, scene_frame_timestamps,
|
||||
focus_point_frames);
|
||||
} else {
|
||||
return mediapipe::Status(StatusCode::kInvalidArgument,
|
||||
"Unknown motion type.");
|
||||
return absl::Status(StatusCode::kInvalidArgument, "Unknown motion type.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,8 +377,7 @@ mediapipe::Status SceneCameraMotionAnalyzer::PopulateFocusPointFrames(
|
||||
// The weight for the focus point is proportional to the interpolated score
|
||||
// and scaled so that the maximum weight is equal to
|
||||
// maximum_focus_point_weight in the SceneCameraMotionAnalyzerOptions.
|
||||
mediapipe::Status
|
||||
SceneCameraMotionAnalyzer::PopulateFocusPointFramesForTracking(
|
||||
absl::Status SceneCameraMotionAnalyzer::PopulateFocusPointFramesForTracking(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const FocusPointFrameType focus_point_frame_type,
|
||||
const std::vector<int64>& scene_frame_timestamps,
|
||||
@@ -440,7 +436,7 @@ SceneCameraMotionAnalyzer::PopulateFocusPointFramesForTracking(
|
||||
focus_point->set_weight(scale * focus_point->weight());
|
||||
}
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -62,7 +62,7 @@ class SceneCameraMotionAnalyzer {
|
||||
// Aggregates information from KeyFrameInfos and KeyFrameCropResults into
|
||||
// SceneKeyFrameCropSummary, and populates FocusPointFrames given scene
|
||||
// frame timestamps. Optionally returns SceneCameraMotion.
|
||||
mediapipe::Status AnalyzeSceneAndPopulateFocusPointFrames(
|
||||
absl::Status AnalyzeSceneAndPopulateFocusPointFrames(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const int scene_frame_width, const int scene_frame_height,
|
||||
@@ -75,7 +75,7 @@ class SceneCameraMotionAnalyzer {
|
||||
protected:
|
||||
// Decides SceneCameraMotion based on SceneKeyFrameCropSummary. Updates the
|
||||
// crop window in SceneKeyFrameCropSummary in the case of steady motion.
|
||||
mediapipe::Status DecideCameraMotionType(
|
||||
absl::Status DecideCameraMotionType(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const double scene_span_sec, const int64 end_time_us,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
@@ -83,7 +83,7 @@ class SceneCameraMotionAnalyzer {
|
||||
|
||||
// Populates the FocusPointFrames for each scene frame based on
|
||||
// SceneKeyFrameCropSummary, SceneCameraMotion, and scene frame timestamps.
|
||||
mediapipe::Status PopulateFocusPointFrames(
|
||||
absl::Status PopulateFocusPointFrames(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const SceneCameraMotion& scene_camera_motion,
|
||||
const std::vector<int64>& scene_frame_timestamps,
|
||||
@@ -91,7 +91,7 @@ class SceneCameraMotionAnalyzer {
|
||||
|
||||
private:
|
||||
// Decides the look-at region when camera is steady.
|
||||
mediapipe::Status DecideSteadyLookAtRegion(
|
||||
absl::Status DecideSteadyLookAtRegion(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
SceneCameraMotion* scene_camera_motion) const;
|
||||
@@ -105,7 +105,7 @@ class SceneCameraMotionAnalyzer {
|
||||
|
||||
// Adds FocusPoint(s) to given FocusPointFrame given center location,
|
||||
// frame size, FocusPointFrameType, weight, and bound.
|
||||
mediapipe::Status AddFocusPointsFromCenterTypeAndWeight(
|
||||
absl::Status AddFocusPointsFromCenterTypeAndWeight(
|
||||
const float center_x, const float center_y, const int frame_width,
|
||||
const int frame_height, const FocusPointFrameType type,
|
||||
const float weight, const float bound,
|
||||
@@ -114,21 +114,22 @@ class SceneCameraMotionAnalyzer {
|
||||
// Populates the FocusPointFrames for each scene frame based on
|
||||
// SceneKeyFrameCropSummary and scene frame timestamps in the case where
|
||||
// camera is tracking the crop regions.
|
||||
mediapipe::Status PopulateFocusPointFramesForTracking(
|
||||
absl::Status PopulateFocusPointFramesForTracking(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const FocusPointFrameType focus_point_frame_type,
|
||||
const std::vector<int64>& scene_frame_timestamps,
|
||||
std::vector<FocusPointFrame>* focus_point_frames) const;
|
||||
|
||||
// Decide to use steady motion.
|
||||
mediapipe::Status ToUseSteadyMotion(
|
||||
const float look_at_center_x, const float look_at_center_y,
|
||||
const int crop_window_width, const int crop_window_height,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
SceneCameraMotion* scene_camera_motion) const;
|
||||
absl::Status ToUseSteadyMotion(const float look_at_center_x,
|
||||
const float look_at_center_y,
|
||||
const int crop_window_width,
|
||||
const int crop_window_height,
|
||||
SceneKeyFrameCropSummary* scene_summary,
|
||||
SceneCameraMotion* scene_camera_motion) const;
|
||||
|
||||
// Decide to use sweeping motion.
|
||||
mediapipe::Status ToUseSweepingMotion(
|
||||
absl::Status ToUseSweepingMotion(
|
||||
const float start_x, const float start_y, const float end_x,
|
||||
const float end_y, const int crop_window_width,
|
||||
const int crop_window_height, const double time_duration_in_sec,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "mediapipe/examples/desktop/autoflip/quality/focus_point.pb.h"
|
||||
#include "mediapipe/examples/desktop/autoflip/quality/piecewise_linear_function.h"
|
||||
#include "mediapipe/framework/deps/file_path.h"
|
||||
#include "mediapipe/framework/port/commandlineflags.h"
|
||||
#include "mediapipe/framework/port/file_helpers.h"
|
||||
#include "mediapipe/framework/port/gmock.h"
|
||||
#include "mediapipe/framework/port/gtest.h"
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr float kWidthFieldOfView = 60;
|
||||
namespace mediapipe {
|
||||
namespace autoflip {
|
||||
|
||||
mediapipe::Status SceneCropper::ProcessKinematicPathSolver(
|
||||
absl::Status SceneCropper::ProcessKinematicPathSolver(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const std::vector<int64>& scene_timestamps,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
@@ -77,10 +77,10 @@ mediapipe::Status SceneCropper::ProcessKinematicPathSolver(
|
||||
-(x_path - scene_summary.crop_window_width() / 2);
|
||||
all_xforms->push_back(transform);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SceneCropper::CropFrames(
|
||||
absl::Status SceneCropper::CropFrames(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const std::vector<int64>& scene_timestamps,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
@@ -151,7 +151,7 @@ mediapipe::Status SceneCropper::CropFrames(
|
||||
|
||||
// If no cropped_frames is passed in, return directly.
|
||||
if (!cropped_frames) {
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
RET_CHECK(!scene_frames_or_empty.empty())
|
||||
<< "If |cropped_frames| != nullptr, scene_frames_or_empty must not be "
|
||||
|
||||
@@ -60,7 +60,7 @@ class SceneCropper {
|
||||
// on the transform matrix if |cropped_frames| is not nullptr and
|
||||
// |scene_frames_or_empty| isn't empty.
|
||||
// TODO: split this function into two separate functions.
|
||||
mediapipe::Status CropFrames(
|
||||
absl::Status CropFrames(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const std::vector<int64>& scene_timestamps,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
@@ -71,7 +71,7 @@ class SceneCropper {
|
||||
const bool continue_last_scene, std::vector<cv::Rect>* crop_from_location,
|
||||
std::vector<cv::Mat>* cropped_frames);
|
||||
|
||||
mediapipe::Status ProcessKinematicPathSolver(
|
||||
absl::Status ProcessKinematicPathSolver(
|
||||
const SceneKeyFrameCropSummary& scene_summary,
|
||||
const std::vector<int64>& scene_timestamps,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
|
||||
@@ -46,7 +46,7 @@ const cv::Scalar kOrange =
|
||||
cv::Scalar(255.0, 165.0, 0.0); // ica object detector
|
||||
const cv::Scalar kWhite = cv::Scalar(255.0, 255.0, 255.0); // others
|
||||
|
||||
mediapipe::Status DrawDetectionsAndCropRegions(
|
||||
absl::Status DrawDetectionsAndCropRegions(
|
||||
const std::vector<cv::Mat>& scene_frames,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
const std::vector<KeyFrameInfo>& key_frame_infos,
|
||||
@@ -130,7 +130,7 @@ mediapipe::Status DrawDetectionsAndCropRegions(
|
||||
}
|
||||
viz_frames->push_back(std::move(viz_frame));
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -147,7 +147,7 @@ cv::Rect LimitBounds(const cv::Rect& rect, const int max_width,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
mediapipe::Status DrawDetectionAndFramingWindow(
|
||||
absl::Status DrawDetectionAndFramingWindow(
|
||||
const std::vector<cv::Mat>& org_scene_frames,
|
||||
const std::vector<cv::Rect>& crop_from_locations,
|
||||
const ImageFormat::Format image_format, const float overlay_opacity,
|
||||
@@ -166,10 +166,10 @@ mediapipe::Status DrawDetectionAndFramingWindow(
|
||||
scene_frame(crop_from_bounded).copyTo(darkened(crop_from_bounded));
|
||||
viz_frames->push_back(std::move(viz_frame));
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status DrawFocusPointAndCropWindow(
|
||||
absl::Status DrawFocusPointAndCropWindow(
|
||||
const std::vector<cv::Mat>& scene_frames,
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const float overlay_opacity, const int crop_window_width,
|
||||
@@ -215,7 +215,7 @@ mediapipe::Status DrawFocusPointAndCropWindow(
|
||||
}
|
||||
viz_frames->push_back(std::move(viz_frame));
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace autoflip {
|
||||
// magenta, logos are red, ocrs are yellow (foreground) and light yellow
|
||||
// (background), brain objects are cyan, ica objects are orange, and the rest
|
||||
// are white.
|
||||
mediapipe::Status DrawDetectionsAndCropRegions(
|
||||
absl::Status DrawDetectionsAndCropRegions(
|
||||
const std::vector<cv::Mat>& scene_frames,
|
||||
const std::vector<bool>& is_key_frames,
|
||||
const std::vector<KeyFrameInfo>& key_frame_infos,
|
||||
@@ -47,7 +47,7 @@ mediapipe::Status DrawDetectionsAndCropRegions(
|
||||
// Draws the focus point from the given FocusPointFrame and the crop window
|
||||
// centered around it on the scene frame in red. This helps visualize the input
|
||||
// to the retargeter.
|
||||
mediapipe::Status DrawFocusPointAndCropWindow(
|
||||
absl::Status DrawFocusPointAndCropWindow(
|
||||
const std::vector<cv::Mat>& scene_frames,
|
||||
const std::vector<FocusPointFrame>& focus_point_frames,
|
||||
const float overlay_opacity, const int crop_window_width,
|
||||
@@ -57,7 +57,7 @@ mediapipe::Status DrawFocusPointAndCropWindow(
|
||||
|
||||
// Draws the final smoothed path of the camera retargeter by darkening the
|
||||
// removed areas.
|
||||
mediapipe::Status DrawDetectionAndFramingWindow(
|
||||
absl::Status DrawDetectionAndFramingWindow(
|
||||
const std::vector<cv::Mat>& org_scene_frames,
|
||||
const std::vector<cv::Rect>& crop_from_locations,
|
||||
const ImageFormat::Format image_format, const float overlay_opacity,
|
||||
|
||||
@@ -53,12 +53,12 @@ void NormalizedRectToRect(const RectF& normalized_location, const int width,
|
||||
ScaleRect(normalized_location, width, height, location);
|
||||
}
|
||||
|
||||
mediapipe::Status ClampRect(const int width, const int height, Rect* location) {
|
||||
absl::Status ClampRect(const int width, const int height, Rect* location) {
|
||||
return ClampRect(0, 0, width, height, location);
|
||||
}
|
||||
|
||||
mediapipe::Status ClampRect(const int x0, const int y0, const int x1,
|
||||
const int y1, Rect* location) {
|
||||
absl::Status ClampRect(const int x0, const int y0, const int x1, const int y1,
|
||||
Rect* location) {
|
||||
RET_CHECK(!(location->x() >= x1 || location->x() + location->width() <= x0 ||
|
||||
location->y() >= y1 || location->y() + location->height() <= y0));
|
||||
|
||||
@@ -73,7 +73,7 @@ mediapipe::Status ClampRect(const int x0, const int y0, const int x1,
|
||||
location->set_y(clamped_top);
|
||||
location->set_width(std::max(0, clamped_right - clamped_left));
|
||||
location->set_height(std::max(0, clamped_bottom - clamped_top));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void RectUnion(const Rect& rect_to_add, Rect* rect) {
|
||||
@@ -89,13 +89,13 @@ void RectUnion(const Rect& rect_to_add, Rect* rect) {
|
||||
rect->set_height(y2 - y1);
|
||||
}
|
||||
|
||||
mediapipe::Status PackKeyFrameInfo(const int64 frame_timestamp_ms,
|
||||
const DetectionSet& detections,
|
||||
const int original_frame_width,
|
||||
const int original_frame_height,
|
||||
const int feature_frame_width,
|
||||
const int feature_frame_height,
|
||||
KeyFrameInfo* key_frame_info) {
|
||||
absl::Status PackKeyFrameInfo(const int64 frame_timestamp_ms,
|
||||
const DetectionSet& detections,
|
||||
const int original_frame_width,
|
||||
const int original_frame_height,
|
||||
const int feature_frame_width,
|
||||
const int feature_frame_height,
|
||||
KeyFrameInfo* key_frame_info) {
|
||||
RET_CHECK(key_frame_info != nullptr) << "KeyFrameInfo is null";
|
||||
RET_CHECK(original_frame_width > 0 && original_frame_height > 0 &&
|
||||
feature_frame_width > 0 && feature_frame_height > 0)
|
||||
@@ -135,13 +135,12 @@ mediapipe::Status PackKeyFrameInfo(const int64 frame_timestamp_ms,
|
||||
}
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SortDetections(
|
||||
const DetectionSet& detections,
|
||||
std::vector<SalientRegion>* required_regions,
|
||||
std::vector<SalientRegion>* non_required_regions) {
|
||||
absl::Status SortDetections(const DetectionSet& detections,
|
||||
std::vector<SalientRegion>* required_regions,
|
||||
std::vector<SalientRegion>* non_required_regions) {
|
||||
required_regions->clear();
|
||||
non_required_regions->clear();
|
||||
|
||||
@@ -174,13 +173,13 @@ mediapipe::Status SortDetections(
|
||||
non_required_regions->push_back(detections.detections(original_idx));
|
||||
}
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status SetKeyFrameCropTarget(const int frame_width,
|
||||
const int frame_height,
|
||||
const double target_aspect_ratio,
|
||||
KeyFrameCropOptions* crop_options) {
|
||||
absl::Status SetKeyFrameCropTarget(const int frame_width,
|
||||
const int frame_height,
|
||||
const double target_aspect_ratio,
|
||||
KeyFrameCropOptions* crop_options) {
|
||||
RET_CHECK_NE(crop_options, nullptr) << "KeyFrameCropOptions is null.";
|
||||
RET_CHECK_GT(frame_width, 0) << "Frame width is non-positive.";
|
||||
RET_CHECK_GT(frame_height, 0) << "Frame height is non-positive.";
|
||||
@@ -198,10 +197,10 @@ mediapipe::Status SetKeyFrameCropTarget(const int frame_width,
|
||||
: std::round(frame_width / target_aspect_ratio);
|
||||
crop_options->set_target_width(crop_target_width);
|
||||
crop_options->set_target_height(crop_target_height);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status AggregateKeyFrameResults(
|
||||
absl::Status AggregateKeyFrameResults(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const int scene_frame_width, const int scene_frame_height,
|
||||
@@ -231,7 +230,7 @@ mediapipe::Status AggregateKeyFrameResults(
|
||||
// Handles the corner case of no key frames.
|
||||
if (num_key_frames == 0) {
|
||||
scene_summary->set_has_salient_region(false);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
scene_summary->set_num_key_frames(num_key_frames);
|
||||
@@ -327,10 +326,10 @@ mediapipe::Status AggregateKeyFrameResults(
|
||||
scene_summary->key_frame_center_min_y()) /
|
||||
scene_frame_height;
|
||||
scene_summary->set_vertical_motion_amount(motion_y);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status ComputeSceneStaticBordersSize(
|
||||
absl::Status ComputeSceneStaticBordersSize(
|
||||
const std::vector<StaticFeatures>& static_features, int* top_border_size,
|
||||
int* bottom_border_size) {
|
||||
RET_CHECK(top_border_size) << "Output top border size is null.";
|
||||
@@ -374,10 +373,10 @@ mediapipe::Status ComputeSceneStaticBordersSize(
|
||||
|
||||
*top_border_size = std::max(0, *top_border_size);
|
||||
*bottom_border_size = std::max(0, *bottom_border_size);
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status FindSolidBackgroundColor(
|
||||
absl::Status FindSolidBackgroundColor(
|
||||
const std::vector<StaticFeatures>& static_features,
|
||||
const std::vector<int64>& static_features_timestamps,
|
||||
const double min_fraction_solid_background_color,
|
||||
@@ -422,13 +421,13 @@ mediapipe::Status FindSolidBackgroundColor(
|
||||
min_fraction_solid_background_color) {
|
||||
*has_solid_background = true;
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status AffineRetarget(const cv::Size& output_size,
|
||||
const std::vector<cv::Mat>& frames,
|
||||
const std::vector<cv::Mat>& affine_projection,
|
||||
std::vector<cv::Mat>* cropped_frames) {
|
||||
absl::Status AffineRetarget(const cv::Size& output_size,
|
||||
const std::vector<cv::Mat>& frames,
|
||||
const std::vector<cv::Mat>& affine_projection,
|
||||
std::vector<cv::Mat>* cropped_frames) {
|
||||
RET_CHECK(frames.size() == affine_projection.size())
|
||||
<< "number of frames and retarget offsets must be the same.";
|
||||
RET_CHECK(cropped_frames->size() == frames.size())
|
||||
@@ -442,7 +441,7 @@ mediapipe::Status AffineRetarget(const cv::Size& output_size,
|
||||
RET_CHECK(affine.rows == 2) << "Affine matrix must be 2x3";
|
||||
cv::warpAffine(frames[i], (*cropped_frames)[i], affine, output_size);
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} // namespace autoflip
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -29,31 +29,30 @@ namespace autoflip {
|
||||
// Packs detected features and timestamp (ms) into a KeyFrameInfo object. Scales
|
||||
// features back to the original frame size if features have been detected on a
|
||||
// different frame size.
|
||||
mediapipe::Status PackKeyFrameInfo(const int64 frame_timestamp_ms,
|
||||
const DetectionSet& detections,
|
||||
const int original_frame_width,
|
||||
const int original_frame_height,
|
||||
const int feature_frame_width,
|
||||
const int feature_frame_height,
|
||||
KeyFrameInfo* key_frame_info);
|
||||
absl::Status PackKeyFrameInfo(const int64 frame_timestamp_ms,
|
||||
const DetectionSet& detections,
|
||||
const int original_frame_width,
|
||||
const int original_frame_height,
|
||||
const int feature_frame_width,
|
||||
const int feature_frame_height,
|
||||
KeyFrameInfo* key_frame_info);
|
||||
|
||||
// Sorts required and non-required salient regions given a detection set.
|
||||
mediapipe::Status SortDetections(
|
||||
const DetectionSet& detections,
|
||||
std::vector<SalientRegion>* required_regions,
|
||||
std::vector<SalientRegion>* non_required_regions);
|
||||
absl::Status SortDetections(const DetectionSet& detections,
|
||||
std::vector<SalientRegion>* required_regions,
|
||||
std::vector<SalientRegion>* non_required_regions);
|
||||
|
||||
// Sets the target crop size in KeyFrameCropOptions based on frame size and
|
||||
// target aspect ratio so that the target crop size covers the biggest area
|
||||
// possible in the frame.
|
||||
mediapipe::Status SetKeyFrameCropTarget(const int frame_width,
|
||||
const int frame_height,
|
||||
const double target_aspect_ratio,
|
||||
KeyFrameCropOptions* crop_options);
|
||||
absl::Status SetKeyFrameCropTarget(const int frame_width,
|
||||
const int frame_height,
|
||||
const double target_aspect_ratio,
|
||||
KeyFrameCropOptions* crop_options);
|
||||
|
||||
// Aggregates information from KeyFrameInfos and KeyFrameCropResults into
|
||||
// SceneKeyFrameCropSummary.
|
||||
mediapipe::Status AggregateKeyFrameResults(
|
||||
absl::Status AggregateKeyFrameResults(
|
||||
const KeyFrameCropOptions& key_frame_crop_options,
|
||||
const std::vector<KeyFrameCropResult>& key_frame_crop_results,
|
||||
const int scene_frame_width, const int scene_frame_height,
|
||||
@@ -61,7 +60,7 @@ mediapipe::Status AggregateKeyFrameResults(
|
||||
|
||||
// Computes the static top and border size across a scene given a vector of
|
||||
// StaticFeatures over frames.
|
||||
mediapipe::Status ComputeSceneStaticBordersSize(
|
||||
absl::Status ComputeSceneStaticBordersSize(
|
||||
const std::vector<StaticFeatures>& static_features, int* top_border_size,
|
||||
int* bottom_border_size);
|
||||
|
||||
@@ -70,7 +69,7 @@ mediapipe::Status ComputeSceneStaticBordersSize(
|
||||
// background color exceeds given threshold, i.e.,
|
||||
// min_fraction_solid_background_color. Builds the background color
|
||||
// interpolation functions in Lab space using input timestamps.
|
||||
mediapipe::Status FindSolidBackgroundColor(
|
||||
absl::Status FindSolidBackgroundColor(
|
||||
const std::vector<StaticFeatures>& static_features,
|
||||
const std::vector<int64>& static_features_timestamps,
|
||||
const double min_fraction_solid_background_color,
|
||||
@@ -93,12 +92,12 @@ void NormalizedRectToRect(const RectF& normalized_location, const int width,
|
||||
|
||||
// Clamps a rectangle to lie within [x0, y0] and [x1, y1]. Returns true if the
|
||||
// rectangle has any overlapping with the target window.
|
||||
mediapipe::Status ClampRect(const int x0, const int y0, const int x1,
|
||||
const int y1, Rect* location);
|
||||
absl::Status ClampRect(const int x0, const int y0, const int x1, const int y1,
|
||||
Rect* location);
|
||||
|
||||
// Convenience function to clamp a rectangle to lie within [0, 0] and
|
||||
// [width, height].
|
||||
mediapipe::Status ClampRect(const int width, const int height, Rect* location);
|
||||
absl::Status ClampRect(const int width, const int height, Rect* location);
|
||||
|
||||
// Enlarges a given rectangle to cover a new rectangle to be added.
|
||||
void RectUnion(const Rect& rect_to_add, Rect* rect);
|
||||
@@ -106,10 +105,10 @@ void RectUnion(const Rect& rect_to_add, Rect* rect);
|
||||
// Performs an affine retarget on a list of input images. Output vector
|
||||
// cropped_frames must be filled with Mats of the same size as output_size and
|
||||
// type.
|
||||
mediapipe::Status AffineRetarget(const cv::Size& output_size,
|
||||
const std::vector<cv::Mat>& frames,
|
||||
const std::vector<cv::Mat>& affine_projection,
|
||||
std::vector<cv::Mat>* cropped_frames);
|
||||
absl::Status AffineRetarget(const cv::Size& output_size,
|
||||
const std::vector<cv::Mat>& frames,
|
||||
const std::vector<cv::Mat>& affine_projection,
|
||||
std::vector<cv::Mat>* cropped_frames);
|
||||
|
||||
} // namespace autoflip
|
||||
} // namespace mediapipe
|
||||
|
||||
@@ -48,9 +48,9 @@ void CropRectToMat(const cv::Mat& image, cv::Rect* rect) {
|
||||
VisualScorer::VisualScorer(const VisualScorerOptions& options)
|
||||
: options_(options) {}
|
||||
|
||||
mediapipe::Status VisualScorer::CalculateScore(const cv::Mat& image,
|
||||
const SalientRegion& region,
|
||||
float* score) const {
|
||||
absl::Status VisualScorer::CalculateScore(const cv::Mat& image,
|
||||
const SalientRegion& region,
|
||||
float* score) const {
|
||||
const float weight_sum = options_.area_weight() +
|
||||
options_.sharpness_weight() +
|
||||
options_.colorfulness_weight();
|
||||
@@ -74,7 +74,7 @@ mediapipe::Status VisualScorer::CalculateScore(const cv::Mat& image,
|
||||
CropRectToMat(image, ®ion_rect);
|
||||
if (region_rect.area() == 0) {
|
||||
*score = 0;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Compute a score based on area covered by this region.
|
||||
@@ -108,11 +108,11 @@ mediapipe::Status VisualScorer::CalculateScore(const cv::Mat& image,
|
||||
if (*score > 1.0f || *score < 0.0f) {
|
||||
LOG(WARNING) << "Score of region outside expected range: " << *score;
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status VisualScorer::CalculateColorfulness(
|
||||
const cv::Mat& image, float* colorfulness) const {
|
||||
absl::Status VisualScorer::CalculateColorfulness(const cv::Mat& image,
|
||||
float* colorfulness) const {
|
||||
// Convert the image to HSV.
|
||||
cv::Mat image_hsv;
|
||||
cv::cvtColor(image, image_hsv, CV_RGB2HSV);
|
||||
@@ -134,7 +134,7 @@ mediapipe::Status VisualScorer::CalculateColorfulness(
|
||||
// If the mask is empty, return.
|
||||
if (empty_mask) {
|
||||
*colorfulness = 0;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Generate a 2D histogram (hue/saturation).
|
||||
@@ -162,7 +162,7 @@ mediapipe::Status VisualScorer::CalculateColorfulness(
|
||||
}
|
||||
if (hue_sum == 0.0f) {
|
||||
*colorfulness = 0;
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Compute the histogram entropy.
|
||||
@@ -175,7 +175,7 @@ mediapipe::Status VisualScorer::CalculateColorfulness(
|
||||
}
|
||||
*colorfulness /= std::log(2.0f);
|
||||
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace autoflip
|
||||
|
||||
@@ -30,13 +30,12 @@ class VisualScorer {
|
||||
explicit VisualScorer(const VisualScorerOptions& options);
|
||||
|
||||
// Computes a score on a salientregion and returns a value [0...1].
|
||||
mediapipe::Status CalculateScore(const cv::Mat& image,
|
||||
const SalientRegion& region,
|
||||
float* score) const;
|
||||
absl::Status CalculateScore(const cv::Mat& image, const SalientRegion& region,
|
||||
float* score) const;
|
||||
|
||||
private:
|
||||
mediapipe::Status CalculateColorfulness(const cv::Mat& image,
|
||||
float* colorfulness) const;
|
||||
absl::Status CalculateColorfulness(const cv::Mat& image,
|
||||
float* colorfulness) const;
|
||||
|
||||
VisualScorerOptions options_;
|
||||
};
|
||||
|
||||
@@ -40,10 +40,11 @@ DEFINE_string(output_video_path, "",
|
||||
"Full path of where to save result (.mp4 only). "
|
||||
"If not provided, show result in a window.");
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
@@ -56,16 +57,16 @@ mediapipe::Status RunMPPGraph() {
|
||||
|
||||
LOG(INFO) << "Initialize the camera or load the video.";
|
||||
cv::VideoCapture capture;
|
||||
const bool load_video = !FLAGS_input_video_path.empty();
|
||||
const bool load_video = !absl::GetFlag(FLAGS_input_video_path).empty();
|
||||
if (load_video) {
|
||||
capture.open(FLAGS_input_video_path);
|
||||
capture.open(absl::GetFlag(FLAGS_input_video_path));
|
||||
} else {
|
||||
capture.open(0);
|
||||
}
|
||||
RET_CHECK(capture.isOpened());
|
||||
|
||||
cv::VideoWriter writer;
|
||||
const bool save_video = !FLAGS_output_video_path.empty();
|
||||
const bool save_video = !absl::GetFlag(FLAGS_output_video_path).empty();
|
||||
if (!save_video) {
|
||||
cv::namedWindow(kWindowName, /*flags=WINDOW_AUTOSIZE*/ 1);
|
||||
#if (CV_MAJOR_VERSION >= 3) && (CV_MINOR_VERSION >= 2)
|
||||
@@ -125,7 +126,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
if (save_video) {
|
||||
if (!writer.isOpened()) {
|
||||
LOG(INFO) << "Prepare video writer.";
|
||||
writer.open(FLAGS_output_video_path,
|
||||
writer.open(absl::GetFlag(FLAGS_output_video_path),
|
||||
mediapipe::fourcc('a', 'v', 'c', '1'), // .mp4
|
||||
capture.get(cv::CAP_PROP_FPS), output_frame_mat.size());
|
||||
RET_CHECK(writer.isOpened());
|
||||
@@ -148,7 +149,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -44,10 +44,11 @@ DEFINE_string(output_video_path, "",
|
||||
"Full path of where to save result (.mp4 only). "
|
||||
"If not provided, show result in a window.");
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
@@ -66,16 +67,16 @@ mediapipe::Status RunMPPGraph() {
|
||||
|
||||
LOG(INFO) << "Initialize the camera or load the video.";
|
||||
cv::VideoCapture capture;
|
||||
const bool load_video = !FLAGS_input_video_path.empty();
|
||||
const bool load_video = !absl::GetFlag(FLAGS_input_video_path).empty();
|
||||
if (load_video) {
|
||||
capture.open(FLAGS_input_video_path);
|
||||
capture.open(absl::GetFlag(FLAGS_input_video_path));
|
||||
} else {
|
||||
capture.open(0);
|
||||
}
|
||||
RET_CHECK(capture.isOpened());
|
||||
|
||||
cv::VideoWriter writer;
|
||||
const bool save_video = !FLAGS_output_video_path.empty();
|
||||
const bool save_video = !absl::GetFlag(FLAGS_output_video_path).empty();
|
||||
if (!save_video) {
|
||||
cv::namedWindow(kWindowName, /*flags=WINDOW_AUTOSIZE*/ 1);
|
||||
#if (CV_MAJOR_VERSION >= 3) && (CV_MINOR_VERSION >= 2)
|
||||
@@ -122,7 +123,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
(double)cv::getTickCount() / (double)cv::getTickFrequency() * 1e6;
|
||||
MP_RETURN_IF_ERROR(
|
||||
gpu_helper.RunInGlContext([&input_frame, &frame_timestamp_us, &graph,
|
||||
&gpu_helper]() -> ::mediapipe::Status {
|
||||
&gpu_helper]() -> absl::Status {
|
||||
// Convert ImageFrame to GpuBuffer.
|
||||
auto texture = gpu_helper.CreateSourceTexture(*input_frame.get());
|
||||
auto gpu_frame = texture.GetFrame<mediapipe::GpuBuffer>();
|
||||
@@ -132,7 +133,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
MP_RETURN_IF_ERROR(graph.AddPacketToInputStream(
|
||||
kInputStream, mediapipe::Adopt(gpu_frame.release())
|
||||
.At(mediapipe::Timestamp(frame_timestamp_us))));
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
|
||||
// Get the graph result packet, or stop if that fails.
|
||||
@@ -142,7 +143,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
|
||||
// Convert GpuBuffer to ImageFrame.
|
||||
MP_RETURN_IF_ERROR(gpu_helper.RunInGlContext(
|
||||
[&packet, &output_frame, &gpu_helper]() -> ::mediapipe::Status {
|
||||
[&packet, &output_frame, &gpu_helper]() -> absl::Status {
|
||||
auto& gpu_frame = packet.Get<mediapipe::GpuBuffer>();
|
||||
auto texture = gpu_helper.CreateSourceTexture(gpu_frame);
|
||||
output_frame = absl::make_unique<mediapipe::ImageFrame>(
|
||||
@@ -150,13 +151,13 @@ mediapipe::Status RunMPPGraph() {
|
||||
gpu_frame.width(), gpu_frame.height(),
|
||||
mediapipe::ImageFrame::kGlDefaultAlignmentBoundary);
|
||||
gpu_helper.BindFramebuffer(texture);
|
||||
const auto info =
|
||||
mediapipe::GlTextureInfoForGpuBufferFormat(gpu_frame.format(), 0);
|
||||
const auto info = mediapipe::GlTextureInfoForGpuBufferFormat(
|
||||
gpu_frame.format(), 0, gpu_helper.GetGlVersion());
|
||||
glReadPixels(0, 0, texture.width(), texture.height(), info.gl_format,
|
||||
info.gl_type, output_frame->MutablePixelData());
|
||||
glFlush();
|
||||
texture.Release();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
|
||||
// Convert back to opencv for display or saving.
|
||||
@@ -168,7 +169,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
if (save_video) {
|
||||
if (!writer.isOpened()) {
|
||||
LOG(INFO) << "Prepare video writer.";
|
||||
writer.open(FLAGS_output_video_path,
|
||||
writer.open(absl::GetFlag(FLAGS_output_video_path),
|
||||
mediapipe::fourcc('a', 'v', 'c', '1'), // .mp4
|
||||
capture.get(cv::CAP_PROP_FPS), output_frame_mat.size());
|
||||
RET_CHECK(writer.isOpened());
|
||||
@@ -191,7 +192,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
mediapipe::Status PrintHelloWorld() {
|
||||
absl::Status PrintHelloWorld() {
|
||||
// Configures a simple graph, which concatenates 2 PassThroughCalculators.
|
||||
CalculatorGraphConfig config = ParseTextProtoOrDie<CalculatorGraphConfig>(R"(
|
||||
input_stream: "in"
|
||||
|
||||
@@ -47,18 +47,16 @@ DEFINE_string(output_image_path, "",
|
||||
|
||||
namespace {
|
||||
|
||||
mediapipe::StatusOr<std::string> ReadFileToString(
|
||||
const std::string& file_path) {
|
||||
absl::StatusOr<std::string> ReadFileToString(const std::string& file_path) {
|
||||
std::string contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(file_path, &contents));
|
||||
return contents;
|
||||
}
|
||||
|
||||
mediapipe::Status ProcessImage(
|
||||
std::unique_ptr<mediapipe::CalculatorGraph> graph) {
|
||||
absl::Status ProcessImage(std::unique_ptr<mediapipe::CalculatorGraph> graph) {
|
||||
LOG(INFO) << "Load the image.";
|
||||
ASSIGN_OR_RETURN(const std::string raw_image,
|
||||
ReadFileToString(FLAGS_input_image_path));
|
||||
ReadFileToString(absl::GetFlag(FLAGS_input_image_path)));
|
||||
|
||||
LOG(INFO) << "Start running the calculator graph.";
|
||||
ASSIGN_OR_RETURN(mediapipe::OutputStreamPoller output_image_poller,
|
||||
@@ -80,7 +78,7 @@ mediapipe::Status ProcessImage(
|
||||
// Get the graph result packets, or stop if that fails.
|
||||
mediapipe::Packet left_iris_depth_packet;
|
||||
if (!left_iris_depth_poller.Next(&left_iris_depth_packet)) {
|
||||
return mediapipe::UnknownError(
|
||||
return absl::UnknownError(
|
||||
"Failed to get packet from output stream 'left_iris_depth_mm'.");
|
||||
}
|
||||
const auto& left_iris_depth_mm = left_iris_depth_packet.Get<float>();
|
||||
@@ -89,7 +87,7 @@ mediapipe::Status ProcessImage(
|
||||
|
||||
mediapipe::Packet right_iris_depth_packet;
|
||||
if (!right_iris_depth_poller.Next(&right_iris_depth_packet)) {
|
||||
return mediapipe::UnknownError(
|
||||
return absl::UnknownError(
|
||||
"Failed to get packet from output stream 'right_iris_depth_mm'.");
|
||||
}
|
||||
const auto& right_iris_depth_mm = right_iris_depth_packet.Get<float>();
|
||||
@@ -99,7 +97,7 @@ mediapipe::Status ProcessImage(
|
||||
|
||||
mediapipe::Packet output_image_packet;
|
||||
if (!output_image_poller.Next(&output_image_packet)) {
|
||||
return mediapipe::UnknownError(
|
||||
return absl::UnknownError(
|
||||
"Failed to get packet from output stream 'output_image'.");
|
||||
}
|
||||
auto& output_frame = output_image_packet.Get<mediapipe::ImageFrame>();
|
||||
@@ -107,10 +105,10 @@ mediapipe::Status ProcessImage(
|
||||
// Convert back to opencv for display or saving.
|
||||
cv::Mat output_frame_mat = mediapipe::formats::MatView(&output_frame);
|
||||
cv::cvtColor(output_frame_mat, output_frame_mat, cv::COLOR_RGB2BGR);
|
||||
const bool save_image = !FLAGS_output_image_path.empty();
|
||||
const bool save_image = !absl::GetFlag(FLAGS_output_image_path).empty();
|
||||
if (save_image) {
|
||||
LOG(INFO) << "Saving image to file...";
|
||||
cv::imwrite(FLAGS_output_image_path, output_frame_mat);
|
||||
cv::imwrite(absl::GetFlag(FLAGS_output_image_path), output_frame_mat);
|
||||
} else {
|
||||
cv::namedWindow(kWindowName, /*flags=WINDOW_AUTOSIZE*/ 1);
|
||||
cv::imshow(kWindowName, output_frame_mat);
|
||||
@@ -123,7 +121,7 @@ mediapipe::Status ProcessImage(
|
||||
return graph->WaitUntilDone();
|
||||
}
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
kCalculatorGraphConfigFile, &calculator_graph_config_contents));
|
||||
@@ -138,11 +136,11 @@ mediapipe::Status RunMPPGraph() {
|
||||
absl::make_unique<mediapipe::CalculatorGraph>();
|
||||
MP_RETURN_IF_ERROR(graph->Initialize(config));
|
||||
|
||||
const bool load_image = !FLAGS_input_image_path.empty();
|
||||
const bool load_image = !absl::GetFlag(FLAGS_input_image_path).empty();
|
||||
if (load_image) {
|
||||
return ProcessImage(std::move(graph));
|
||||
} else {
|
||||
return mediapipe::InvalidArgumentError("Missing image file.");
|
||||
return absl::InvalidArgumentError("Missing image file.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +149,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -38,10 +38,11 @@ DEFINE_string(output_side_packets, "",
|
||||
"side packets and paths to write to disk for the "
|
||||
"CalculatorGraph.");
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
@@ -49,7 +50,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
calculator_graph_config_contents);
|
||||
std::map<std::string, mediapipe::Packet> input_side_packets;
|
||||
std::vector<std::string> kv_pairs =
|
||||
absl::StrSplit(FLAGS_input_side_packets, ',');
|
||||
absl::StrSplit(absl::GetFlag(FLAGS_input_side_packets), ',');
|
||||
for (const std::string& kv_pair : kv_pairs) {
|
||||
std::vector<std::string> name_and_value = absl::StrSplit(kv_pair, '=');
|
||||
RET_CHECK(name_and_value.size() == 2);
|
||||
@@ -66,26 +67,26 @@ mediapipe::Status RunMPPGraph() {
|
||||
LOG(INFO) << "Start running the calculator graph.";
|
||||
MP_RETURN_IF_ERROR(graph.Run());
|
||||
LOG(INFO) << "Gathering output side packets.";
|
||||
kv_pairs = absl::StrSplit(FLAGS_output_side_packets, ',');
|
||||
kv_pairs = absl::StrSplit(absl::GetFlag(FLAGS_output_side_packets), ',');
|
||||
for (const std::string& kv_pair : kv_pairs) {
|
||||
std::vector<std::string> name_and_value = absl::StrSplit(kv_pair, '=');
|
||||
RET_CHECK(name_and_value.size() == 2);
|
||||
mediapipe::StatusOr<mediapipe::Packet> output_packet =
|
||||
absl::StatusOr<mediapipe::Packet> output_packet =
|
||||
graph.GetOutputSidePacket(name_and_value[0]);
|
||||
RET_CHECK(output_packet.ok())
|
||||
<< "Packet " << name_and_value[0] << " was not available.";
|
||||
const std::string& serialized_string =
|
||||
output_packet.ValueOrDie().Get<std::string>();
|
||||
output_packet.value().Get<std::string>();
|
||||
MP_RETURN_IF_ERROR(
|
||||
mediapipe::file::SetContents(name_and_value[1], serialized_string));
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -22,9 +22,9 @@ package(default_visibility = ["//mediapipe/examples:__subpackages__"])
|
||||
# --calculator_graph_config_file=mediapipe/graphs/object_detection_3d/objectron_desktop_cpu.pbtxt \
|
||||
# --input_side_packets="input_video_path=<input_video_path>,box_landmark_model_path=mediapipe/models/object_detection_3d_sneakers.tflite,output_video_path=<output_video_path>,allowed_labels=Footwear"
|
||||
# To detect objects from other categories, change box_landmark_model_path and allowed_labels accordingly.
|
||||
# Chair: box_landmark_model_path=mediapipe/models/object_detection_3d_chair.tflite,allowed_labels=Chair
|
||||
# Camera: box_landmark_model_path=mediapipe/models/object_detection_3d_camera.tflite,allowed_labels=Camera
|
||||
# Cup: box_landmark_model_path=mediapipe/models/object_detection_3d_cup.tflite,allowed_labels=Mug
|
||||
# Chair: box_landmark_model_path=mediapipe/modules/objectron/object_detection_3d_chair.tflite,allowed_labels=Chair
|
||||
# Camera: box_landmark_model_path=mediapipe/modules/objectron/object_detection_3d_camera.tflite,allowed_labels=Camera
|
||||
# Cup: box_landmark_model_path=mediapipe/modules/objectron/object_detection_3d_cup.tflite,allowed_labels=Mug
|
||||
cc_binary(
|
||||
name = "objectron_cpu",
|
||||
deps = [
|
||||
|
||||
@@ -58,31 +58,29 @@ DEFINE_string(output_side_packets_file, "",
|
||||
"The name of the local file to output all side packets specified "
|
||||
"with --output_side_packets. ");
|
||||
|
||||
mediapipe::Status OutputStreamToLocalFile(
|
||||
mediapipe::OutputStreamPoller& poller) {
|
||||
absl::Status OutputStreamToLocalFile(mediapipe::OutputStreamPoller& poller) {
|
||||
std::ofstream file;
|
||||
file.open(FLAGS_output_stream_file);
|
||||
file.open(absl::GetFlag(FLAGS_output_stream_file));
|
||||
mediapipe::Packet packet;
|
||||
while (poller.Next(&packet)) {
|
||||
std::string output_data;
|
||||
if (!FLAGS_strip_timestamps) {
|
||||
if (!absl::GetFlag(FLAGS_strip_timestamps)) {
|
||||
absl::StrAppend(&output_data, packet.Timestamp().Value(), ",");
|
||||
}
|
||||
absl::StrAppend(&output_data, packet.Get<std::string>(), "\n");
|
||||
file << output_data;
|
||||
}
|
||||
file.close();
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status OutputSidePacketsToLocalFile(
|
||||
mediapipe::CalculatorGraph& graph) {
|
||||
if (!FLAGS_output_side_packets.empty() &&
|
||||
!FLAGS_output_side_packets_file.empty()) {
|
||||
absl::Status OutputSidePacketsToLocalFile(mediapipe::CalculatorGraph& graph) {
|
||||
if (!absl::GetFlag(FLAGS_output_side_packets).empty() &&
|
||||
!absl::GetFlag(FLAGS_output_side_packets_file).empty()) {
|
||||
std::ofstream file;
|
||||
file.open(FLAGS_output_side_packets_file);
|
||||
file.open(absl::GetFlag(FLAGS_output_side_packets_file));
|
||||
std::vector<std::string> side_packet_names =
|
||||
absl::StrSplit(FLAGS_output_side_packets, ',');
|
||||
absl::StrSplit(absl::GetFlag(FLAGS_output_side_packets), ',');
|
||||
for (const std::string& side_packet_name : side_packet_names) {
|
||||
ASSIGN_OR_RETURN(auto status_or_packet,
|
||||
graph.GetOutputSidePacket(side_packet_name));
|
||||
@@ -91,27 +89,28 @@ mediapipe::Status OutputSidePacketsToLocalFile(
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
RET_CHECK(FLAGS_output_side_packets.empty() &&
|
||||
FLAGS_output_side_packets_file.empty())
|
||||
RET_CHECK(absl::GetFlag(FLAGS_output_side_packets).empty() &&
|
||||
absl::GetFlag(FLAGS_output_side_packets_file).empty())
|
||||
<< "--output_side_packets and --output_side_packets_file should be "
|
||||
"specified in pair.";
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
mediapipe::ParseTextProtoOrDie<mediapipe::CalculatorGraphConfig>(
|
||||
calculator_graph_config_contents);
|
||||
std::map<std::string, mediapipe::Packet> input_side_packets;
|
||||
if (!FLAGS_input_side_packets.empty()) {
|
||||
if (!absl::GetFlag(FLAGS_input_side_packets).empty()) {
|
||||
std::vector<std::string> kv_pairs =
|
||||
absl::StrSplit(FLAGS_input_side_packets, ',');
|
||||
absl::StrSplit(absl::GetFlag(FLAGS_input_side_packets), ',');
|
||||
for (const std::string& kv_pair : kv_pairs) {
|
||||
std::vector<std::string> name_and_value = absl::StrSplit(kv_pair, '=');
|
||||
RET_CHECK(name_and_value.size() == 2);
|
||||
@@ -123,14 +122,16 @@ mediapipe::Status RunMPPGraph() {
|
||||
LOG(INFO) << "Initialize the calculator graph.";
|
||||
mediapipe::CalculatorGraph graph;
|
||||
MP_RETURN_IF_ERROR(graph.Initialize(config, input_side_packets));
|
||||
if (!FLAGS_output_stream.empty() && !FLAGS_output_stream_file.empty()) {
|
||||
ASSIGN_OR_RETURN(auto poller,
|
||||
graph.AddOutputStreamPoller(FLAGS_output_stream));
|
||||
if (!absl::GetFlag(FLAGS_output_stream).empty() &&
|
||||
!absl::GetFlag(FLAGS_output_stream_file).empty()) {
|
||||
ASSIGN_OR_RETURN(auto poller, graph.AddOutputStreamPoller(
|
||||
absl::GetFlag(FLAGS_output_stream)));
|
||||
LOG(INFO) << "Start running the calculator graph.";
|
||||
MP_RETURN_IF_ERROR(graph.StartRun({}));
|
||||
MP_RETURN_IF_ERROR(OutputStreamToLocalFile(poller));
|
||||
} else {
|
||||
RET_CHECK(FLAGS_output_stream.empty() && FLAGS_output_stream_file.empty())
|
||||
RET_CHECK(absl::GetFlag(FLAGS_output_stream).empty() &&
|
||||
absl::GetFlag(FLAGS_output_stream_file).empty())
|
||||
<< "--output_stream and --output_stream_file should be specified in "
|
||||
"pair.";
|
||||
LOG(INFO) << "Start running the calculator graph.";
|
||||
@@ -143,7 +144,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -21,7 +21,6 @@ cc_binary(
|
||||
"@com_google_absl//absl/strings",
|
||||
"//mediapipe/framework:calculator_framework",
|
||||
"//mediapipe/framework/formats:matrix",
|
||||
"//mediapipe/framework/formats:matrix_data_cc_proto",
|
||||
"//mediapipe/framework/port:commandlineflags",
|
||||
"//mediapipe/framework/port:file_helpers",
|
||||
"//mediapipe/framework/port:map_util",
|
||||
|
||||
@@ -39,10 +39,11 @@ DEFINE_string(output_side_packets, "",
|
||||
"side packets and paths to write to disk for the "
|
||||
"CalculatorGraph.");
|
||||
|
||||
mediapipe::Status RunMPPGraph() {
|
||||
absl::Status RunMPPGraph() {
|
||||
std::string calculator_graph_config_contents;
|
||||
MP_RETURN_IF_ERROR(mediapipe::file::GetContents(
|
||||
FLAGS_calculator_graph_config_file, &calculator_graph_config_contents));
|
||||
absl::GetFlag(FLAGS_calculator_graph_config_file),
|
||||
&calculator_graph_config_contents));
|
||||
LOG(INFO) << "Get calculator graph config contents: "
|
||||
<< calculator_graph_config_contents;
|
||||
mediapipe::CalculatorGraphConfig config =
|
||||
@@ -50,7 +51,7 @@ mediapipe::Status RunMPPGraph() {
|
||||
calculator_graph_config_contents);
|
||||
std::map<std::string, mediapipe::Packet> input_side_packets;
|
||||
std::vector<std::string> kv_pairs =
|
||||
absl::StrSplit(FLAGS_input_side_packets, ',');
|
||||
absl::StrSplit(absl::GetFlag(FLAGS_input_side_packets), ',');
|
||||
for (const std::string& kv_pair : kv_pairs) {
|
||||
std::vector<std::string> name_and_value = absl::StrSplit(kv_pair, '=');
|
||||
RET_CHECK(name_and_value.size() == 2);
|
||||
@@ -107,26 +108,26 @@ mediapipe::Status RunMPPGraph() {
|
||||
LOG(INFO) << "Start running the calculator graph.";
|
||||
MP_RETURN_IF_ERROR(graph.Run());
|
||||
LOG(INFO) << "Gathering output side packets.";
|
||||
kv_pairs = absl::StrSplit(FLAGS_output_side_packets, ',');
|
||||
kv_pairs = absl::StrSplit(absl::GetFlag(FLAGS_output_side_packets), ',');
|
||||
for (const std::string& kv_pair : kv_pairs) {
|
||||
std::vector<std::string> name_and_value = absl::StrSplit(kv_pair, '=');
|
||||
RET_CHECK(name_and_value.size() == 2);
|
||||
mediapipe::StatusOr<mediapipe::Packet> output_packet =
|
||||
absl::StatusOr<mediapipe::Packet> output_packet =
|
||||
graph.GetOutputSidePacket(name_and_value[0]);
|
||||
RET_CHECK(output_packet.ok())
|
||||
<< "Packet " << name_and_value[0] << " was not available.";
|
||||
const std::string& serialized_string =
|
||||
output_packet.ValueOrDie().Get<std::string>();
|
||||
output_packet.value().Get<std::string>();
|
||||
MP_RETURN_IF_ERROR(
|
||||
mediapipe::file::SetContents(name_and_value[1], serialized_string));
|
||||
}
|
||||
return mediapipe::OkStatus();
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
mediapipe::Status run_status = RunMPPGraph();
|
||||
absl::Status run_status = RunMPPGraph();
|
||||
if (!run_status.ok()) {
|
||||
LOG(ERROR) << "Failed to run the graph: " << run_status.message();
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -137,10 +137,10 @@ static const char* kVideoQueueLabel = "com.google.mediapipe.example.videoQueue";
|
||||
|
||||
[self.cameraSource requestCameraAccessWithCompletionHandler:^void(BOOL granted) {
|
||||
if (granted) {
|
||||
[self startGraphAndCamera];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.noCameraLabel.hidden = YES;
|
||||
});
|
||||
[self startGraphAndCamera];
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -155,6 +155,9 @@ static const char* kVideoQueueLabel = "com.google.mediapipe.example.videoQueue";
|
||||
if (![self.mediapipeGraph startWithError:&error]) {
|
||||
NSLog(@"Failed to start graph: %@", error);
|
||||
}
|
||||
else if (![self.mediapipeGraph waitUntilIdleWithError:&error]) {
|
||||
NSLog(@"Failed to complete graph initial run: %@", error);
|
||||
}
|
||||
|
||||
// Start fetching frames from the camera.
|
||||
dispatch_async(self.videoQueue, ^{
|
||||
|
||||
@@ -57,6 +57,21 @@ objc_library(
|
||||
"FaceEffectViewController.h",
|
||||
],
|
||||
copts = ["-std=c++17"],
|
||||
data = [
|
||||
"Base.lproj/LaunchScreen.storyboard",
|
||||
"Base.lproj/Main.storyboard",
|
||||
"//mediapipe/graphs/face_effect:face_effect_gpu.binarypb",
|
||||
"//mediapipe/graphs/face_effect/data:axis.binarypb",
|
||||
"//mediapipe/graphs/face_effect/data:axis.pngblob",
|
||||
"//mediapipe/graphs/face_effect/data:facepaint.pngblob",
|
||||
"//mediapipe/graphs/face_effect/data:glasses.binarypb",
|
||||
"//mediapipe/graphs/face_effect/data:glasses.pngblob",
|
||||
"//mediapipe/modules/face_detection:face_detection_front.tflite",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata.binarypb",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata_detection.binarypb",
|
||||
"//mediapipe/modules/face_geometry/data:geometry_pipeline_metadata_landmarks.binarypb",
|
||||
"//mediapipe/modules/face_landmark:face_landmark.tflite",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"AVFoundation",
|
||||
"CoreGraphics",
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#import "mediapipe/objc/MPPGraph.h"
|
||||
#import "mediapipe/objc/MPPLayerRenderer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "mediapipe/framework/formats/matrix_data.pb.h"
|
||||
@@ -27,13 +29,19 @@
|
||||
static NSString* const kGraphName = @"face_effect_gpu";
|
||||
|
||||
static const char* kInputStream = "input_video";
|
||||
static const char* kIsFacepaintEffectSelectedInputStream = "is_facepaint_effect_selected";
|
||||
static const char* kOutputStream = "output_video";
|
||||
static const char* kMultiFaceGeometryStream = "multi_face_geometry";
|
||||
static const char* kVideoQueueLabel = "com.google.mediapipe.example.videoQueue";
|
||||
static const char* kSelectedEffectIdInputStream = "selected_effect_id";
|
||||
static const char* kUseFaceDetectionInputSourceInputSidePacket = "use_face_detection_input_source";
|
||||
|
||||
static const BOOL kUseFaceDetectionInputSource = NO;
|
||||
static const int kMatrixTranslationZIndex = 14;
|
||||
|
||||
static const int kSelectedEffectIdAxis = 0;
|
||||
static const int kSelectedEffectIdFacepaint = 1;
|
||||
static const int kSelectedEffectIdGlasses = 2;
|
||||
|
||||
@interface FaceEffectViewController () <MPPGraphDelegate, MPPInputSourceDelegate>
|
||||
|
||||
// The MediaPipe graph currently in use. Initialized in viewDidLoad, started in viewWillAppear: and
|
||||
@@ -45,7 +53,7 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
@implementation FaceEffectViewController {
|
||||
/// Handle tap gestures.
|
||||
UITapGestureRecognizer* _tapGestureRecognizer;
|
||||
BOOL _isFacepaintEffectSelected;
|
||||
int _selectedEffectId;
|
||||
|
||||
/// Handles camera access via AVCaptureSession library.
|
||||
MPPCameraInputSource* _cameraSource;
|
||||
@@ -93,8 +101,14 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
mediapipe::CalculatorGraphConfig config;
|
||||
config.ParseFromArray(data.bytes, data.length);
|
||||
|
||||
// Pass the kUseFaceDetectionInputSource flag value as an input side packet into the graph.
|
||||
std::map<std::string, mediapipe::Packet> side_packets;
|
||||
side_packets[kUseFaceDetectionInputSourceInputSidePacket] =
|
||||
mediapipe::MakePacket<bool>(kUseFaceDetectionInputSource);
|
||||
|
||||
// Create MediaPipe graph with mediapipe::CalculatorGraphConfig proto object.
|
||||
MPPGraph* newGraph = [[MPPGraph alloc] initWithGraphConfig:config];
|
||||
[newGraph addSidePackets:side_packets];
|
||||
[newGraph addFrameOutputStream:kOutputStream outputPacketType:MPPPacketTypePixelBuffer];
|
||||
[newGraph addFrameOutputStream:kMultiFaceGeometryStream outputPacketType:MPPPacketTypeRaw];
|
||||
return newGraph;
|
||||
@@ -110,8 +124,13 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
action:@selector(handleTap)];
|
||||
[self.view addGestureRecognizer:_tapGestureRecognizer];
|
||||
|
||||
// By default, render the glasses effect.
|
||||
_isFacepaintEffectSelected = NO;
|
||||
// By default, render the axis effect for the face detection input source and the glasses effect
|
||||
// for the face landmark input source.
|
||||
if (kUseFaceDetectionInputSource) {
|
||||
_selectedEffectId = kSelectedEffectIdAxis;
|
||||
} else {
|
||||
_selectedEffectId = kSelectedEffectIdGlasses;
|
||||
}
|
||||
|
||||
_renderer = [[MPPLayerRenderer alloc] init];
|
||||
_renderer.layer.frame = _liveView.layer.bounds;
|
||||
@@ -175,7 +194,28 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
// multiple pre-bundled face effects without a need to recompile the app.
|
||||
- (void)handleTap {
|
||||
dispatch_async(_videoQueue, ^{
|
||||
_isFacepaintEffectSelected = !_isFacepaintEffectSelected;
|
||||
// Avoid switching the Axis effect for the face detection input source.
|
||||
if (kUseFaceDetectionInputSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Looped effect order: glasses -> facepaint -> axis -> glasses -> ...
|
||||
switch (_selectedEffectId) {
|
||||
case kSelectedEffectIdAxis: {
|
||||
_selectedEffectId = kSelectedEffectIdGlasses;
|
||||
break;
|
||||
}
|
||||
|
||||
case kSelectedEffectIdFacepaint: {
|
||||
_selectedEffectId = kSelectedEffectIdAxis;
|
||||
break;
|
||||
}
|
||||
|
||||
case kSelectedEffectIdGlasses: {
|
||||
_selectedEffectId = kSelectedEffectIdFacepaint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,7 +229,7 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
// Display the captured image on the screen.
|
||||
CVPixelBufferRetain(pixelBuffer);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_effectSwitchingHintLabel.hidden = NO;
|
||||
_effectSwitchingHintLabel.hidden = kUseFaceDetectionInputSource;
|
||||
[_renderer renderPixelBuffer:pixelBuffer];
|
||||
CVPixelBufferRelease(pixelBuffer);
|
||||
});
|
||||
@@ -236,18 +276,18 @@ static const int kMatrixTranslationZIndex = 14;
|
||||
mediapipe::Timestamp graphTimestamp(static_cast<mediapipe::TimestampBaseType>(
|
||||
mediapipe::Timestamp::kTimestampUnitsPerSecond * CMTimeGetSeconds(timestamp)));
|
||||
|
||||
mediapipe::Packet isFacepaintEffectSelectedPacket =
|
||||
mediapipe::MakePacket<bool>(_isFacepaintEffectSelected).At(graphTimestamp);
|
||||
mediapipe::Packet selectedEffectIdPacket =
|
||||
mediapipe::MakePacket<int>(_selectedEffectId).At(graphTimestamp);
|
||||
|
||||
[self.graph sendPixelBuffer:imageBuffer
|
||||
intoStream:kInputStream
|
||||
packetType:MPPPacketTypePixelBuffer
|
||||
timestamp:graphTimestamp];
|
||||
|
||||
// Alongside the input camera frame, we also send the `is_facepaint_effect_selected` boolean
|
||||
// packet to indicate which effect should be rendered on this frame.
|
||||
[self.graph movePacket:std::move(isFacepaintEffectSelectedPacket)
|
||||
intoStream:kIsFacepaintEffectSelectedInputStream
|
||||
// Alongside the input camera frame, we also send the `selected_effect_id` int packet to indicate
|
||||
// which effect should be rendered on this frame.
|
||||
[self.graph movePacket:std::move(selectedEffectIdPacket)
|
||||
intoStream:kSelectedEffectIdInputStream
|
||||
error:nil];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright 2019 The MediaPipe Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load(
|
||||
"@build_bazel_rules_apple//apple:ios.bzl",
|
||||
"ios_application",
|
||||
)
|
||||
load(
|
||||
"//mediapipe/examples/ios:bundle_id.bzl",
|
||||
"BUNDLE_ID_PREFIX",
|
||||
"example_provisioning",
|
||||
)
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
MIN_IOS_VERSION = "10.0"
|
||||
|
||||
alias(
|
||||
name = "objectdetectiontrackinggpu",
|
||||
actual = "ObjectDetectionTrackingGpuApp",
|
||||
)
|
||||
|
||||
ios_application(
|
||||
name = "ObjectDetectionTrackingGpuApp",
|
||||
app_icons = ["//mediapipe/examples/ios/common:AppIcon"],
|
||||
bundle_id = BUNDLE_ID_PREFIX + ".ObjectDetectionTrackingGpu",
|
||||
families = [
|
||||
"iphone",
|
||||
"ipad",
|
||||
],
|
||||
infoplists = [
|
||||
"//mediapipe/examples/ios/common:Info.plist",
|
||||
"Info.plist",
|
||||
],
|
||||
minimum_os_version = MIN_IOS_VERSION,
|
||||
provisioning_profile = example_provisioning(),
|
||||
deps = [
|
||||
":ObjectDetectionTrackingGpuAppLibrary",
|
||||
"@ios_opencv//:OpencvFramework",
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "ObjectDetectionTrackingGpuAppLibrary",
|
||||
data = [
|
||||
"//mediapipe/graphs/tracking:mobile_gpu_binary_graph",
|
||||
"//mediapipe/models:ssdlite_object_detection.tflite",
|
||||
"//mediapipe/models:ssdlite_object_detection_labelmap.txt",
|
||||
],
|
||||
deps = [
|
||||
"//mediapipe/examples/ios/common:CommonMediaPipeAppLibrary",
|
||||
] + select({
|
||||
"//mediapipe:ios_i386": [],
|
||||
"//mediapipe:ios_x86_64": [],
|
||||
"//conditions:default": [
|
||||
"//mediapipe/graphs/tracking:mobile_calculators",
|
||||
],
|
||||
}),
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CameraPosition</key>
|
||||
<string>back</string>
|
||||
<key>GraphName</key>
|
||||
<string>mobile_gpu</string>
|
||||
<key>GraphOutputStream</key>
|
||||
<string>output_video</string>
|
||||
<key>GraphInputStream</key>
|
||||
<string>input_video</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Reference in New Issue
Block a user