Commit e2ba3b87 authored by Matteo's avatar Matteo
Browse files

refactor Generalized Hough Guild code

parent 4f6e9774
...@@ -194,78 +194,48 @@ bool getArguments(int argc, char** argv) { ...@@ -194,78 +194,48 @@ bool getArguments(int argc, char** argv) {
/** /**
* @brief Identifies the Regions Of Interest (ROIs) on the video, * @brief Find the model in the scene using the Generalized Hough Transform. It returns the best matches.
* which are: * Find the best matches for positive and negative angles.
* - The reading head; * If there are more than one shapes, then choose the one with the highest score.
* - The tape area under the tape head (computed on the basis of the detected reading head); * If there are more than one with the same highest score, then arbitrarily choose the latest
* - The capstan. *
* @param myFrame The current frame of the video. * @param model the template image to be searched with the Generalized Hough Transform
* @return true if some areas have been detected; * @param object the sceneObject struct containing the parameters for the Generalized Hough Transform
* @return false otherwise. * @return std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> a tuple containing the best matches for positive and negative angles
*/ */
bool findProcessingAreas(Mat myFrame) { std::tuple<int, int, double, double, vector<Vec4f>, vector<Vec4f>> findObject(Mat model, SceneObject object, Mat processing_area) {
/*********************************************************************************************/
/*********************************** READING HEAD DETECTION **********************************/
/*********************************************************************************************/
// Save a grayscale version of myFrame in myFrameGrayscale and downsample it in half pixels for performance reasons
Frame gray_current_frame = Frame(myFrame)
.convertColor(COLOR_BGR2GRAY);
Frame halved_gray_current_frame = gray_current_frame
.clone()
.downsample(2);
// Get input shape in grayscale and downsample it in half pixels
Frame reading_head_template = Frame(cv::imread(READING_HEAD_IMG, IMREAD_GRAYSCALE)).downsample(2);
// Process only the bottom-central portion of the input video -> best results with our videos
Rect readingHeadProcessingAreaRect(
halved_gray_current_frame.cols/4,
halved_gray_current_frame.rows/2,
halved_gray_current_frame.cols/2,
halved_gray_current_frame.rows/2
);
Mat processingImage = halved_gray_current_frame(readingHeadProcessingAreaRect);
// Algorithm and parameters // Algorithm and parameters
// for informations about the Generalized Hough Guild interface see the tutorial at https://docs.opencv.org/4.7.0/da/ddc/tutorial_generalized_hough_ballard_guil.html // for informations about the Generalized Hough Guild usage see the tutorial at https://docs.opencv.org/4.7.0/da/ddc/tutorial_generalized_hough_ballard_guil.html
Ptr<GeneralizedHoughGuil> alg = createGeneralizedHoughGuil(); Ptr<GeneralizedHoughGuil> alg = createGeneralizedHoughGuil();
vector<Vec4f> positionsPos, positionsNeg; vector<Vec4f> positionsPos, positionsNeg;
Mat votesPos, votesNeg; Mat votesPos, votesNeg;
int oldPosThresh = tape.threshold.pos;
RotatedRect rectPos, rectNeg;
ofstream myFile;
// Find the best matches for positive and negative angles
// If there are more than one shapes, then choose the one with the highest score
// If there are more than one with the same highest score, then arbitrarily choose the latest
double maxValPos = 0, maxValNeg = 0; double maxValPos = 0, maxValNeg = 0;
int indexPos = 0, indexNeg = 0; int indexPos = 0, indexNeg = 0;
alg->setMinDist(tape.minDist); alg->setMinDist(object.minDist);
alg->setLevels(360); alg->setLevels(360);
alg->setDp(2); alg->setDp(2);
alg->setMaxBufferSize(1000); alg->setMaxBufferSize(1000);
alg->setAngleStep(1); alg->setAngleStep(1);
alg->setAngleThresh(tape.threshold.angle); alg->setAngleThresh(object.threshold.angle);
alg->setMinScale(0.9); alg->setMinScale(0.9);
alg->setMaxScale(1.1); alg->setMaxScale(1.1);
alg->setScaleStep(0.01); alg->setScaleStep(0.01);
alg->setScaleThresh(tape.threshold.scale); alg->setScaleThresh(object.threshold.scale);
alg->setPosThresh(tape.threshold.pos); alg->setPosThresh(object.threshold.pos);
alg->setCannyLowThresh(150); // Old: 100 alg->setCannyLowThresh(150); // Old: 100
alg->setCannyHighThresh(240); // Old: 300 alg->setCannyHighThresh(240); // Old: 300
alg->setTemplate(reading_head_template); alg->setTemplate(model);
utility::detectShape(alg, reading_head_template, tape.threshold.pos, positionsPos, votesPos, positionsNeg, votesNeg, processingImage); utility::detectShape(alg, model, object.threshold.pos, positionsPos, votesPos, positionsNeg, votesNeg, processing_area);
for (int i = 0; i < votesPos.size().width; i++) { for (int i = 0; i < votesPos.size().width; i++) {
if (votesPos.at<int>(i) >= maxValPos) { if (votesPos.at<int>(i) >= maxValPos) {
...@@ -281,6 +251,49 @@ bool findProcessingAreas(Mat myFrame) { ...@@ -281,6 +251,49 @@ bool findProcessingAreas(Mat myFrame) {
} }
} }
return { indexPos, indexNeg, maxValPos, maxValNeg, positionsPos, positionsNeg };
}
/**
* @brief Identifies the Regions Of Interest (ROIs) on the video,
* which are:
* - The reading head;
* - The tape area under the tape head (computed on the basis of the detected reading head);
* - The capstan.
* @param myFrame The current frame of the video.
* @return true if some areas have been detected;
* @return false otherwise.
*/
bool findProcessingAreas(Mat myFrame) {
/*********************************************************************************************/
/*********************************** READING HEAD DETECTION **********************************/
/*********************************************************************************************/
// Save a grayscale version of myFrame in myFrameGrayscale and downsample it in half pixels for performance reasons
Frame gray_current_frame = Frame(myFrame)
.convertColor(COLOR_BGR2GRAY);
Frame halved_gray_current_frame = gray_current_frame
.clone()
.downsample(2);
// Get input shape in grayscale and downsample it in half pixels
Frame reading_head_template = Frame(cv::imread(READING_HEAD_IMG, IMREAD_GRAYSCALE)).downsample(2);
// Process only the bottom-central portion of the input video -> best results with our videos
Rect readingHeadProcessingAreaRect(
halved_gray_current_frame.cols/4,
halved_gray_current_frame.rows/2,
halved_gray_current_frame.cols/2,
halved_gray_current_frame.rows/2
);
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);
// The color is progressively darkened to emphasize that the algorithm found more than one shape // The color is progressively darkened to emphasize that the algorithm found more than one shape
if (positionsPos.size() > 0) if (positionsPos.size() > 0)
rectPos = utility::drawShapes(myFrame, positionsPos[indexPos], Scalar(0, 0, 255-indexPos*64), reading_head_template.cols, reading_head_template.rows, halved_gray_current_frame.cols/4, halved_gray_current_frame.rows/2, 2); rectPos = utility::drawShapes(myFrame, positionsPos[indexPos], Scalar(0, 0, 255-indexPos*64), reading_head_template.cols, reading_head_template.rows, halved_gray_current_frame.cols/4, halved_gray_current_frame.rows/2, 2);
...@@ -406,7 +419,7 @@ bool findProcessingAreas(Mat myFrame) { ...@@ -406,7 +419,7 @@ bool findProcessingAreas(Mat myFrame) {
} else { } else {
// Process only right portion of the image, wherw the capstain always appears // Process only right portion of the image, where the capstain always appears
int capstanProcessingAreaRectX = myFrame.cols*3/4; int capstanProcessingAreaRectX = myFrame.cols*3/4;
int capstanProcessingAreaRectY = myFrame.rows/2; int capstanProcessingAreaRectY = myFrame.rows/2;
int capstanProcessingAreaRectWidth = myFrame.cols/4; int capstanProcessingAreaRectWidth = myFrame.cols/4;
...@@ -414,53 +427,8 @@ bool findProcessingAreas(Mat myFrame) { ...@@ -414,53 +427,8 @@ bool findProcessingAreas(Mat myFrame) {
Rect capstanProcessingAreaRect(capstanProcessingAreaRectX, capstanProcessingAreaRectY, capstanProcessingAreaRectWidth, capstanProcessingAreaRectHeight); Rect capstanProcessingAreaRect(capstanProcessingAreaRectX, capstanProcessingAreaRectY, capstanProcessingAreaRectWidth, capstanProcessingAreaRectHeight);
Mat capstanProcessingAreaGrayscale = gray_current_frame(capstanProcessingAreaRect); Mat capstanProcessingAreaGrayscale = gray_current_frame(capstanProcessingAreaRect);
// Reset algorithm and set parameters // Reset algorithm and set parameters
alg = createGeneralizedHoughGuil();
alg->setMinDist(capstan.minDist);
alg->setLevels(360);
alg->setDp(2);
alg->setMaxBufferSize(1000);
alg->setAngleStep(1);
alg->setAngleThresh(capstan.threshold.angle);
alg->setMinScale(0.9);
alg->setMaxScale(1.1);
alg->setScaleStep(0.01);
alg->setScaleThresh(capstan.threshold.scale);
alg->setPosThresh(capstan.threshold.pos);
alg->setCannyLowThresh(150); auto [indexPos, indexNeg, maxValPos, maxValNeg, positionsC1Pos, positionsC1Neg] = findObject(templateShape, capstan, capstanProcessingAreaGrayscale);
alg->setCannyHighThresh(240);
alg->setTemplate(templateShape);
oldPosThresh = capstan.threshold.pos;
vector<Vec4f> positionsC1Pos, positionsC1Neg;
Mat votesC1Pos, votesC1Neg;
utility::detectShape(alg, templateShape, capstan.threshold.pos, positionsC1Pos, votesC1Pos, positionsC1Neg, votesC1Neg, capstanProcessingAreaGrayscale);
// Find the best matches for positive and negative angles
// If there are more than one shapes, then choose the one with the highest score
// If there are more than one with the same highest score, then choose the latest
maxValPos = 0, maxValNeg = 0, indexPos = 0, indexNeg = 0;
for (int i = 0; i < votesC1Pos.size().width; i++) {
if (votesC1Pos.at<int>(i) >= maxValPos) {
maxValPos = votesC1Pos.at<int>(i);
indexPos = i;
}
}
for (int i = 0; i < votesC1Neg.size().width; i++) {
if (votesC1Neg.at<int>(i) >= maxValNeg) {
maxValNeg = votesC1Neg.at<int>(i);
indexNeg = i;
}
}
RotatedRect rectCapstanPos, rectCapstanNeg; RotatedRect rectCapstanPos, rectCapstanNeg;
if (positionsC1Pos.size() > 0) if (positionsC1Pos.size() > 0)
......
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