| 591 | } |
| 592 | |
| 593 | DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp) |
| 594 | { |
| 595 | auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2); |
| 596 | if (!fpQuad) |
| 597 | return {}; |
| 598 | |
| 599 | auto srcQuad = Rectangle(7, 7, 0.5); |
| 600 | |
| 601 | #if defined(_MSVC_LANG) // TODO: see MSVC issue https://developercommunity.visualstudio.com/t/constexpr-object-is-unable-to-be-used-as/10035065 |
| 602 | static |
| 603 | #else |
| 604 | constexpr |
| 605 | #endif |
| 606 | const PointI FORMAT_INFO_COORDS[] = {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {6, 8}, {7, 8}, {8, 8}, |
| 607 | {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {8, 0}}; |
| 608 | |
| 609 | FormatInformation bestFI; |
| 610 | PerspectiveTransform bestPT; |
| 611 | |
| 612 | for (int i = 0; i < 4; ++i) { |
| 613 | auto mod2Pix = PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, i)); |
| 614 | |
| 615 | auto check = [&](int i, bool checkOne) { |
| 616 | auto p = mod2Pix(centered(FORMAT_INFO_COORDS[i])); |
| 617 | return image.isIn(p) && (!checkOne || image.get(p)); |
| 618 | }; |
| 619 | |
| 620 | // check that we see both innermost timing pattern modules |
| 621 | if (!check(0, true) || !check(8, false) || !check(16, true)) |
| 622 | continue; |
| 623 | |
| 624 | int formatInfoBits = 0; |
| 625 | for (int i = 1; i <= 15; ++i) |
| 626 | AppendBit(formatInfoBits, image.get(mod2Pix(centered(FORMAT_INFO_COORDS[i])))); |
| 627 | |
| 628 | auto fi = FormatInformation::DecodeMQR(formatInfoBits); |
| 629 | if (fi.hammingDistance < bestFI.hammingDistance) { |
| 630 | bestFI = fi; |
| 631 | bestPT = mod2Pix; |
| 632 | } |
| 633 | } |
| 634 | |
| 635 | if (!bestFI.isValid()) |
| 636 | return {}; |
| 637 | |
| 638 | const int dim = Version::DimensionOfVersion(bestFI.microVersion, true); |
| 639 | |
| 640 | // check that we are in fact not looking at a corner of a non-micro QRCode symbol |
| 641 | // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2). |
| 642 | int blackPixels = 0; |
| 643 | for (int i = 0; i < dim; ++i) { |
| 644 | auto px = bestPT(centered(PointI{i, dim})); |
| 645 | auto py = bestPT(centered(PointI{dim, i})); |
| 646 | blackPixels += (image.isIn(px) && image.get(px)) + (image.isIn(py) && image.get(py)); |
| 647 | } |
| 648 | if (blackPixels > 2 * dim / 3) |
| 649 | return {}; |
| 650 |
no test coverage detected