Commit e4ffbd13 authored by Matteo's avatar Matteo
Browse files

update

parent e2ba3b87
......@@ -21,6 +21,7 @@
#include <iostream>
#include <stdlib.h>
#include <sys/timeb.h>
#include <ranges>
#include <boost/program_options.hpp>
#include <boost/uuid/uuid.hpp> // uuid class
......@@ -108,6 +109,10 @@ 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;
}
/**
* @brief Get operation arguments from command line or config.json file.
*
......@@ -290,7 +295,6 @@ bool findProcessingAreas(Mat myFrame) {
);
Mat processingImage = halved_gray_current_frame(readingHeadProcessingAreaRect);
ofstream myFile;
RotatedRect rectPos, rectNeg;
auto [indexPos, indexNeg, maxValPos, maxValNeg, positionsPos, positionsNeg] = findObject(reading_head_template, tape, processingImage);
......@@ -300,26 +304,19 @@ bool findProcessingAreas(Mat myFrame) {
if (positionsNeg.size() > 0)
rectNeg = utility::drawShapes(myFrame, positionsNeg[indexNeg], Scalar(128, 128, 255-indexNeg*64), reading_head_template.cols, reading_head_template.rows, halved_gray_current_frame.cols/4, halved_gray_current_frame.rows/2, 2);
myFile.open("log.txt", ios::app);
if (maxValPos > 0)
if (maxValNeg > 0)
if (maxValPos > maxValNeg) {
myFile << "READING HEAD: Positive angle is best, match number: " << indexPos << endl;
rect = rectPos;
} else {
myFile << "READING HEAD: Negative angle is best, match number: " << indexNeg << endl;
rect = rectNeg;
}
else {
myFile << "READING HEAD: Positive angle is the only choice, match number: " << indexPos << endl;
rect = rectPos;
}
else if (maxValNeg > 0) {
myFile << "READING HEAD: Negative angle is the only choice, match number: " << indexNeg << endl;
rect = rectNeg;
} else {
myFile.close();
return false;
}
......@@ -331,11 +328,6 @@ bool findProcessingAreas(Mat myFrame) {
Vec4f positionTape( rect.center.x, rect.center.y + rect.size.height / 2 + 20 * (rect.size.width / 200), 1, rect.angle );
rectTape = utility::drawShapes(myFrame, positionTape, Scalar(0, 255-indexPos*64, 0), rect.size.width, 50 * (rect.size.width / 200), 0, 0, 1);
myFile << "Tape area:" << endl;
myFile << " Center (x, y): (" << rectTape.center.x << ", " << rectTape.center.y << ")" << endl;
myFile << " Size (w, h): (" << rectTape.size.width << ", " << rectTape.size.height << ")" << endl;
myFile << " Angle (deg): (" << rectTape.angle << ")" << endl;
json autoJSON;
autoJSON["PreservationAudioVisualFile"] = fileName;
autoJSON["RotatedRect"] = {
......@@ -439,31 +431,20 @@ bool findProcessingAreas(Mat myFrame) {
if (maxValPos > 0)
if (maxValNeg > 0)
if (maxValPos > maxValNeg) {
myFile << "CAPSTAN: Positive is best, match number: " << indexPos << endl;
rectCapstan = rectCapstanPos;
} else {
myFile << "CAPSTAN: Negative is best, match number: " << indexNeg << endl;
rectCapstan = rectCapstanNeg;
}
else {
myFile << "CAPSTAN: Positive is the only choice, match number: " << indexPos << endl;
rectCapstan = rectCapstanPos;
}
else if (maxValNeg > 0) {
myFile << "CAPSTAN: Negative is the only choice, match number: " << indexNeg << endl;
rectCapstan = rectCapstanNeg;
} else {
myFile.close();
return false;
}
}
myFile << "Capstan ROI:" << endl;
myFile << " Center (x, y): (" << rectCapstan.center.x << ", " << rectCapstan.center.y << ")" << endl;
myFile << " Size (w, h): (" << rectCapstan.size.width << ", " << rectCapstan.size.height << ")" << endl;
myFile << " Angle (deg): (" << rectCapstan.angle << ")" << endl;
myFile.close();
cout << endl;
// Save the image containing the detected areas
......@@ -549,7 +530,7 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
/*********************************************************************************************/
// Tape area
int tapeAreaPixels = rectTape.size.width * rectTape.size.height;
int tapeAreaPixels = rotatedRectArea(rectTape);
float tapeDifferentPixelsThreshold = tapeAreaPixels * tape.threshold.percentual / 100;
// Extract matrices corresponding to the processing area
......@@ -643,13 +624,11 @@ bool frameDifference(cv::Mat prevFrame, cv::Mat currentFrame, int msToEnd) {
*/
void processing(cv::VideoCapture videoCapture) {
// Video duration
int frameNumbers_v = videoCapture.get(CAP_PROP_FRAME_COUNT);
float fps_v = videoCapture.get(CAP_PROP_FPS); // FPS can be non-integers!!!
float videoLength = (float) frameNumbers_v / fps_v; // [s]
int videoLength_ms = videoLength * 1000;
int savedFrames = 0, unsavedFrames = 0;
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);
// counters
int savedFrames = 0;
int unsavedFrames = 0;
float lastSaved = -160;
// 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.
......@@ -660,110 +639,100 @@ void processing(cv::VideoCapture videoCapture) {
// The first frame of the video won't be processed
cv::Mat prevFrame;
videoCapture >> prevFrame;
firstInstant = videoLength_ms - videoCapture.get(CAP_PROP_POS_MSEC);
firstInstant = video_length_ms - video_current_ms;
while (videoCapture.isOpened()) {
cv::Mat frame;
videoCapture >> frame;
video_current_ms = videoCapture.get(CAP_PROP_POS_MSEC);
if (!frame.empty()) {
int ms = videoCapture.get(CAP_PROP_POS_MSEC);
int msToEnd = videoLength_ms - ms;
if (ms == 0) // With OpenCV library, this happens at the last few frames of the video before realising that "frame" is empty.
break;
// Variables to display program status
int secToEnd = msToEnd / 1000;
int minToEnd = (secToEnd / 60) % 60;
secToEnd = secToEnd % 60;
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 << "Remaining video time [mm:ss]: " << minStrToEnd << ":" << secStrToEnd << flush;
if ((ms - lastSaved > savingRate) && frameDifference(prevFrame, frame, msToEnd)) {
// An Irregularity has been found!
// De-interlacing frame
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
Point2f pts[4];
if (savingPinchRoller)
rectCapstan.points(pts);
else
rectTape.points(pts);
cv::Mat subImage(frame, cv::Rect(100, min(pts[1].y, pts[2].y), frame.cols - 100, static_cast<int>(rectTape.size.height)));
// 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(ms, ":");
string safeTimeLabel = getTimeLabel(ms, "-");
string irregularityImageFilename = to_string(savedFrames) + "_" + safeTimeLabel + ".jpg";
cv::imwrite(irregularityImagesPath / irregularityImageFilename, oddFrame);
// Append Irregularity information to JSON
boost::uuids::uuid uuid = boost::uuids::random_generator()();
irregularityFileOutput1["Irregularities"] += {
{
"IrregularityID", boost::lexical_cast<string>(uuid)
}, {
"Source", "v"
}, {
"TimeLabel", timeLabel
}
};
irregularityFileOutput2["Irregularities"] += {
{
"IrregularityID", boost::lexical_cast<string>(uuid)
}, {
"Source", "v"
}, {
"TimeLabel", timeLabel
}, {
"ImageURI", irregularityImagesPath.string() + "/" + irregularityImageFilename
}
};
lastSaved = ms;
savedFrames++;
} else {
unsavedFrames++;
}
prevFrame = frame;
} else {
if (frame.empty()) {
cout << endl << "Empty frame!" << endl;
videoCapture.release();
break;
}
}
}
int msToEnd = video_length_ms - video_current_ms;
if (video_current_ms == 0) // With OpenCV library, this happens at the last few frames of the video before realising that "frame" is empty.
break;
// Variables to display program status
int secToEnd = msToEnd / 1000;
int minToEnd = (secToEnd / 60) % 60;
secToEnd = secToEnd % 60;
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 << "Remaining video time [mm:ss]: " << minStrToEnd << ":" << secStrToEnd << flush;
if ((video_current_ms - lastSaved > savingRate) && frameDifference(prevFrame, frame, msToEnd)) {
// An Irregularity has been found!
// De-interlacing frame
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
Point2f pts[4];
if (savingPinchRoller)
rectCapstan.points(pts);
else
rectTape.points(pts);
cv::Mat subImage(frame, cv::Rect(100, min(pts[1].y, pts[2].y), frame.cols - 100, static_cast<int>(rectTape.size.height)));
// 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 safeTimeLabel = getTimeLabel(video_current_ms, "-");
string irregularityImageFilename = to_string(savedFrames) + "_" + safeTimeLabel + ".jpg";
cv::imwrite(irregularityImagesPath / irregularityImageFilename, oddFrame);
// Append Irregularity information to JSON
boost::uuids::uuid uuid = boost::uuids::random_generator()();
irregularityFileOutput1["Irregularities"] += {
{
"IrregularityID", boost::lexical_cast<string>(uuid)
}, {
"Source", "v"
}, {
"TimeLabel", timeLabel
}
};
irregularityFileOutput2["Irregularities"] += {
{
"IrregularityID", boost::lexical_cast<string>(uuid)
}, {
"Source", "v"
}, {
"TimeLabel", timeLabel
}, {
"ImageURI", irregularityImagesPath.string() + "/" + irregularityImageFilename
}
};
ofstream myFile;
myFile.open("log.txt", ios::app);
myFile << "Saved frames are: " << savedFrames << endl;
myFile.close();
lastSaved = video_current_ms;
savedFrames++;
} else {
unsavedFrames++;
}
prevFrame = frame;
}
}
......@@ -805,7 +774,7 @@ int main(int argc, char** argv) {
return -1;
}
fs::path VIDEO_PATH = config.workingPath / "PreservationAudioVisualFile" / config.filesName;
const fs::path VIDEO_PATH = config.workingPath / "PreservationAudioVisualFile" / config.filesName;
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;
......@@ -862,15 +831,9 @@ int main(int argc, char** argv) {
// Make directory with fileName name
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
fs::path logPath = outputPath / "log.txt";
string logInfo = fileName + '\n' + "tsh: " + to_string(tape.threshold.percentual) + " tshp: " + to_string(capstan.threshold.percentual) + '\n' + ts;
files::saveFile(logPath, logInfo, true);
irregularityImagesPath = outputPath / "IrregularityImages";
int fullFrameDirectory = fs::create_directory(irregularityImagesPath);
/*********************************************************************************************/
/************************************** AREAS DETECTION **************************************/
......@@ -882,41 +845,24 @@ int main(int argc, char** argv) {
return -1;
}
// Get total number of frames
int totalFrames = videoCapture.get(CAP_PROP_FRAME_COUNT);
int frames_number = videoCapture.get(CAP_PROP_FRAME_COUNT);
// Set frame position to half video length
videoCapture.set(CAP_PROP_POS_FRAMES, totalFrames/2);
videoCapture.set(CAP_PROP_POS_FRAMES, frames_number/2);
// Get frame
videoCapture >> myFrame;
cout << "Video resolution: " << myFrame.cols << "x" << myFrame.rows << endl << endl;
cout << "Video resolution: " << myFrame.cols << "x" << myFrame.rows << endl;
// Find the processing area corresponding to the tape area over the reading head
bool found = findProcessingAreas(myFrame);
// Reset frame position
videoCapture.set(CAP_PROP_POS_FRAMES, 0);
// Write useful information to log file
string message;
if (found) {
message = "Processing areas found!\n";
cout << message;
files::saveFile(logPath, message, true);
} else {
message = "Processing area not found. Try changing JSON parameters.\n";
cout << message;
files::saveFile(logPath, message, true);
if (!found) {
cout << RED << "Processing area not found. Try changing JSON parameters." << END << endl;
return -1; // Program terminated early
}
/*********************************************************************************************/
/***************************** MAKE ADDITIONAL OUTPUT DIRECTORIES ****************************/
/*********************************************************************************************/
irregularityImagesPath = outputPath / "IrregularityImages";
int fullFrameDirectory = fs::create_directory(irregularityImagesPath);
/*********************************************************************************************/
/**************************************** PROCESSING *****************************************/
/*********************************************************************************************/
......@@ -936,8 +882,6 @@ int main(int argc, char** argv) {
string result("Processing elapsed time: " + to_string((int)min) + ":" + to_string((int)sec));
cout << endl << result << endl;
files::saveFile("log.txt", result + '\n', true);
/*********************************************************************************************/
/************************************* IRREGULARITY FILES ************************************/
/*********************************************************************************************/
......
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