mirror of
https://github.com/opencv/opencv.git
synced 2026-07-26 22:03:04 +04:00
Merge pull request #23666 from mshabunin:barcode-move
Moved barcode from opencv_contrib #23666 Merge with https://github.com/opencv/opencv_contrib/pull/3497 ##### TODO - [x] Documentation (bib) - [x] Tutorial (references) - [x] Sample app (refactored) - [x] Java (test passes) - [x] Python (test passes) - [x] Build without DNN
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
// 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) 2020-2021 darkliang wangberlinT Certseeds
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "abs_decoder.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace barcode {
|
||||
|
||||
void cropROI(const Mat &src, Mat &dst, const std::vector<Point2f> &rects)
|
||||
{
|
||||
std::vector<Point2f> vertices = rects;
|
||||
int height = cvRound(norm(vertices[0] - vertices[1]));
|
||||
int width = cvRound(norm(vertices[1] - vertices[2]));
|
||||
if (height > width)
|
||||
{
|
||||
std::swap(height, width);
|
||||
Point2f v0 = vertices[0];
|
||||
vertices.erase(vertices.begin());
|
||||
vertices.push_back(v0);
|
||||
}
|
||||
std::vector<Point2f> dst_vertices{
|
||||
Point2f(0, (float) (height - 1)), Point2f(0, 0), Point2f((float) (width - 1), 0),
|
||||
Point2f((float) (width - 1), (float) (height - 1))};
|
||||
dst.create(Size(width, height), CV_8UC1);
|
||||
Mat M = getPerspectiveTransform(vertices, dst_vertices);
|
||||
warpPerspective(src, dst, M, dst.size(), cv::INTER_LINEAR, BORDER_CONSTANT, Scalar(255));
|
||||
}
|
||||
|
||||
void fillCounter(const std::vector<uchar> &row, uint start, Counter &counter)
|
||||
{
|
||||
size_t counter_length = counter.pattern.size();
|
||||
std::fill(counter.pattern.begin(), counter.pattern.end(), 0);
|
||||
counter.sum = 0;
|
||||
size_t end = row.size();
|
||||
uchar color = row[start];
|
||||
uint counterPosition = 0;
|
||||
while (start < end)
|
||||
{
|
||||
if (row[start] == color)
|
||||
{ // that is, exactly one is true
|
||||
counter.pattern[counterPosition]++;
|
||||
counter.sum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
counterPosition++;
|
||||
if (counterPosition == counter_length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
counter.pattern[counterPosition] = 1;
|
||||
counter.sum++;
|
||||
color = 255 - color;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint
|
||||
patternMatchVariance(const Counter &counter, const std::vector<int> &pattern, uint maxIndividualVariance)
|
||||
{
|
||||
size_t numCounters = counter.pattern.size();
|
||||
int total = static_cast<int>(counter.sum);
|
||||
int patternLength = std::accumulate(pattern.cbegin(), pattern.cend(), 0);
|
||||
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:
|
||||
// and use constexpr functions
|
||||
return WHITE;// 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 << INTEGER_MATH_SHIFT) / patternLength;
|
||||
maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
|
||||
uint totalVariance = 0;
|
||||
for (uint x = 0; x < numCounters; x++)
|
||||
{
|
||||
int cnt = counter.pattern[x] << INTEGER_MATH_SHIFT;
|
||||
int scaledPattern = pattern[x] * unitBarWidth;
|
||||
uint variance = std::abs(cnt - scaledPattern);
|
||||
if (variance > maxIndividualVariance)
|
||||
{
|
||||
return WHITE;
|
||||
}
|
||||
totalVariance += variance;
|
||||
}
|
||||
return totalVariance / total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
uint patternMatch(const Counter &counters, const std::vector<int> &pattern, uint maxIndividual)
|
||||
{
|
||||
CV_Assert(counters.pattern.size() == pattern.size());
|
||||
return patternMatchVariance(counters, pattern, maxIndividual);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user