diff --git a/modules/barcode/misc/java/src/cpp/barcode_converters.cpp b/modules/barcode/misc/java/src/cpp/barcode_converters.cpp index 5ab938740e2..b0dbc660029 100644 --- a/modules/barcode/misc/java/src/cpp/barcode_converters.cpp +++ b/modules/barcode/misc/java/src/cpp/barcode_converters.cpp @@ -16,8 +16,8 @@ void Copy_vector_BarcodeType_to_List(JNIEnv* env, std::vectorCallVoidMethod(list, m_clear); - static jclass jInteger = env->FindClass("java/lang/Integer"); - static jmethodID m_create_Integer = env->GetMethodID(jInteger, "", "(I)V"); + jclass jInteger = env->FindClass("java/lang/Integer"); + jmethodID m_create_Integer = CONSTRUCTOR(env, jInteger); for (size_t i = 0; i < vs.size(); ++i) { diff --git a/modules/barcode/misc/java/test/BarcodeDetectorTest.java b/modules/barcode/misc/java/test/BarcodeDetectorTest.java new file mode 100644 index 00000000000..b07ea6fae3f --- /dev/null +++ b/modules/barcode/misc/java/test/BarcodeDetectorTest.java @@ -0,0 +1,51 @@ +package org.opencv.test.barcode; + +import java.util.List; +import org.opencv.core.Mat; +import org.opencv.barcode.BarcodeDetector; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.test.OpenCVTestCase; +import java.util.ArrayList; +import static org.opencv.barcode.Barcode.EAN_13; + +public class BarcodeDetectorTest extends OpenCVTestCase { + + private final static String ENV_OPENCV_TEST_DATA_PATH = "OPENCV_TEST_DATA_PATH"; + private String testDataPath; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + testDataPath = System.getenv(ENV_OPENCV_TEST_DATA_PATH); + if (testDataPath == null) + throw new Exception(ENV_OPENCV_TEST_DATA_PATH + " has to be defined!"); + } + + public void testDetectAndDecode() { + Mat img = Imgcodecs.imread(testDataPath + "/cv/barcode/multiple/4_barcodes.jpg"); + assertFalse(img.empty()); + BarcodeDetector detector = new BarcodeDetector(); + assertNotNull(detector); + List < String > infos = new ArrayList< String >(); + List < Integer > types = new ArrayList< Integer >(); + + boolean result = detector.detectAndDecode(img, infos, types); + assertTrue(result); + assertEquals(infos.size(), 4); + assertEquals(types.size(), 4); + final String[] correctResults = {"9787122276124", "9787118081473", "9787564350840", "9783319200064"}; + for (int i = 0; i < 4; i++) { + assertEquals(types.get(i).intValue(), EAN_13); + result = false; + for (int j = 0; j < 4; j++) { + if (correctResults[j].equals(infos.get(i))) { + result = true; + break; + } + } + assertTrue(result); + } + + } +} diff --git a/modules/barcode/misc/python/test/test_barcode_detector.py b/modules/barcode/misc/python/test/test_barcode_detector.py new file mode 100644 index 00000000000..b939ee567c5 --- /dev/null +++ b/modules/barcode/misc/python/test/test_barcode_detector.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +''' +=============================================================================== +Barcode detect and decode pipeline. +=============================================================================== +''' +import os +import numpy as np +import cv2 as cv + +from tests_common import NewOpenCVTests + +class barcode_detector_test(NewOpenCVTests): + + def test_detect(self): + img = cv.imread(os.path.join(self.extraTestDataPath, 'cv/barcode/multiple/4_barcodes.jpg')) + self.assertFalse(img is None) + detector = cv.barcode_BarcodeDetector() + retval, corners = detector.detect(img) + self.assertTrue(retval) + self.assertEqual(corners.shape, (4, 4, 2)) + + def test_detect_and_decode(self): + img = cv.imread(os.path.join(self.extraTestDataPath, 'cv/barcode/single/book.jpg')) + self.assertFalse(img is None) + detector = cv.barcode_BarcodeDetector() + retval, decoded_info, decoded_type, corners = detector.detectAndDecode(img) + self.assertEqual(decoded_info[0], "9787115279460") + self.assertEqual(decoded_type[0], cv.barcode.EAN_13) + self.assertEqual(corners.shape, (1, 4, 2)) diff --git a/modules/barcode/src/barcode.cpp b/modules/barcode/src/barcode.cpp index e1029c8111f..f07df8ebebe 100644 --- a/modules/barcode/src/barcode.cpp +++ b/modules/barcode/src/barcode.cpp @@ -130,30 +130,17 @@ struct BarcodeDetector::Impl ~Impl() = default; - vector initDecode(const Mat &src, const vector &points) const; + vector initDecode(const Mat &src, const vector> &points) const; std::shared_ptr sr; bool use_nn_sr = false; }; // return cropped and scaled bar img -vector BarcodeDetector::Impl::initDecode(const Mat &src, const vector &points) const +vector BarcodeDetector::Impl::initDecode(const Mat &src, const vector> &points) const { - vector> src_points; - CV_Assert(!points.empty()); - CV_Assert((points.size() % 4) == 0); - src_points.clear(); - for (int i = 0; (uint) i < points.size(); i += 4) - { - vector tempMat{points.cbegin() + i, points.cbegin() + i + 4}; - if (contourArea(tempMat) > 0.0) - { - src_points.push_back(tempMat); - } - } - CV_Assert(!src_points.empty()); vector bar_imgs; - for (auto &corners : src_points) + for (auto &corners : points) { Mat bar_img; cropROI(src, bar_img, corners); @@ -224,8 +211,18 @@ bool BarcodeDetector::decode(InputArray img, InputArray points, vector 0); CV_Assert((points.size().width % 4) == 0); - vector src_points; - points.copyTo(src_points); + vector> src_points; + Mat bar_points = points.getMat(); + bar_points = bar_points.reshape(2, 1); + for (int i = 0; i < bar_points.size().width; i += 4) + { + vector tempMat = bar_points.colRange(i, i + 4); + if (contourArea(tempMat) > 0.0) + { + src_points.push_back(tempMat); + } + } + CV_Assert(!src_points.empty()); vector bar_imgs = p->initDecode(inarr, src_points); BarDecode bardec; bardec.init(bar_imgs); diff --git a/modules/barcode/src/decoder/abs_decoder.cpp b/modules/barcode/src/decoder/abs_decoder.cpp index bc51c4fabbd..9eadf4bc31d 100644 --- a/modules/barcode/src/decoder/abs_decoder.cpp +++ b/modules/barcode/src/decoder/abs_decoder.cpp @@ -73,7 +73,7 @@ patternMatchVariance(const Counter &counter, const std::vector &pattern, ui // 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 std::numeric_limits::max();// max + 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 @@ -89,7 +89,7 @@ patternMatchVariance(const Counter &counter, const std::vector &pattern, ui uint variance = std::abs(cnt - scaledPattern); if (variance > maxIndividualVariance) { - return std::numeric_limits::max(); + return WHITE; } totalVariance += variance; } diff --git a/modules/barcode/src/decoder/abs_decoder.hpp b/modules/barcode/src/decoder/abs_decoder.hpp index a7087eb62eb..cd38eed1d29 100644 --- a/modules/barcode/src/decoder/abs_decoder.hpp +++ b/modules/barcode/src/decoder/abs_decoder.hpp @@ -12,9 +12,9 @@ namespace cv { namespace barcode { using std::string; using std::vector; -constexpr static int BLACK = std::numeric_limits::min(); +constexpr static uchar BLACK = std::numeric_limits::min(); // WHITE elemental area is 0xff -constexpr static int WHITE = std::numeric_limits::max(); +constexpr static uchar WHITE = std::numeric_limits::max(); struct Result diff --git a/modules/barcode/src/decoder/upcean_decoder.cpp b/modules/barcode/src/decoder/upcean_decoder.cpp index 3e07e01a064..aa5a7b8f9f3 100644 --- a/modules/barcode/src/decoder/upcean_decoder.cpp +++ b/modules/barcode/src/decoder/upcean_decoder.cpp @@ -145,11 +145,17 @@ std::pair UPCEANDecoder::decodeROI(const Mat &bar_img) const std::string max_result; BarcodeType max_type = BarcodeType::NONE; - int step = bar_img.rows / (DIVIDE_PART + BIAS_PART); + const int step = bar_img.rows / (DIVIDE_PART + BIAS_PART); Result result; + int row_num; for (int i = 0; i < DIVIDE_PART; ++i) { - const auto *ptr = bar_img.ptr(i * step); + row_num = (i + BIAS_PART / 2) * step; + if (row_num < 0 || row_num > bar_img.rows) + { + continue; + } + const auto *ptr = bar_img.ptr(row_num); vector line(ptr, ptr + bar_img.cols); result = decodeLine(line); if (result.format != BarcodeType::NONE) @@ -159,21 +165,17 @@ std::pair UPCEANDecoder::decodeROI(const Mat &bar_img) const if (result_vote[result.result] > vote_cnt) { vote_cnt = result_vote[result.result]; - if ((vote_cnt << 1) > total_vote) - { - max_result = result.result; - max_type = result.format; - } + max_result = result.result; + max_type = result.format; } } } - - float confidence = 0; - if (total_vote != 0) + if (total_vote == 0 || (vote_cnt << 2) < total_vote) { - confidence = (float) vote_cnt / (float) total_vote; + return std::make_pair(Result(string(), BarcodeType::NONE), 0.0f); } + float confidence = (float) vote_cnt / (float) DIVIDE_PART; //Check if it is UPC-A format if (max_type == BarcodeType::EAN_13 && max_result[0] == '0') { diff --git a/modules/barcode/src/detector/bardetect.cpp b/modules/barcode/src/detector/bardetect.cpp index 544b1e3c25a..72990b3cc8a 100644 --- a/modules/barcode/src/detector/bardetect.cpp +++ b/modules/barcode/src/detector/bardetect.cpp @@ -131,7 +131,7 @@ bool Detect::computeTransformationPoints() void Detect::preprocess() { Mat scharr_x, scharr_y, temp; - static constexpr double THRESHOLD_MAGNITUDE = 56.; + static constexpr double THRESHOLD_MAGNITUDE = 64.; Scharr(resized_barcode, scharr_x, CV_32F, 1, 0); Scharr(resized_barcode, scharr_y, CV_32F, 0, 1); // calculate magnitude of gradient and truncate