Skip to content

Commit ff9b0a1

Browse files
authored
Merge pull request #2929 from SUSTech-OpenCV:bugfix-barcode
Bugfix: barcode module * bugfix: 1. jni crashing while coping vector<BarcodeType> to list; 2. in python/java, assertion fails when calling decode(), because of (2D Mat).copyTo(vector<Point>); 3. the algorithm of decodeROI() is wrong. * add python and java tests * use constexpr
1 parent 342f892 commit ff9b0a1

File tree

8 files changed

+116
-36
lines changed

8 files changed

+116
-36
lines changed

modules/barcode/misc/java/src/cpp/barcode_converters.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ void Copy_vector_BarcodeType_to_List(JNIEnv* env, std::vector<cv::barcode::Barco
1616
jmethodID m_clear = LIST_CLEAR(env, juArrayList);
1717
env->CallVoidMethod(list, m_clear);
1818

19-
static jclass jInteger = env->FindClass("java/lang/Integer");
20-
static jmethodID m_create_Integer = env->GetMethodID(jInteger, "<init>", "(I)V");
19+
jclass jInteger = env->FindClass("java/lang/Integer");
20+
jmethodID m_create_Integer = CONSTRUCTOR(env, jInteger);
2121

2222
for (size_t i = 0; i < vs.size(); ++i)
2323
{
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.opencv.test.barcode;
2+
3+
import java.util.List;
4+
import org.opencv.core.Mat;
5+
import org.opencv.barcode.BarcodeDetector;
6+
import org.opencv.imgcodecs.Imgcodecs;
7+
import org.opencv.test.OpenCVTestCase;
8+
import java.util.ArrayList;
9+
import static org.opencv.barcode.Barcode.EAN_13;
10+
11+
public class BarcodeDetectorTest extends OpenCVTestCase {
12+
13+
private final static String ENV_OPENCV_TEST_DATA_PATH = "OPENCV_TEST_DATA_PATH";
14+
private String testDataPath;
15+
16+
@Override
17+
protected void setUp() throws Exception {
18+
super.setUp();
19+
20+
testDataPath = System.getenv(ENV_OPENCV_TEST_DATA_PATH);
21+
if (testDataPath == null)
22+
throw new Exception(ENV_OPENCV_TEST_DATA_PATH + " has to be defined!");
23+
}
24+
25+
public void testDetectAndDecode() {
26+
Mat img = Imgcodecs.imread(testDataPath + "/cv/barcode/multiple/4_barcodes.jpg");
27+
assertFalse(img.empty());
28+
BarcodeDetector detector = new BarcodeDetector();
29+
assertNotNull(detector);
30+
List < String > infos = new ArrayList< String >();
31+
List < Integer > types = new ArrayList< Integer >();
32+
33+
boolean result = detector.detectAndDecode(img, infos, types);
34+
assertTrue(result);
35+
assertEquals(infos.size(), 4);
36+
assertEquals(types.size(), 4);
37+
final String[] correctResults = {"9787122276124", "9787118081473", "9787564350840", "9783319200064"};
38+
for (int i = 0; i < 4; i++) {
39+
assertEquals(types.get(i).intValue(), EAN_13);
40+
result = false;
41+
for (int j = 0; j < 4; j++) {
42+
if (correctResults[j].equals(infos.get(i))) {
43+
result = true;
44+
break;
45+
}
46+
}
47+
assertTrue(result);
48+
}
49+
50+
}
51+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
'''
3+
===============================================================================
4+
Barcode detect and decode pipeline.
5+
===============================================================================
6+
'''
7+
import os
8+
import numpy as np
9+
import cv2 as cv
10+
11+
from tests_common import NewOpenCVTests
12+
13+
class barcode_detector_test(NewOpenCVTests):
14+
15+
def test_detect(self):
16+
img = cv.imread(os.path.join(self.extraTestDataPath, 'cv/barcode/multiple/4_barcodes.jpg'))
17+
self.assertFalse(img is None)
18+
detector = cv.barcode_BarcodeDetector()
19+
retval, corners = detector.detect(img)
20+
self.assertTrue(retval)
21+
self.assertEqual(corners.shape, (4, 4, 2))
22+
23+
def test_detect_and_decode(self):
24+
img = cv.imread(os.path.join(self.extraTestDataPath, 'cv/barcode/single/book.jpg'))
25+
self.assertFalse(img is None)
26+
detector = cv.barcode_BarcodeDetector()
27+
retval, decoded_info, decoded_type, corners = detector.detectAndDecode(img)
28+
self.assertEqual(decoded_info[0], "9787115279460")
29+
self.assertEqual(decoded_type[0], cv.barcode.EAN_13)
30+
self.assertEqual(corners.shape, (1, 4, 2))

modules/barcode/src/barcode.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -130,30 +130,17 @@ struct BarcodeDetector::Impl
130130

131131
~Impl() = default;
132132

133-
vector<Mat> initDecode(const Mat &src, const vector<Point2f> &points) const;
133+
vector<Mat> initDecode(const Mat &src, const vector<vector<Point2f>> &points) const;
134134

135135
std::shared_ptr<SuperScale> sr;
136136
bool use_nn_sr = false;
137137
};
138138

139139
// return cropped and scaled bar img
140-
vector<Mat> BarcodeDetector::Impl::initDecode(const Mat &src, const vector<Point2f> &points) const
140+
vector<Mat> BarcodeDetector::Impl::initDecode(const Mat &src, const vector<vector<Point2f>> &points) const
141141
{
142-
vector<vector<Point2f>> src_points;
143-
CV_Assert(!points.empty());
144-
CV_Assert((points.size() % 4) == 0);
145-
src_points.clear();
146-
for (int i = 0; (uint) i < points.size(); i += 4)
147-
{
148-
vector<Point2f> tempMat{points.cbegin() + i, points.cbegin() + i + 4};
149-
if (contourArea(tempMat) > 0.0)
150-
{
151-
src_points.push_back(tempMat);
152-
}
153-
}
154-
CV_Assert(!src_points.empty());
155142
vector<Mat> bar_imgs;
156-
for (auto &corners : src_points)
143+
for (auto &corners : points)
157144
{
158145
Mat bar_img;
159146
cropROI(src, bar_img, corners);
@@ -224,8 +211,18 @@ bool BarcodeDetector::decode(InputArray img, InputArray points, vector<std::stri
224211
}
225212
CV_Assert(points.size().width > 0);
226213
CV_Assert((points.size().width % 4) == 0);
227-
vector<Point2f> src_points;
228-
points.copyTo(src_points);
214+
vector<vector<Point2f>> src_points;
215+
Mat bar_points = points.getMat();
216+
bar_points = bar_points.reshape(2, 1);
217+
for (int i = 0; i < bar_points.size().width; i += 4)
218+
{
219+
vector<Point2f> tempMat = bar_points.colRange(i, i + 4);
220+
if (contourArea(tempMat) > 0.0)
221+
{
222+
src_points.push_back(tempMat);
223+
}
224+
}
225+
CV_Assert(!src_points.empty());
229226
vector<Mat> bar_imgs = p->initDecode(inarr, src_points);
230227
BarDecode bardec;
231228
bardec.init(bar_imgs);

modules/barcode/src/decoder/abs_decoder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ patternMatchVariance(const Counter &counter, const std::vector<int> &pattern, ui
7373
// If we don't even have one pixel per unit of bar width, assume this is too small
7474
// to reliably match, so fail:
7575
// and use constexpr functions
76-
return std::numeric_limits<uint>::max();// max
76+
return WHITE;// max
7777
}
7878
// We're going to fake floating-point math in integers. We just need to use more bits.
7979
// Scale up patternLength so that intermediate values below like scaledCounter will have
@@ -89,7 +89,7 @@ patternMatchVariance(const Counter &counter, const std::vector<int> &pattern, ui
8989
uint variance = std::abs(cnt - scaledPattern);
9090
if (variance > maxIndividualVariance)
9191
{
92-
return std::numeric_limits<uint>::max();
92+
return WHITE;
9393
}
9494
totalVariance += variance;
9595
}

modules/barcode/src/decoder/abs_decoder.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ namespace cv {
1212
namespace barcode {
1313
using std::string;
1414
using std::vector;
15-
constexpr static int BLACK = std::numeric_limits<uchar>::min();
15+
constexpr static uchar BLACK = std::numeric_limits<uchar>::min();
1616
// WHITE elemental area is 0xff
17-
constexpr static int WHITE = std::numeric_limits<uchar>::max();
17+
constexpr static uchar WHITE = std::numeric_limits<uchar>::max();
1818

1919

2020
struct Result

modules/barcode/src/decoder/upcean_decoder.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,17 @@ std::pair<Result, float> UPCEANDecoder::decodeROI(const Mat &bar_img) const
145145
std::string max_result;
146146
BarcodeType max_type = BarcodeType::NONE;
147147

148-
int step = bar_img.rows / (DIVIDE_PART + BIAS_PART);
148+
const int step = bar_img.rows / (DIVIDE_PART + BIAS_PART);
149149
Result result;
150+
int row_num;
150151
for (int i = 0; i < DIVIDE_PART; ++i)
151152
{
152-
const auto *ptr = bar_img.ptr<uchar>(i * step);
153+
row_num = (i + BIAS_PART / 2) * step;
154+
if (row_num < 0 || row_num > bar_img.rows)
155+
{
156+
continue;
157+
}
158+
const auto *ptr = bar_img.ptr<uchar>(row_num);
153159
vector<uchar> line(ptr, ptr + bar_img.cols);
154160
result = decodeLine(line);
155161
if (result.format != BarcodeType::NONE)
@@ -159,21 +165,17 @@ std::pair<Result, float> UPCEANDecoder::decodeROI(const Mat &bar_img) const
159165
if (result_vote[result.result] > vote_cnt)
160166
{
161167
vote_cnt = result_vote[result.result];
162-
if ((vote_cnt << 1) > total_vote)
163-
{
164-
max_result = result.result;
165-
max_type = result.format;
166-
}
168+
max_result = result.result;
169+
max_type = result.format;
167170
}
168171
}
169172
}
170-
171-
float confidence = 0;
172-
if (total_vote != 0)
173+
if (total_vote == 0 || (vote_cnt << 2) < total_vote)
173174
{
174-
confidence = (float) vote_cnt / (float) total_vote;
175+
return std::make_pair(Result(string(), BarcodeType::NONE), 0.0f);
175176
}
176177

178+
float confidence = (float) vote_cnt / (float) DIVIDE_PART;
177179
//Check if it is UPC-A format
178180
if (max_type == BarcodeType::EAN_13 && max_result[0] == '0')
179181
{

modules/barcode/src/detector/bardetect.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ bool Detect::computeTransformationPoints()
131131
void Detect::preprocess()
132132
{
133133
Mat scharr_x, scharr_y, temp;
134-
static constexpr double THRESHOLD_MAGNITUDE = 56.;
134+
static constexpr double THRESHOLD_MAGNITUDE = 64.;
135135
Scharr(resized_barcode, scharr_x, CV_32F, 1, 0);
136136
Scharr(resized_barcode, scharr_y, CV_32F, 0, 1);
137137
// calculate magnitude of gradient and truncate

0 commit comments

Comments
 (0)