mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
commit
583bd1a6e2
@ -122,11 +122,14 @@ imgElement.onload = function() {
|
||||
mat.delete();
|
||||
};
|
||||
|
||||
function onOpenCvReady() {
|
||||
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
|
||||
}
|
||||
var Module = {
|
||||
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
|
||||
onRuntimeInitialized() {
|
||||
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script async src="opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
|
||||
<script async src="opencv.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
@endcode
|
||||
|
@ -1348,3 +1348,13 @@
|
||||
year={1991},
|
||||
publisher={IEEE Computer Society}
|
||||
}
|
||||
@article{Kannala2006,
|
||||
author = {Kannala, Juho and Brandt, Sami},
|
||||
year = {2006},
|
||||
month = {09},
|
||||
pages = {1335-40},
|
||||
title = {A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses},
|
||||
volume = {28},
|
||||
journal = {IEEE transactions on pattern analysis and machine intelligence},
|
||||
doi = {10.1109/TPAMI.2006.153}
|
||||
}
|
||||
|
@ -430,6 +430,9 @@ R & t \\
|
||||
\f[u = f_x (x' + \alpha y') + c_x \\
|
||||
v = f_y y' + c_y\f]
|
||||
|
||||
Summary:
|
||||
Generic camera model @cite Kannala2006 with perspective projection and without distortion correction
|
||||
|
||||
@defgroup calib3d_c C API
|
||||
|
||||
@}
|
||||
@ -3883,7 +3886,7 @@ namespace fisheye
|
||||
CV_EXPORTS_W void estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R,
|
||||
OutputArray P, double balance = 0.0, const Size& new_size = Size(), double fov_scale = 1.0);
|
||||
|
||||
/** @brief Performs camera calibaration
|
||||
/** @brief Performs camera calibration
|
||||
|
||||
@param objectPoints vector of vectors of calibration pattern points in the calibration pattern
|
||||
coordinate space.
|
||||
|
@ -365,6 +365,7 @@ extern CV_EXPORTS
|
||||
bool __termination; // skip some cleanups, because process is terminating
|
||||
// (for example, if ExitProcess() was already called)
|
||||
|
||||
CV_EXPORTS
|
||||
cv::Mutex& getInitializationMutex();
|
||||
|
||||
/// @brief Returns timestamp in nanoseconds since program launch
|
||||
|
@ -207,7 +207,7 @@ Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= Str
|
||||
std::ifstream cfgStream(cfgFile.c_str());
|
||||
if (!cfgStream.is_open())
|
||||
{
|
||||
CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(cfgFile));
|
||||
CV_Error(cv::Error::StsParseError, "Failed to open NetParameter file: " + std::string(cfgFile));
|
||||
}
|
||||
if (darknetModel != String())
|
||||
{
|
||||
|
@ -990,6 +990,7 @@ void sortByExecutionOrder(tensorflow::GraphDef& net)
|
||||
nodesMap.insert(std::make_pair(node.name(), i));
|
||||
}
|
||||
|
||||
CV_CheckEQ(nodesMap.size(), (size_t)net.node_size(), "Node names must be unique");
|
||||
// Indices of nodes which use specific node as input.
|
||||
std::vector<std::vector<int> > edges(nodesMap.size());
|
||||
std::vector<int> numRefsToAdd(nodesMap.size(), 0);
|
||||
@ -1007,7 +1008,7 @@ void sortByExecutionOrder(tensorflow::GraphDef& net)
|
||||
nodesMapIt = nodesMap.find(inpName);
|
||||
if (nodesMapIt != nodesMap.end())
|
||||
{
|
||||
edges[nodesMapIt->second].push_back(i);
|
||||
edges.at(nodesMapIt->second).push_back(i);
|
||||
numInputsInGraph += 1;
|
||||
}
|
||||
}
|
||||
@ -1019,11 +1020,11 @@ void sortByExecutionOrder(tensorflow::GraphDef& net)
|
||||
{
|
||||
int numControlEdges = 0;
|
||||
for (int j = 0; j < numInputsInGraph; ++j)
|
||||
numControlEdges += node.input(j)[0] == '^';
|
||||
numRefsToAdd[i] = numControlEdges + 1;
|
||||
numControlEdges += node.input(j).at(0) == '^';
|
||||
numRefsToAdd.at(i) = numControlEdges + 1;
|
||||
}
|
||||
else
|
||||
numRefsToAdd[i] = numInputsInGraph;
|
||||
numRefsToAdd.at(i) = numInputsInGraph;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1035,17 +1036,16 @@ void sortByExecutionOrder(tensorflow::GraphDef& net)
|
||||
nodesToAdd.pop_back();
|
||||
|
||||
permIds.push_back(nodeToAdd);
|
||||
CV_Assert(nodeToAdd < edges.size());
|
||||
for (int i = 0; i < edges[nodeToAdd].size(); ++i)
|
||||
for (int i = 0; i < edges.at(nodeToAdd).size(); ++i)
|
||||
{
|
||||
int consumerId = edges[nodeToAdd][i];
|
||||
if (numRefsToAdd[consumerId] > 0)
|
||||
int consumerId = edges.at(nodeToAdd).at(i);
|
||||
if (numRefsToAdd.at(consumerId) > 0)
|
||||
{
|
||||
if (numRefsToAdd[consumerId] == 1)
|
||||
if (numRefsToAdd.at(consumerId) == 1)
|
||||
nodesToAdd.push_back(consumerId);
|
||||
else
|
||||
CV_Assert(numRefsToAdd[consumerId] >= 0);
|
||||
numRefsToAdd[consumerId] -= 1;
|
||||
CV_Assert(numRefsToAdd.at(consumerId) >= 0);
|
||||
numRefsToAdd.at(consumerId) -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1719,13 +1719,6 @@ TEST_P(Test_TensorFlow_layers, tf2_permute_nhwc_ncwh)
|
||||
runTensorFlowNet("tf2_permute_nhwc_ncwh");
|
||||
}
|
||||
|
||||
// issue #21852
|
||||
TEST_P(Test_TensorFlow_layers, tf_graph_simplifier_buffer_overflow)
|
||||
{
|
||||
// This just shouldn't segfault, otherwise it's fine
|
||||
EXPECT_ANY_THROW(readNetFromTensorflow(path("tf_graph_simplifier_buffer_overflow_net.pb")));
|
||||
}
|
||||
|
||||
TEST_P(Test_TensorFlow_layers, squeeze)
|
||||
{
|
||||
#if defined(INF_ENGINE_RELEASE)
|
||||
@ -1899,4 +1892,25 @@ TEST_P(Test_TensorFlow_nets, EfficientDet)
|
||||
expectNoFallbacksFromIE(net);
|
||||
}
|
||||
|
||||
TEST(Test_TensorFlow_Importer, tf_graph_simplifier_buffer_overflow_21852)
|
||||
{
|
||||
uint8_t payload[] = {0x08, 0x08, 0x0a, 0x00, 0x0a, 0x00};
|
||||
EXPECT_ANY_THROW(readNetFromTensorflow(reinterpret_cast<const char*>(payload), sizeof(payload) / sizeof(payload[0])));
|
||||
}
|
||||
|
||||
// can be triggered with -fsanitize=address
|
||||
TEST(Test_TensorFlow_Importer, tf_graph_simplifier_buffer_overflow_21947)
|
||||
{
|
||||
uint8_t payload[] = {0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00,
|
||||
0xba, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00,
|
||||
0x0a, 0xbd, 0x00, 0x1a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xba,
|
||||
0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00,
|
||||
0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xba, 0x0a, 0x00,
|
||||
0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0xba,
|
||||
0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00,
|
||||
0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x2a, 0x00, 0xba, 0x0a, 0x00,
|
||||
0x0a, 0x00, 0x5d, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x0a, 0x40};
|
||||
EXPECT_ANY_THROW(readNetFromTensorflow(reinterpret_cast<const char*>(payload), sizeof(payload) / sizeof(payload[0])));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ cv::flann::L2 - Squared Euclidean distance functor, optimized version.
|
||||
|
||||
cv::flann::L1 - Manhattan distance functor, optimized version.
|
||||
|
||||
cv::flann::MinkowskiDistance - The Minkowsky distance functor.
|
||||
cv::flann::MinkowskiDistance - The Minkowski distance functor.
|
||||
This is highly optimised with loop unrolling.
|
||||
The computation of squared root at the end is omitted for efficiency.
|
||||
|
||||
|
@ -375,7 +375,7 @@ struct MinkowskiDistance
|
||||
MinkowskiDistance(int order_) : order(order_) {}
|
||||
|
||||
/**
|
||||
* Compute the Minkowsky (L_p) distance between two vectors.
|
||||
* Compute the Minkowski (L_p) distance between two vectors.
|
||||
*
|
||||
* This is highly optimised, with loop unrolling, as it is one
|
||||
* of the most expensive inner loops.
|
||||
|
@ -2198,23 +2198,58 @@ void CvWindow::displayPropertiesWin()
|
||||
global_control_panel->hide();
|
||||
}
|
||||
|
||||
static bool isTranslatableKey(Qt::Key key)
|
||||
{
|
||||
// https://github.com/opencv/opencv/issues/21899
|
||||
// https://doc.qt.io/qt-5/qt.html#Key-enum
|
||||
// https://doc.qt.io/qt-6/qt.html#Key-enum
|
||||
// https://github.com/qt/qtbase/blob/dev/src/testlib/qasciikey.cpp
|
||||
|
||||
bool ret = false;
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
// Special keys
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab:
|
||||
case Qt::Key_Backspace:
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
ret = true;
|
||||
break;
|
||||
|
||||
// latin-1 keys.
|
||||
default:
|
||||
ret = (
|
||||
( ( Qt::Key_Space <= key ) && ( key <= Qt::Key_AsciiTilde ) ) // 0x20--0x7e
|
||||
||
|
||||
( ( Qt::Key_nobreakspace <= key ) && ( key <= Qt::Key_ssharp ) ) // 0x0a0--0x0de
|
||||
||
|
||||
( key == Qt::Key_division ) // 0x0f7
|
||||
||
|
||||
( key == Qt::Key_ydiaeresis ) // 0x0ff
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Need more test here !
|
||||
void CvWindow::keyPressEvent(QKeyEvent *evnt)
|
||||
{
|
||||
//see http://doc.trolltech.com/4.6/qt.html#Key-enum
|
||||
int key = evnt->key();
|
||||
const Qt::Key qtkey = static_cast<Qt::Key>(key);
|
||||
|
||||
Qt::Key qtkey = static_cast<Qt::Key>(key);
|
||||
char asciiCode = QTest::keyToAscii(qtkey);
|
||||
if (asciiCode != 0)
|
||||
key = static_cast<int>(asciiCode);
|
||||
else
|
||||
key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend
|
||||
if ( isTranslatableKey( qtkey ) )
|
||||
key = static_cast<int>( QTest::keyToAscii( qtkey ) );
|
||||
else
|
||||
key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend
|
||||
|
||||
//control plus (Z, +, -, up, down, left, right) are used for zoom/panning functions
|
||||
if (evnt->modifiers() != Qt::ControlModifier)
|
||||
{
|
||||
if (evnt->modifiers() != Qt::ControlModifier)
|
||||
{
|
||||
mutexKey.lock();
|
||||
last_key = key;
|
||||
mutexKey.unlock();
|
||||
|
@ -39,36 +39,51 @@ struct RGB2HSV_b
|
||||
: srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange)
|
||||
{
|
||||
CV_Assert( hrange == 180 || hrange == 256 );
|
||||
|
||||
const TablesSingleton& global_tables = TablesSingleton::getInstance();
|
||||
hdiv_table_ = hrange == 180 ? global_tables.hdiv_table180 : global_tables.hdiv_table256;
|
||||
sdiv_table_ = global_tables.sdiv_table;
|
||||
}
|
||||
|
||||
void operator()(const uchar* src, uchar* dst, int n) const
|
||||
struct TablesSingleton
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
int sdiv_table[256];
|
||||
int hdiv_table180[256];
|
||||
int hdiv_table256[256];
|
||||
|
||||
int i, bidx = blueIdx, scn = srccn;
|
||||
const int hsv_shift = 12;
|
||||
|
||||
static int sdiv_table[256];
|
||||
static int hdiv_table180[256];
|
||||
static int hdiv_table256[256];
|
||||
static volatile bool initialized = false;
|
||||
|
||||
int hr = hrange;
|
||||
const int* hdiv_table = hr == 180 ? hdiv_table180 : hdiv_table256;
|
||||
|
||||
if( !initialized )
|
||||
protected:
|
||||
TablesSingleton()
|
||||
{
|
||||
const int hsv_shift = 12;
|
||||
|
||||
sdiv_table[0] = hdiv_table180[0] = hdiv_table256[0] = 0;
|
||||
for( i = 1; i < 256; i++ )
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
sdiv_table[i] = saturate_cast<int>((255 << hsv_shift)/(1.*i));
|
||||
hdiv_table180[i] = saturate_cast<int>((180 << hsv_shift)/(6.*i));
|
||||
hdiv_table256[i] = saturate_cast<int>((256 << hsv_shift)/(6.*i));
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
public:
|
||||
static TablesSingleton& getInstance()
|
||||
{
|
||||
static TablesSingleton g_tables;
|
||||
return g_tables;
|
||||
}
|
||||
};
|
||||
|
||||
i = 0;
|
||||
void operator()(const uchar* src, uchar* dst, int n) const
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
|
||||
int bidx = blueIdx, scn = srccn;
|
||||
const int hsv_shift = 12;
|
||||
|
||||
int hr = hrange;
|
||||
const int* hdiv_table/*[256]*/ = hdiv_table_;
|
||||
const int* sdiv_table/*[256]*/ = sdiv_table_;
|
||||
|
||||
int i = 0;
|
||||
|
||||
#if CV_SIMD
|
||||
const int vsize = v_uint8::nlanes;
|
||||
@ -231,6 +246,9 @@ struct RGB2HSV_b
|
||||
}
|
||||
|
||||
int srccn, blueIdx, hrange;
|
||||
|
||||
const int* hdiv_table_/*[256]*/;
|
||||
const int* sdiv_table_/*[256]*/;
|
||||
};
|
||||
|
||||
|
||||
|
@ -115,4 +115,12 @@ inline bool isStorageOrMat(void * arr)
|
||||
CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
|
||||
}
|
||||
|
||||
#endif /*__OPENCV_CV_INTERNAL_H_*/
|
||||
|
||||
namespace cv {
|
||||
|
||||
CV_EXPORTS
|
||||
cv::Mutex& getInitializationMutex(); // defined in core module
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif /*__OPENCV_PRECOMP_H__*/
|
||||
|
@ -106,10 +106,11 @@ PERF_TEST_P_(Perf_Objdetect_QRCode_Multi, decodeMulti)
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_QRCode,
|
||||
::testing::Values(
|
||||
"version_1_down.jpg", "version_1_left.jpg", "version_1_right.jpg", "version_1_up.jpg", "version_1_top.jpg",
|
||||
"version_5_down.jpg", "version_5_left.jpg", "version_5_right.jpg", "version_5_up.jpg", "version_5_top.jpg",
|
||||
"version_5_down.jpg", "version_5_left.jpg",/*version_5_right.jpg*/ "version_5_up.jpg", "version_5_top.jpg",
|
||||
"russian.jpg", "kanji.jpg", "link_github_ocv.jpg", "link_ocv.jpg", "link_wiki_cv.jpg"
|
||||
)
|
||||
);
|
||||
// version_5_right.jpg DISABLED after tile fix, PR #22025
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Perf_Objdetect_QRCode_Multi,
|
||||
::testing::Values(
|
||||
|
@ -1061,6 +1061,15 @@ protected:
|
||||
};
|
||||
};
|
||||
|
||||
float static getMinSideLen(const vector<Point2f> &points) {
|
||||
CV_Assert(points.size() == 4ull);
|
||||
double res = norm(points[1]-points[0]);
|
||||
for (size_t i = 1ull; i < points.size(); i++) {
|
||||
res = min(res, norm(points[i]-points[(i+1ull) % points.size()]));
|
||||
}
|
||||
return static_cast<float>(res);
|
||||
}
|
||||
|
||||
void QRDecode::init(const Mat &src, const vector<Point2f> &points)
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
@ -1072,7 +1081,7 @@ void QRDecode::init(const Mat &src, const vector<Point2f> &points)
|
||||
original_points = bbox;
|
||||
version = 0;
|
||||
version_size = 0;
|
||||
test_perspective_size = 251;
|
||||
test_perspective_size = max(getMinSideLen(points)+1.f, 251.f);
|
||||
result_info = "";
|
||||
}
|
||||
|
||||
@ -2088,7 +2097,7 @@ bool QRDecode::straightenQRCodeInParts()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float perspective_curved_size = 251.0;
|
||||
float perspective_curved_size = max(getMinSideLen(original_points)+1.f, 251.f);;
|
||||
const Size temporary_size(cvRound(perspective_curved_size), cvRound(perspective_curved_size));
|
||||
|
||||
float dist = perspective_curved_size / (number_pnts_to_cut - 1);
|
||||
@ -2359,9 +2368,9 @@ bool QRDecode::versionDefinition()
|
||||
bool QRDecode::samplingForVersion()
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
const double multiplyingFactor = (version < 3) ? 1 :
|
||||
(version == 3) ? 1.5 :
|
||||
version * (version + 1);
|
||||
const double multiplyingFactor = (version < 3) ? 1. :
|
||||
(version == 3) ? 2. :
|
||||
3.;
|
||||
const Size newFactorSize(
|
||||
cvRound(no_border_intermediate.size().width * multiplyingFactor),
|
||||
cvRound(no_border_intermediate.size().height * multiplyingFactor));
|
||||
@ -2370,45 +2379,38 @@ bool QRDecode::samplingForVersion()
|
||||
|
||||
const int delta_rows = cvRound((postIntermediate.rows * 1.0) / version_size);
|
||||
const int delta_cols = cvRound((postIntermediate.cols * 1.0) / version_size);
|
||||
// number of elements in the tail
|
||||
const int skipped_rows = postIntermediate.rows - delta_rows * version_size;
|
||||
const int skipped_cols = postIntermediate.cols - delta_cols * version_size;
|
||||
|
||||
vector<double> listFrequencyElem;
|
||||
for (int r = 0; r < postIntermediate.rows; r += delta_rows)
|
||||
{
|
||||
for (int c = 0; c < postIntermediate.cols; c += delta_cols)
|
||||
{
|
||||
vector<int> deltas_rows(version_size, delta_rows);
|
||||
vector<int> deltas_cols(version_size, delta_cols);
|
||||
|
||||
for (int i = 0; i < abs(skipped_rows); i++) {
|
||||
// fix deltas_rows at each skip_step
|
||||
const double skip_step = static_cast<double>(version_size)/abs(skipped_rows);
|
||||
const int corrected_index = static_cast<int>(i*skip_step + skip_step/2);
|
||||
deltas_rows[corrected_index] += skipped_rows > 0 ? 1 : -1;
|
||||
}
|
||||
for (int i = 0; i < abs(skipped_cols); i++) {
|
||||
// fix deltas_cols at each skip_step
|
||||
const double skip_step = static_cast<double>(version_size)/abs(skipped_cols);
|
||||
const int corrected_index = static_cast<int>(i*skip_step + skip_step/2);
|
||||
deltas_cols[corrected_index] += skipped_cols > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
const double totalFrequencyElem = countNonZero(postIntermediate) / static_cast<double>(postIntermediate.total());
|
||||
straight = Mat(Size(version_size, version_size), CV_8UC1, Scalar(0));
|
||||
|
||||
for (int r = 0, i = 0; i < version_size; r += deltas_rows[i], i++) {
|
||||
for (int c = 0, j = 0; j < version_size; c += deltas_cols[j], j++) {
|
||||
Mat tile = postIntermediate(
|
||||
Range(r, min(r + delta_rows, postIntermediate.rows)),
|
||||
Range(c, min(c + delta_cols, postIntermediate.cols)));
|
||||
const double frequencyElem = (countNonZero(tile) * 1.0) / tile.total();
|
||||
listFrequencyElem.push_back(frequencyElem);
|
||||
straight.ptr<uint8_t>(i)[j] = (frequencyElem < totalFrequencyElem) ? 0 : 255;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
for (int r = 0; r < version_size * version_size; r++)
|
||||
{
|
||||
int i = r / straight.cols;
|
||||
int j = r % straight.cols;
|
||||
straight.ptr<uint8_t>(i)[j] = (listFrequencyElem[r] < experimentalFrequencyElem) ? 0 : 255;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -975,7 +975,7 @@ void QRCodeEncoderImpl::writeReservedArea()
|
||||
original.at<uint8_t>(x, y) = INVALID_REGION_VALUE;
|
||||
if (version_level >= 7)
|
||||
{
|
||||
for (int i = 0; i <= 6; i++)
|
||||
for (int i = 0; i <= 5; i++)
|
||||
{
|
||||
for (int j = version_size - 11; j <= version_size - 8; j++)
|
||||
{
|
||||
|
@ -11,8 +11,9 @@ std::string qrcode_images_name[] = {
|
||||
"version_2_down.jpg", "version_2_left.jpg", "version_2_right.jpg", "version_2_up.jpg", "version_2_top.jpg",
|
||||
"version_3_down.jpg", "version_3_left.jpg", "version_3_right.jpg", "version_3_up.jpg", "version_3_top.jpg",
|
||||
"version_4_down.jpg", "version_4_left.jpg", "version_4_right.jpg", "version_4_up.jpg", "version_4_top.jpg",
|
||||
"version_5_down.jpg", "version_5_left.jpg", "version_5_right.jpg", "version_5_up.jpg", "version_5_top.jpg",
|
||||
"version_5_down.jpg", "version_5_left.jpg"/*"version_5_right.jpg"*/,
|
||||
"russian.jpg", "kanji.jpg", "link_github_ocv.jpg", "link_ocv.jpg", "link_wiki_cv.jpg"
|
||||
// version_5_right.jpg DISABLED after tile fix, PR #22025
|
||||
};
|
||||
|
||||
std::string qrcode_images_close[] = {
|
||||
@ -22,8 +23,9 @@ std::string qrcode_images_monitor[] = {
|
||||
"monitor_1.png", "monitor_2.png", "monitor_3.png", "monitor_4.png", "monitor_5.png"
|
||||
};
|
||||
std::string qrcode_images_curved[] = {
|
||||
"curved_1.jpg", "curved_2.jpg", "curved_3.jpg", "curved_4.jpg", "curved_5.jpg", "curved_6.jpg", "curved_7.jpg", "curved_8.jpg"
|
||||
"curved_1.jpg", "curved_2.jpg", "curved_3.jpg", /*"curved_4.jpg",*/ "curved_5.jpg", /*"curved_6.jpg",*/ "curved_7.jpg", "curved_8.jpg"
|
||||
};
|
||||
// curved_4.jpg, curved_6.jpg DISABLED after tile fix, PR #22025
|
||||
std::string qrcode_images_multiple[] = {
|
||||
"2_qrcodes.png", "3_close_qrcodes.png", "3_qrcodes.png", "4_qrcodes.png",
|
||||
"5_qrcodes.png", "6_qrcodes.png", "7_qrcodes.png", "8_close_qrcodes.png"
|
||||
@ -683,7 +685,78 @@ TEST(Objdetect_QRCode_basic, not_found_qrcode)
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Objdetect_QRCode_detect, detect_regression_21287)
|
||||
{
|
||||
const std::string name_current_image = "issue_21287.png";
|
||||
const std::string root = "qrcode/";
|
||||
|
||||
std::string image_path = findDataFile(root + name_current_image);
|
||||
Mat src = imread(image_path);
|
||||
ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path;
|
||||
|
||||
QRCodeDetector qrcode;
|
||||
std::vector<Point> corners;
|
||||
Mat straight_barcode;
|
||||
cv::String decoded_info;
|
||||
EXPECT_TRUE(qrcode.detect(src, corners));
|
||||
EXPECT_TRUE(!corners.empty());
|
||||
#ifdef HAVE_QUIRC
|
||||
EXPECT_NO_THROW(qrcode.decode(src, corners, straight_barcode));
|
||||
#endif
|
||||
}
|
||||
|
||||
// @author Kumataro, https://github.com/Kumataro
|
||||
TEST(Objdetect_QRCode_decode, decode_regression_21929)
|
||||
{
|
||||
const cv::String expect_msg = "OpenCV";
|
||||
Mat qrImg;
|
||||
QRCodeEncoder::Params params;
|
||||
params.version = 8; // 49x49
|
||||
Ptr<QRCodeEncoder> qrcode_enc = cv::QRCodeEncoder::create(params);;
|
||||
qrcode_enc->encode(expect_msg, qrImg);
|
||||
|
||||
Mat src;
|
||||
cv::resize(qrImg, src, Size(200,200), 1.0, 1.0, INTER_NEAREST);
|
||||
|
||||
QRCodeDetector qrcode;
|
||||
std::vector<Point> corners;
|
||||
Mat straight_barcode;
|
||||
|
||||
EXPECT_TRUE(qrcode.detect(src, corners));
|
||||
EXPECT_TRUE(!corners.empty());
|
||||
#ifdef HAVE_QUIRC
|
||||
cv::String decoded_msg;
|
||||
EXPECT_NO_THROW(decoded_msg = qrcode.decode(src, corners, straight_barcode));
|
||||
ASSERT_FALSE(straight_barcode.empty()) << "Can't decode qrimage.";
|
||||
EXPECT_EQ(expect_msg, decoded_msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Objdetect_QRCode_decode, decode_regression_version_25)
|
||||
{
|
||||
const cv::String expect_msg = "OpenCV";
|
||||
Mat qrImg;
|
||||
QRCodeEncoder::Params params;
|
||||
params.version = 25; // 117x117
|
||||
Ptr<QRCodeEncoder> qrcode_enc = cv::QRCodeEncoder::create(params);;
|
||||
qrcode_enc->encode(expect_msg, qrImg);
|
||||
|
||||
Mat src;
|
||||
cv::resize(qrImg, src, qrImg.size()*3, 1.0, 1.0, INTER_NEAREST);
|
||||
|
||||
QRCodeDetector qrcode;
|
||||
std::vector<Point> corners;
|
||||
Mat straight_barcode;
|
||||
|
||||
EXPECT_TRUE(qrcode.detect(src, corners));
|
||||
EXPECT_TRUE(!corners.empty());
|
||||
#ifdef HAVE_QUIRC
|
||||
cv::String decoded_msg;
|
||||
EXPECT_NO_THROW(decoded_msg = qrcode.decode(src, corners, straight_barcode));
|
||||
ASSERT_FALSE(straight_barcode.empty()) << "Can't decode qrimage.";
|
||||
EXPECT_EQ(expect_msg, decoded_msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // UPDATE_QRCODE_TEST_DATA
|
||||
|
||||
|
@ -433,4 +433,82 @@ TEST(Objdetect_QRCode_Encode_Decode_Structured_Append, DISABLED_regression)
|
||||
|
||||
#endif // UPDATE_QRCODE_TEST_DATA
|
||||
|
||||
TEST(Objdetect_QRCode_Encode_Decode, regression_issue22029)
|
||||
{
|
||||
const cv::String msg = "OpenCV";
|
||||
const int min_version = 1;
|
||||
const int max_version = 40;
|
||||
|
||||
for ( int v = min_version ; v <= max_version ; v++ )
|
||||
{
|
||||
SCOPED_TRACE(cv::format("version=%d",v));
|
||||
|
||||
Mat qrimg;
|
||||
QRCodeEncoder::Params params;
|
||||
params.version = v;
|
||||
Ptr<QRCodeEncoder> qrcode_enc = cv::QRCodeEncoder::create(params);
|
||||
qrcode_enc->encode(msg, qrimg);
|
||||
|
||||
const int white_margin = 2;
|
||||
const int finder_width = 7;
|
||||
|
||||
const int timing_pos = white_margin + 6;
|
||||
int i;
|
||||
|
||||
// Horizontal Check
|
||||
// (1) White margin(Left)
|
||||
for(i = 0; i < white_margin ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
|
||||
}
|
||||
// (2) Finder pattern(Left)
|
||||
for( ; i < white_margin + finder_width ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
|
||||
}
|
||||
// (3) Timing pattern
|
||||
for( ; i < qrimg.rows - finder_width - white_margin; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)(i % 2 == 0)?0:255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
|
||||
}
|
||||
// (4) Finder pattern(Right)
|
||||
for( ; i < qrimg.rows - white_margin; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
|
||||
}
|
||||
// (5) White margin(Right)
|
||||
for( ; i < qrimg.rows ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(i, timing_pos)) << "i=" << i;
|
||||
}
|
||||
|
||||
// Vertical Check
|
||||
// (1) White margin(Top)
|
||||
for(i = 0; i < white_margin ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
|
||||
}
|
||||
// (2) Finder pattern(Top)
|
||||
for( ; i < white_margin + finder_width ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
|
||||
}
|
||||
// (3) Timing pattern
|
||||
for( ; i < qrimg.rows - finder_width - white_margin; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)(i % 2 == 0)?0:255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
|
||||
}
|
||||
// (4) Finder pattern(Bottom)
|
||||
for( ; i < qrimg.rows - white_margin; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)0, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
|
||||
}
|
||||
// (5) White margin(Bottom)
|
||||
for( ; i < qrimg.rows ; i++ )
|
||||
{
|
||||
ASSERT_EQ((uint8_t)255, qrimg.at<uint8_t>(timing_pos, i)) << "i=" << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
Loading…
Reference in New Issue
Block a user