qrcode.cpp 38.4 KB
Newer Older
N
Nesterov Alexander 已提交
1 2 3 4 5 6 7 8 9
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2018, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.

#include "precomp.hpp"
#include "opencv2/objdetect.hpp"
A
Alexander Nesterov 已提交
10 11 12 13 14
#include "opencv2/calib3d.hpp"

#ifdef HAVE_QUIRC
#include "quirc.h"
#endif
N
Nesterov Alexander 已提交
15 16 17 18

#include <limits>
#include <cmath>
#include <iostream>
A
Alexander Nesterov 已提交
19
#include <queue>
N
Nesterov Alexander 已提交
20 21 22

namespace cv
{
23 24
using std::vector;

25
class QRDetect
N
Nesterov Alexander 已提交
26
{
27
public:
28
    void init(const Mat& src, double eps_vertical_ = 0.2, double eps_horizontal_ = 0.1);
N
Nesterov Alexander 已提交
29
    bool localization();
30
    bool computeTransformationPoints();
N
Nesterov Alexander 已提交
31 32
    Mat getBinBarcode() { return bin_barcode; }
    Mat getStraightBarcode() { return straight_barcode; }
33
    vector<Point2f> getTransformationPoints() { return transformation_points; }
A
Alexander Nesterov 已提交
34
    static Point2f intersectionLines(Point2f a1, Point2f a2, Point2f b1, Point2f b2);
35
protected:
36 37
    vector<Vec3d> searchHorizontalLines();
    vector<Point2f> separateVerticalLines(const vector<Vec3d> &list_lines);
38 39 40
    void fixationPoints(vector<Point2f> &local_point);
    vector<Point2f> getQuadrilateral(vector<Point2f> angle_list);
    bool testBypassRoute(vector<Point2f> hull, int start, int finish);
A
Alexander Nesterov 已提交
41
    inline double getCosVectors(Point2f a, Point2f b, Point2f c);
42 43 44

    Mat barcode, bin_barcode, straight_barcode;
    vector<Point2f> localization_points, transformation_points;
45
    double eps_vertical, eps_horizontal, coeff_expansion;
N
Nesterov Alexander 已提交
46 47
};

48

49
void QRDetect::init(const Mat& src, double eps_vertical_, double eps_horizontal_)
N
Nesterov Alexander 已提交
50
{
51 52
    CV_Assert(!src.empty());
    const double min_side = std::min(src.size().width, src.size().height);
53 54 55
    if (min_side < 512.0)
    {
        coeff_expansion = 512.0 / min_side;
56 57
        const int width  = cvRound(src.size().width  * coeff_expansion);
        const int height = cvRound(src.size().height  * coeff_expansion);
58
        Size new_size(width, height);
59
        resize(src, barcode, new_size, 0, 0, INTER_LINEAR);
60 61 62 63 64 65
    }
    else
    {
        coeff_expansion = 1.0;
        barcode = src;
    }
66

N
Nesterov Alexander 已提交
67 68
    eps_vertical   = eps_vertical_;
    eps_horizontal = eps_horizontal_;
69
    adaptiveThreshold(barcode, bin_barcode, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
A
Alexander Nesterov 已提交
70

N
Nesterov Alexander 已提交
71 72
}

73
vector<Vec3d> QRDetect::searchHorizontalLines()
N
Nesterov Alexander 已提交
74
{
75
    vector<Vec3d> result;
76 77 78 79 80 81 82 83 84
    const int height_bin_barcode = bin_barcode.rows;
    const int width_bin_barcode  = bin_barcode.cols;
    const size_t test_lines_size = 5;
    double test_lines[test_lines_size];
    const size_t count_pixels_position = 1024;
    size_t pixels_position[count_pixels_position];
    size_t index = 0;

    for (int y = 0; y < height_bin_barcode; y++)
N
Nesterov Alexander 已提交
85
    {
86
        const uint8_t *bin_barcode_row = bin_barcode.ptr<uint8_t>(y);
N
Nesterov Alexander 已提交
87

88 89 90
        int pos = 0;
        for (; pos < width_bin_barcode; pos++) { if (bin_barcode_row[pos] == 0) break; }
        if (pos == width_bin_barcode) { continue; }
N
Nesterov Alexander 已提交
91

92 93 94
        index = 0;
        pixels_position[index] = pixels_position[index + 1] = pixels_position[index + 2] = pos;
        index +=3;
N
Nesterov Alexander 已提交
95

96 97 98 99
        uint8_t future_pixel = 255;
        for (int x = pos; x < width_bin_barcode; x++)
        {
            if (bin_barcode_row[x] == future_pixel)
N
Nesterov Alexander 已提交
100
            {
101 102 103
                future_pixel = 255 - future_pixel;
                pixels_position[index] = x;
                index++;
N
Nesterov Alexander 已提交
104
            }
105 106 107 108 109 110 111 112 113 114
        }
        pixels_position[index] = width_bin_barcode - 1;
        index++;
        for (size_t i = 2; i < index - 4; i+=2)
        {
            test_lines[0] = static_cast<double>(pixels_position[i - 1] - pixels_position[i - 2]);
            test_lines[1] = static_cast<double>(pixels_position[i    ] - pixels_position[i - 1]);
            test_lines[2] = static_cast<double>(pixels_position[i + 1] - pixels_position[i    ]);
            test_lines[3] = static_cast<double>(pixels_position[i + 2] - pixels_position[i + 1]);
            test_lines[4] = static_cast<double>(pixels_position[i + 3] - pixels_position[i + 2]);
N
Nesterov Alexander 已提交
115

116
            double length = 0.0, weight = 0.0;
N
Nesterov Alexander 已提交
117

118
            for (size_t j = 0; j < test_lines_size; j++) { length += test_lines[j]; }
N
Nesterov Alexander 已提交
119

120 121 122 123 124 125
            if (length == 0) { continue; }
            for (size_t j = 0; j < test_lines_size; j++)
            {
                if (j == 2) { weight += fabs((test_lines[j] / length) - 3.0/7.0); }
                else        { weight += fabs((test_lines[j] / length) - 1.0/7.0); }
            }
N
Nesterov Alexander 已提交
126

127 128 129 130 131 132 133
            if (weight < eps_vertical)
            {
                Vec3d line;
                line[0] = static_cast<double>(pixels_position[i - 2]);
                line[1] = y;
                line[2] = length;
                result.push_back(line);
N
Nesterov Alexander 已提交
134 135 136 137 138 139
            }
        }
    }
    return result;
}

140
vector<Point2f> QRDetect::separateVerticalLines(const vector<Vec3d> &list_lines)
N
Nesterov Alexander 已提交
141
{
142
    vector<Vec3d> result;
N
Nesterov Alexander 已提交
143
    int temp_length = 0;
144
    uint8_t next_pixel;
145
    vector<double> test_lines;
N
Nesterov Alexander 已提交
146

147

N
Nesterov Alexander 已提交
148 149
    for (size_t pnt = 0; pnt < list_lines.size(); pnt++)
    {
150 151 152 153
        const int x = cvRound(list_lines[pnt][0] + list_lines[pnt][2] * 0.5);
        const int y = cvRound(list_lines[pnt][1]);

        // --------------- Search vertical up-lines --------------- //
N
Nesterov Alexander 已提交
154 155

        test_lines.clear();
156
        uint8_t future_pixel_up = 255;
N
Nesterov Alexander 已提交
157

158
        for (int j = y; j < bin_barcode.rows - 1; j++)
N
Nesterov Alexander 已提交
159
        {
160
            next_pixel = bin_barcode.at<uint8_t>(j + 1, x);
N
Nesterov Alexander 已提交
161
            temp_length++;
162
            if (next_pixel == future_pixel_up)
N
Nesterov Alexander 已提交
163
            {
164
                future_pixel_up = 255 - future_pixel_up;
N
Nesterov Alexander 已提交
165 166 167 168 169 170
                test_lines.push_back(temp_length);
                temp_length = 0;
                if (test_lines.size() == 3) { break; }
            }
        }

171
        // --------------- Search vertical down-lines --------------- //
N
Nesterov Alexander 已提交
172

173
        uint8_t future_pixel_down = 255;
N
Nesterov Alexander 已提交
174 175
        for (int j = y; j >= 1; j--)
        {
176
            next_pixel = bin_barcode.at<uint8_t>(j - 1, x);
N
Nesterov Alexander 已提交
177
            temp_length++;
178
            if (next_pixel == future_pixel_down)
N
Nesterov Alexander 已提交
179
            {
180
                future_pixel_down = 255 - future_pixel_down;
N
Nesterov Alexander 已提交
181 182 183 184 185 186
                test_lines.push_back(temp_length);
                temp_length = 0;
                if (test_lines.size() == 6) { break; }
            }
        }

187
        // --------------- Compute vertical lines --------------- //
N
Nesterov Alexander 已提交
188 189 190

        if (test_lines.size() == 6)
        {
191
            double length = 0.0, weight = 0.0;
N
Nesterov Alexander 已提交
192 193 194

            for (size_t i = 0; i < test_lines.size(); i++) { length += test_lines[i]; }

195
            CV_Assert(length > 0);
N
Nesterov Alexander 已提交
196 197
            for (size_t i = 0; i < test_lines.size(); i++)
            {
198 199
                if (i % 3 == 0) { weight += fabs((test_lines[i] / length) - 3.0/14.0); }
                else            { weight += fabs((test_lines[i] / length) - 1.0/ 7.0); }
N
Nesterov Alexander 已提交
200 201
            }

202 203 204 205
            if(weight < eps_horizontal)
            {
                result.push_back(list_lines[pnt]);
            }
N
Nesterov Alexander 已提交
206 207 208 209

        }
    }

210 211
    vector<Point2f> point2f_result;
    for (size_t i = 0; i < result.size(); i++)
N
Nesterov Alexander 已提交
212
    {
213
        point2f_result.push_back(
214 215
              Point2f(static_cast<float>(result[i][0] + result[i][2] * 0.5),
                      static_cast<float>(result[i][1])));
N
Nesterov Alexander 已提交
216
    }
217
    return point2f_result;
N
Nesterov Alexander 已提交
218 219
}

220
void QRDetect::fixationPoints(vector<Point2f> &local_point)
N
Nesterov Alexander 已提交
221
{
222

N
Nesterov Alexander 已提交
223 224 225 226 227 228
    double cos_angles[3], norm_triangl[3];

    norm_triangl[0] = norm(local_point[1] - local_point[2]);
    norm_triangl[1] = norm(local_point[0] - local_point[2]);
    norm_triangl[2] = norm(local_point[1] - local_point[0]);

229 230 231 232 233 234 235 236 237 238 239 240 241
    cos_angles[0] = (norm_triangl[1] * norm_triangl[1] + norm_triangl[2] * norm_triangl[2]
                  -  norm_triangl[0] * norm_triangl[0]) / (2 * norm_triangl[1] * norm_triangl[2]);
    cos_angles[1] = (norm_triangl[0] * norm_triangl[0] + norm_triangl[2] * norm_triangl[2]
                  -  norm_triangl[1] * norm_triangl[1]) / (2 * norm_triangl[0] * norm_triangl[2]);
    cos_angles[2] = (norm_triangl[0] * norm_triangl[0] + norm_triangl[1] * norm_triangl[1]
                  -  norm_triangl[2] * norm_triangl[2]) / (2 * norm_triangl[0] * norm_triangl[1]);

    const double angle_barrier = 0.85;
    if (fabs(cos_angles[0]) > angle_barrier || fabs(cos_angles[1]) > angle_barrier || fabs(cos_angles[2]) > angle_barrier)
    {
        local_point.clear();
        return;
    }
242 243

    size_t i_min_cos =
244 245
       (cos_angles[0] < cos_angles[1] && cos_angles[0] < cos_angles[2]) ? 0 :
       (cos_angles[1] < cos_angles[0] && cos_angles[1] < cos_angles[2]) ? 1 : 2;
246

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    size_t index_max = 0;
    double max_area = std::numeric_limits<double>::min();
    for (size_t i = 0; i < local_point.size(); i++)
    {
        const size_t current_index = i % 3;
        const size_t left_index  = (i + 1) % 3;
        const size_t right_index = (i + 2) % 3;

        const Point2f current_point(local_point[current_index]),
            left_point(local_point[left_index]), right_point(local_point[right_index]),
            central_point(intersectionLines(current_point,
                              Point2f(static_cast<float>((local_point[left_index].x + local_point[right_index].x) * 0.5),
                                      static_cast<float>((local_point[left_index].y + local_point[right_index].y) * 0.5)),
                              Point2f(0, static_cast<float>(bin_barcode.rows - 1)),
                              Point2f(static_cast<float>(bin_barcode.cols - 1),
                                      static_cast<float>(bin_barcode.rows - 1))));


        vector<Point2f> list_area_pnt;
        list_area_pnt.push_back(current_point);

        vector<LineIterator> list_line_iter;
        list_line_iter.push_back(LineIterator(bin_barcode, current_point, left_point));
        list_line_iter.push_back(LineIterator(bin_barcode, current_point, central_point));
        list_line_iter.push_back(LineIterator(bin_barcode, current_point, right_point));
272

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        for (size_t k = 0; k < list_line_iter.size(); k++)
        {
            uint8_t future_pixel = 255, count_index = 0;
            for(int j = 0; j < list_line_iter[k].count; j++, ++list_line_iter[k])
            {
                if (list_line_iter[k].pos().x >= bin_barcode.cols ||
                    list_line_iter[k].pos().y >= bin_barcode.rows) { break; }
                const uint8_t value = bin_barcode.at<uint8_t>(list_line_iter[k].pos());
                if (value == future_pixel)
                {
                    future_pixel = 255 - future_pixel;
                    count_index++;
                    if (count_index == 3)
                    {
                        list_area_pnt.push_back(list_line_iter[k].pos());
                        break;
                    }
                }
            }
        }

        const double temp_check_area = contourArea(list_area_pnt);
        if (temp_check_area > max_area)
        {
            index_max = current_index;
            max_area = temp_check_area;
        }

    }
    if (index_max == i_min_cos) { std::swap(local_point[0], local_point[index_max]); }
    else { local_point.clear(); return; }

    const Point2f rpt = local_point[0], bpt = local_point[1], gpt = local_point[2];
306 307
    Matx22f m(rpt.x - bpt.x, rpt.y - bpt.y, gpt.x - rpt.x, gpt.y - rpt.y);
    if( determinant(m) > 0 )
N
Nesterov Alexander 已提交
308
    {
309
        std::swap(local_point[1], local_point[2]);
N
Nesterov Alexander 已提交
310 311 312
    }
}

313
bool QRDetect::localization()
N
Nesterov Alexander 已提交
314
{
315
    Point2f begin, end;
316
    vector<Vec3d> list_lines_x = searchHorizontalLines();
317
    if( list_lines_x.empty() ) { return false; }
318 319
    vector<Point2f> list_lines_y = separateVerticalLines(list_lines_x);
    if( list_lines_y.size() < 3 ) { return false; }
320 321 322 323

    vector<Point2f> centers;
    Mat labels;
    kmeans(list_lines_y, 3, labels,
324
           TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1),
325 326 327
           3, KMEANS_PP_CENTERS, localization_points);

    fixationPoints(localization_points);
N
Nesterov Alexander 已提交
328 329
    if (localization_points.size() != 3) { return false; }

330
    if (coeff_expansion > 1.0)
N
Nesterov Alexander 已提交
331
    {
332 333
        const int width  = cvRound(bin_barcode.size().width  / coeff_expansion);
        const int height = cvRound(bin_barcode.size().height / coeff_expansion);
334
        Size new_size(width, height);
335 336
        Mat intermediate = Mat::zeros(new_size, CV_8UC1);
        resize(bin_barcode, intermediate, new_size, 0, 0, INTER_LINEAR);
337 338 339 340 341
        bin_barcode = intermediate.clone();
        for (size_t i = 0; i < localization_points.size(); i++)
        {
            localization_points[i] /= coeff_expansion;
        }
N
Nesterov Alexander 已提交
342 343
    }

344 345 346 347 348 349 350 351 352 353
    for (size_t i = 0; i < localization_points.size(); i++)
    {
        for (size_t j = i + 1; j < localization_points.size(); j++)
        {
            if (norm(localization_points[i] - localization_points[j]) < 10)
            {
                return false;
            }
        }
    }
N
Nesterov Alexander 已提交
354
    return true;
355

N
Nesterov Alexander 已提交
356 357
}

358
bool QRDetect::computeTransformationPoints()
N
Nesterov Alexander 已提交
359
{
360
    if (localization_points.size() != 3) { return false; }
N
Nesterov Alexander 已提交
361

362 363 364
    vector<Point> locations, non_zero_elem[3], newHull;
    vector<Point2f> new_non_zero_elem[3];
    for (size_t i = 0; i < 3; i++)
N
Nesterov Alexander 已提交
365
    {
366 367
        Mat mask = Mat::zeros(bin_barcode.rows + 2, bin_barcode.cols + 2, CV_8UC1);
        uint8_t next_pixel, future_pixel = 255;
368
        int count_test_lines = 0, index = cvRound(localization_points[i].x);
369
        for (; index < bin_barcode.cols - 1; index++)
N
Nesterov Alexander 已提交
370
        {
371
            next_pixel = bin_barcode.at<uint8_t>(
372
                            cvRound(localization_points[i].y), index + 1);
373
            if (next_pixel == future_pixel)
N
Nesterov Alexander 已提交
374
            {
375 376 377
                future_pixel = 255 - future_pixel;
                count_test_lines++;
                if (count_test_lines == 2)
N
Nesterov Alexander 已提交
378
                {
379
                    floodFill(bin_barcode, mask,
380
                              Point(index + 1, cvRound(localization_points[i].y)), 255,
381 382
                              0, Scalar(), Scalar(), FLOODFILL_MASK_ONLY);
                    break;
N
Nesterov Alexander 已提交
383 384 385
                }
            }
        }
386 387 388 389 390 391 392 393
        Mat mask_roi = mask(Range(1, bin_barcode.rows - 1), Range(1, bin_barcode.cols - 1));
        findNonZero(mask_roi, non_zero_elem[i]);
        newHull.insert(newHull.end(), non_zero_elem[i].begin(), non_zero_elem[i].end());
    }
    convexHull(Mat(newHull), locations);
    for (size_t i = 0; i < locations.size(); i++)
    {
        for (size_t j = 0; j < 3; j++)
N
Nesterov Alexander 已提交
394
        {
395 396 397 398 399 400 401
            for (size_t k = 0; k < non_zero_elem[j].size(); k++)
            {
                if (locations[i] == non_zero_elem[j][k])
                {
                    new_non_zero_elem[j].push_back(locations[i]);
                }
            }
N
Nesterov Alexander 已提交
402 403 404
        }
    }

405 406 407
    double pentagon_diag_norm = -1;
    Point2f down_left_edge_point, up_right_edge_point, up_left_edge_point;
    for (size_t i = 0; i < new_non_zero_elem[1].size(); i++)
N
Nesterov Alexander 已提交
408
    {
409
        for (size_t j = 0; j < new_non_zero_elem[2].size(); j++)
N
Nesterov Alexander 已提交
410
        {
411 412 413 414 415 416 417
            double temp_norm = norm(new_non_zero_elem[1][i] - new_non_zero_elem[2][j]);
            if (temp_norm > pentagon_diag_norm)
            {
                down_left_edge_point = new_non_zero_elem[1][i];
                up_right_edge_point  = new_non_zero_elem[2][j];
                pentagon_diag_norm = temp_norm;
            }
N
Nesterov Alexander 已提交
418 419
        }
    }
A
Alexander Nesterov 已提交
420

421
    if (down_left_edge_point == Point2f(0, 0) ||
A
Alexander Nesterov 已提交
422 423
        up_right_edge_point  == Point2f(0, 0) ||
        new_non_zero_elem[0].size() == 0) { return false; }
N
Nesterov Alexander 已提交
424

425 426
    double max_area = -1;
    up_left_edge_point = new_non_zero_elem[0][0];
A
Alexander Nesterov 已提交
427

428 429
    for (size_t i = 0; i < new_non_zero_elem[0].size(); i++)
    {
A
Alexander Nesterov 已提交
430 431 432 433 434
        vector<Point2f> list_edge_points;
        list_edge_points.push_back(new_non_zero_elem[0][i]);
        list_edge_points.push_back(down_left_edge_point);
        list_edge_points.push_back(up_right_edge_point);

A
Alexander Nesterov 已提交
435
        double temp_area = fabs(contourArea(list_edge_points));
A
Alexander Nesterov 已提交
436

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
        if (max_area < temp_area)
        {
            up_left_edge_point = new_non_zero_elem[0][i];
            max_area = temp_area;
        }
    }

    Point2f down_max_delta_point, up_max_delta_point;
    double norm_down_max_delta = -1, norm_up_max_delta = -1;
    for (size_t i = 0; i < new_non_zero_elem[1].size(); i++)
    {
        double temp_norm_delta = norm(up_left_edge_point - new_non_zero_elem[1][i])
                               + norm(down_left_edge_point - new_non_zero_elem[1][i]);
        if (norm_down_max_delta < temp_norm_delta)
        {
            down_max_delta_point = new_non_zero_elem[1][i];
            norm_down_max_delta = temp_norm_delta;
        }
    }

A
Alexander Nesterov 已提交
457

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
    for (size_t i = 0; i < new_non_zero_elem[2].size(); i++)
    {
        double temp_norm_delta = norm(up_left_edge_point - new_non_zero_elem[2][i])
                               + norm(up_right_edge_point - new_non_zero_elem[2][i]);
        if (norm_up_max_delta < temp_norm_delta)
        {
            up_max_delta_point = new_non_zero_elem[2][i];
            norm_up_max_delta = temp_norm_delta;
        }
    }

    transformation_points.push_back(down_left_edge_point);
    transformation_points.push_back(up_left_edge_point);
    transformation_points.push_back(up_right_edge_point);
    transformation_points.push_back(
        intersectionLines(down_left_edge_point, down_max_delta_point,
                          up_right_edge_point, up_max_delta_point));

    vector<Point2f> quadrilateral = getQuadrilateral(transformation_points);
    transformation_points = quadrilateral;

    return true;
N
Nesterov Alexander 已提交
480 481
}

482
Point2f QRDetect::intersectionLines(Point2f a1, Point2f a2, Point2f b1, Point2f b2)
N
Nesterov Alexander 已提交
483
{
484 485 486 487 488 489 490 491 492 493
    Point2f result_square_angle(
                              ((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)),
                              ((a1.x * a2.y  -  a1.y * a2.x) * (b1.y - b2.y) -
                               (b1.x * b2.y  -  b1.y * b2.x) * (a1.y - a2.y)) /
                              ((a1.x - a2.x) * (b1.y - b2.y) -
                               (a1.y - a2.y) * (b1.x - b2.x))
                              );
N
Nesterov Alexander 已提交
494 495 496
    return result_square_angle;
}

497
// test function (if true then ------> else <------ )
498
bool QRDetect::testBypassRoute(vector<Point2f> hull, int start, int finish)
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
{
    int index_hull = start, next_index_hull, hull_size = (int)hull.size();
    double test_length[2] = { 0.0, 0.0 };
    do
    {
        next_index_hull = index_hull + 1;
        if (next_index_hull == hull_size) { next_index_hull = 0; }
        test_length[0] += norm(hull[index_hull] - hull[next_index_hull]);
        index_hull = next_index_hull;
    }
    while(index_hull != finish);

    index_hull = start;
    do
    {
        next_index_hull = index_hull - 1;
        if (next_index_hull == -1) { next_index_hull = hull_size - 1; }
        test_length[1] += norm(hull[index_hull] - hull[next_index_hull]);
        index_hull = next_index_hull;
    }
    while(index_hull != finish);

    if (test_length[0] < test_length[1]) { return true; } else { return false; }
}

524
vector<Point2f> QRDetect::getQuadrilateral(vector<Point2f> angle_list)
N
Nesterov Alexander 已提交
525 526 527
{
    size_t angle_size = angle_list.size();
    uint8_t value, mask_value;
528 529
    Mat mask = Mat::zeros(bin_barcode.rows + 2, bin_barcode.cols + 2, CV_8UC1);
    Mat fill_bin_barcode = bin_barcode.clone();
N
Nesterov Alexander 已提交
530 531 532 533 534 535 536 537 538 539
    for (size_t i = 0; i < angle_size; i++)
    {
        LineIterator line_iter(bin_barcode, angle_list[ i      % angle_size],
                                            angle_list[(i + 1) % angle_size]);
        for(int j = 0; j < line_iter.count; j++, ++line_iter)
        {
            value = bin_barcode.at<uint8_t>(line_iter.pos());
            mask_value = mask.at<uint8_t>(line_iter.pos() + Point(1, 1));
            if (value == 0 && mask_value == 0)
            {
540 541
                floodFill(fill_bin_barcode, mask, line_iter.pos(), 255,
                          0, Scalar(), Scalar(), FLOODFILL_MASK_ONLY);
N
Nesterov Alexander 已提交
542 543 544
            }
        }
    }
545 546
    vector<Point> locations;
    Mat mask_roi = mask(Range(1, bin_barcode.rows - 1), Range(1, bin_barcode.cols - 1));
N
Nesterov Alexander 已提交
547

A
Alexander Nesterov 已提交
548
    findNonZero(mask_roi, locations);
N
Nesterov Alexander 已提交
549 550 551

    for (size_t i = 0; i < angle_list.size(); i++)
    {
552 553
        int x = cvRound(angle_list[i].x);
        int y = cvRound(angle_list[i].y);
554
        locations.push_back(Point(x, y));
N
Nesterov Alexander 已提交
555 556
    }

557 558 559 560 561
    vector<Point> integer_hull;
    convexHull(Mat(locations), integer_hull);
    int hull_size = (int)integer_hull.size();
    vector<Point2f> hull(hull_size);
    for (int i = 0; i < hull_size; i++)
N
Nesterov Alexander 已提交
562
    {
563 564
        float x = saturate_cast<float>(integer_hull[i].x);
        float y = saturate_cast<float>(integer_hull[i].y);
565
        hull[i] = Point2f(x, y);
N
Nesterov Alexander 已提交
566 567
    }

A
Alexander Nesterov 已提交
568
    const double experimental_area = fabs(contourArea(hull));
569

570 571
    vector<Point2f> result_hull_point(angle_size);
    double min_norm;
N
Nesterov Alexander 已提交
572 573 574 575
    for (size_t i = 0; i < angle_size; i++)
    {
        min_norm = std::numeric_limits<double>::max();
        Point closest_pnt;
576
        for (int j = 0; j < hull_size; j++)
N
Nesterov Alexander 已提交
577
        {
578 579
            double temp_norm = norm(hull[j] - angle_list[i]);
            if (min_norm > temp_norm)
N
Nesterov Alexander 已提交
580
            {
581 582
                min_norm = temp_norm;
                closest_pnt = hull[j];
N
Nesterov Alexander 已提交
583 584 585 586 587
            }
        }
        result_hull_point[i] = closest_pnt;
    }

588
    int start_line[2] = { 0, 0 }, finish_line[2] = { 0, 0 }, unstable_pnt = 0;
N
Nesterov Alexander 已提交
589 590
    for (int i = 0; i < hull_size; i++)
    {
591 592 593 594
        if (result_hull_point[2] == hull[i]) { start_line[0] = i; }
        if (result_hull_point[1] == hull[i]) { finish_line[0] = start_line[1] = i; }
        if (result_hull_point[0] == hull[i]) { finish_line[1] = i; }
        if (result_hull_point[3] == hull[i]) { unstable_pnt = i; }
N
Nesterov Alexander 已提交
595 596
    }

597
    int index_hull, extra_index_hull, next_index_hull, extra_next_index_hull;
N
Nesterov Alexander 已提交
598 599
    Point result_side_begin[4], result_side_end[4];

600 601
    bool bypass_orientation = testBypassRoute(hull, start_line[0], finish_line[0]);

N
Nesterov Alexander 已提交
602 603 604 605
    min_norm = std::numeric_limits<double>::max();
    index_hull = start_line[0];
    do
    {
606
        if (bypass_orientation) { next_index_hull = index_hull + 1; }
N
Nesterov Alexander 已提交
607 608 609 610 611
        else { next_index_hull = index_hull - 1; }

        if (next_index_hull == hull_size) { next_index_hull = 0; }
        if (next_index_hull == -1) { next_index_hull = hull_size - 1; }

612 613
        Point angle_closest_pnt =  norm(hull[index_hull] - angle_list[1]) >
        norm(hull[index_hull] - angle_list[2]) ? angle_list[2] : angle_list[1];
N
Nesterov Alexander 已提交
614 615

        Point intrsc_line_hull =
616 617 618
        intersectionLines(hull[index_hull], hull[next_index_hull],
                          angle_list[1], angle_list[2]);
        double temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
N
Nesterov Alexander 已提交
619
        if (min_norm > temp_norm &&
620
            norm(hull[index_hull] - hull[next_index_hull]) >
A
Alexander Nesterov 已提交
621
            norm(angle_list[1] - angle_list[2]) * 0.1)
N
Nesterov Alexander 已提交
622 623
        {
            min_norm = temp_norm;
624 625
            result_side_begin[0] = hull[index_hull];
            result_side_end[0]   = hull[next_index_hull];
N
Nesterov Alexander 已提交
626 627 628 629 630 631 632 633 634
        }


        index_hull = next_index_hull;
    }
    while(index_hull != finish_line[0]);

    if (min_norm == std::numeric_limits<double>::max())
    {
635 636
        result_side_begin[0] = angle_list[1];
        result_side_end[0]   = angle_list[2];
N
Nesterov Alexander 已提交
637 638 639 640
    }

    min_norm = std::numeric_limits<double>::max();
    index_hull = start_line[1];
641
    bypass_orientation = testBypassRoute(hull, start_line[1], finish_line[1]);
N
Nesterov Alexander 已提交
642 643
    do
    {
644
        if (bypass_orientation) { next_index_hull = index_hull + 1; }
N
Nesterov Alexander 已提交
645 646 647 648 649
        else { next_index_hull = index_hull - 1; }

        if (next_index_hull == hull_size) { next_index_hull = 0; }
        if (next_index_hull == -1) { next_index_hull = hull_size - 1; }

650 651
        Point angle_closest_pnt =  norm(hull[index_hull] - angle_list[0]) >
        norm(hull[index_hull] - angle_list[1]) ? angle_list[1] : angle_list[0];
N
Nesterov Alexander 已提交
652 653

        Point intrsc_line_hull =
654 655 656
        intersectionLines(hull[index_hull], hull[next_index_hull],
                          angle_list[0], angle_list[1]);
        double temp_norm = getCosVectors(hull[index_hull], intrsc_line_hull, angle_closest_pnt);
N
Nesterov Alexander 已提交
657
        if (min_norm > temp_norm &&
658
            norm(hull[index_hull] - hull[next_index_hull]) >
A
Alexander Nesterov 已提交
659
            norm(angle_list[0] - angle_list[1]) * 0.05)
N
Nesterov Alexander 已提交
660 661
        {
            min_norm = temp_norm;
662 663
            result_side_begin[1] = hull[index_hull];
            result_side_end[1]   = hull[next_index_hull];
N
Nesterov Alexander 已提交
664 665 666 667 668 669 670 671
        }

        index_hull = next_index_hull;
    }
    while(index_hull != finish_line[1]);

    if (min_norm == std::numeric_limits<double>::max())
    {
672 673
        result_side_begin[1] = angle_list[0];
        result_side_end[1]   = angle_list[1];
N
Nesterov Alexander 已提交
674 675
    }

676
    bypass_orientation = testBypassRoute(hull, start_line[0], unstable_pnt);
677
    const bool extra_bypass_orientation = testBypassRoute(hull, finish_line[1], unstable_pnt);
N
Nesterov Alexander 已提交
678

679
    vector<Point2f> result_angle_list(4), test_result_angle_list(4);
680
    double min_diff_area = std::numeric_limits<double>::max();
N
Nesterov Alexander 已提交
681
    index_hull = start_line[0];
682
    const double standart_norm = std::max(
683 684
        norm(result_side_begin[0] - result_side_end[0]),
        norm(result_side_begin[1] - result_side_end[1]));
N
Nesterov Alexander 已提交
685 686
    do
    {
687
        if (bypass_orientation) { next_index_hull = index_hull + 1; }
N
Nesterov Alexander 已提交
688 689 690 691 692
        else { next_index_hull = index_hull - 1; }

        if (next_index_hull == hull_size) { next_index_hull = 0; }
        if (next_index_hull == -1) { next_index_hull = hull_size - 1; }

A
Alexander Nesterov 已提交
693
        if (norm(hull[index_hull] - hull[next_index_hull]) < standart_norm * 0.1)
694 695
        { index_hull = next_index_hull; continue; }

N
Nesterov Alexander 已提交
696 697 698
        extra_index_hull = finish_line[1];
        do
        {
699
            if (extra_bypass_orientation) { extra_next_index_hull = extra_index_hull + 1; }
N
Nesterov Alexander 已提交
700 701 702 703 704
            else { extra_next_index_hull = extra_index_hull - 1; }

            if (extra_next_index_hull == hull_size) { extra_next_index_hull = 0; }
            if (extra_next_index_hull == -1) { extra_next_index_hull = hull_size - 1; }

A
Alexander Nesterov 已提交
705
            if (norm(hull[extra_index_hull] - hull[extra_next_index_hull]) < standart_norm * 0.1)
706 707
            { extra_index_hull = extra_next_index_hull; continue; }

N
Nesterov Alexander 已提交
708
            test_result_angle_list[0]
709 710
            = intersectionLines(result_side_begin[0], result_side_end[0],
                                result_side_begin[1], result_side_end[1]);
N
Nesterov Alexander 已提交
711
            test_result_angle_list[1]
712 713
            = intersectionLines(result_side_begin[1], result_side_end[1],
                                hull[extra_index_hull], hull[extra_next_index_hull]);
N
Nesterov Alexander 已提交
714
            test_result_angle_list[2]
715 716
            = intersectionLines(hull[extra_index_hull], hull[extra_next_index_hull],
                                hull[index_hull], hull[next_index_hull]);
N
Nesterov Alexander 已提交
717
            test_result_angle_list[3]
718 719 720
            = intersectionLines(hull[index_hull], hull[next_index_hull],
                                result_side_begin[0], result_side_end[0]);

721 722
            const double test_diff_area
                = fabs(fabs(contourArea(test_result_angle_list)) - experimental_area);
723
            if (min_diff_area > test_diff_area)
N
Nesterov Alexander 已提交
724
            {
725
                min_diff_area = test_diff_area;
N
Nesterov Alexander 已提交
726 727 728 729 730 731 732 733 734 735 736 737 738
                for (size_t i = 0; i < test_result_angle_list.size(); i++)
                {
                    result_angle_list[i] = test_result_angle_list[i];
                }
            }

            extra_index_hull = extra_next_index_hull;
        }
        while(extra_index_hull != unstable_pnt);

        index_hull = next_index_hull;
    }
    while(index_hull != unstable_pnt);
A
Alexander Nesterov 已提交
739

740
    // check label points
A
Alexander Nesterov 已提交
741 742 743 744
    if (norm(result_angle_list[0] - angle_list[1]) > 2) { result_angle_list[0] = angle_list[1]; }
    if (norm(result_angle_list[1] - angle_list[0]) > 2) { result_angle_list[1] = angle_list[0]; }
    if (norm(result_angle_list[3] - angle_list[2]) > 2) { result_angle_list[3] = angle_list[2]; }

745 746 747 748 749 750
    // check calculation point
    if (norm(result_angle_list[2] - angle_list[3]) >
       (norm(result_angle_list[0] - result_angle_list[1]) +
        norm(result_angle_list[0] - result_angle_list[3])) * 0.5 )
    { result_angle_list[2] = angle_list[3]; }

N
Nesterov Alexander 已提交
751 752 753 754 755 756 757 758
    return result_angle_list;
}

//      / | b
//     /  |
//    /   |
//  a/    | c

759
inline double QRDetect::getCosVectors(Point2f a, Point2f b, Point2f c)
N
Nesterov Alexander 已提交
760
{
A
Alexander Nesterov 已提交
761
    return ((a - b).x * (c - b).x + (a - b).y * (c - b).y) / (norm(a - b) * norm(c - b));
N
Nesterov Alexander 已提交
762 763
}

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
struct QRCodeDetector::Impl
{
public:
    Impl() { epsX = 0.2; epsY = 0.1; }
    ~Impl() {}

    double epsX, epsY;
};

QRCodeDetector::QRCodeDetector() : p(new Impl) {}
QRCodeDetector::~QRCodeDetector() {}

void QRCodeDetector::setEpsX(double epsX) { p->epsX = epsX; }
void QRCodeDetector::setEpsY(double epsY) { p->epsY = epsY; }

bool QRCodeDetector::detect(InputArray in, OutputArray points) const
{
    Mat inarr = in.getMat();
    CV_Assert(!inarr.empty());
    CV_Assert(inarr.type() == CV_8UC1);
784 785 786 787 788
    QRDetect qrdet;
    qrdet.init(inarr, p->epsX, p->epsY);
    if (!qrdet.localization()) { return false; }
    if (!qrdet.computeTransformationPoints()) { return false; }
    vector<Point2f> pnts2f = qrdet.getTransformationPoints();
789
    Mat(pnts2f).convertTo(points, points.fixedType() ? points.type() : CV_32FC2);
N
Nesterov Alexander 已提交
790 791 792
    return true;
}

A
Alexander Nesterov 已提交
793
CV_EXPORTS bool detectQRCode(InputArray in, vector<Point> &points, double eps_x, double eps_y)
794 795 796 797 798 799 800 801
{
    QRCodeDetector qrdetector;
    qrdetector.setEpsX(eps_x);
    qrdetector.setEpsY(eps_y);

    return qrdetector.detect(in, points);
}

A
Alexander Nesterov 已提交
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
class QRDecode
{
public:
    void init(const Mat &src, const vector<Point2f> &points);
    Mat getIntermediateBarcode() { return intermediate; }
    Mat getStraightBarcode() { return straight; }
    size_t getVersion() { return version; }
    std::string getDecodeInformation() { return result_info; }
    bool fullDecodingProcess();
protected:
    bool updatePerspective();
    bool versionDefinition();
    bool samplingForVersion();
    bool decodingProcess();
    Mat original, no_border_intermediate, intermediate, straight;
    vector<Point2f> original_points;
    std::string result_info;
    uint8_t version, version_size;
    float test_perspective_size;
};

void QRDecode::init(const Mat &src, const vector<Point2f> &points)
{
    original = src.clone();
    intermediate = Mat::zeros(src.size(), CV_8UC1);
    original_points = points;
    version = 0;
    version_size = 0;
    test_perspective_size = 251;
    result_info = "";
}

bool QRDecode::updatePerspective()
{
    const Size temporary_size(cvRound(test_perspective_size), cvRound(test_perspective_size));

    vector<Point2f> perspective_points;
    perspective_points.push_back(Point2f(0.f, 0.f));
    perspective_points.push_back(Point2f(test_perspective_size, 0.f));

    perspective_points.push_back(Point2f(static_cast<float>(test_perspective_size * 0.5),
                                         static_cast<float>(test_perspective_size * 0.5)));
    original_points.insert(original_points.begin() + 2,
                           QRDetect::intersectionLines(
                                original_points[0], original_points[2],
                                original_points[1], original_points[3]));

    perspective_points.push_back(Point2f(test_perspective_size, test_perspective_size));
    perspective_points.push_back(Point2f(0.f, test_perspective_size));

    Mat H = findHomography(original_points, perspective_points);
    Mat bin_original = Mat::zeros(original.size(), CV_8UC1);
    adaptiveThreshold(original, bin_original, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 83, 2);
    Mat temp_intermediate = Mat::zeros(temporary_size, CV_8UC1);
    warpPerspective(bin_original, temp_intermediate, H, temporary_size, INTER_NEAREST);
    no_border_intermediate = temp_intermediate(Range(1, temp_intermediate.rows), Range(1, temp_intermediate.cols));

    const int border = cvRound(0.1 * test_perspective_size);
    const int borderType = BORDER_CONSTANT;
    copyMakeBorder(no_border_intermediate, intermediate, border, border, border, border, borderType, Scalar(255));
    return true;
}

bool QRDecode::versionDefinition()
{
    LineIterator line_iter(intermediate, Point2f(0, 0), Point2f(test_perspective_size, test_perspective_size));
    Point black_point = Point(0, 0);
    for(int j = 0; j < line_iter.count; j++, ++line_iter)
    {
        const uint8_t value = intermediate.at<uint8_t>(line_iter.pos());
        if (value == 0) { black_point = line_iter.pos(); break; }
    }

    Mat mask = Mat::zeros(intermediate.rows + 2, intermediate.cols + 2, CV_8UC1);
    floodFill(intermediate, mask, black_point, 255, 0, Scalar(), Scalar(), FLOODFILL_MASK_ONLY);

    vector<Point> locations, non_zero_elem;
    Mat mask_roi = mask(Range(1, intermediate.rows - 1), Range(1, intermediate.cols - 1));
    findNonZero(mask_roi, non_zero_elem);
    convexHull(Mat(non_zero_elem), locations);

    Point temp_remote = locations[0], remote_point;
    const Point delta_diff = Point(4, 4);
    for (size_t i = 0; i < locations.size(); i++)
    {
        if (norm(black_point - temp_remote) <  norm(black_point - locations[i]))
        {
            const uint8_t value = intermediate.at<uint8_t>(temp_remote - delta_diff);
            if (value == 0) { remote_point = temp_remote - delta_diff; }
            else { remote_point = temp_remote; }
            temp_remote = locations[i];
        }
    }

    size_t transition_x = 0 , transition_y = 0;

    uint8_t future_pixel = 255;
    const uint8_t *intermediate_row = intermediate.ptr<uint8_t>(remote_point.y);
    for(int i = remote_point.x; i < intermediate.cols; i++)
    {
        if (intermediate_row[i] == future_pixel)
        {
            future_pixel = 255 - future_pixel;
            transition_x++;
        }
    }

    future_pixel = 255;
    for(int j = remote_point.y; j < intermediate.rows; j++)
    {
        const uint8_t value = intermediate.at<uint8_t>(Point(j, remote_point.x));
        if (value == future_pixel)
        {
            future_pixel = 255 - future_pixel;
            transition_y++;
        }
    }

    version = saturate_cast<uint8_t>((std::min(transition_x, transition_y) - 1) * 0.25 - 1);
    if ( !(  0 < version && version <= 40 ) ) { return false; }
    version_size = 21 + (version - 1) * 4;
    return true;
}

bool QRDecode::samplingForVersion()
{
    const double multiplyingFactor = (version < 3)  ? 1 :
                                     (version == 3) ? 1.5 :
                                     version * (5 + version - 4);
    const Size newFactorSize(
                  cvRound(no_border_intermediate.size().width  * multiplyingFactor),
                  cvRound(no_border_intermediate.size().height * multiplyingFactor));
    Mat postIntermediate(newFactorSize, CV_8UC1);
    resize(no_border_intermediate, postIntermediate, newFactorSize, 0, 0, INTER_AREA);

    const int no_inter_rows = postIntermediate.rows;
    const int no_inter_cols = postIntermediate.cols;
    const int delta_rows = cvRound((no_inter_rows * 1.0) / version_size);
    const int delta_cols = cvRound((no_inter_cols * 1.0) / version_size);

    vector<double> listFrequencyElem;
    for (int r = 0; r < no_inter_rows; r += delta_rows)
    {
        for (int c = 0; c < no_inter_cols; c += delta_cols)
        {
            Mat tile = postIntermediate(
                           Range(r, min(r + delta_rows, no_inter_rows)),
                           Range(c, min(c + delta_cols, no_inter_cols)));
            const double frequencyElem = (countNonZero(tile) * 1.0) / tile.total();
            listFrequencyElem.push_back(frequencyElem);
        }
    }

    double dispersionEFE = std::numeric_limits<double>::max();
    double experimentalFrequencyElem = 0;
    for (double expVal = 0; expVal < 1; expVal+=0.001)
    {
        double testDispersionEFE = 0.0;
        for (size_t i = 0; i < listFrequencyElem.size(); i++)
        {
            testDispersionEFE += (listFrequencyElem[i] - expVal) *
                                 (listFrequencyElem[i] - expVal);
        }
        testDispersionEFE /= (listFrequencyElem.size() - 1);
        if (dispersionEFE > testDispersionEFE)
        {
            dispersionEFE = testDispersionEFE;
            experimentalFrequencyElem = expVal;
        }
    }

    straight = Mat(Size(version_size, version_size), CV_8UC1, Scalar(0));
    size_t k = 0;
    for (int r = 0; r < no_inter_rows &&
                    k < listFrequencyElem.size() &&
                    floor((r * 1.0) / delta_rows) < version_size; r += delta_rows)
    {
        for (int c = 0; c < no_inter_cols &&
                        k < listFrequencyElem.size() &&
                        floor((c * 1.0) / delta_cols) < version_size; c += delta_cols, k++)
        {
            Mat tile = postIntermediate(
                           Range(r, min(r + delta_rows, no_inter_rows)),
                           Range(c, min(c + delta_cols, no_inter_cols)));

            if (listFrequencyElem[k] < experimentalFrequencyElem) { tile.setTo(0); }
            else
            {
                tile.setTo(255);
                straight.at<uint8_t>(cvRound(floor((r * 1.0) / delta_rows)),
                                     cvRound(floor((c * 1.0) / delta_cols))) = 255;
            }
        }
    }
    return true;
}

bool QRDecode::decodingProcess()
{
#ifdef HAVE_QUIRC
    if (straight.empty()) { return false; }

    quirc_code qr_code;
    memset(&qr_code, 0, sizeof(qr_code));

    qr_code.size = straight.size().width;
    for (int x = 0; x < qr_code.size; x++)
    {
        for (int y = 0; y < qr_code.size; y++)
        {
            int position = y * qr_code.size + x;
            qr_code.cell_bitmap[position >> 3]
                |= straight.at<uint8_t>(y, x) ? 0 : (1 << (position & 7));
        }
    }

    quirc_data qr_code_data;
    quirc_decode_error_t errorCode = quirc_decode(&qr_code, &qr_code_data);
    if (errorCode != 0) { return false; }

    for (int i = 0; i < qr_code_data.payload_len; i++)
    {
        result_info += qr_code_data.payload[i];
    }
    return true;
#else
    return false;
#endif

}

bool QRDecode::fullDecodingProcess()
{
#ifdef HAVE_QUIRC
    if (!updatePerspective())  { return false; }
    if (!versionDefinition())  { return false; }
    if (!samplingForVersion()) { return false; }
    if (!decodingProcess())    { return false; }
    return true;
#else
    std::cout << "Library QUIRC is not linked. No decoding is performed. Take it to the OpenCV repository." << std::endl;
    return false;
#endif
}

CV_EXPORTS bool decodeQRCode(InputArray in, InputArray points, std::string &decoded_info, OutputArray straight_qrcode)
{
    Mat inarr = in.getMat();
    CV_Assert(!inarr.empty());
    inarr.convertTo(inarr, CV_8UC1);

    CV_Assert(points.isVector());
    vector<Point2f> src_points;
    points.copyTo(src_points);
    CV_Assert(src_points.size() == 4);

    QRDecode qrdec;
    qrdec.init(inarr, src_points);
    bool exit_flag = qrdec.fullDecodingProcess();

    decoded_info = qrdec.getDecodeInformation();

    if (straight_qrcode.needed())
    {
        qrdec.getStraightBarcode().convertTo(straight_qrcode,
                                             straight_qrcode.fixedType() ?
                                             straight_qrcode.type() : CV_32FC2);
    }

    return exit_flag;
}

N
Nesterov Alexander 已提交
1074
}