Skip to content

Detection and decoding of curved QR-codes#18003

Merged
alalek merged 9 commits intoopencv:3.4from
APrigarina:curved_qrcodes_decoding
Oct 23, 2020
Merged

Detection and decoding of curved QR-codes#18003
alalek merged 9 commits intoopencv:3.4from
APrigarina:curved_qrcodes_decoding

Conversation

@APrigarina
Copy link
Copy Markdown
Contributor

These changes add detection and decoding of curved QR-codes

@APrigarina APrigarina marked this pull request as ready for review September 27, 2020 09:17
APrigarina and others added 2 commits September 28, 2020 11:11
Co-authored-by: Nesterov Alexander <nesoldr@gmail.com>
@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from bb90559 to 79a37c5 Compare September 30, 2020 12:34
@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from 89e1815 to f67ef55 Compare October 7, 2020 09:56
@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from f67ef55 to a243657 Compare October 7, 2020 10:52
}
num_points_at_side += it->second.size();
}
mean_step /= num_points_at_side;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add test for check zero divided

int count = -1;
for(size_t j = 0; j < it->second.size() - 1; j++)
{
count++;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please replace near with j++

for (it=complete_curved_sides.begin(); it!=complete_curved_sides.end(); ++it)
{
int count = -1;
for(size_t j = 0; j < it->second.size() - 1; j++)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please replace all constants outside cycles because cycle call size() function every iteration

return true;
}

vector<vector<float> > QRDecode::computeSpline(vector<int> &x_arr, vector<int> &y_arr)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
vector<vector<float> > QRDecode::computeSpline(vector<int> &x_arr, vector<int> &y_arr)
vector<vector<float> > QRDecode::computeSpline(const vector<int> &x_arr, const vector<int> &y_arr)


vector<vector<float> > QRDecode::computeSpline(vector<int> &x_arr, vector<int> &y_arr)
{
int n = (int)y_arr.size();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int n = (int)y_arr.size();
const int n = (int)y_arr.size();

{
if ((x > x_arr[i]) && (x <= x_arr[i + 1]))
{
float y = S[i][0] + S[i][1] * (x - x_arr[i]) + S[i][2] * pow((x - x_arr[i]), 2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use multiplication instead pow

x_arr.push_back(cvRound(spline_points[j].x));
y_arr.push_back(cvRound(spline_points[j].y));
}
if (abs(x_arr.front() - x_arr.back()) > abs(y_arr.front() - y_arr.back()))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use swap between x and y for calculate only one condition branch


bool QRDecode::divideIntoEvenSegments(vector<vector<Point2f> > &segments_points)
{
vector<vector<Point2f> > spline_lines(NUM_SIDES);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add NUM_SIDES into class

mean_num_points_in_line += spline_lines[i].size();
}
mean_num_points_in_line /= NUM_SIDES;
int min_num_points = 1, max_num_points = cvRound(mean_num_points_in_line / 2.0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int min_num_points = 1, max_num_points = cvRound(mean_num_points_in_line / 2.0);
const int min_num_points = 1, max_num_points = cvRound(mean_num_points_in_line / 2.0);

mean_of_two_sides += mean_dist_in_segment;
}
mean_of_two_sides /= NUM_SIDES;
if (mean_of_two_sides < 0.5)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please name magic number

Comment on lines +1973 to +1990
if (abs(temp_point_start.x - temp_point_end.x) >
abs(temp_point_start.y - temp_point_end.y))
{
if(segments_points[i].front().y > segments_points[(i+1)%2].front().y)
{
current_curved_side = segments_points[i];
opposite_curved_side = segments_points[(i+1)%2];
}
}
else
{
if(segments_points[i].front().x < segments_points[(i+1)%2].front().x)
{
current_curved_side = segments_points[i];
opposite_curved_side = segments_points[(i+1)%2];
}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revise conditions (maybe you can do it simpler)

Comment on lines +2139 to +2163
if (complete_curved_sides.size() < 2)
{
for (size_t i = 0; i < NUM_SIDES; i++)
{
if(complete_curved_sides.count(curved_indexes[i]) == 0)
{
int idx_second_cur_side = curved_indexes[i];
complete_curved_sides.insert(std::pair<int,vector<Point> >(idx_second_cur_side, sides_points[idx_second_cur_side]));
}
}
}
std::map<int,vector<Point> >::iterator it;
for (it = complete_curved_sides.begin(); it != complete_curved_sides.end(); ++it)
{
Point p1 = it->second.front();
Point p2 = it->second.back();
if (abs(p1.x - p2.x) > abs(p1.y - p2.y))
{
sort(it->second.begin(), it->second.end(), sortPointsByX());
}
else
{
sort(it->second.begin(), it->second.end(), sortPointsByY());
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add it into new method

CV_TRACE_FUNCTION();
const double multiplyingFactor = (version < 3) ? 1 :
(version == 3) ? 1.5 :
version * (5 + version - 4);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
version * (5 + version - 4);
version * (version + 1);

@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from 872654c to 5d3f886 Compare October 16, 2020 10:00
@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from 5d3f886 to 7380ea4 Compare October 19, 2020 08:07
((a1.x * a2.y - a1.y * a2.x) * (b1.x - b2.x) -
(b1.x * b2.y - b1.y * b2.x) * (a1.x - a2.x)) /
((a1.x - a2.x) * (b1.y - b2.y) -
(a1.y - a2.y) * (b1.x - b2.x)),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

divisor should be pre-calculated and checked for 0 (eps tolerance) or NaNs.

Or ensure that caller works well with Inf/NaN values and filter them out later.

Comment on lines +1084 to +1085
if (sqrt(A*A + B*B) == 0) return 0;
result = abs((A * a.x - B * a.y + C)) / sqrt(A*A + B*B);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid calculation of sqrt() expression twice.

}
num_points_at_side += num_points_at_pattern;
}
if (num_points_at_side == 0) { return false; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use separate line for if body, even for simple cases.
It is important to see the real code coverage.

@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch 2 times, most recently from a06167d to 064142a Compare October 23, 2020 10:39
@APrigarina APrigarina force-pushed the curved_qrcodes_decoding branch from 064142a to 8d05d93 Compare October 23, 2020 11:29
@APrigarina APrigarina changed the title WIP: detection and decoding of curved QR-codes Detection and decoding of curved QR-codes Oct 23, 2020
@alalek alalek merged commit c71f271 into opencv:3.4 Oct 23, 2020
@ismael-benito
Copy link
Copy Markdown

Hi! Last year, I defended my PhD in Engineering and Applied Science, regarding a thesis which involved huge use of QR Codes, at the time we didn't realize OpenCV had included a curved QR Code decoder, it is amazing the work the community has been done in recent years. In the thesis, we tackled the recovery of QR Codes from curved surfaces using Thin Plate Splines (Chapter 3 of https://diposit.ub.edu/dspace/bitstream/2445/185845/1/IBA_PhD_THESIS.pdf). Is there any paper regarding the implementation here presented of the use of splines to extract the QR Code? If we understand correctly, the above presented method uses the splines to fit the outer contour of the QR Code? We would like to be able to compare our method and the one presented here, and if able to present the research of the comparison and later attempt to make a pull request.

TL;DR: Looking for a paper related with this method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants