Skip to content

Commit

Permalink
Merge pull request openvinotoolkit#1229 from Wovchena/imgCap
Browse files Browse the repository at this point in the history
Unify input processing
  • Loading branch information
Roman Donchenko authored Aug 7, 2020
2 parents 4b6bebf + ae83ae1 commit 649aa93
Show file tree
Hide file tree
Showing 25 changed files with 446 additions and 380 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ The demo's name should end with `_demo` suffix to follow the convention of the p

Demos are required to support the following keys:

- `-i "<input>"`: Required. Input to process.
- `-i "<input>"`: Required. An input to process. The input can usually be a single image, a folder of images or anything that OpenCV's `VideoCapture` can process.
- `-m "<path>"`: Required. Path to an .xml file with a trained model. If the demo uses several models at the same time, use other keys prefixed with `-m_`.
- `-d "<device>"`: Optional. Specifies a target device to infer on. CPU, GPU, FPGA, HDDL or MYRIAD is acceptable. Default must be CPU. If the demo uses several models at the same time, use keys prefixed with `d_` (just like keys `m_*` above) to specify device for each model.
- `-no_show`: Optional. Do not visualize inference results.
Expand Down
4 changes: 2 additions & 2 deletions demos/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#

find_package(InferenceEngine 2.0 REQUIRED)
find_package(OpenCV REQUIRED COMPONENTS core)
find_package(OpenCV REQUIRED COMPONENTS core imgcodecs videoio)

add_subdirectory(monitors)

Expand All @@ -15,4 +15,4 @@ source_group("include" FILES ${HEADERS})

add_library(common STATIC ${HEADERS} ${SOURCES})
target_include_directories(common PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(common PRIVATE gflags ${InferenceEngine_LIBRARIES} opencv_core)
target_link_libraries(common PRIVATE gflags ${InferenceEngine_LIBRARIES} opencv_core opencv_imgcodecs opencv_videoio)
2 changes: 1 addition & 1 deletion demos/common/include/samples/args_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
void readInputFilesArguments(std::vector<std::string>& files, const std::string& arg);

/**
* @brief This function find -i/--images key in input args
* @brief This function finds -i/--i key in input args
* It's necessary to process multiple values for single key
* @return files updated vector of verified input files
*/
Expand Down
15 changes: 15 additions & 0 deletions demos/common/include/samples/default_flags.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <gflags/gflags.h>

#define DEFINE_INPUT_FLAGS \
DEFINE_string(i, "", input_message); \
DEFINE_bool(loop, false, loop_message);

static const char input_message[] = "Required. An input to process. The input must be a single image, a folder of "
"images or anything that cv::VideoCapture can process.";
static const char loop_message[] = "Optional. Enable reading the input in a loop.";
34 changes: 34 additions & 0 deletions demos/common/include/samples/images_capture.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <memory>
#include <string>

#include <opencv2/core/mat.hpp>
#include <opencv2/videoio.hpp>

class ImagesCapture {
public:
const bool loop;

ImagesCapture(bool loop) : loop{loop} {}
virtual double fps() const = 0;
virtual size_t lastImageId() const = 0;
virtual cv::Mat read() = 0;
virtual ~ImagesCapture() = default;
};

// An advanced version of
// try {
// return cv::VideoCapture(std::stoi(input));
// } catch (const std::invalid_argument&) {
// return cv::VideoCapture(input);
// } catch (const std::out_of_range&) {
// return cv::VideoCapture(input);
// }
std::unique_ptr<ImagesCapture> openImagesCapture(const std::string &input,
bool loop, size_t initialImageId=0, // Non camera options
size_t readLengthLimit=std::numeric_limits<size_t>::max(), // general option
// Camera option:
bool autoFocus=true);
2 changes: 1 addition & 1 deletion demos/common/src/args_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void parseInputFilesArguments(std::vector<std::string>& files) {
std::vector<std::string> args = gflags::GetArgvs();
bool readArguments = false;
for (size_t i = 0; i < args.size(); i++) {
if (args.at(i) == "-i" || args.at(i) == "--images") {
if (args.at(i) == "-i" || args.at(i) == "--i") {
readArguments = true;
continue;
}
Expand Down
178 changes: 178 additions & 0 deletions demos/common/src/images_capture.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "samples/images_capture.h"

#ifdef _WIN32
#include "w_dirent.hpp"
#else
#include <dirent.h>
#endif

#include <opencv2/imgcodecs.hpp>

#include <stdexcept>
#include <string>
#include <memory>

class InvalidInput {};

class ImreadWrapper : public ImagesCapture {
cv::Mat img;
bool canRead;

public:
ImreadWrapper(const std::string &input, bool loop) : ImagesCapture{loop}, canRead{true} {
img = cv::imread(input);
if(!img.data) throw InvalidInput{};
}

double fps() const override {return 0.0;}

size_t lastImageId() const override {return 0;}

cv::Mat read() override {
if (loop) return img.clone();
if (canRead) {
canRead = false;
return img.clone();
}
return cv::Mat{};
}
};

class DirReader : public ImagesCapture {
std::vector<std::string> names;
size_t fileId;
size_t nextImgId;
const size_t initialImageId;
const size_t readLengthLimit;
const std::string input;

public:
DirReader(const std::string &input, bool loop, size_t initialImageId, size_t readLengthLimit) : ImagesCapture{loop},
fileId{0}, nextImgId{0}, initialImageId{initialImageId}, readLengthLimit{readLengthLimit}, input{input} {
DIR *dir = opendir(input.c_str());
if (!dir) throw InvalidInput{};
while (struct dirent *ent = readdir(dir))
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
names.emplace_back(ent->d_name);
closedir(dir);
if (names.empty()) throw InvalidInput{};
sort(names.begin(), names.end());
size_t readImgs = 0;
while (fileId < names.size()) {
cv::Mat img = cv::imread(input + '/' + names[fileId]);
if (img.data) {
++readImgs;
if (readImgs - 1 >= initialImageId) return;
}
++fileId;
}
throw std::runtime_error{"Can't read the first image from " + input + " dir"};
}

double fps() const override {return 0.0;}

size_t lastImageId() const override {return nextImgId - 1;}

cv::Mat read() override {
while (fileId < names.size() && nextImgId < readLengthLimit) {
cv::Mat img = cv::imread(input + '/' + names[fileId]);
++fileId;
if (img.data) {
++nextImgId;
return img;
}
}
if (loop) {
fileId = 0;
size_t readImgs = 0;
while (fileId < names.size()) {
cv::Mat img = cv::imread(input + '/' + names[fileId]);
++fileId;
if (img.data) {
++readImgs;
if (readImgs - 1 >= initialImageId) {
nextImgId = 1;
return img;
}
}
}
}
return cv::Mat{};
}
};

class VideoCapWrapper : public ImagesCapture {
cv::VideoCapture cap;
size_t nextImgId;
const double initialImageId;
size_t readLengthLimit;

public:
VideoCapWrapper(const std::string &input, bool loop, size_t initialImageId, size_t readLengthLimit, bool autoFocus)
: ImagesCapture{loop}, nextImgId{0}, initialImageId{static_cast<double>(initialImageId)} {
try {
cap.open(std::stoi(input));
this->readLengthLimit = loop ? std::numeric_limits<size_t>::max() : readLengthLimit;
cap.set(cv::CAP_PROP_BUFFERSIZE, 1);
cap.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
cap.set(cv::CAP_PROP_AUTOFOCUS, autoFocus);
cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
} catch (const std::invalid_argument&) {
cap.open(input);
this->readLengthLimit = readLengthLimit;
if (!cap.set(cv::CAP_PROP_POS_FRAMES, this->initialImageId))
throw std::runtime_error{"Can't set the frame to begin with"};
} catch (const std::out_of_range&) {
cap.open(input);
this->readLengthLimit = readLengthLimit;
if (!cap.set(cv::CAP_PROP_POS_FRAMES, this->initialImageId))
throw std::runtime_error{"Can't set the frame to begin with"};
}
if (!cap.isOpened()) throw InvalidInput{};
}

double fps() const override {return cap.get(cv::CAP_PROP_FPS);}

size_t lastImageId() const override {return nextImgId - 1;}

cv::Mat read() override {
if (nextImgId >= readLengthLimit) {
if (loop && cap.set(cv::CAP_PROP_POS_FRAMES, initialImageId)) {
nextImgId = 1;
cv::Mat img;
cap.read(img);
return img;
}
return cv::Mat{};
}
cv::Mat img;
if (!cap.read(img) && loop && cap.set(cv::CAP_PROP_POS_FRAMES, initialImageId)) {
nextImgId = 1;
cap.read(img);
} else {
++nextImgId;
}
return img;
}
};

std::unique_ptr<ImagesCapture> openImagesCapture(const std::string &input, bool loop, size_t initialImageId,
size_t readLengthLimit, bool autoFocus) {
if (readLengthLimit == 0) throw std::runtime_error{"Read length limit must be positive"};
try {
return std::unique_ptr<ImagesCapture>(new ImreadWrapper{input, loop});
} catch (const InvalidInput &) {}
try {
return std::unique_ptr<ImagesCapture>(new DirReader{input, loop, initialImageId, readLengthLimit});
} catch (const InvalidInput &) {}
try {
return std::unique_ptr<ImagesCapture>(new VideoCapWrapper{input, loop, initialImageId, readLengthLimit,
autoFocus});
} catch (const InvalidInput &) {}
throw std::runtime_error{"Can't read " + input};
}
12 changes: 4 additions & 8 deletions demos/crossroad_camera_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,18 @@ REID value is assigned. Otherwise, the vector is added to a global list, and new

Running the application with the `-h` option yields the following usage message:
```
./crossroad_camera_demo -h
InferenceEngine:
API version ............ <version>
Build .................. <number>
crossroad_camera_demo [OPTION]
Options:
-h Print a usage message.
-i "<path>" Required. Path to a video or image file. Default value is "cam" to work with camera.
-i Required. An input to process. The input must be a single image, a folder of images or anything that cv::VideoCapture can process.
-loop Optional. Enable reading the input in a loop.
-m "<path>" Required. Path to the Person/Vehicle/Bike Detection Crossroad model (.xml) file.
-m_pa "<path>" Optional. Path to the Person Attributes Recognition Crossroad model (.xml) file.
-m_reid "<path>" Optional. Path to the Person Reidentification Retail model (.xml) file.
-l "<absolute_path>" Optional. For CPU custom layers, if any. Absolute path to a shared library with the kernels impl.
-l "<absolute_path>" Optional. For MKLDNN (CPU)-targeted custom layers, if any. Absolute path to a shared library with the kernels impl.
Or
-c "<absolute_path>" Optional. For GPU custom kernels, if any. Absolute path to the xml file with the kernels desc.
-c "<absolute_path>" Optional. For clDNN (GPU)-targeted custom kernels, if any. Absolute path to the xml file with the kernels desc.
-d "<device>" Optional. Specify the target device for Person/Vehicle/Bike Detection. The list of available devices is shown below. Default value is CPU. Use "-d HETERO:<comma-separated_devices_list>" format to specify HETERO plugin. The application looks for a suitable plugin for the specified device.
-d_pa "<device>" Optional. Specify the target device for Person Attributes Recognition. The list of available devices is shown below. Default value is CPU. Use "-d HETERO:<comma-separated_devices_list>" format to specify HETERO plugin. The application looks for a suitable plugin for the specified device.
-d_reid "<device>" Optional. Specify the target device for Person Reidentification Retail. The list of available devices is shown below. Default value is CPU. Use "-d HETERO:<comma-separated_devices_list>" format to specify HETERO plugin. The application looks for a suitable plugin for the specified device.
Expand Down
9 changes: 6 additions & 3 deletions demos/crossroad_camera_demo/crossroad_camera_demo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
#include <vector>
#include <gflags/gflags.h>

#include <samples/default_flags.hpp>

DEFINE_INPUT_FLAGS

static const char help_message[] = "Print a usage message.";
static const char video_message[] = "Required. Path to a video or image file. Default value is \"cam\" to work with camera.";
static const char person_vehicle_bike_detection_model_message[] = "Required. Path to the Person/Vehicle/Bike Detection Crossroad model (.xml) file.";
static const char person_attribs_model_message[] = "Optional. Path to the Person Attributes Recognition Crossroad model (.xml) file.";
static const char person_reid_model_message[] = "Optional. Path to the Person Reidentification Retail model (.xml) file.";
Expand Down Expand Up @@ -42,7 +45,6 @@ static const char utilization_monitors_message[] = "Optional. List of monitors t


DEFINE_bool(h, false, help_message);
DEFINE_string(i, "cam", video_message);
DEFINE_string(m, "", person_vehicle_bike_detection_model_message);
DEFINE_string(m_pa, "", person_attribs_model_message);
DEFINE_string(m_reid, "", person_reid_model_message);
Expand Down Expand Up @@ -72,7 +74,8 @@ static void showUsage() {
std::cout << "Options:" << std::endl;
std::cout << std::endl;
std::cout << " -h " << help_message << std::endl;
std::cout << " -i \"<path>\" " << video_message << std::endl;
std::cout << " -i " << input_message << std::endl;
std::cout << " -loop " << loop_message << std::endl;
std::cout << " -m \"<path>\" " << person_vehicle_bike_detection_model_message<< std::endl;
std::cout << " -m_pa \"<path>\" " << person_attribs_model_message << std::endl;
std::cout << " -m_reid \"<path>\" " << person_reid_model_message << std::endl;
Expand Down
Loading

0 comments on commit 649aa93

Please sign in to comment.