Commit 8f5a80ed authored by Matteo's avatar Matteo
Browse files

major refactoring

parent df88fb26
#include "time.h"
#include "time.hpp"
std::string getTimeLabel(int ms, std::string delim) {
int mil = ms % 1000;
......
......@@ -16,4 +16,4 @@
*/
std::string getTimeLabel(int ms, std::string delim = ":");
#endif
\ No newline at end of file
#endif // GETTIMELABEL_H
\ No newline at end of file
This diff is collapsed.
#include "utility.h"
#include "utility.hpp"
#include <filesystem>
#include <fstream>
......@@ -10,134 +10,88 @@ namespace fs = std::filesystem;
using json = nlohmann::json;
// Constructors
utility::Frame::Frame() : Mat() {}
utility::Frame::Frame(const Mat& m) : Mat(m) {}
utility::Frame::Frame(const Frame& f) : Mat(f) {}
// Operators
utility::Frame& utility::Frame::operator=(const Mat& m) {
Mat::operator=(m);
return *this;
}
utility::Frame& utility::Frame::operator=(const Frame& f) {
Mat::operator=(f);
return *this;
}
// Methods
utility::Frame utility::Frame::clone() const { return utility::Frame(Mat::clone()); }
utility::Frame& utility::Frame::downsample(int factor) {
pyrDown(*this, *this, Size(size().width / factor, size().height / factor));
return *this;
}
utility::Frame& utility::Frame::convertColor(int code) {
cvtColor(*this, *this, code);
return *this;
}
utility::Frame utility::Frame::difference(Frame& f) { return Frame(utility::difference(*this, f)); }
utility::Frame& utility::Frame::crop(Size rect_size, Point2f center) {
cv::getRectSubPix(*this, rect_size, center, *this);
return *this;
}
utility::Frame& utility::Frame::warp(cv::Mat rotationMatrix) {
cv::warpAffine(*this, *this, rotationMatrix, this->size(), INTER_CUBIC);
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);
void utility::detect_shape(Ptr<GeneralizedHoughGuil> alg, int pos_thresh, vector<Vec4f>& positive_positions,
Mat& positive_votes, vector<Vec4f>& negative_positions, Mat& negative_votes,
Mat processing_area) {
alg->setPosThresh(pos_thresh);
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) {
alg->setPosThresh(posThresh);
alg->setTemplate(templateShape);
int oldSizePositive = 0;
int i = 0;
int maxVote = 0;
int num_prev_matches = 0;
int threshold_increment = 0;
int max_match_score = 0;
// Process shapes with positive angles
alg->setMinAngle(0);
alg->setMaxAngle(3);
while (true) {
alg->detect(processingArea, positivePositions, positiveVotes);
int currentSize = positivePositions.size();
if (currentSize == 1) {
alg->detect(processing_area, positive_positions, positive_votes);
int current_matches = positive_positions.size();
if (current_matches == 1 || (current_matches == 0 && num_prev_matches == 0)) {
// We detected the most interesting shape
// Impossible to find with these parameters
break;
} else if (currentSize == 0 && oldSizePositive > 0) {
} else if (current_matches == 0 && num_prev_matches > 0) {
// It is not possible to detect only one shape with the current
// parameters
alg->setPosThresh(posThresh + i - 1); // Decrease position value
alg->detect(processingArea, positivePositions,
positiveVotes); // Detect all available shapes
break;
} else if (currentSize == 0 && oldSizePositive == 0) {
// Impossible to find with these parameters
alg->setPosThresh(pos_thresh + threshold_increment - 1); // Decrease position value
alg->detect(processing_area, positive_positions,
positive_votes); // Detect all available shapes
break;
}
oldSizePositive = currentSize;
num_prev_matches = current_matches;
// Find maximum vote
for (int j = 0; j < positiveVotes.cols / 3; j++) {
if (positiveVotes.at<int>(3 * j) > maxVote) maxVote = positiveVotes.at<int>(3 * j);
for (int j = 0; j < positive_votes.cols / 3; j++) {
if (positive_votes.at<int>(3 * j) > max_match_score) max_match_score = positive_votes.at<int>(3 * j);
}
if (currentSize > 10) {
i += 5; // To speed up computation when there are too many matches
} else if (maxVote - (posThresh + i) > 100) {
i += 100; // To speed up computation when there are few super high
// matches
if (current_matches > 10) {
threshold_increment += 5; // To speed up computation when there are too many matches
} else if (max_match_score - (pos_thresh + threshold_increment) > 100) {
threshold_increment += 100; // To speed up computation when there are few super high
// matches
} else {
i++;
threshold_increment++;
}
alg->setPosThresh(posThresh + i);
alg->setPosThresh(pos_thresh + threshold_increment);
}
int oldSizeNegative = 0;
// Reset incremental position value
i = 0;
maxVote = 0;
threshold_increment = 0;
num_prev_matches = 0;
max_match_score = 0;
// Process shapes with negative angles
alg->setMinAngle(357);
alg->setMaxAngle(360);
while (true) {
alg->detect(processingArea, negativePositions, negativeVotes);
int currentSize = negativePositions.size();
if (currentSize == 1) {
alg->detect(processing_area, negative_positions, negative_votes);
int current_matches = negative_positions.size();
if (current_matches == 1 || (current_matches == 0 && num_prev_matches == 0)) {
// We detected the most interesting shape
// Impossible to found with these parameters
break;
} else if (currentSize == 0 && oldSizeNegative > 0) {
} else if (current_matches == 0 && num_prev_matches > 0) {
// It is not possible to detect only one shape with the current
// parameters
alg->setPosThresh(posThresh + i - 1); // Decrease position value
alg->detect(processingArea, negativePositions,
negativeVotes); // Detect all available shapes
break;
} else if (currentSize == 0 && oldSizeNegative == 0) {
// Impossible to found with these parameters
alg->setPosThresh(pos_thresh + threshold_increment - 1); // Decrease position value
alg->detect(processing_area, negative_positions,
negative_votes); // Detect all available shapes
break;
}
oldSizeNegative = currentSize;
num_prev_matches = current_matches;
// Find maximum vote
for (int j = 0; j < positiveVotes.cols / 3; j++) {
if (positiveVotes.at<int>(3 * j) > maxVote) maxVote = positiveVotes.at<int>(3 * j);
for (int j = 0; j < positive_votes.cols / 3; j++) {
if (positive_votes.at<int>(3 * j) > max_match_score) max_match_score = positive_votes.at<int>(3 * j);
}
if (currentSize > 10) {
i += 5; // To speed up computation when there are too many matches
} else if (maxVote - (posThresh + i) > 100) {
i += 100; // To speed up computation when there are few super high
// matches
if (current_matches > 10) {
threshold_increment += 5; // To speed up computation when there are too many matches
} else if (max_match_score - (pos_thresh + threshold_increment) > 100) {
threshold_increment += 100; // To speed up computation when there are few super high
// matches
} else {
i++;
threshold_increment++;
}
alg->setPosThresh(posThresh + i);
alg->setPosThresh(pos_thresh + threshold_increment);
}
}
......@@ -164,51 +118,6 @@ RotatedRect utility::drawShapes(Mat frame, const Vec4f& positions, Scalar color,
return rr;
}
void utility::separateFrame(const cv::Mat frame, cv::Mat& odd_frame, cv::Mat& even_frame) {
int i_odd_frame = 0;
int i_even_frame = 0;
for (int i = 0; i < frame.rows; i++) {
for (int j = 0; j < frame.cols; j++) {
if (i % 2 == 0) {
even_frame.at<cv::Vec3b>(i_even_frame, j)[0] = frame.at<cv::Vec3b>(i, j)[0];
even_frame.at<cv::Vec3b>(i_even_frame, j)[1] = frame.at<cv::Vec3b>(i, j)[1];
even_frame.at<cv::Vec3b>(i_even_frame, j)[2] = frame.at<cv::Vec3b>(i, j)[2];
} else {
odd_frame.at<cv::Vec3b>(i_odd_frame, j)[0] = frame.at<cv::Vec3b>(i, j)[0];
odd_frame.at<cv::Vec3b>(i_odd_frame, j)[1] = frame.at<cv::Vec3b>(i, j)[1];
odd_frame.at<cv::Vec3b>(i_odd_frame, j)[2] = frame.at<cv::Vec3b>(i, j)[2];
}
}
if (i % 2 == 0) {
i_even_frame++;
} else {
i_odd_frame++;
}
}
return;
}
cv::Mat utility::difference(cv::Mat& prevFrame, cv::Mat& currentFrame) {
cv::Mat diff = currentFrame.clone();
for (int i = 0; i < currentFrame.rows; i++) {
for (int j = 0; j < currentFrame.cols; j++) {
if (prevFrame.at<cv::Vec3b>(i, j)[0] != currentFrame.at<cv::Vec3b>(i, j)[0] ||
prevFrame.at<cv::Vec3b>(i, j)[1] != currentFrame.at<cv::Vec3b>(i, j)[1] ||
prevFrame.at<cv::Vec3b>(i, j)[2] != currentFrame.at<cv::Vec3b>(i, j)[2]) {
// Different pixels
diff.at<cv::Vec3b>(i, j)[0] = 0;
} else {
// Identical pixels
diff.at<cv::Vec3b>(i, j)[0] = 255;
}
}
}
return diff;
}
Threshold::Threshold(float percentual, int angle, int scale, int pos) {
if (percentual < 0 || percentual > 100) throw std::invalid_argument("Percentual must be between 0 and 100");
......
......@@ -13,87 +13,31 @@ namespace fs = std::filesystem;
/**
* @brief Namespace containing a set of utility functions used in the project.
* The functions are mainly used to perform operations on images.
*
*/
namespace utility {
/**
* @class Frame
* @brief Class that extends the OpenCV Mat class, adding some useful methods
* frequently used in the project.
*
*/
class Frame : public Mat {
public:
Frame();
Frame(const Mat& m);
Frame(const Frame& f);
Frame& operator=(const Mat& m);
Frame& operator=(const Frame& f);
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);
/**
* @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 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);
/**
* @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);
/**
* @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)
* @brief Detects a given shape in an image, using a the OpenCV algorithm
* @fn void detect_shape(Ptr<GeneralizedHoughGuil> alg, int
* pos_thresh, vector<Vec4f> &positive_positions, Mat &positive_votes,
* vector<Vec4f> &negative_positions, Mat &negative_votes, Mat processing_area)
* @brief Detects a shape in an image, using a the OpenCV algorithm
* GeneralizedHoughGuil.
*
* @param[in] alg the algorithm instance;
* @param[in] templateShape the shape to detect;
* @param[in] posThresh the position votes threshold;
* @param[out] positivePositions vector representing the position assigned to
* @param[in] pos_thresh the position votes threshold, which determines the minimum number of votes required to consider
* a detection valid;
* @param[out] positive_positions vector representing the position assigned to
* each found rectangle for positive angles;
* @param[out] positiveVotes vector representing the vote assigned to each found
* @param[out] positive_votes vector representing the vote assigned to each found
* rectangle for positive angles;
* @param[out] negativePositions vector representing the position assigned to
* @param[out] negative_positions vector representing the position assigned to
* each found rectangle for negative angles;
* @param[out] negativeVotes vector representing the vote assigned to each found
* @param[out] negative_votes vector representing the vote assigned to each found
* rectangle for negative angles;
* @param[in] processingArea the image to be processed.
* @param[in] processing_area the image to be processed.
*/
void detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh, vector<Vec4f>& positivePositions,
Mat& positiveVotes, vector<Vec4f>& negativePositions, Mat& negativeVotes, Mat processingArea);
void detect_shape(Ptr<GeneralizedHoughGuil> alg, int pos_thresh, vector<Vec4f>& positive_positions, Mat& positive_votes,
vector<Vec4f>& negative_positions, Mat& negative_votes, Mat processing_area);
/**
* @fn RotatedRect drawShapes(Mat frame, Vec4f &positions, Scalar color, int
......@@ -112,29 +56,6 @@ void detectShape(Ptr<GeneralizedHoughGuil> alg, Mat templateShape, int posThresh
*/
RotatedRect drawShapes(Mat frame, const Vec4f& positions, Scalar color, int width, int height, int offsetX, int offsetY,
float processingScale);
/**
* @fn void separateFrame(cv::Mat frame, cv::Mat &odd_frame, cv::Mat
* &even_frame)
* @brief Function to deinterlace the current image.
*
* @param[in] frame image to be processed;
* @param[out] odd_frame odd plane;
* @param[out] even_frame even plane.
*/
void separateFrame(const cv::Mat frame, cv::Mat& odd_frame, cv::Mat& even_frame);
/**
* @fn void separateFrame(cv::Mat frame, cv::Mat &odd_frame, cv::Mat
* &even_frame)
* @brief Compute the number of different pixels between two frames.
*
* @param prevFrame the first frame;
* @param currentFrame the second frame.
* @return cv::Mat A black and white frame, where black pixels represent a
* difference, while white pixels represent an equality.
*/
cv::Mat difference(cv::Mat& prevFrame, cv::Mat& currentFrame);
} // namespace utility
/**
......@@ -164,7 +85,7 @@ struct Threshold {
* @brief Enum containing the possible objects to detect.
*
*/
enum ROI { TAPE, CAPSTAN };
enum class ROI { TAPE, CAPSTAN };
/**
* @struct SceneObject
......
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