Commit ac7d28ad authored by Matteo's avatar Matteo
Browse files

refactor Args reading with dependency injection and add doxygen docs

parent cc3faa0d
using json = nlohmann::json; using json = nlohmann::json;
void extractIrregularityImagesForAudio(std::string outputPath, std::string videoPath, json irregularityFileInput, json &irregularityFileOutput2) { void extractIrregularityImagesForAudio(std::string outputPath, const std::string videoPath, json irregularityFileInput, json &irregularityFileOutput2) {
// Make fromAudioAnalyser folder // Make fromAudioAnalyser folder
int capsDirectory = fs::create_directory(outputPath + "fromAudioAnalyser/"); int capsDirectory = fs::create_directory(outputPath + "fromAudioAnalyser/");
......
/**
* @file Irregularity.h
* @author Matteo Spanio (dev2@audioinnova.com)
* @brief Header file containing the Irregularity class
* @version 1.0
* @date 2023-05-14
*
* @copyright Copyright (c) 2023
*
*/
#ifndef IRREGULARITY_H #ifndef IRREGULARITY_H
#define IRREGULARITY_H #define IRREGULARITY_H
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
......
/**
* @file IrregularityFile.h
* @author Matteo Spanio (dev2@audioinnova.com)
* @brief Header file containing the IrregularityFile class
* @version 1.0
* @date 2023-05-14
*
* @copyright Copyright (c) 2023
*
*/
#ifndef IRREGULARITY_FILE_H #ifndef IRREGULARITY_FILE_H
#define IRREGULARITY_FILE_H #define IRREGULARITY_FILE_H
......
...@@ -85,39 +85,6 @@ static json irregularityFileOutput2 {}; ...@@ -85,39 +85,6 @@ static json irregularityFileOutput2 {};
// RotatedRect identifying the processing area // RotatedRect identifying the processing area
RotatedRect rect, rectTape, rectCapstan; RotatedRect rect, rectTape, rectCapstan;
// config.json parameters
struct Config {
fs::path workingPath;
string filesName;
bool brands;
float speed;
};
struct Threshold {
float percentual;
int angle;
int scale;
int pos;
};
struct SceneObject {
int minDist;
Threshold threshold;
};
static Config config;
static SceneObject tape;
static SceneObject capstan;
// Constants Paths
static const string READING_HEAD_IMG = "input/readingHead.png";
static const string CAPSTAN_TEMPLATE_IMG = "input/capstanBERIO058prova.png";
static const string CONFIG_FILE = "config/config.json";
double rotatedRectArea(RotatedRect rect) {
return rect.size.width * rect.size.height;
}
/** /**
* @fn void pprint(string text, string color) * @fn void pprint(string text, string color)
* @brief Prints a text in a given color. * @brief Prints a text in a given color.
...@@ -129,33 +96,34 @@ void pprint(string text, string color) { ...@@ -129,33 +96,34 @@ void pprint(string text, string color) {
cout << color << text << END << endl; cout << color << text << END << endl;
} }
/** struct Args {
* @fn bool getArguments(int argc, char** argv) fs::path workingPath;
* @brief Get operation arguments from command line or config.json file. string filesName;
* bool brands;
* @param argc Command line arguments count; float speed;
* @param argv Command line arguments.
* @return true if input configuration is valid;
* @return false otherwise.
*/
bool getArguments(int argc, char** argv) {
// Read configuration file
ifstream iConfig(CONFIG_FILE);
iConfig >> configurationFile;
if (argc == 1) {
// Read from JSON file
string working_path = configurationFile["WorkingPath"];
config = {
fs::path(working_path),
configurationFile["FilesName"],
configurationFile["Brands"],
configurationFile["Speed"]
};
} else { Args(fs::path workingPath, string filesName, bool brands, float speed) {
// Get from command line this->workingPath = workingPath;
this->filesName = filesName;
this->brands = brands;
this->speed = speed;
}
~Args() {}
static Args from_file(fs::path path) {
ifstream iConfig(path);
json j;
iConfig >> j;
return Args(
fs::path(string(j["WorkingPath"])),
j["FilesName"],
j["Brands"],
j["Speed"]
);
}
static Args from_cli(int argc, char** argv) {
po::variables_map vm;
try { try {
po::options_description desc( po::options_description desc(
"A tool that implements MPAI CAE-ARP Video Analyser Technical Specification.\n" "A tool that implements MPAI CAE-ARP Video Analyser Technical Specification.\n"
...@@ -168,53 +136,41 @@ bool getArguments(int argc, char** argv) { ...@@ -168,53 +136,41 @@ bool getArguments(int argc, char** argv) {
("files-name,f", po::value<string>()->required(), "Specify the name of the Preservation files (without extension)") ("files-name,f", po::value<string>()->required(), "Specify the name of the Preservation files (without extension)")
("brands,b", po::value<bool>()->required(), "Specify if the tape presents brands on its surface") ("brands,b", po::value<bool>()->required(), "Specify if the tape presents brands on its surface")
("speed,s", po::value<float>()->required(), "Specify the speed at which the tape was read"); ("speed,s", po::value<float>()->required(), "Specify the speed at which the tape was read");
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
if (vm.count("help")) { if (vm.count("help")) {
cout << desc << "\n"; cout << desc << "\n";
return false; std::exit(EXIT_SUCCESS);
} }
po::notify(vm); po::notify(vm);
// Access the stored options
config.workingPath = fs::path(vm["working-path"].as<string>());
config.filesName = vm["files-name"].as<string>();
config.brands = vm["brands"].as<bool>();
config.speed = vm["speed"].as<float>();
} catch (po::invalid_command_line_syntax& e) { } catch (po::invalid_command_line_syntax& e) {
cerr << RED << BOLD << "The command line syntax is invalid: " << END << RED << e.what() << END << endl; pprint("The command line syntax is invalid: " + string(e.what()), RED + BOLD);
return false; std::exit(EXIT_FAILURE);
} catch (po::required_option& e) { } catch (po::required_option& e) {
cerr << "Error: " << e.what() << endl; cerr << "Error: " << e.what() << endl;
return false; std::exit(EXIT_FAILURE);
} catch (nlohmann::detail::type_error e) {
pprint("config.json error! " + string(e.what()), RED);
std::exit(EXIT_FAILURE);
} }
return Args(
fs::path(vm["working-path"].as<string>()),
vm["files-name"].as<string>(),
vm["brands"].as<bool>(),
vm["speed"].as<float>()
);
} }
};
capstan = { // Constants Paths
configurationFile["MinDistCapstan"], static const string READING_HEAD_IMG = "input/readingHead.png";
{ static const string CAPSTAN_TEMPLATE_IMG = "input/capstanBERIO058prova.png";
configurationFile["CapstanThresholdPercentual"], static const string CONFIG_FILE = "config/config.json";
configurationFile["AngleThreshCapstan"],
configurationFile["ScaleThreshCapstan"],
configurationFile["PosThreshCapstan"]
}
};
tape = {
configurationFile["MinDist"],
{
configurationFile["TapeThresholdPercentual"],
configurationFile["AngleThresh"],
configurationFile["ScaleThresh"],
configurationFile["PosThresh"]
}
};
return true; double rotatedRectArea(RotatedRect rect) {
return rect.size.width * rect.size.height;
} }
/** /**
* @fn std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> findObject(Mat model, SceneObject object) * @fn std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> findObject(Mat model, SceneObject object)
* @brief Find the model in the scene using the Generalized Hough Transform. It returns the best matches. * @brief Find the model in the scene using the Generalized Hough Transform. It returns the best matches.
...@@ -288,7 +244,7 @@ std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> findObject(Ma ...@@ -288,7 +244,7 @@ std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> findObject(Ma
* @return true if some areas have been detected; * @return true if some areas have been detected;
* @return false otherwise. * @return false otherwise.
*/ */
bool findProcessingAreas(Mat myFrame) { bool findProcessingAreas(Mat myFrame, SceneObject tape, SceneObject capstan) {
/*********************************************************************************************/ /*********************************************************************************************/
/*********************************** READING HEAD DETECTION **********************************/ /*********************************** READING HEAD DETECTION **********************************/
...@@ -353,7 +309,6 @@ bool findProcessingAreas(Mat myFrame) { ...@@ -353,7 +309,6 @@ bool findProcessingAreas(Mat myFrame) {
// Read template image - it is smaller than before, therefore there is no need to downsample // Read template image - it is smaller than before, therefore there is no need to downsample
Mat templateShape = imread(CAPSTAN_TEMPLATE_IMG, IMREAD_GRAYSCALE); Mat templateShape = imread(CAPSTAN_TEMPLATE_IMG, IMREAD_GRAYSCALE);
// templateShape = imread("../input/capstanBERIO058.png", IMREAD_GRAYSCALE);
if (useSURF) { if (useSURF) {
...@@ -506,7 +461,7 @@ Frame get_difference_for_roi(Frame previous, Frame current, RotatedRect roi) { ...@@ -506,7 +461,7 @@ Frame get_difference_for_roi(Frame previous, Frame current, RotatedRect roi) {
* @return true if a potential Irregularity has been found; * @return true if a potential Irregularity has been found;
* @return false otherwise. * @return false otherwise.
*/ */
bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) { bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd, SceneObject capstan, SceneObject tape, Args args) {
bool result = false; bool result = false;
/********************************** Capstan analysis *****************************************/ /********************************** Capstan analysis *****************************************/
...@@ -586,7 +541,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) { ...@@ -586,7 +541,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
} }
/***** BRANDS MANAGEMENT *****/ /***** BRANDS MANAGEMENT *****/
if (config.brands) { if (args.brands) {
// At the beginning of the video, wait at least 5 seconds before the next Irregularity to consider it as a brand. // At the beginning of the video, wait at least 5 seconds before the next Irregularity to consider it as a brand.
// It is not guaranteed that it will be the first brand, but it is generally a safe approach to have a correct image // It is not guaranteed that it will be the first brand, but it is generally a safe approach to have a correct image
if (firstBrand) { if (firstBrand) {
...@@ -616,7 +571,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) { ...@@ -616,7 +571,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
* *
* @param videoCapture the input Preservation Audio-Visual File; * @param videoCapture the input Preservation Audio-Visual File;
*/ */
void processing(cv::VideoCapture videoCapture) { void processing(cv::VideoCapture videoCapture, SceneObject capstan, SceneObject tape, Args args) {
const int video_length_ms = ((float) videoCapture.get(CAP_PROP_FRAME_COUNT) / videoCapture.get(CAP_PROP_FPS)) * 1000; const int video_length_ms = ((float) videoCapture.get(CAP_PROP_FRAME_COUNT) / videoCapture.get(CAP_PROP_FPS)) * 1000;
int video_current_ms = videoCapture.get(CAP_PROP_POS_MSEC); int video_current_ms = videoCapture.get(CAP_PROP_POS_MSEC);
...@@ -627,7 +582,7 @@ void processing(cv::VideoCapture videoCapture) { ...@@ -627,7 +582,7 @@ void processing(cv::VideoCapture videoCapture) {
// Whenever we find an Irregularity, we want to skip a lenght equal to the Studer reading head (3 cm = 1.18 inches). // Whenever we find an Irregularity, we want to skip a lenght equal to the Studer reading head (3 cm = 1.18 inches).
int savingRate = 79; // [ms]. Time taken to cross 3 cm at 15 ips, or 1.5 cm at 7.5 ips. The considered lengths are the widths of the tape areas. int savingRate = 79; // [ms]. Time taken to cross 3 cm at 15 ips, or 1.5 cm at 7.5 ips. The considered lengths are the widths of the tape areas.
// The following condition constitutes a valid approach if the tape areas have widths always equal to the reading head // The following condition constitutes a valid approach if the tape areas have widths always equal to the reading head
if (config.speed == 7.5) if (args.speed == 7.5)
savingRate = 157; // Time taken to cross 3 cm at 7.5 ips savingRate = 157; // Time taken to cross 3 cm at 7.5 ips
// The first frame of the video won't be processed // The first frame of the video won't be processed
...@@ -636,7 +591,7 @@ void processing(cv::VideoCapture videoCapture) { ...@@ -636,7 +591,7 @@ void processing(cv::VideoCapture videoCapture) {
firstInstant = video_length_ms - video_current_ms; firstInstant = video_length_ms - video_current_ms;
while (videoCapture.isOpened()) { while (videoCapture.isOpened()) {
cv::Mat frame; Frame frame;
videoCapture >> frame; videoCapture >> frame;
video_current_ms = videoCapture.get(CAP_PROP_POS_MSEC); video_current_ms = videoCapture.get(CAP_PROP_POS_MSEC);
...@@ -650,49 +605,34 @@ void processing(cv::VideoCapture videoCapture) { ...@@ -650,49 +605,34 @@ void processing(cv::VideoCapture videoCapture) {
if (video_current_ms == 0) // With OpenCV library, this happens at the last few frames of the video before realising that "frame" is empty. if (video_current_ms == 0) // With OpenCV library, this happens at the last few frames of the video before realising that "frame" is empty.
return; return;
// Variables to display program status // Display program status
int secToEnd = msToEnd / 1000; int secToEnd = msToEnd / 1000;
int minToEnd = (secToEnd / 60) % 60; int minToEnd = (secToEnd / 60) % 60;
secToEnd = secToEnd % 60; secToEnd = secToEnd % 60;
string secStrToEnd = secToEnd < 10 ? "0" + to_string(secToEnd) : to_string(secToEnd);
string minStrToEnd = minToEnd < 10 ? "0" + to_string(minToEnd) : to_string(minToEnd);
string secStrToEnd = to_string(secToEnd), minStrToEnd = to_string(minToEnd);
if (minToEnd < 10)
minStrToEnd = "0" + minStrToEnd;
if (secToEnd < 10)
secStrToEnd = "0" + secStrToEnd;
// Display program status
cout << "\rIrregularities: " << savedFrames << ". "; cout << "\rIrregularities: " << savedFrames << ". ";
cout << "Remaining video time [mm:ss]: " << minStrToEnd << ":" << secStrToEnd << flush; cout << "Remaining video time [mm:ss]: " << minStrToEnd << ":" << secStrToEnd << flush;
if ((video_current_ms - lastSaved > savingRate) && frameDifference(prevFrame, frame, msToEnd)) { if ((video_current_ms - lastSaved > savingRate) && frameDifference(prevFrame, frame, msToEnd, capstan, tape, args)) {
// An Irregularity has been found! // An Irregularity has been found!
// De-interlacing frame auto [odd_frame, even_frame] = frame.deinterlace();
cv::Mat oddFrame(frame.rows/2, frame.cols, CV_8UC3);
cv::Mat evenFrame(frame.rows/2, frame.cols, CV_8UC3);
utility::separateFrame(frame, oddFrame, evenFrame);
// Extract the image corresponding to the ROIs // Extract the image corresponding to the ROIs
Point2f pts[4]; Point2f pts[4];
if (savingPinchRoller) savingPinchRoller ? rectCapstan.points(pts) : rectTape.points(pts);
rectCapstan.points(pts);
else Frame subImage(cv::Mat(frame, cv::Rect(100, min(pts[1].y, pts[2].y), frame.cols - 100, static_cast<int>(rectTape.size.height))));
rectTape.points(pts); // the following comment was in the previous code, if some errors occur, add this correction in the deinterlace method
cv::Mat subImage(frame, cv::Rect(100, min(pts[1].y, pts[2].y), frame.cols - 100, static_cast<int>(rectTape.size.height))); // If the found rectangle is of odd height, we must increase evenSubImage height by 1, otherwise we have segmentation_fault!!!
auto [oddSubImage, evenSubImage] = subImage.deinterlace();
// De-interlacing
cv::Mat oddSubImage(subImage.rows/2, subImage.cols, CV_8UC3);
int evenSubImageRows = subImage.rows/2;
if (subImage.rows % 2 != 0) // If the found rectangle is of odd height, we must increase evenSubImage height by 1, otherwise we have segmentation_fault!!!
evenSubImageRows += 1;
cv::Mat evenSubImage(evenSubImageRows, subImage.cols, CV_8UC3);
utility::separateFrame(subImage, oddSubImage, evenSubImage);
string timeLabel = getTimeLabel(video_current_ms, ":"); string timeLabel = getTimeLabel(video_current_ms, ":");
string safeTimeLabel = getTimeLabel(video_current_ms, "-"); string safeTimeLabel = getTimeLabel(video_current_ms, "-");
string irregularityImageFilename = to_string(savedFrames) + "_" + safeTimeLabel + ".jpg"; string irregularityImageFilename = to_string(savedFrames) + "_" + safeTimeLabel + ".jpg";
cv::imwrite(irregularityImagesPath / irregularityImageFilename, oddFrame); cv::imwrite(irregularityImagesPath / irregularityImageFilename, odd_frame); // FIXME: should it be frame? or maybe is only odd for the classification step?
// Append Irregularity information to JSON // Append Irregularity information to JSON
Irregularity irreg = Irregularity(Source::Video, timeLabel); Irregularity irreg = Irregularity(Source::Video, timeLabel);
...@@ -726,68 +666,56 @@ void processing(cv::VideoCapture videoCapture) { ...@@ -726,68 +666,56 @@ void processing(cv::VideoCapture videoCapture) {
*/ */
int main(int argc, char** argv) { int main(int argc, char** argv) {
Args args = argc > 1 ? Args::from_cli(argc, argv) : Args::from_file(CONFIG_FILE);
SceneObject capstan = SceneObject::from_file(CONFIG_FILE, Object::CAPSTAN);
SceneObject tape = SceneObject::from_file(CONFIG_FILE, Object::TAPE);
json irregularityFileInput; json irregularityFileInput;
fs::path irregularityFileInputPath; fs::path irregularityFileInputPath;
cv::Mat myFrame; cv::Mat myFrame;
/*********************************************************************************************/ const fs::path VIDEO_PATH = args.workingPath / "PreservationAudioVisualFile" / args.filesName;
/*************************************** CONFIGURATION ***************************************/
/*********************************************************************************************/
// Get the input from config.json or command line
try {
bool continueExecution = getArguments(argc, argv);
if (!continueExecution) {
return 0;
}
} catch (nlohmann::detail::type_error e) {
cerr << RED << "config.json error!" << endl << e.what() << END << endl;
return -1;
}
const fs::path VIDEO_PATH = config.workingPath / "PreservationAudioVisualFile" / config.filesName;
if (files::findFileName(VIDEO_PATH, fileName, extension) == -1) { if (files::findFileName(VIDEO_PATH, fileName, extension) == -1) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << VIDEO_PATH.string() << " cannot be found or opened." << END << endl; cerr << RED << BOLD << "Input error!" << END << endl << RED << VIDEO_PATH.string() << " cannot be found or opened." << END << endl;
return -1; std::exit(EXIT_FAILURE);
} }
irregularityFileInputPath = config.workingPath / "temp" / fileName / "AudioAnalyser_IrregularityFileOutput1.json"; irregularityFileInputPath = args.workingPath / "temp" / fileName / "AudioAnalyser_IrregularityFileOutput1.json";
// Input JSON check // Input JSON check
ifstream iJSON(irregularityFileInputPath); ifstream iJSON(irregularityFileInputPath);
if (iJSON.fail()) { if (iJSON.fail()) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << irregularityFileInputPath.string() << " cannot be found or opened." << END << endl; cerr << RED << BOLD << "config.json error!" << END << endl << RED << irregularityFileInputPath.string() << " cannot be found or opened." << END << endl;
return -1; std::exit(EXIT_FAILURE);
} }
if (config.speed != 7.5 && config.speed != 15) { if (args.speed != 7.5 && args.speed != 15) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "Speed parameter must be 7.5 or 15 ips." << END << endl; cerr << RED << BOLD << "config.json error!" << END << endl << RED << "Speed parameter must be 7.5 or 15 ips." << END << endl;
return -1; std::exit(EXIT_FAILURE);
} }
if (tape.threshold.percentual < 0 || tape.threshold.percentual > 100) { if (tape.threshold.percentual < 0 || tape.threshold.percentual > 100) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "TapeThresholdPercentual parameter must be a percentage value." << END << endl; cerr << RED << BOLD << "config.json error!" << END << endl << RED << "TapeThresholdPercentual parameter must be a percentage value." << END << endl;
return -1; std::exit(EXIT_FAILURE);
} }
if (capstan.threshold.percentual < 0 || capstan.threshold.percentual > 100) { if (capstan.threshold.percentual < 0 || capstan.threshold.percentual > 100) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "CapstanThresholdPercentual parameter must be a percentage value." << END << endl; cerr << RED << BOLD << "config.json error!" << END << endl << RED << "CapstanThresholdPercentual parameter must be a percentage value." << END << endl;
return -1; std::exit(EXIT_FAILURE);
} }
// Adjust input paramenters (considering given ones as pertinent to a speed reference = 7.5) // Adjust input paramenters (considering given ones as pertinent to a speed reference = 7.5)
if (config.brands) { if (args.brands) {
if (config.speed == 15) if (args.speed == 15)
tape.threshold.percentual += 6; tape.threshold.percentual += 6;
} else } else
if (config.speed == 15) if (args.speed == 15)
tape.threshold.percentual += 20; tape.threshold.percentual += 20;
else else
tape.threshold.percentual += 21; tape.threshold.percentual += 21;
cout << endl; cout << endl;
cout << "Parameters:" << endl; cout << "Parameters:" << endl;
cout << " Brands: " << config.brands << endl; cout << " Brands: " << args.brands << endl;
cout << " Speed: " << config.speed << endl; cout << " Speed: " << args.speed << endl;
cout << " ThresholdPercentual: " << tape.threshold.percentual << endl; cout << " ThresholdPercentual: " << tape.threshold.percentual << endl;
cout << " ThresholdPercentualCapstan: " << capstan.threshold.percentual << endl; cout << " ThresholdPercentualCapstan: " << capstan.threshold.percentual << endl;
cout << endl; cout << endl;
...@@ -800,7 +728,7 @@ int main(int argc, char** argv) { ...@@ -800,7 +728,7 @@ int main(int argc, char** argv) {
/*********************************************************************************************/ /*********************************************************************************************/
// Make directory with fileName name // Make directory with fileName name
outputPath = config.workingPath / "temp" / fileName; outputPath = args.workingPath / "temp" / fileName;
int outputFileNameDirectory = create_directory(outputPath); int outputFileNameDirectory = create_directory(outputPath);
irregularityImagesPath = outputPath / "IrregularityImages"; irregularityImagesPath = outputPath / "IrregularityImages";
...@@ -812,8 +740,8 @@ int main(int argc, char** argv) { ...@@ -812,8 +740,8 @@ int main(int argc, char** argv) {
cv::VideoCapture videoCapture(VIDEO_PATH); cv::VideoCapture videoCapture(VIDEO_PATH);
if (!videoCapture.isOpened()) { if (!videoCapture.isOpened()) {
cerr << RED << BOLD << "Video unreadable." << END << endl; pprint("Video unreadable.", RED + BOLD);
return -1; std::exit(EXIT_FAILURE);
} }
int frames_number = videoCapture.get(CAP_PROP_FRAME_COUNT); int frames_number = videoCapture.get(CAP_PROP_FRAME_COUNT);
...@@ -824,14 +752,14 @@ int main(int argc, char** argv) { ...@@ -824,14 +752,14 @@ int main(int argc, char** argv) {
cout << "Video resolution: " << myFrame.cols << "x" << myFrame.rows << endl; cout << "Video resolution: " << myFrame.cols << "x" << myFrame.rows << endl;
bool found = findProcessingAreas(myFrame); bool found = findProcessingAreas(myFrame, tape, capstan);
// Reset frame position // Reset frame position
videoCapture.set(CAP_PROP_POS_FRAMES, 0); videoCapture.set(CAP_PROP_POS_FRAMES, 0);
if (!found) { if (!found) {
pprint("Processing area not found. Try changing JSON parameters.", RED); pprint("Processing area not found. Try changing JSON parameters.", RED);
return -1; // Program terminated early std::exit(EXIT_FAILURE);
} }
/*********************************************************************************************/ /*********************************************************************************************/
...@@ -844,7 +772,7 @@ int main(int argc, char** argv) { ...@@ -844,7 +772,7 @@ int main(int argc, char** argv) {
time_t startTimer, endTimer; time_t startTimer, endTimer;
startTimer = time(NULL); startTimer = time(NULL);
processing(videoCapture); processing(videoCapture, capstan, tape, args);
endTimer = time(NULL); endTimer = time(NULL);
float min = (endTimer - startTimer) / 60; float min = (endTimer - startTimer) / 60;
......
#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
#include "utility.h" #include "utility.h"
using namespace cv; using namespace cv;
using namespace std; using namespace std;
using json = nlohmann::json;
// Constructors // Constructors
utility::Frame::Frame() : Mat() {} utility::Frame::Frame() : Mat() {}
utility::Frame::Frame(const Mat& m) : Mat(m) {} utility::Frame::Frame(const Mat& m) : Mat(m) {}
...@@ -39,6 +44,14 @@ utility::Frame& utility::Frame::warp(cv::Mat rotationMatrix) { ...@@ -39,6 +44,14 @@ utility::Frame& utility::Frame::warp(cv::Mat rotationMatrix) {
cv::warpAffine(*this, *this, rotationMatrix, this->size(), INTER_CUBIC); cv::warpAffine(*this, *this, rotationMatrix, this->size(), INTER_CUBIC);
return *this; return *this;
} }
pair<utility::Frame, utility::Frame> utility::Frame::deinterlace() const {
Frame odd_frame(cv::Mat(this->rows/2, this->cols, CV_8UC3));
Frame even_frame(cv::Mat(this->rows/2, this->cols, CV_8UC3));
utility::separateFrame(*this, odd_frame, even_frame);
return make_pair(odd_frame, even_frame);
}
void utility::detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh, vector<Vec4f> &positivePositions, Mat &positiveVotes, vector<Vec4f> &negativePositions, Mat &negativeVotes, Mat processingArea) { void utility::detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh, vector<Vec4f> &positivePositions, Mat &positiveVotes, vector<Vec4f> &negativePositions, Mat &negativeVotes, Mat processingArea) {
...@@ -147,7 +160,7 @@ RotatedRect utility::drawShapes(Mat frame, Vec4f &positions, Scalar color, int w ...@@ -147,7 +160,7 @@ RotatedRect utility::drawShapes(Mat frame, Vec4f &positions, Scalar color, int w
return rr; return rr;
} }
void utility::separateFrame(cv::Mat frame, cv::Mat &odd_frame, cv::Mat &even_frame) { void utility::separateFrame(const cv::Mat frame, cv::Mat &odd_frame, cv::Mat &even_frame) {
int i_odd_frame = 0; int i_odd_frame = 0;
int i_even_frame = 0; int i_even_frame = 0;
...@@ -190,4 +203,37 @@ cv::Mat utility::difference(cv::Mat &prevFrame, cv::Mat &currentFrame) { ...@@ -190,4 +203,37 @@ cv::Mat utility::difference(cv::Mat &prevFrame, cv::Mat &currentFrame) {
} }
} }
return diff; return diff;
}
SceneObject::SceneObject(int minDist, Threshold threshold) {
this->minDist = minDist;
this->threshold = threshold;
}
SceneObject SceneObject::from_file(fs::path path, Object obj) {
ifstream iConfig(path);
json j;
iConfig >> j;
if (obj == Object::TAPE) {
return SceneObject(
j["MinDist"],
Threshold {
j["TapeThresholdPercentual"],
j["AngleThresh"],
j["ScaleThresh"],
j["PosThresh"]
}
);
} else {
return SceneObject(
j["MinDistCapstan"],
Threshold {
j["CapstanThresholdPercentual"],
j["AngleThreshCapstan"],
j["ScaleThreshCapstan"],
j["PosThreshCapstan"]
}
);
}
} }
\ No newline at end of file
...@@ -27,14 +27,44 @@ namespace utility { ...@@ -27,14 +27,44 @@ namespace utility {
Frame& operator=(const Mat& m); Frame& operator=(const Mat& m);
Frame& operator=(const Frame& f); Frame& operator=(const Frame& f);
Frame clone() const; Frame clone() const;
/**
* @brief Downsample the image by a given factor.
*
* @param factor The factor by which the image will be downsampled.
* @return Frame& The downsampled image.
*/
Frame& downsample(int factor); Frame& downsample(int factor);
/**
* @brief Convert the image to a given color space.
*
* @param code The code of the color space to which the image will be converted.
* @return Frame& The converted image.
*/
Frame& convertColor(int code); Frame& convertColor(int code);
Frame difference(Frame& f); Frame difference(Frame& f);
/**
* @brief Crop the image to a given size, centered in a given point.
*
* @param rect_size The size of the cropped image.
* @param center The center of the cropped image.
* @return Frame& The cropped image.
*/
Frame& crop(Size rect_size, Point2f center); Frame& crop(Size rect_size, Point2f center);
/**
* @brief Warp the image using a given rotation matrix.
*
* @param rotationMatrix The rotation matrix used to warp the image.
* @return Frame& The warped image.
*/
Frame& warp(cv::Mat rotationMatrix); Frame& warp(cv::Mat rotationMatrix);
/**
* @brief Deinterlace the image, returning two images, one containing the odd lines and the other containing the even lines.
*
* @return std::pair<Frame, Frame> The two images containing the odd and even lines.
*/
std::pair<Frame, Frame> deinterlace() const;
}; };
/** /**
* @fn void detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh, vector<Vec4f> &positivePositions, Mat &positiveVotes, vector<Vec4f> &negativePositions, Mat &negativeVotes, Mat processingArea) * @fn void detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh, vector<Vec4f> &positivePositions, Mat &positiveVotes, vector<Vec4f> &negativePositions, Mat &negativeVotes, Mat processingArea)
* @brief Detects a given shape in an image, using a the OpenCV algorithm GeneralizedHoughGuil. * @brief Detects a given shape in an image, using a the OpenCV algorithm GeneralizedHoughGuil.
...@@ -75,7 +105,7 @@ namespace utility { ...@@ -75,7 +105,7 @@ namespace utility {
* @param[out] odd_frame odd plane; * @param[out] odd_frame odd plane;
* @param[out] even_frame even plane. * @param[out] even_frame even plane.
*/ */
void separateFrame(cv::Mat frame, cv::Mat &odd_frame, cv::Mat &even_frame); void separateFrame(const cv::Mat frame, cv::Mat &odd_frame, cv::Mat &even_frame);
/** /**
...@@ -88,3 +118,25 @@ namespace utility { ...@@ -88,3 +118,25 @@ namespace utility {
*/ */
cv::Mat difference(cv::Mat &prevFrame, cv::Mat &currentFrame); cv::Mat difference(cv::Mat &prevFrame, cv::Mat &currentFrame);
} }
struct Threshold {
float percentual;
int angle;
int scale;
int pos;
};
enum Object {
TAPE,
CAPSTAN
};
struct SceneObject {
int minDist;
Threshold threshold;
SceneObject(int minDist, Threshold threshold);
~SceneObject() = default;
static SceneObject from_file(fs::path path, Object obj);
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment