Commit b9bc6ead authored by Matteo's avatar Matteo
Browse files

update

parent d0acaf14
......@@ -2,6 +2,6 @@
.vscode
/input/*.mov
/output/*
.bin/
bin/
build/
log.txt
......@@ -7,6 +7,19 @@ SET(CMAKE_CXX_STANDARD 23)
LINK_DIRECTORIES(/usr/local/lib)
add_library(analyser_lib
src/lib/colors.h
src/lib/Irregularity.cpp
src/lib/IrregularityFile.cpp
src/lib/Irregularity.h
src/lib/parser.cpp
src/lib/parser.h
src/lib/time.cpp
src/lib/time.h
src/lib/validation.cpp
src/lib/validation.h
)
FIND_PACKAGE(OpenCV REQUIRED)
FIND_PACKAGE(nlohmann_json 3.2.0 REQUIRED)
FIND_PACKAGE(Boost COMPONENTS program_options REQUIRED)
......@@ -14,5 +27,11 @@ FIND_PACKAGE(Boost COMPONENTS program_options REQUIRED)
INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
ADD_EXECUTABLE(video_analyser ./src/script.cpp)
TARGET_LINK_LIBRARIES(video_analyser ${OpenCV_LIBRARIES} nlohmann_json::nlohmann_json ${Boost_PROGRAM_OPTIONS_LIBRARY})
ADD_EXECUTABLE(video_analyser ./src/main.cpp)
TARGET_LINK_LIBRARIES(video_analyser
${OpenCV_LIBRARIES}
nlohmann_json::nlohmann_json
${Boost_PROGRAM_OPTIONS_LIBRARY}
analyser_lib
)
......@@ -6,9 +6,9 @@ WORKDIR /app
COPY . ./
RUN apt update && apt install libboost-program-options-dev git build-essential cmake g++ wget unzip python3 python3-pip -y
RUN apt update && apt install libboost-program-options-dev git build-essential cmake g++ wget unzip python3 python3-pip libgtk-3-dev libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libjpeg-dev libpng-dev python3-dev libavdevice-dev libdc1394-dev libgstreamer-opencv1.0-0 libavutil-dev ffmpeg -y
RUN mkdir opencv_source && cd ./opencv_source && wget -O opencv.zip https://github.com/opencv/opencv/archive/4.5.4.zip && wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.5.4.zip && unzip opencv.zip && unzip opencv_contrib.zip && mkdir -p build && cd ./build && cmake -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.5.4/modules ../opencv-4.5.4 && make -j4 && make install && cd /app
RUN mkdir opencv_source && cd ./opencv_source && wget -O opencv.zip https://github.com/opencv/opencv/archive/4.5.4.zip && wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.5.4.zip && unzip opencv.zip && unzip opencv_contrib.zip && mkdir -p build && cd ./build && cmake -D OPENCV_GENERATE_PKGCONFIG=YES -D WITH_FFMPEG=ON -D WITH_V4L=ON -D WITH_PNG=ON -D WITH_GSTREAMER=ON -D BUILD_opencv_video=ON -D BUILD_opencv_videoio=ON -D OPENCV_ENABLE_NONFREE=ON -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.5.4/modules ../opencv-4.5.4 && make -j4 && make install && cd /app
RUN git clone https://github.com/nlohmann/json.git
......@@ -18,8 +18,4 @@ RUN rm -r opencv_source json
RUN cd ./build && cmake .. && make && cd /app
RUN cd ./server && pip install --no-cache-dir -r requirements.txt && cd /app
VOLUME [ "/data" ]
CMD ["uvicorn", "server.main:app", "--host", "0.0.0.0", "--log-config", "server/config.yaml", "--port", "80", "--root-path", "/video-analyzer"]
\ No newline at end of file
VOLUME [ "/data" ]
\ No newline at end of file
{
"WorkingPath": "/home/matteo/Scrivania/Projects/workflow/data",
"FilesName": "BERIO100.mov",
"FilesName": "BERIO052.mov",
"Brands": true,
"Speed": 7.5,
"TapeThresholdPercentual": 80,
......
#include "Irregularity.h"
Irregularity::Irregularity()
{
}
Irregularity Irregularity::fromJSON(json irregularityJSON)
{
Irregularity irregularity;
return irregularity;
}
json Irregularity::toJSON()
{
json irregularityJSON;
return irregularityJSON;
}
\ No newline at end of file
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#ifndef IRREGULARITY_H
#define IRREGULARITY_H
class Irregularity
{
public:
Irregularity();
static Irregularity fromJSON(json irregularityJSON);
json toJSON();
};
#endif // IRREGULARITY_H
\ No newline at end of file
#include "IrregularityFile.h"
IrregularityFile::IrregularityFile(/* args */)
{
}
IrregularityFile::~IrregularityFile()
{
}
#ifndef IRREGULARITYFILE_H
#define IRREGULARITYFILE_H
class IrregularityFile
{
private:
/* data */
public:
IrregularityFile(/* args */);
~IrregularityFile();
};
#endif // IRREGULARITYFILE_H
\ No newline at end of file
#include <stdlib.h>
#include <string>
using std::string;
string PURPLE = "\033[95m";
string CYAN = "\033[96m";
string DARK_CYAN = "\033[36m";
string BLUE = "\033[94m";
string GREEN = "\033[92m";
string YELLOW = "\033[93m";
string RED = "\033[91m";
string BOLD = "\033[1m";
string UNDERLINE = "\033[4m";
string END = "\033[0m";
\ No newline at end of file
#include <iostream>
#include "parser.h"
using std::string, std::cout, std::endl, std::cerr;
/**
* @brief Separates video file name from its extension.
*
* @param[in] path Full video path;
* @param[out] fileName Video file name;
* @param[out] extension Video extension.
*/
void findFileNameFromPath(string* path, string* fileName, string* extension) {
*path = path->substr(path->find_last_of("'") + 1, path->size());
string path_without_extension = path->substr(0, path->find_last_of("."));
*fileName = path_without_extension.substr(path_without_extension.find_last_of("/") + 1, path_without_extension.size());
*extension = path->substr(path->find_last_of(".") + 1, path->size());
}
/**
* @brief Check if the specified input video file exists and is supported.
*
* @param[in] videoPath Full video path;
* @param[out] fileName Video file name;
* @param[out] extension Video extension.
* @return int -1 if the format is not supported, 0 otherwise.
*/
int findFileName(string videoPath, string &fileName, string &extension) {
findFileNameFromPath(&videoPath, &fileName, &extension);
if (extension.compare("avi") != 0 && extension.compare("mp4") != 0 && extension.compare("mov") != 0) {
cerr << "Input file extension must be \"avi\", \"mp4\" or \"mov\"." << endl;
return -1;
} else {
cout << "Video to be analysed: " << endl;
cout << " File name: " << fileName << endl;
cout << " Extension: " << extension << endl;
}
return 0;
}
\ No newline at end of file
#ifndef FINDFILENAME_H
#define FINDFILENAME_H
#include <stdlib.h>
#include <filesystem>
using std::string;
void findFileNameFromPath(string* path, string* fileName, string* extension);
int findFileName(string videoPath, string &fileName, string &extension);
#endif
\ No newline at end of file
#include "time.h"
using namespace std;
/**
* @brief Convert an int representing milliseconds to the corresponding Time Label string.
*
* @param ms the number of milliseconds.
* @param delim the time separator
* @return string the corresponding Time Label string.
*/
string getTimeLabel(int ms, string delim) {
int mil = ms % 1000;
int sec = ms / 1000;
int min = (sec / 60) % 60;
int hours = sec / 3600;
sec = sec % 60;
string hoursStr = to_string(hours), minStr = to_string(min), secStr = to_string(sec), milStr = to_string(mil);
if (hours < 10)
hoursStr = "0" + hoursStr;
if (min < 10)
minStr = "0" + minStr;
if (sec < 10)
secStr = "0" + secStr;
if (mil < 100) {
if (mil < 10) {
milStr = "00" + milStr;
} else {
milStr = "0" + milStr;
}
}
string timeLabel = hoursStr + delim + minStr + delim + secStr + delim + milStr;
return timeLabel;
}
#ifndef GETTIMELABEL_H
#define GETTIMELABEL_H
#include <stdlib.h>
#include <string>
std::string getTimeLabel(int ms, std::string delim = ":");
#endif
\ No newline at end of file
#include <iostream>
#include <fstream>
#include "validation.h"
#include "colors.h"
using namespace std;
namespace fs = std::filesystem;
int checkJSON(fs::path irregularityFileInputPath, float speed, int tapeThresholdPercentual, int capstanThresholdPercentual) {
// Input JSON check
ifstream iJSON(irregularityFileInputPath);
if (iJSON.fail()) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << irregularityFileInputPath.string() << " cannot be found or opened." << END << endl;
return -1;
}
if (speed != 7.5 && speed != 15) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "Speed parameter must be 7.5 or 15 ips." << END << endl;
return -1;
}
if (tapeThresholdPercentual < 0 || tapeThresholdPercentual > 100) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "TapeThresholdPercentual parameter must be a percentage value." << END << endl;
return -1;
}
if (capstanThresholdPercentual < 0 || capstanThresholdPercentual > 100) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "CapstanThresholdPercentual parameter must be a percentage value." << END << endl;
return -1;
}
return 0;
}
\ No newline at end of file
#include <stdlib.h>
#include <filesystem>
int checkJSON(std::filesystem::path irregularityFileInputPath);
\ No newline at end of file
......@@ -47,6 +47,10 @@
#include "utility.h"
#include "forAudioAnalyser.h"
#include "lib/colors.h"
#include "lib/time.h"
#include "lib/parser.h"
using namespace cv;
using namespace std;
using json = nlohmann::json;
......@@ -54,12 +58,12 @@ namespace fs = std::filesystem;
namespace po = boost::program_options;
// For capstan detection, there are two alternative approaches:
// Generalized Hough Transform and SURF.
bool useSURF = true;
bool savingPinchRoller = false, pinchRollerRect = false;
bool savingPinchRoller = false;
bool pinchRollerRect = false;
bool savingBrand = false;
bool endTapeSaved = false;
cv::Mat myFrame;
......@@ -68,41 +72,53 @@ bool firstBrand = true; // The first frame containing brands on tape must be sav
float firstInstant = 0;
string fileName, extension;
// config.json parameters
fs::path workingPath;
string filesName;
bool brands;
float speed, tapeThresholdPercentual, capstanThresholdPercentual;
int minDist, angleThresh, scaleThresh, posThresh, minDistCapstan, angleThreshCapstan, scaleThreshCapstan, posThreshCapstan;
// Path variables
fs::path outputPath;
fs::path irregularityImagesPath;
fs::path videoPath;
fs::path irregularityFileInputPath;
// JSON files
json configurationFile;
json irregularityFileInput;
json irregularityFileOutput1;
json irregularityFileOutput2;
// RotatedRect identifying the processing area
RotatedRect rect, rectTape, rectCapstan;
// Structs
string PURPLE = "\033[95m";
string CYAN = "\033[96m";
string DARK_CYAN = "\033[36m";
string BLUE = "\033[94m";
string GREEN = "\033[92m";
string YELLOW = "\033[93m";
string RED = "\033[91m";
string BOLD = "\033[1m";
string UNDERLINE = "\033[4m";
string END = "\033[0m";
/*************************************************************************************************/
/**************************************** SUPPORT METHODS ****************************************/
/*************************************************************************************************/
// 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;
};
Config config;
SceneObject tape;
SceneObject capstan;
void saveFile(fs::path fileName, auto content, bool append) {
ofstream outputFile;
if (append) {
outputFile.open(fileName, ios::app);
} else {
outputFile.open(fileName);
}
outputFile << content << endl;
outputFile.close();
}
/**
* @brief Get operation arguments from command line or config.json file.
......@@ -120,10 +136,14 @@ bool getArguments(int argc, char** argv) {
if (argc == 1) {
// Read from JSON file
string wp = configurationFile["WorkingPath"];
workingPath = fs::path(wp);
filesName = configurationFile["FilesName"];
brands = configurationFile["Brands"];
speed = configurationFile["Speed"];
config = {
fs::path(wp),
configurationFile["FilesName"],
configurationFile["Brands"],
configurationFile["Speed"]
};
} else {
// Get from command line
try {
......@@ -154,16 +174,25 @@ bool getArguments(int argc, char** argv) {
}
}
tapeThresholdPercentual = configurationFile["TapeThresholdPercentual"];
capstanThresholdPercentual = configurationFile["CapstanThresholdPercentual"];
minDist = configurationFile["MinDist"];
angleThresh = configurationFile["AngleThresh"];
scaleThresh = configurationFile["ScaleThresh"];
posThresh = configurationFile["PosThresh"];
minDistCapstan = configurationFile["MinDistCapstan"];
angleThreshCapstan = configurationFile["AngleThreshCapstan"];
scaleThreshCapstan = configurationFile["ScaleThreshCapstan"];
posThreshCapstan = configurationFile["PosThreshCapstan"];
capstan = {
configurationFile["MinDistCapstan"],
{
configurationFile["CapstanThresholdPercentual"],
configurationFile["AngleThreshCapstan"],
configurationFile["ScaleThreshCapstan"],
configurationFile["PosThreshCapstan"]
}
};
tape = {
configurationFile["MinDist"],
{
configurationFile["TapeThresholdPercentual"],
configurationFile["AngleThresh"],
configurationFile["ScaleThresh"],
configurationFile["PosThresh"]
}
};
return true;
}
......@@ -176,11 +205,10 @@ bool getArguments(int argc, char** argv) {
* - The tape area under the tape head (computed on the basis of the detected reading head);
* - The capstan.
*
* @param configurationFile the config.json containing working parameters.
* @return true if some areas have been detected;
* @return false otherwise.
*/
bool findProcessingAreas(json configurationFile) {
bool findProcessingAreas() {
/*********************************************************************************************/
/*********************************** READING HEAD DETECTION **********************************/
......@@ -210,7 +238,7 @@ bool findProcessingAreas(json configurationFile) {
vector<Vec4f> positionsPos, positionsNeg;
Mat votesPos, votesNeg;
TickMeter tm;
int oldPosThresh = posThresh;
int oldPosThresh = tape.threshold.pos;
RotatedRect rectPos, rectNeg;
ofstream myFile;
Point2f pts[4];
......@@ -221,20 +249,20 @@ bool findProcessingAreas(json configurationFile) {
double maxValPos = 0, maxValNeg = 0;
int indexPos = 0, indexNeg = 0;
alg -> setMinDist(minDist);
alg -> setMinDist(tape.minDist);
alg -> setLevels(360);
alg -> setDp(2);
alg -> setMaxBufferSize(1000);
alg -> setAngleStep(1);
alg -> setAngleThresh(angleThresh);
alg -> setAngleThresh(tape.threshold.angle);
alg -> setMinScale(0.9);
alg -> setMaxScale(1.1);
alg -> setScaleStep(0.01);
alg -> setScaleThresh(scaleThresh);
alg -> setScaleThresh(tape.threshold.scale);
alg -> setPosThresh(posThresh);
alg -> setPosThresh(tape.threshold.pos);
alg -> setCannyLowThresh(150); // Old: 100
alg -> setCannyHighThresh(240); // Old: 300
......@@ -244,7 +272,8 @@ bool findProcessingAreas(json configurationFile) {
cout << DARK_CYAN << "Reading head" << END << endl;
tm.start();
// Invoke utility.h function
detectShape(alg, templateShape, posThresh, positionsPos, votesPos, positionsNeg, votesNeg, processingImage);
detectShape(alg, templateShape, tape.threshold.pos, positionsPos, votesPos, positionsNeg, votesNeg, processingImage);
tm.stop();
cout << "Reading head detection time: " << tm.getTimeMilli() << " ms" << endl;
......@@ -410,34 +439,34 @@ bool findProcessingAreas(json configurationFile) {
// Reset algorithm and set parameters
alg = createGeneralizedHoughGuil();
alg -> setMinDist(minDistCapstan);
alg -> setMinDist(capstan.minDist);
alg -> setLevels(360);
alg -> setDp(2);
alg -> setMaxBufferSize(1000);
alg -> setAngleStep(1);
alg -> setAngleThresh(angleThreshCapstan);
alg -> setAngleThresh(capstan.threshold.angle);
alg -> setMinScale(0.9);
alg -> setMaxScale(1.1);
alg -> setScaleStep(0.01);
alg -> setScaleThresh(scaleThreshCapstan);
alg -> setScaleThresh(capstan.threshold.scale);
alg -> setPosThresh(posThreshCapstan);
alg -> setPosThresh(capstan.threshold.pos);
alg -> setCannyLowThresh(150);
alg -> setCannyHighThresh(240);
alg -> setTemplate(templateShape);
oldPosThresh = posThreshCapstan;
oldPosThresh = capstan.threshold.pos;
vector<Vec4f> positionsC1Pos, positionsC1Neg;
Mat votesC1Pos, votesC1Neg;
tm.reset();
tm.start();
detectShape(alg, templateShape, posThreshCapstan, positionsC1Pos, votesC1Pos, positionsC1Neg, votesC1Neg, capstanProcessingAreaGrayscale);
detectShape(alg, templateShape, capstan.threshold.pos, positionsC1Pos, votesC1Pos, positionsC1Neg, votesC1Neg, capstanProcessingAreaGrayscale);
tm.stop();
cout << "Capstan detection time: " << tm.getTimeMilli() << " ms" << endl;
......@@ -524,7 +553,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
// Capstan area
int capstanAreaPixels = rectCapstan.size.width * rectCapstan.size.height;
float capstanDifferentPixelsThreshold = capstanAreaPixels * capstanThresholdPercentual / 100;
float capstanDifferentPixelsThreshold = capstanAreaPixels * capstan.threshold.percentual / 100;
// Extract matrices corresponding to the processing area
// CODE FROM https://answers.opencv.org/question/497/extract-a-rotatedrect-area/
......@@ -580,7 +609,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
// Tape area
int tapeAreaPixels = rectTape.size.width * rectTape.size.height;
float tapeDifferentPixelsThreshold = tapeAreaPixels * tapeThresholdPercentual / 100;
float tapeDifferentPixelsThreshold = tapeAreaPixels * tape.threshold.percentual / 100;
// Extract matrices corresponding to the processing area
// CODE FROM https://answers.opencv.org/question/497/extract-a-rotatedrect-area/
......@@ -642,7 +671,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
}
/***** BRANDS MANAGEMENT *****/
if (brands) {
if (config.brands) {
// 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
if (firstBrand) {
......@@ -684,7 +713,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).
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
if (speed == 7.5)
if (config.speed == 7.5)
savingRate = 157; // Time taken to cross 3 cm at 7.5 ips
// The first frame of the video won't be processed
......@@ -744,8 +773,8 @@ void processing(cv::VideoCapture videoCapture) {
cv::Mat evenSubImage(evenSubImageRows, subImage.cols, CV_8UC3);
separateFrame(subImage, oddSubImage, evenSubImage);
string timeLabel = getTimeLabel(ms);
string safeTimeLabel = getSafeTimeLabel(ms);
string timeLabel = getTimeLabel(ms, ":");
string safeTimeLabel = getTimeLabel(ms, "-");
string irregularityImageFilename = to_string(savedFrames) + "_" + safeTimeLabel + ".jpg";
cv::imwrite(irregularityImagesPath / irregularityImageFilename, oddFrame);
......@@ -816,6 +845,8 @@ void processing(cv::VideoCapture videoCapture) {
*/
int main(int argc, char** argv) {
json irregularityFileInput;
fs::path irregularityFileInputPath;
/*********************************************************************************************/
/*************************************** CONFIGURATION ***************************************/
/*********************************************************************************************/
......@@ -831,13 +862,14 @@ int main(int argc, char** argv) {
return -1;
}
videoPath = workingPath / "PreservationAudioVisualFile" / filesName;
videoPath = config.workingPath / "PreservationAudioVisualFile" / config.filesName;
if (findFileName(videoPath, fileName, extension) == -1) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << videoPath.string() << " cannot be found or opened." << END << endl;
return -1;
}
irregularityFileInputPath = workingPath / "temp" / fileName / "AudioAnalyser_IrregularityFileOutput1.json";
irregularityFileInputPath = config.workingPath / "temp" / fileName / "AudioAnalyser_IrregularityFileOutput1.json";
// Input JSON check
ifstream iJSON(irregularityFileInputPath);
......@@ -845,35 +877,35 @@ int main(int argc, char** argv) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << irregularityFileInputPath.string() << " cannot be found or opened." << END << endl;
return -1;
}
if (speed != 7.5 && speed != 15) {
if (config.speed != 7.5 && config.speed != 15) {
cerr << RED << BOLD << "config.json error!" << END << endl << RED << "Speed parameter must be 7.5 or 15 ips." << END << endl;
return -1;
}
if (tapeThresholdPercentual < 0 || tapeThresholdPercentual > 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;
return -1;
}
if (capstanThresholdPercentual < 0 || capstanThresholdPercentual > 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;
return -1;
}
// Adjust input paramenters (considering given ones as pertinent to a speed reference = 7.5)
if (brands) {
if (speed == 15)
tapeThresholdPercentual += 6;
if (config.brands) {
if (config.speed == 15)
tape.threshold.percentual += 6;
} else
if (speed == 15)
tapeThresholdPercentual += 20;
if (config.speed == 15)
tape.threshold.percentual += 20;
else
tapeThresholdPercentual += 21;
tape.threshold.percentual += 21;
cout << endl;
cout << "Parameters:" << endl;
cout << " Brands: " << brands << endl;
cout << " Speed: " << speed << endl;
cout << " ThresholdPercentual: " << tapeThresholdPercentual << endl;
cout << " ThresholdPercentualCapstan: " << capstanThresholdPercentual << endl;
cout << " Brands: " << config.brands << endl;
cout << " Speed: " << config.speed << endl;
cout << " ThresholdPercentual: " << tape.threshold.percentual << endl;
cout << " ThresholdPercentualCapstan: " << capstan.threshold.percentual << endl;
cout << endl;
// Read input JSON
......@@ -884,18 +916,17 @@ int main(int argc, char** argv) {
/*********************************************************************************************/
// Make directory with fileName name
outputPath = workingPath / "temp" / fileName;
outputPath = config.workingPath / "temp" / fileName;
int outputFileNameDirectory = create_directory(outputPath);
// Get now time
time_t t = chrono::system_clock::to_time_t(chrono::system_clock::now());
string ts = ctime(&t);
// Write useful info to log file
ofstream myFile;
myFile.open(outputPath / "log.txt", ios::app);
myFile << endl << fileName << endl;
myFile << "tsh: " << tapeThresholdPercentual << " tshp: " << capstanThresholdPercentual << endl;
myFile << ts; // No endline character for avoiding middle blank line.
myFile.close();
fs::path logPath = outputPath / "log.txt";
string logInfo = fileName + '\n' + "tsh: " + to_string(tape.threshold.percentual) + " tshp: " + to_string(capstan.threshold.percentual) + '\n' + ts;
saveFile(logPath, logInfo, true);
/*********************************************************************************************/
/************************************** AREAS DETECTION **************************************/
......@@ -917,21 +948,21 @@ int main(int argc, char** argv) {
cout << "Video resolution: " << myFrame.cols << "x" << myFrame.rows << endl << endl;
// Find the processing area corresponding to the tape area over the reading head
bool found = findProcessingAreas(configurationFile);
bool found = findProcessingAreas();
// Reset frame position
videoCapture.set(CAP_PROP_POS_FRAMES, 0);
// Write useful information to log file
myFile.open("log.txt", ios::app);
string message;
if (found) {
cout << "Processing areas found!" << endl;
myFile << "Processing areas found!" << endl;
myFile.close();
message = "Processing areas found!\n";
cout << message;
saveFile(logPath, message, true);
} else {
cout << "Processing area not found. Try changing JSON parameters." << endl;
myFile << "Processing area not found." << endl;
myFile.close();
message = "Processing area not found. Try changing JSON parameters.\n";
cout << message;
saveFile(logPath, message, true);
return -1; // Program terminated early
}
......@@ -946,7 +977,7 @@ int main(int argc, char** argv) {
/**************************************** PROCESSING *****************************************/
/*********************************************************************************************/
cout << endl << CYAN << "Starting processing..." << END << endl;
cout << '\n' << CYAN << "Starting processing..." << END << '\n';
// Processing timer
time_t startTimer, endTimer;
......@@ -961,27 +992,20 @@ int main(int argc, char** argv) {
string result("Processing elapsed time: " + to_string((int)min) + ":" + to_string((int)sec));
cout << endl << result << endl;
myFile.open("log.txt", ios::app);
myFile << result << endl << endl;
myFile.close();
saveFile("log.txt", result + '\n', true);
/*********************************************************************************************/
/************************************* IRREGULARITY FILES ************************************/
/*********************************************************************************************/
ofstream outputFile1;
fs::path outputFile1Name = outputPath / "VideoAnalyser_IrregularityFileOutput1.json";
outputFile1.open(outputFile1Name);
outputFile1 << irregularityFileOutput1 << endl;
saveFile(outputFile1Name, irregularityFileOutput1, false);
// Irregularities to extract for the AudioAnalyser and to the TapeIrregularityClassifier
extractIrregularityImagesForAudio(outputPath, videoPath, irregularityFileInput, irregularityFileOutput2);
ofstream outputFile2;
fs::path outputFile2Name = outputPath / "VideoAnalyser_IrregularityFileOutput2.json";
outputFile2.open(outputFile2Name);
outputFile2 << irregularityFileOutput2 << endl;
saveFile(outputFile2Name, irregularityFileOutput2, false);
return 0;
}
......@@ -2,128 +2,6 @@ using namespace cv;
using namespace std;
namespace fs = std::filesystem;
/*************************************************************************************************/
/**************************************** TIME FUNCTIONS *****************************************/
/*************************************************************************************************/
/**
* @brief Convert an int representing milliseconds to the corresponding Time Label string.
*
* @param ms the number of milliseconds.
* @return string the corresponding Time Label string.
*/
string getTimeLabel(int ms) {
int mil = ms % 1000;
int sec = ms / 1000;
int min = (sec / 60) % 60;
int hours = sec / 3600;
sec = sec % 60;
string hoursStr = to_string(hours), minStr = to_string(min), secStr = to_string(sec), milStr = to_string(mil);
if (hours < 10)
hoursStr = "0" + hoursStr;
if (min < 10)
minStr = "0" + minStr;
if (sec < 10)
secStr = "0" + secStr;
if (mil < 100) {
if (mil < 10) {
milStr = "00" + milStr;
} else {
milStr = "0" + milStr;
}
}
string timeLabel = hoursStr + ":" + minStr + ":" + secStr + "." + milStr;
return timeLabel;
}
/**
* @brief Convert an int representing milliseconds to the corresponding Time Label string, but with dashes '-' charachers instead of periods '.' and colons ':'.
* Useful for file names.
*
* @param ms the number of milliseconds.
* @return string the corresponding Time Label string.
*/
string getSafeTimeLabel(int ms) {
int mil = ms % 1000;
int sec = ms / 1000;
int min = (sec / 60) % 60;
int hours = sec / 3600;
sec = sec % 60;
string hoursStr = to_string(hours), minStr = to_string(min), secStr = to_string(sec), milStr = to_string(mil);
if (hours < 10)
hoursStr = "0" + hoursStr;
if (min < 10)
minStr = "0" + minStr;
if (sec < 10)
secStr = "0" + secStr;
if (mil < 100) {
if (mil < 10) {
milStr = "00" + milStr;
} else {
milStr = "0" + milStr;
}
}
string timeLabel = hoursStr + "-" + minStr + "-" + secStr + "-" + milStr;
return timeLabel;
}
/*************************************************************************************************/
/*************************************** PARSING FUNCTIONS ***************************************/
/*************************************************************************************************/
/**
* @brief Separates video file name from its extension.
*
* @param[in] path Full video path;
* @param[out] fileName Video file name;
* @param[out] extension Video extension.
*/
void findFileNameFromPath(string* path, string* fileName, string* extension) {
*path = path->substr(path->find_last_of("'") + 1, path->size());
string path_without_extension = path->substr(0, path->find_last_of("."));
*fileName = path_without_extension.substr(path_without_extension.find_last_of("/") + 1, path_without_extension.size());
*extension = path->substr(path->find_last_of(".") + 1, path->size());
}
/**
* @brief Check if the specified input video file exists and is supported.
*
* @param[in] videoPath Full video path;
* @param[out] fileName Video file name;
* @param[out] extension Video extension.
* @return int -1 if the format is not supported, 0 otherwise.
*/
int findFileName(string videoPath, string &fileName, string &extension) {
findFileNameFromPath(&videoPath, &fileName, &extension);
if (extension.compare("avi") != 0 && extension.compare("mp4") != 0 && extension.compare("mov") != 0) {
cerr << "Input file extension must be \"avi\", \"mp4\" or \"mov\"." << endl;
return -1;
} else {
cout << "Video to be analysed: " << endl;
cout << " File name: " << fileName << endl;
cout << " Extension: " << extension << endl;
}
return 0;
}
/*************************************************************************************************/
/*************************************** OpenCV FUNCTIONS ****************************************/
/*************************************************************************************************/
......
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