mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge b91ffb8f1c
into aef6ae4872
This commit is contained in:
commit
a3584a1e04
@ -1002,6 +1002,9 @@ class JavaWrapperGenerator(object):
|
||||
ret = "return (jlong) _retval_;"
|
||||
elif type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
|
||||
ret = "return _da_retval_;"
|
||||
elif "jni_var" in type_dict[ret_type]:
|
||||
c_epilogue.append(type_dict[ret_type]["jni_var"] % {"n" : '_retval_'})
|
||||
ret = f"return {type_dict[ret_type]['jni_name'] % {'n' : '_retval_'}};"
|
||||
|
||||
# hack: replacing func call with property set/get
|
||||
name = fi.name
|
||||
|
@ -729,7 +729,8 @@ public:
|
||||
};
|
||||
|
||||
enum ECIEncodings {
|
||||
ECI_UTF8 = 26
|
||||
ECI_SHIFT_JIS = 20,
|
||||
ECI_UTF8 = 26,
|
||||
};
|
||||
|
||||
/** @brief QR code encoder parameters. */
|
||||
@ -808,6 +809,13 @@ public:
|
||||
*/
|
||||
CV_WRAP std::string detectAndDecodeCurved(InputArray img, OutputArray points=noArray(),
|
||||
OutputArray straight_qrcode = noArray());
|
||||
|
||||
/** @brief Returns a kind of encoding for the decoded info from the latest @ref decode or @ref detectAndDecode call
|
||||
@param codeIdx an index of the previously decoded QR code.
|
||||
When @ref decode or @ref detectAndDecode is used, valid value is zero.
|
||||
For @ref decodeMulti or @ref detectAndDecodeMulti use indices corresponding to the output order.
|
||||
*/
|
||||
CV_WRAP QRCodeEncoder::ECIEncodings getEncoding(int codeIdx = 0);
|
||||
};
|
||||
|
||||
class CV_EXPORTS_W_SIMPLE QRCodeDetectorAruco : public GraphicalCodeDetector {
|
||||
|
@ -73,6 +73,17 @@ public:
|
||||
*/
|
||||
CV_WRAP bool detectAndDecodeMulti(InputArray img, CV_OUT std::vector<std::string>& decoded_info, OutputArray points = noArray(),
|
||||
OutputArrayOfArrays straight_code = noArray()) const;
|
||||
|
||||
#ifdef OPENCV_BINDINGS_PARSER
|
||||
CV_WRAP_AS(detectAndDecodeBytes) NativeByteArray detectAndDecode(InputArray img, OutputArray points = noArray(),
|
||||
OutputArray straight_code = noArray()) const;
|
||||
CV_WRAP_AS(decodeBytes) NativeByteArray decode(InputArray img, InputArray points, OutputArray straight_code = noArray()) const;
|
||||
CV_WRAP_AS(decodeBytesMulti) bool decodeMulti(InputArray img, InputArray points, CV_OUT std::vector<NativeByteArray>& decoded_info,
|
||||
OutputArrayOfArrays straight_code = noArray()) const;
|
||||
CV_WRAP_AS(detectAndDecodeBytesMulti) bool detectAndDecodeMulti(InputArray img, CV_OUT std::vector<NativeByteArray>& decoded_info, OutputArray points = noArray(),
|
||||
OutputArrayOfArrays straight_code = noArray()) const;
|
||||
#endif
|
||||
|
||||
struct Impl;
|
||||
protected:
|
||||
Ptr<Impl> p;
|
||||
|
1
modules/objdetect/misc/java/filelist_common
Normal file
1
modules/objdetect/misc/java/filelist_common
Normal file
@ -0,0 +1 @@
|
||||
misc/java/src/cpp/objdetect_converters.hpp
|
68
modules/objdetect/misc/java/gen_dict.json
Normal file
68
modules/objdetect/misc/java/gen_dict.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"ManualFuncs" : {
|
||||
"QRCodeEncoder" : {
|
||||
"QRCodeEncoder" : {
|
||||
"j_code" : [
|
||||
"\n",
|
||||
"/** Generates QR code from input string.",
|
||||
"@param encoded_info Input bytes to encode.",
|
||||
"@param qrcode Generated QR code.",
|
||||
"*/",
|
||||
"public void encode(byte[] encoded_info, Mat qrcode) {",
|
||||
" encode_1(nativeObj, encoded_info, qrcode.nativeObj);",
|
||||
"}",
|
||||
"\n"
|
||||
],
|
||||
"jn_code": [
|
||||
"\n",
|
||||
"private static native void encode_1(long nativeObj, byte[] encoded_info, long qrcode_nativeObj);",
|
||||
"\n"
|
||||
],
|
||||
"cpp_code": [
|
||||
"//",
|
||||
"// void cv::QRCodeEncoder::encode(String encoded_info, Mat& qrcode)",
|
||||
"//",
|
||||
"\n",
|
||||
"JNIEXPORT void JNICALL Java_org_opencv_objdetect_QRCodeEncoder_encode_11 (JNIEnv*, jclass, jlong, jbyteArray, jlong);",
|
||||
"\n",
|
||||
"JNIEXPORT void JNICALL Java_org_opencv_objdetect_QRCodeEncoder_encode_11",
|
||||
"(JNIEnv* env, jclass , jlong self, jbyteArray encoded_info, jlong qrcode_nativeObj)",
|
||||
"{",
|
||||
"",
|
||||
" static const char method_name[] = \"objdetect::encode_11()\";",
|
||||
" try {",
|
||||
" LOGD(\"%s\", method_name);",
|
||||
" Ptr<cv::QRCodeEncoder>* me = (Ptr<cv::QRCodeEncoder>*) self; //TODO: check for NULL",
|
||||
" const char* n_encoded_info = reinterpret_cast<char*>(env->GetByteArrayElements(encoded_info, NULL));",
|
||||
" Mat& qrcode = *((Mat*)qrcode_nativeObj);",
|
||||
" (*me)->encode( n_encoded_info, qrcode );",
|
||||
" } catch(const std::exception &e) {",
|
||||
" throwJavaException(env, &e, method_name);",
|
||||
" } catch (...) {",
|
||||
" throwJavaException(env, 0, method_name);",
|
||||
" }",
|
||||
"}",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"type_dict": {
|
||||
"NativeByteArray": {
|
||||
"j_type" : "byte[]",
|
||||
"jn_type": "byte[]",
|
||||
"jni_type": "jbyteArray",
|
||||
"jni_name": "n_%(n)s",
|
||||
"jni_var": "jbyteArray n_%(n)s = env->NewByteArray(static_cast<jsize>(%(n)s.size())); env->SetByteArrayRegion(n_%(n)s, 0, static_cast<jsize>(%(n)s.size()), reinterpret_cast<const jbyte*>(%(n)s.c_str()));",
|
||||
"cast_from": "std::string"
|
||||
},
|
||||
"vector_NativeByteArray": {
|
||||
"j_type": "List<byte[]>",
|
||||
"jn_type": "List<byte[]>",
|
||||
"jni_type": "jobject",
|
||||
"jni_var": "std::vector< std::string > %(n)s",
|
||||
"suffix": "Ljava_util_List",
|
||||
"v_type": "vector_NativeByteArray"
|
||||
}
|
||||
}
|
||||
}
|
20
modules/objdetect/misc/java/src/cpp/objdetect_converters.cpp
Normal file
20
modules/objdetect/misc/java/src/cpp/objdetect_converters.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "objdetect_converters.hpp"
|
||||
|
||||
#define LOG_TAG "org.opencv.objdetect"
|
||||
|
||||
void Copy_vector_NativeByteArray_to_List(JNIEnv* env, std::vector<std::string>& vs, jobject list)
|
||||
{
|
||||
static jclass juArrayList = ARRAYLIST(env);
|
||||
jmethodID m_clear = LIST_CLEAR(env, juArrayList);
|
||||
jmethodID m_add = LIST_ADD(env, juArrayList);
|
||||
|
||||
env->CallVoidMethod(list, m_clear);
|
||||
for (std::vector<std::string>::iterator it = vs.begin(); it != vs.end(); ++it)
|
||||
{
|
||||
jsize sz = static_cast<jsize>((*it).size());
|
||||
jbyteArray element = env->NewByteArray(sz);
|
||||
env->SetByteArrayRegion(element, 0, sz, reinterpret_cast<const jbyte*>((*it).c_str()));
|
||||
env->CallBooleanMethod(list, m_add, element);
|
||||
env->DeleteLocalRef(element);
|
||||
}
|
||||
}
|
14
modules/objdetect/misc/java/src/cpp/objdetect_converters.hpp
Normal file
14
modules/objdetect/misc/java/src/cpp/objdetect_converters.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
// 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
|
||||
|
||||
#ifndef OBJDETECT_CONVERTERS_HPP
|
||||
#define OBJDETECT_CONVERTERS_HPP
|
||||
|
||||
#include <jni.h>
|
||||
#include "opencv_java.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
void Copy_vector_NativeByteArray_to_List(JNIEnv* env, std::vector<std::string>& vs, jobject list);
|
||||
|
||||
#endif /* OBJDETECT_CONVERTERS_HPP */
|
@ -2,13 +2,19 @@ package org.opencv.test.objdetect;
|
||||
|
||||
import java.util.List;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Size;
|
||||
import org.opencv.objdetect.QRCodeDetector;
|
||||
import org.opencv.objdetect.QRCodeEncoder;
|
||||
import org.opencv.objdetect.QRCodeEncoder_Params;
|
||||
import org.opencv.imgcodecs.Imgcodecs;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.test.OpenCVTestCase;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class QRCodeDetectorTest extends OpenCVTestCase {
|
||||
|
||||
@ -50,4 +56,26 @@ public class QRCodeDetectorTest extends OpenCVTestCase {
|
||||
List < String > expectedResults = Arrays.asList("SKIP", "EXTRA", "TWO STEPS FORWARD", "STEP BACK", "QUESTION", "STEP FORWARD");
|
||||
assertEquals(new HashSet<String>(output), new HashSet<String>(expectedResults));
|
||||
}
|
||||
|
||||
public void testKanji() {
|
||||
byte[] inp = new byte[]{(byte)0x82, (byte)0xb1, (byte)0x82, (byte)0xf1, (byte)0x82, (byte)0xc9, (byte)0x82,
|
||||
(byte)0xbf, (byte)0x82, (byte)0xcd, (byte)0x90, (byte)0xa2, (byte)0x8a, (byte)0x45};
|
||||
QRCodeEncoder_Params params = new QRCodeEncoder_Params();
|
||||
params.set_mode(QRCodeEncoder.MODE_KANJI);
|
||||
QRCodeEncoder encoder = QRCodeEncoder.create(params);
|
||||
|
||||
Mat qrcode = new Mat();
|
||||
encoder.encode(inp, qrcode);
|
||||
Imgproc.resize(qrcode, qrcode, new Size(0, 0), 2, 2, Imgproc.INTER_NEAREST);
|
||||
|
||||
QRCodeDetector detector = new QRCodeDetector();
|
||||
byte[] output = detector.detectAndDecodeBytes(qrcode);
|
||||
assertEquals(detector.getEncoding(), QRCodeEncoder.ECI_SHIFT_JIS);
|
||||
assertArrayEquals(inp, output);
|
||||
|
||||
List < byte[] > outputs = new ArrayList< byte[] >();
|
||||
assertTrue(detector.detectAndDecodeBytesMulti(qrcode, outputs));
|
||||
assertEquals(detector.getEncoding(0), QRCodeEncoder.ECI_SHIFT_JIS);
|
||||
assertArrayEquals(inp, outputs.get(0));
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,31 @@ typedef QRCodeEncoder::Params QRCodeEncoder_Params;
|
||||
typedef HOGDescriptor::HistogramNormType HOGDescriptor_HistogramNormType;
|
||||
typedef HOGDescriptor::DescriptorStorageFormat HOGDescriptor_DescriptorStorageFormat;
|
||||
|
||||
class NativeByteArray
|
||||
{
|
||||
public:
|
||||
inline NativeByteArray& operator=(const std::string& from) {
|
||||
val = from;
|
||||
return *this;
|
||||
}
|
||||
std::string val;
|
||||
};
|
||||
|
||||
class vector_NativeByteArray : public std::vector<std::string> {};
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const NativeByteArray& from)
|
||||
{
|
||||
return PyBytes_FromStringAndSize(from.val.c_str(), from.val.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
PyObject* pyopencv_from(const vector_NativeByteArray& results)
|
||||
{
|
||||
PyObject* list = PyList_New(results.size());
|
||||
for(size_t i = 0; i < results.size(); ++i)
|
||||
PyList_SetItem(list, i, PyBytes_FromStringAndSize(results[i].c_str(), results[i].size()));
|
||||
return list;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
===============================================================================
|
||||
@ -8,7 +9,7 @@ import os
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
from tests_common import NewOpenCVTests
|
||||
from tests_common import NewOpenCVTests, unittest
|
||||
|
||||
class qrcode_detector_test(NewOpenCVTests):
|
||||
|
||||
@ -50,3 +51,36 @@ class qrcode_detector_test(NewOpenCVTests):
|
||||
self.assertTrue("STEP BACK" in decoded_data)
|
||||
self.assertTrue("QUESTION" in decoded_data)
|
||||
self.assertEqual(points.shape, (6, 4, 2))
|
||||
|
||||
def test_decode_non_ascii(self):
|
||||
import sys
|
||||
if sys.version_info[0] < 3:
|
||||
raise unittest.SkipTest('Python 2.x is not supported')
|
||||
|
||||
img = cv.imread(os.path.join(self.extraTestDataPath, 'cv/qrcode/umlaut.png'))
|
||||
self.assertFalse(img is None)
|
||||
detector = cv.QRCodeDetector()
|
||||
decoded_data, _, _ = detector.detectAndDecode(img)
|
||||
self.assertTrue(isinstance(decoded_data, str))
|
||||
self.assertTrue("Müllheimstrasse" in decoded_data)
|
||||
|
||||
def test_kanji(self):
|
||||
inp = "こんにちは世界"
|
||||
inp_bytes = inp.encode("shift-jis")
|
||||
|
||||
params = cv.QRCodeEncoder_Params()
|
||||
params.mode = cv.QRCodeEncoder_MODE_KANJI
|
||||
encoder = cv.QRCodeEncoder_create(params)
|
||||
qrcode = encoder.encode(inp_bytes)
|
||||
qrcode = cv.resize(qrcode, (0, 0), fx=2, fy=2, interpolation=cv.INTER_NEAREST)
|
||||
|
||||
detector = cv.QRCodeDetector()
|
||||
data, _, _ = detector.detectAndDecodeBytes(qrcode)
|
||||
self.assertEqual(data, inp_bytes)
|
||||
self.assertEqual(detector.getEncoding(), cv.QRCodeEncoder_ECI_SHIFT_JIS)
|
||||
self.assertEqual(data.decode("shift-jis"), inp)
|
||||
|
||||
_, data, _, _ = detector.detectAndDecodeBytesMulti(qrcode)
|
||||
self.assertEqual(data[0], inp_bytes)
|
||||
self.assertEqual(detector.getEncoding(0), cv.QRCodeEncoder_ECI_SHIFT_JIS)
|
||||
self.assertEqual(data[0].decode("shift-jis"), inp)
|
||||
|
@ -963,6 +963,7 @@ public:
|
||||
double epsX, epsY;
|
||||
mutable vector<vector<Point2f>> alignmentMarkers;
|
||||
mutable vector<Point2f> updateQrCorners;
|
||||
mutable vector<QRCodeEncoder::ECIEncodings> encodings;
|
||||
bool useAlignmentMarkers = true;
|
||||
|
||||
bool detect(InputArray in, OutputArray points) const override;
|
||||
@ -978,6 +979,8 @@ public:
|
||||
String decodeCurved(InputArray in, InputArray points, OutputArray straight_qrcode);
|
||||
|
||||
std::string detectAndDecodeCurved(InputArray in, OutputArray points, OutputArray straight_qrcode);
|
||||
|
||||
QRCodeEncoder::ECIEncodings getEncoding(int codeIdx);
|
||||
};
|
||||
|
||||
QRCodeDetector::QRCodeDetector() {
|
||||
@ -994,6 +997,13 @@ QRCodeDetector& QRCodeDetector::setEpsY(double epsY) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
QRCodeEncoder::ECIEncodings QRCodeDetector::getEncoding(int codeIdx) {
|
||||
auto& encodings = std::dynamic_pointer_cast<ImplContour>(p)->encodings;
|
||||
CV_Assert(codeIdx >= 0);
|
||||
CV_Assert(codeIdx < static_cast<int>(encodings.size()));
|
||||
return encodings[codeIdx];
|
||||
}
|
||||
|
||||
bool ImplContour::detect(InputArray in, OutputArray points) const
|
||||
{
|
||||
Mat inarr;
|
||||
@ -1035,6 +1045,8 @@ public:
|
||||
uint8_t total_num = 1;
|
||||
} structure_info;
|
||||
|
||||
QRCodeEncoder::ECIEncodings eci;
|
||||
|
||||
protected:
|
||||
double getNumModules();
|
||||
Mat getHomography() {
|
||||
@ -2802,7 +2814,6 @@ static std::string encodeUTF8_bytesarray(const uint8_t* str, const size_t size)
|
||||
|
||||
bool QRDecode::decodingProcess()
|
||||
{
|
||||
QRCodeEncoder::ECIEncodings eci;
|
||||
const uint8_t* payload;
|
||||
size_t payload_len;
|
||||
#ifdef HAVE_QUIRC
|
||||
@ -2895,7 +2906,7 @@ bool QRDecode::decodingProcess()
|
||||
return true;
|
||||
case QRCodeEncoder::EncodeMode::MODE_KANJI:
|
||||
// FIXIT BUG: we must return UTF-8 compatible string
|
||||
CV_LOG_WARNING(NULL, "QR: Kanji is not supported properly");
|
||||
eci = QRCodeEncoder::ECIEncodings::ECI_SHIFT_JIS;
|
||||
result_info.assign((const char*)payload, payload_len);
|
||||
return true;
|
||||
case QRCodeEncoder::EncodeMode::MODE_ECI:
|
||||
@ -2966,6 +2977,7 @@ std::string ImplContour::decode(InputArray in, InputArray points, OutputArray st
|
||||
alignmentMarkers = {qrdec.alignment_coords};
|
||||
updateQrCorners = qrdec.getOriginalPoints();
|
||||
}
|
||||
encodings.resize(1, qrdec.eci);
|
||||
return ok ? decoded_info : std::string();
|
||||
}
|
||||
|
||||
@ -2999,6 +3011,7 @@ String ImplContour::decodeCurved(InputArray in, InputArray points, OutputArray s
|
||||
{
|
||||
qrdec.getStraightBarcode().convertTo(straight_qrcode, CV_8UC1);
|
||||
}
|
||||
encodings.resize(1, qrdec.eci);
|
||||
|
||||
return ok ? decoded_info : std::string();
|
||||
}
|
||||
@ -4111,20 +4124,22 @@ bool ImplContour::decodeMulti(
|
||||
straight_qrcode.assign(tmp_straight_qrcodes);
|
||||
}
|
||||
|
||||
decoded_info.clear();
|
||||
decoded_info.resize(info.size());
|
||||
encodings.resize(info.size());
|
||||
for (size_t i = 0; i < info.size(); i++)
|
||||
{
|
||||
auto& decoder = qrdec[i];
|
||||
encodings[i] = decoder.eci;
|
||||
if (!decoder.isStructured())
|
||||
{
|
||||
decoded_info.push_back(info[i]);
|
||||
decoded_info[i] = info[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store final message corresponding to 0-th code in a sequence.
|
||||
if (decoder.structure_info.sequence_num != 0)
|
||||
{
|
||||
decoded_info.push_back("");
|
||||
decoded_info[i] = "";
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -4145,7 +4160,7 @@ bool ImplContour::decodeMulti(
|
||||
break;
|
||||
}
|
||||
}
|
||||
decoded_info.push_back(decoded);
|
||||
decoded_info[i] = decoded;
|
||||
}
|
||||
|
||||
alignmentMarkers.resize(src_points.size());
|
||||
|
@ -343,9 +343,11 @@ TEST(Objdetect_QRCode_Encode_Kanji, regression)
|
||||
}
|
||||
|
||||
Mat straight_barcode;
|
||||
std::string decoded_info = QRCodeDetector().decode(resized_src, corners, straight_barcode);
|
||||
QRCodeDetector detector;
|
||||
std::string decoded_info = detector.decode(resized_src, corners, straight_barcode);
|
||||
EXPECT_FALSE(decoded_info.empty()) << "The generated QRcode cannot be decoded.";
|
||||
EXPECT_EQ(input_info, decoded_info);
|
||||
EXPECT_EQ(detector.getEncoding(), QRCodeEncoder::ECIEncodings::ECI_SHIFT_JIS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,15 @@ static inline bool getUnicodeString(PyObject * obj, std::string &str)
|
||||
}
|
||||
Py_XDECREF(bytes);
|
||||
}
|
||||
else if (PyBytes_Check(obj))
|
||||
{
|
||||
const char * raw = PyBytes_AsString(obj);
|
||||
if (raw)
|
||||
{
|
||||
str = std::string(raw);
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
else if (PyString_Check(obj))
|
||||
{
|
||||
|
@ -265,6 +265,7 @@ _PREDEFINED_TYPES = (
|
||||
export_name="ExtractMetaCallback",
|
||||
required_modules=("gapi",)
|
||||
),
|
||||
PrimitiveTypeNode("NativeByteArray", "bytes"),
|
||||
)
|
||||
|
||||
PREDEFINED_TYPES = dict(
|
||||
|
Loading…
Reference in New Issue
Block a user