Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

PDF417Detector.cpp Example File

appdemos/qtws/QZXing/zxing/zxing/pdf417/detector/PDF417Detector.cpp
 // -*- mode:c++; tab-width:2; indent-tabs-mode:nil; c-basic-offset:2 -*-
 /*
  * Copyright 2010 ZXing authors All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 #include <algorithm>
 #include <limits>
 #include <zxing/pdf417/detector/Detector.h>
 #include <zxing/pdf417/detector/LinesSampler.h>
 #include <zxing/common/GridSampler.h>
 #include <zxing/common/detector/JavaMath.h>
 #include <zxing/common/detector/MathUtils.h>

 using std::max;
 using std::abs;
 using std::numeric_limits;
 using zxing::pdf417::detector::Detector;
 using zxing::common::detector::Math;
 using zxing::common::detector::MathUtils;
 using zxing::Ref;
 using zxing::ArrayRef;
 using zxing::DetectorResult;
 using zxing::ResultPoint;
 using zxing::Point;
 using zxing::BitMatrix;
 using zxing::GridSampler;

 // VC++

 using zxing::BinaryBitmap;
 using zxing::DecodeHints;
 using zxing::Line;

 /**
  * <p>Encapsulates logic that can detect a PDF417 Code in an image, even if the
  * PDF417 Code is rotated or skewed, or partially obscured.</p>
  *
  * @author SITA Lab (kevin.osullivan@sita.aero)
  * @author Daniel Switkin (dswitkin@google.com)
  * @author Schweers Informationstechnologie GmbH (hartmut.neubauer@schweers.de)
  * @author creatale GmbH (christoph.schulz@creatale.de)
  */

 const int Detector::MAX_AVG_VARIANCE= (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42f);
 const int Detector::MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.8f);

 // B S B S B S B S Bar/Space pattern
 // 11111111 0 1 0 1 0 1 000
 const int Detector::START_PATTERN[] = {8, 1, 1, 1, 1, 1, 1, 3};
 const int Detector::START_PATTERN_LENGTH = sizeof(START_PATTERN) / sizeof(int);

 // 11111111 0 1 0 1 0 1 000
 const int Detector::START_PATTERN_REVERSE[] = {3, 1, 1, 1, 1, 1, 1, 8};
 const int Detector::START_PATTERN_REVERSE_LENGTH = sizeof(START_PATTERN_REVERSE) / sizeof(int);

 // 1111111 0 1 000 1 0 1 00 1
 const int Detector::STOP_PATTERN[] = {7, 1, 1, 3, 1, 1, 1, 2, 1};
 const int Detector::STOP_PATTERN_LENGTH = sizeof(STOP_PATTERN) / sizeof(int);

 // B S B S B S B S B Bar/Space pattern
 // 1111111 0 1 000 1 0 1 00 1
 const int Detector::STOP_PATTERN_REVERSE[] = {1, 2, 1, 1, 1, 3, 1, 1, 7};
 const int Detector::STOP_PATTERN_REVERSE_LENGTH = sizeof(STOP_PATTERN_REVERSE) / sizeof(int);

 Detector::Detector(Ref<BinaryBitmap> image) : image_(image) {}

 Ref<DetectorResult> Detector::detect() {
   return detect(DecodeHints());
 }

 Ref<DetectorResult> Detector::detect(DecodeHints const& hints) {
   (void)hints;
   // Fetch the 1 bit matrix once up front.
   Ref<BitMatrix> matrix = image_->getBlackMatrix();

   // Try to find the vertices assuming the image is upright.
   const int rowStep = 8;
   ArrayRef< Ref<ResultPoint> > vertices (findVertices(matrix, rowStep));
   if (!vertices) {
     // Maybe the image is rotated 180 degrees?
     vertices = findVertices180(matrix, rowStep);
     if (vertices) {
       correctVertices(matrix, vertices, true);
     }
   } else {
     correctVertices(matrix, vertices, false);
   }

   if (!vertices) {
     throw NotFoundException("No vertices found.");
   }

   float moduleWidth = computeModuleWidth(vertices);
   if (moduleWidth < 1.0f) {
     throw NotFoundException("Bad module width.");
   }

   int dimension = computeDimension(vertices[12], vertices[14],
                                    vertices[13], vertices[15], moduleWidth);
   if (dimension < 1) {
     throw NotFoundException("Bad dimension.");
   }

   int yDimension = max(computeYDimension(vertices[12], vertices[14],
                                          vertices[13], vertices[15], moduleWidth), dimension);

   // Deskew and sample lines from image.
   Ref<BitMatrix> linesMatrix = sampleLines(vertices, dimension, yDimension);
   Ref<BitMatrix> linesGrid(LinesSampler(linesMatrix, dimension).sample());

   ArrayRef< Ref<ResultPoint> > points(4);
   points[0] = vertices[5];
   points[1] = vertices[4];
   points[2] = vertices[6];
   points[3] = vertices[7];
   return Ref<DetectorResult>(new DetectorResult(linesGrid, points));
 }

 /**
  * Locate the vertices and the codewords area of a black blob using the Start
  * and Stop patterns as locators.
  *
  * @param matrix the scanned barcode image.
  * @param rowStep the step size for iterating rows (every n-th row).
  * @return an array containing the vertices:
  *           vertices[0] x, y top left barcode
  *           vertices[1] x, y bottom left barcode
  *           vertices[2] x, y top right barcode
  *           vertices[3] x, y bottom right barcode
  *           vertices[4] x, y top left codeword area
  *           vertices[5] x, y bottom left codeword area
  *           vertices[6] x, y top right codeword area
  *           vertices[7] x, y bottom right codeword area
  */
 ArrayRef< Ref<ResultPoint> > Detector::findVertices(Ref<BitMatrix> matrix, int rowStep)
 {
   const int height = matrix->getHeight();
   const int width = matrix->getWidth();

   ArrayRef< Ref<ResultPoint> > result(16);
   bool found = false;

   ArrayRef<int> counters(new Array<int>(START_PATTERN_LENGTH));

   // Top Left
   for (int i = 0; i < height; i += rowStep) {
     ArrayRef<int> loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN,
                                          START_PATTERN_LENGTH, counters);
     if (loc) {
       result[0] = new ResultPoint((float)loc[0], (float)i);
       result[4] = new ResultPoint((float)loc[1], (float)i);
       found = true;
       break;
     }
   }
   // Bottom left
   if (found) { // Found the Top Left vertex
     found = false;
     for (int i = height - 1; i > 0; i -= rowStep) {
       ArrayRef<int> loc = findGuardPattern(matrix, 0, i, width, false, START_PATTERN,
                                            START_PATTERN_LENGTH, counters);
       if (loc) {
         result[1] = new ResultPoint((float)loc[0], (float)i);
         result[5] = new ResultPoint((float)loc[1], (float)i);
         found = true;
         break;
       }
     }
   }

   counters = new Array<int>(STOP_PATTERN_LENGTH);

   // Top right
   if (found) { // Found the Bottom Left vertex
     found = false;
     for (int i = 0; i < height; i += rowStep) {
       ArrayRef<int> loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN,
                                            STOP_PATTERN_LENGTH, counters);
       if (loc) {
         result[2] = new ResultPoint((float)loc[1], (float)i);
         result[6] = new ResultPoint((float)loc[0], (float)i);
         found = true;
         break;
       }
     }
   }
   // Bottom right
   if (found) { // Found the Top right vertex
     found = false;
     for (int i = height - 1; i > 0; i -= rowStep) {
       ArrayRef<int> loc = findGuardPattern(matrix, 0, i, width, false, STOP_PATTERN,
                                            STOP_PATTERN_LENGTH, counters);
       if (loc) {
         result[3] = new ResultPoint((float)loc[1], (float)i);
         result[7] = new ResultPoint((float)loc[0], (float)i);
         found = true;
         break;
       }
     }
   }

   return found ? result : ArrayRef< Ref<ResultPoint> >();
 }

 ArrayRef< Ref<ResultPoint> > Detector::findVertices180(Ref<BitMatrix> matrix, int rowStep) {
   const int height = matrix->getHeight();
   const int width = matrix->getWidth();
   const int halfWidth = width >> 1;

   ArrayRef< Ref<ResultPoint> > result(16);
   bool found = false;

   ArrayRef<int> counters = new Array<int>(START_PATTERN_REVERSE_LENGTH);

   // Top Left
   for (int i = height - 1; i > 0; i -= rowStep) {
     ArrayRef<int> loc =
         findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE,
                          START_PATTERN_REVERSE_LENGTH, counters);
     if (loc) {
       result[0] = new ResultPoint((float)loc[1], (float)i);
       result[4] = new ResultPoint((float)loc[0], (float)i);
       found = true;
       break;
     }
   }
   // Bottom Left
   if (found) { // Found the Top Left vertex
     found = false;
     for (int i = 0; i < height; i += rowStep) {
       ArrayRef<int> loc =
           findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE,
                            START_PATTERN_REVERSE_LENGTH, counters);
       if (loc) {
         result[1] = new ResultPoint((float)loc[1], (float)i);
         result[5] = new ResultPoint((float)loc[0], (float)i);
         found = true;
         break;
       }
     }
   }

   counters = new Array<int>(STOP_PATTERN_REVERSE_LENGTH);

   // Top Right
   if (found) { // Found the Bottom Left vertex
     found = false;
     for (int i = height - 1; i > 0; i -= rowStep) {
       ArrayRef<int> loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE,
                                            STOP_PATTERN_REVERSE_LENGTH, counters);
       if (loc) {
         result[2] = new ResultPoint((float)loc[0], (float)i);
         result[6] = new ResultPoint((float)loc[1], (float)i);
         found = true;
         break;
       }
     }
   }
   // Bottom Right
   if (found) { // Found the Top Right vertex
     found = false;
     for (int i = 0; i < height; i += rowStep) {
       ArrayRef<int> loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE,
                                            STOP_PATTERN_REVERSE_LENGTH, counters);
       if (loc) {
         result[3] = new ResultPoint((float)loc[0], (float)i);
         result[7] = new ResultPoint((float)loc[1], (float)i);
         found = true;
         break;
       }
     }
   }

   return found ? result : ArrayRef< Ref<ResultPoint> >();
 }

 /**
  * @param matrix row of black/white values to search
  * @param column x position to start search
  * @param row y position to start search
  * @param width the number of pixels to search on this row
  * @param pattern pattern of counts of number of black and white pixels that are
  *                 being searched for as a pattern
  * @param counters array of counters, as long as pattern, to re-use
  * @return start/end horizontal offset of guard pattern, as an array of two ints.
  */
 ArrayRef<int> Detector::findGuardPattern(Ref<BitMatrix> matrix,
                                          int column,
                                          int row,
                                          int width,
                                          bool whiteFirst,
                                          const int pattern[],
                                          int patternSize,
                                          ArrayRef<int>& counters) {
   counters->values().assign(counters->size(), 0);
   int patternLength = patternSize;
   bool isWhite = whiteFirst;

   int counterPosition = 0;
   int patternStart = column;
   for (int x = column; x < column + width; x++) {
     bool pixel = matrix->get(x, row);
     if (pixel ^ isWhite) {
       counters[counterPosition]++;
     } else {
       if (counterPosition == patternLength - 1) {
         if (patternMatchVariance(counters, pattern,
                                  MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
           ArrayRef<int> result = new Array<int>(2);
           result[0] = patternStart;
           result[1] = x;
           return result;
         }
         patternStart += counters[0] + counters[1];
         for(int i = 0; i < patternLength - 2; ++i)
           counters[i] = counters[ i + 2];
         counters[patternLength - 2] = 0;
         counters[patternLength - 1] = 0;
         counterPosition--;
       } else {
         counterPosition++;
       }
       counters[counterPosition] = 1;
       isWhite = !isWhite;
     }
   }
   return ArrayRef<int>();
 }

 /**
  * Determines how closely a set of observed counts of runs of black/white
  * values matches a given target pattern. This is reported as the ratio of
  * the total variance from the expected pattern proportions across all
  * pattern elements, to the length of the pattern.
  *
  * @param counters observed counters
  * @param pattern expected pattern
  * @param maxIndividualVariance The most any counter can differ before we give up
  * @return ratio of total variance between counters and pattern compared to
  *         total pattern size, where the ratio has been multiplied by 256.
  *         So, 0 means no variance (perfect match); 256 means the total
  *         variance between counters and patterns equals the pattern length,
  *         higher values mean even more variance
  */
 int Detector::patternMatchVariance(ArrayRef<int>& counters,
                                    const int pattern[],
                                    int maxIndividualVariance)
 {
   int numCounters = counters->size();
   int total = 0;
   int patternLength = 0;
   for (int i = 0; i < numCounters; i++) {
     total += counters[i];
     patternLength += pattern[i];
   }
   if (total < patternLength) {
     // If we don't even have one pixel per unit of bar width, assume this
     // is too small to reliably match, so fail:
     return numeric_limits<int>::max();
   }
   // We're going to fake floating-point math in integers. We just need to use more bits.
   // Scale up patternLength so that intermediate values below like scaledCounter will have
   // more "significant digits".
   int unitBarWidth = (total << 8) / patternLength;
   maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> 8;

   int totalVariance = 0;
   for (int x = 0; x < numCounters; x++) {
     int counter = counters[x] << 8;
     int scaledPattern = pattern[x] * unitBarWidth;
     int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
     if (variance > maxIndividualVariance) {
       return numeric_limits<int>::max();
     }
     totalVariance += variance;
   }
   return totalVariance / total;
 }

 /**
  * <p>Correct the vertices by searching for top and bottom vertices of wide
  * bars, then locate the intersections between the upper and lower horizontal
  * line and the inner vertices vertical lines.</p>
  *
  * @param matrix the scanned barcode image.
  * @param vertices the vertices vector is extended and the new members are:
  *           vertices[ 8] x,y point on upper border of left wide bar
  *           vertices[ 9] x,y point on lower border of left wide bar
  *           vertices[10] x,y point on upper border of right wide bar
  *           vertices[11] x,y point on lower border of right wide bar
  *           vertices[12] x,y final top left codeword area
  *           vertices[13] x,y final bottom left codeword area
  *           vertices[14] x,y final top right codeword area
  *           vertices[15] x,y final bottom right codeword area
  * @param upsideDown true if rotated by 180 degree.
  */
 void Detector::correctVertices(Ref<BitMatrix> matrix,
                                ArrayRef< Ref<ResultPoint> >& vertices,
                                bool upsideDown)
 {
   bool isLowLeft = abs(vertices[4]->getY() - vertices[5]->getY()) < 20.0;
   bool isLowRight = abs(vertices[6]->getY() - vertices[7]->getY()) < 20.0;
   if (isLowLeft || isLowRight) {
     throw NotFoundException("Cannot find enough PDF417 guard patterns!");
   } else {
     findWideBarTopBottom(matrix, vertices, 0, 0,  8, 17, upsideDown ? 1 : -1);
     findWideBarTopBottom(matrix, vertices, 1, 0,  8, 17, upsideDown ? -1 : 1);
     findWideBarTopBottom(matrix, vertices, 2, 11, 7, 18, upsideDown ? 1 : -1);
     findWideBarTopBottom(matrix, vertices, 3, 11, 7, 18, upsideDown ? -1 : 1);
     findCrossingPoint(vertices, 12, 4, 5, 8, 10, matrix);
     findCrossingPoint(vertices, 13, 4, 5, 9, 11, matrix);
     findCrossingPoint(vertices, 14, 6, 7, 8, 10, matrix);
     findCrossingPoint(vertices, 15, 6, 7, 9, 11, matrix);
   }
 }

 /**
  * <p>Locate the top or bottom of one of the two wide black bars of a guard pattern.</p>
  *
  * <p>Warning: it only searches along the y axis, so the return points would not be
  * right if the barcode is too curved.</p>
  *
  * @param matrix The bit matrix.
  * @param vertices The 16 vertices located by findVertices(); the result
  *           points are stored into vertices[8], ... , vertices[11].
  * @param offsetVertice The offset of the outer vertice and the inner
  *           vertice (+ 4) to be corrected and (+ 8) where the result is stored.
  * @param startWideBar start of a wide bar.
  * @param lenWideBar length of wide bar.
  * @param lenPattern length of the pattern.
  * @param rowStep +1 if corner should be exceeded towards the bottom, -1 towards the top.
  */
 void Detector::findWideBarTopBottom(Ref<BitMatrix> matrix,
                                     ArrayRef< Ref<ResultPoint> > &vertices,
                                     int offsetVertice,
                                     int startWideBar,
                                     int lenWideBar,
                                     int lenPattern,
                                     int rowStep)
 {
   Ref<ResultPoint> verticeStart(vertices[offsetVertice]);
   Ref<ResultPoint> verticeEnd(vertices[offsetVertice + 4]);

   // Start horizontally at the middle of the bar.
   int endWideBar = startWideBar + lenWideBar;
   float barDiff = verticeEnd->getX() - verticeStart->getX();
   float barStart = verticeStart->getX() + barDiff * (float)startWideBar / (float)lenPattern;
   float barEnd = verticeStart->getX() + barDiff * (float)endWideBar / (float)lenPattern;
   int x = Math::round((barStart + barEnd) / 2.0f);

   // Start vertically between the preliminary vertices.
   int yStart = Math::round(verticeStart->getY());
   int y = yStart;

   // Find offset of thin bar to the right as additional safeguard.
   int nextBarX = int(max(barStart, barEnd) + 1);
   for (; nextBarX < matrix->getWidth(); nextBarX++)
     if (!matrix->get(nextBarX - 1, y) && matrix->get(nextBarX, y)) break;
   nextBarX -= x;

   bool isEnd = false;
   while (!isEnd) {
     if (matrix->get(x, y)) {
       // If the thin bar to the right ended, stop as well
       isEnd = !matrix->get(x + nextBarX, y) && !matrix->get(x + nextBarX + 1, y);
       y += rowStep;
       if (y <= 0 || y >= (int)matrix->getHeight() - 1) {
         // End of barcode image reached.
         isEnd = true;
       }
     } else {
       // Look sidewise whether black bar continues? (in the case the image is skewed)
       if (x > 0 && matrix->get(x - 1, y)) {
         x--;
       } else if (x < (int)matrix->getWidth() - 1 && matrix->get(x + 1, y)) {
         x++;
       } else {
         // End of pattern regarding big bar and big gap reached.
         isEnd = true;
         if (y != yStart) {
           // Turn back one step, because target has been exceeded.
           y -= rowStep;
         }
       }
     }
   }

   vertices[offsetVertice + 8] = new ResultPoint((float)x, (float)y);
 }

 /**
  * <p>Finds the intersection of two lines.</p>
  *
  * @param vertices The reference of the vertices vector
  * @param idxResult Index of result point inside the vertices vector.
  * @param idxLineA1
  * @param idxLineA2 Indices two points inside the vertices vector that define the first line.
  * @param idxLineB1
  * @param idxLineB2 Indices two points inside the vertices vector that define the second line.
  * @param matrix: bit matrix, here only for testing whether the result is inside the matrix.
  * @return Returns true when the result is valid and lies inside the matrix. Otherwise throws an
  * exception.
  **/
 void Detector::findCrossingPoint(ArrayRef< Ref<ResultPoint> >& vertices,
                                  int idxResult,
                                  int idxLineA1, int idxLineA2,
                                  int idxLineB1, int idxLineB2,
                                  Ref<BitMatrix>& matrix)
 {
   Point p1(vertices[idxLineA1]->getX(), vertices[idxLineA1]->getY());
   Point p2(vertices[idxLineA2]->getX(), vertices[idxLineA2]->getY());
   Point p3(vertices[idxLineB1]->getX(), vertices[idxLineB1]->getY());
   Point p4(vertices[idxLineB2]->getX(), vertices[idxLineB2]->getY());

   Point result(intersection(Line(p1, p2), Line(p3, p4)));
   if (result.x == numeric_limits<float>::infinity() ||
       result.y == numeric_limits<float>::infinity()) {
     throw NotFoundException("PDF:Detector: cannot find the crossing of parallel lines!");
   }

   int x = Math::round(result.x);
   int y = Math::round(result.y);
   if (x < 0 || x >= (int)matrix->getWidth() || y < 0 || y >= (int)matrix->getHeight()) {
     throw NotFoundException("PDF:Detector: crossing points out of region!");
   }

   vertices[idxResult] = Ref<ResultPoint>(new ResultPoint(result.x, result.y));
 }

 /**
  * Computes the intersection between two lines.
  */
 Point Detector::intersection(Line a, Line b) {
   float dxa = a.start.x - a.end.x;
   float dxb = b.start.x - b.end.x;
   float dya = a.start.y - a.end.y;
   float dyb = b.start.y - b.end.y;

   float p = a.start.x * a.end.y - a.start.y * a.end.x;
   float q = b.start.x * b.end.y - b.start.y * b.end.x;
   float denom = dxa * dyb - dya * dxb;
   if(abs(denom) < 1e-12)  // Lines don't intersect (replaces "denom == 0")
     return Point(numeric_limits<float>::infinity(),
                  numeric_limits<float>::infinity());

   float x = (p * dxb - dxa * q) / denom;
   float y = (p * dyb - dya * q) / denom;

   return Point(x, y);
 }

 /**
  * <p>Estimates module size (pixels in a module) based on the Start and End
  * finder patterns.</p>
  *
  * @param vertices an array of vertices:
  *           vertices[0] x, y top left barcode
  *           vertices[1] x, y bottom left barcode
  *           vertices[2] x, y top right barcode
  *           vertices[3] x, y bottom right barcode
  *           vertices[4] x, y top left codeword area
  *           vertices[5] x, y bottom left codeword area
  *           vertices[6] x, y top right codeword area
  *           vertices[7] x, y bottom right codeword area
  * @return the module size.
  */
 float Detector::computeModuleWidth(ArrayRef< Ref<ResultPoint> >& vertices) {
   float pixels1 = ResultPoint::distance(vertices[0], vertices[4]);
   float pixels2 = ResultPoint::distance(vertices[1], vertices[5]);
   float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f);
   float pixels3 = ResultPoint::distance(vertices[6], vertices[2]);
   float pixels4 = ResultPoint::distance(vertices[7], vertices[3]);
   float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f);
   return (moduleWidth1 + moduleWidth2) / 2.0f;
 }

 /**
  * Computes the dimension (number of modules in a row) of the PDF417 Code
  * based on vertices of the codeword area and estimated module size.
  *
  * @param topLeft     of codeword area
  * @param topRight    of codeword area
  * @param bottomLeft  of codeword area
  * @param bottomRight of codeword are
  * @param moduleWidth estimated module size
  * @return the number of modules in a row.
  */
 int Detector::computeDimension(Ref<ResultPoint> const& topLeft,
                                Ref<ResultPoint> const& topRight,
                                Ref<ResultPoint> const& bottomLeft,
                                Ref<ResultPoint> const& bottomRight,
                                float moduleWidth)
 {
   int topRowDimension = MathUtils::round(ResultPoint::distance(topLeft, topRight) / moduleWidth);
   int bottomRowDimension =
       MathUtils::round(ResultPoint::distance(bottomLeft, bottomRight) / moduleWidth);
   return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17;
 }

 /**
  * Computes the y dimension (number of modules in a column) of the PDF417 Code
  * based on vertices of the codeword area and estimated module size.
  *
  * @param topLeft     of codeword area
  * @param topRight    of codeword area
  * @param bottomLeft  of codeword area
  * @param bottomRight of codeword are
  * @param moduleWidth estimated module size
  * @return the number of modules in a row.
  */
 int Detector::computeYDimension(Ref<ResultPoint> const& topLeft,
                                 Ref<ResultPoint> const& topRight,
                                 Ref<ResultPoint> const& bottomLeft,
                                 Ref<ResultPoint> const& bottomRight,
                                 float moduleWidth)
 {
   int leftColumnDimension =
       MathUtils::round(ResultPoint::distance(topLeft, bottomLeft) / moduleWidth);
   int rightColumnDimension =
       MathUtils::round(ResultPoint::distance(topRight, bottomRight) / moduleWidth);
   return (leftColumnDimension + rightColumnDimension) >> 1;
 }

 /**
  * Deskew and over-sample image.
  *
  * @param vertices vertices from findVertices()
  * @param dimension x dimension
  * @param yDimension y dimension
  * @return an over-sampled BitMatrix.
  */
 Ref<BitMatrix> Detector::sampleLines(ArrayRef< Ref<ResultPoint> > const& vertices,
                                      int dimensionY,
                                      int dimension) {
   const int sampleDimensionX = dimension * 8;
   const int sampleDimensionY = dimensionY * 4;
   Ref<PerspectiveTransform> transform(
       PerspectiveTransform::quadrilateralToQuadrilateral(
           0.0f, 0.0f,
           (float)sampleDimensionX, 0.0f,
           0.0f, (float)sampleDimensionY,
           (float)sampleDimensionX, (float)sampleDimensionY,
           vertices[12]->getX(), vertices[12]->getY(),
           vertices[14]->getX(), vertices[14]->getY(),
           vertices[13]->getX(), vertices[13]->getY(),
           vertices[15]->getX(), vertices[15]->getY()));

   Ref<BitMatrix> linesMatrix = GridSampler::getInstance().sampleGrid(
       image_->getBlackMatrix(), sampleDimensionX, sampleDimensionY, transform);

   return linesMatrix;
 }
Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded