OLD | NEW |
| (Empty) |
1 // Copyright 2014 PDFium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
6 // Original code is licensed as follows: | |
7 /* | |
8 * Copyright 2008 ZXing authors | |
9 * | |
10 * Licensed under the Apache License, Version 2.0 (the "License"); | |
11 * you may not use this file except in compliance with the License. | |
12 * You may obtain a copy of the License at | |
13 * | |
14 * http://www.apache.org/licenses/LICENSE-2.0 | |
15 * | |
16 * Unless required by applicable law or agreed to in writing, software | |
17 * distributed under the License is distributed on an "AS IS" BASIS, | |
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
19 * See the License for the specific language governing permissions and | |
20 * limitations under the License. | |
21 */ | |
22 | |
23 #include "barcode.h" | |
24 #include "include/BC_DataMatrixDetector.h" | |
25 #include "include/BC_WhiteRectangleDetector.h" | |
26 #include "include/BC_ResultPoint.h" | |
27 #include "include/BC_QRFinderPatternFinder.h" | |
28 #include "include/BC_CommonBitMatrix.h" | |
29 #include "include/BC_QRDetectorResult.h" | |
30 #include "include/BC_QRGridSampler.h" | |
31 const FX_INT32 CBC_DataMatrixDetector::INTEGERS[5] = {0, 1, 2, 3, 4}; | |
32 CBC_DataMatrixDetector::CBC_DataMatrixDetector(CBC_CommonBitMatrix *image): | |
33 m_image(image), m_rectangleDetector(NULL) | |
34 { | |
35 } | |
36 void CBC_DataMatrixDetector::Init(FX_INT32 &e) | |
37 { | |
38 m_rectangleDetector = FX_NEW CBC_WhiteRectangleDetector(m_image); | |
39 m_rectangleDetector->Init(e); | |
40 BC_EXCEPTION_CHECK_ReturnVoid(e); | |
41 } | |
42 CBC_DataMatrixDetector::~CBC_DataMatrixDetector() | |
43 { | |
44 if(m_rectangleDetector != NULL) { | |
45 delete m_rectangleDetector; | |
46 } | |
47 m_rectangleDetector = NULL; | |
48 } | |
49 inline FX_BOOL ResultPointsAndTransitionsComparator(FX_LPVOID a, FX_LPVOID b) | |
50 { | |
51 return ((CBC_ResultPointsAndTransitions *)b)->GetTransitions() > ((CBC_Resul
tPointsAndTransitions *)a)->GetTransitions(); | |
52 } | |
53 CBC_QRDetectorResult *CBC_DataMatrixDetector::Detect(FX_INT32 &e) | |
54 { | |
55 CFX_PtrArray* cornerPoints = m_rectangleDetector->Detect(e); | |
56 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
57 CBC_ResultPoint *pointA = (CBC_ResultPoint*)(*cornerPoints)[0]; | |
58 CBC_ResultPoint *pointB = (CBC_ResultPoint*)(*cornerPoints)[1]; | |
59 CBC_ResultPoint *pointC = (CBC_ResultPoint*)(*cornerPoints)[2]; | |
60 CBC_ResultPoint *pointD = (CBC_ResultPoint*)(*cornerPoints)[3]; | |
61 delete cornerPoints; | |
62 cornerPoints = NULL; | |
63 CFX_PtrArray transitions; | |
64 transitions.Add(TransitionsBetween(pointA, pointB)); | |
65 transitions.Add(TransitionsBetween(pointA, pointC)); | |
66 transitions.Add(TransitionsBetween(pointB, pointD)); | |
67 transitions.Add(TransitionsBetween(pointC, pointD)); | |
68 BC_FX_PtrArray_Sort(transitions, &ResultPointsAndTransitionsComparator); | |
69 delete ( (CBC_ResultPointsAndTransitions *)transitions[2] ); | |
70 delete ( (CBC_ResultPointsAndTransitions *)transitions[3] ); | |
71 CBC_ResultPointsAndTransitions *lSideOne = (CBC_ResultPointsAndTransitions*)
transitions[0]; | |
72 CBC_ResultPointsAndTransitions *lSideTwo = (CBC_ResultPointsAndTransitions*)
transitions[1]; | |
73 CFX_MapPtrTemplate<CBC_ResultPoint*, FX_INT32> pointCount; | |
74 Increment(pointCount, lSideOne->GetFrom()); | |
75 Increment(pointCount, lSideOne->GetTo()); | |
76 Increment(pointCount, lSideTwo->GetFrom()); | |
77 Increment(pointCount, lSideTwo->GetTo()); | |
78 delete ( (CBC_ResultPointsAndTransitions *)transitions[1] ); | |
79 delete ( (CBC_ResultPointsAndTransitions *)transitions[0] ); | |
80 transitions.RemoveAll(); | |
81 CBC_ResultPoint *maybeTopLeft = NULL; | |
82 CBC_ResultPoint *bottomLeft = NULL; | |
83 CBC_ResultPoint *maybeBottomRight = NULL; | |
84 FX_POSITION itBegin = pointCount.GetStartPosition(); | |
85 while(itBegin != NULL) { | |
86 CBC_ResultPoint *key = 0; | |
87 FX_INT32 value = 0; | |
88 pointCount.GetNextAssoc(itBegin, key, value); | |
89 if(value == 2) { | |
90 bottomLeft = key; | |
91 } else { | |
92 if (maybeBottomRight == NULL) { | |
93 maybeBottomRight = key; | |
94 } else { | |
95 maybeTopLeft = key; | |
96 } | |
97 } | |
98 } | |
99 if (maybeTopLeft == NULL || bottomLeft == NULL || maybeBottomRight == NULL)
{ | |
100 delete pointA; | |
101 delete pointB; | |
102 delete pointC; | |
103 delete pointD; | |
104 e = BCExceptionNotFound; | |
105 return NULL; | |
106 } | |
107 CFX_PtrArray corners; | |
108 corners.SetSize(3); | |
109 corners[0] = maybeTopLeft; | |
110 corners[1] = bottomLeft; | |
111 corners[2] = maybeBottomRight; | |
112 OrderBestPatterns(&corners); | |
113 CBC_ResultPoint *bottomRight = (CBC_ResultPoint*)corners[0]; | |
114 bottomLeft = (CBC_ResultPoint*)corners[1]; | |
115 CBC_ResultPoint *topLeft = (CBC_ResultPoint*)corners[2]; | |
116 CBC_ResultPoint *topRight = NULL; | |
117 FX_INT32 value; | |
118 if (!pointCount.Lookup(pointA, value)) { | |
119 topRight = pointA; | |
120 } else if (!pointCount.Lookup(pointB, value)) { | |
121 topRight = pointB; | |
122 } else if (!pointCount.Lookup(pointC, value)) { | |
123 topRight = pointC; | |
124 } else { | |
125 topRight = pointD; | |
126 } | |
127 FX_INT32 dimensionTop = CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transiti
onsBetween(topLeft, topRight))->GetTransitions(); | |
128 FX_INT32 dimensionRight = CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transi
tionsBetween(bottomRight, topRight))->GetTransitions(); | |
129 if ((dimensionTop & 0x01) == 1) { | |
130 dimensionTop++; | |
131 } | |
132 dimensionTop += 2; | |
133 if ((dimensionRight & 0x01) == 1) { | |
134 dimensionRight++; | |
135 } | |
136 dimensionRight += 2; | |
137 CBC_AutoPtr<CBC_CommonBitMatrix> bits(NULL); | |
138 CBC_AutoPtr<CBC_ResultPoint> correctedTopRight(NULL); | |
139 if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dime
nsionTop) { | |
140 correctedTopRight = | |
141 CBC_AutoPtr<CBC_ResultPoint>(CorrectTopRightRectangular(bottomLeft,
bottomRight, topLeft, topRight, | |
142 dimensionTop, dimensionRight)); | |
143 if (correctedTopRight.get() == NULL) { | |
144 correctedTopRight = CBC_AutoPtr<CBC_ResultPoint>(topRight); | |
145 } else { | |
146 delete topRight; | |
147 topRight = NULL; | |
148 } | |
149 dimensionTop = CBC_AutoPtr<CBC_ResultPointsAndTransitions>(TransitionsBe
tween(topLeft, correctedTopRight.get()))->GetTransitions(); | |
150 dimensionRight = CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transitions
Between(bottomRight, correctedTopRight.get()))->GetTransitions(); | |
151 if ((dimensionTop & 0x01) == 1) { | |
152 dimensionTop++; | |
153 } | |
154 if ((dimensionRight & 0x01) == 1) { | |
155 dimensionRight++; | |
156 } | |
157 bits = CBC_AutoPtr<CBC_CommonBitMatrix>(SampleGrid(m_image, topLeft, bot
tomLeft, bottomRight, | |
158 correctedTopRight.get(), dimensi
onTop, dimensionRight, e)); | |
159 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
160 } else { | |
161 FX_INT32 dimension = FX_MIN(dimensionRight, dimensionTop); | |
162 correctedTopRight = CBC_AutoPtr<CBC_ResultPoint>(CorrectTopRight(bottomL
eft, bottomRight, | |
163 topLeft, topRight, dimension)); | |
164 if (correctedTopRight.get() == NULL) { | |
165 correctedTopRight = CBC_AutoPtr<CBC_ResultPoint>(topRight); | |
166 } else { | |
167 delete topRight; | |
168 topRight = NULL; | |
169 } | |
170 FX_INT32 dimensionCorrected = FX_MAX(CBC_AutoPtr<CBC_ResultPointsAndTran
sitions>(TransitionsBetween(topLeft, correctedTopRight.get()))->GetTransitions()
, | |
171 CBC_AutoPtr<CBC_ResultPointsAndTran
sitions>(TransitionsBetween(bottomRight, correctedTopRight.get()))->GetTransitio
ns()); | |
172 dimensionCorrected++; | |
173 if ((dimensionCorrected & 0x01) == 1) { | |
174 dimensionCorrected++; | |
175 } | |
176 bits = CBC_AutoPtr<CBC_CommonBitMatrix>(SampleGrid(m_image, | |
177 topLeft, | |
178 bottomLeft, | |
179 bottomRight, | |
180 correctedTopRight.get(), | |
181 dimensionCorrected, | |
182 dimensionCorrected, e)); | |
183 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
184 } | |
185 CFX_PtrArray *result = FX_NEW CFX_PtrArray; | |
186 result->SetSize(4); | |
187 result->Add(topLeft); | |
188 result->Add(bottomLeft); | |
189 result->Add(bottomRight); | |
190 result->Add(correctedTopRight.release()); | |
191 return FX_NEW CBC_QRDetectorResult(bits.release(), result); | |
192 } | |
193 CBC_ResultPoint *CBC_DataMatrixDetector::CorrectTopRightRectangular(CBC_ResultPo
int *bottomLeft, CBC_ResultPoint *bottomRight, CBC_ResultPoint *topLeft, CBC_Res
ultPoint *topRight, FX_INT32 dimensionTop, FX_INT32 dimensionRight) | |
194 { | |
195 FX_FLOAT corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT)dimensionTop; | |
196 FX_INT32 norm = Distance(topLeft, topRight); | |
197 FX_FLOAT cos = (topRight->GetX() - topLeft->GetX()) / norm; | |
198 FX_FLOAT sin = (topRight->GetY() - topLeft->GetY()) / norm; | |
199 CBC_AutoPtr<CBC_ResultPoint> c1(FX_NEW CBC_ResultPoint(topRight->GetX() + co
rr * cos, topRight->GetY() + corr * sin)); | |
200 corr = Distance(bottomLeft, topLeft) / (FX_FLOAT)dimensionRight; | |
201 norm = Distance(bottomRight, topRight); | |
202 cos = (topRight->GetX() - bottomRight->GetX()) / norm; | |
203 sin = (topRight->GetY() - bottomRight->GetY()) / norm; | |
204 CBC_AutoPtr<CBC_ResultPoint> c2(FX_NEW CBC_ResultPoint(topRight->GetX() + co
rr * cos, topRight->GetY() + corr * sin)); | |
205 if (!IsValid(c1.get())) { | |
206 if (IsValid(c2.get())) { | |
207 return c2.release(); | |
208 } | |
209 return NULL; | |
210 } else if (!IsValid(c2.get())) { | |
211 return c1.release(); | |
212 } | |
213 FX_INT32 l1 = FXSYS_abs(dimensionTop - CBC_AutoPtr<CBC_ResultPointsAndTransi
tions>(TransitionsBetween(topLeft, c1.get()))->GetTransitions()) + | |
214 FXSYS_abs(dimensionRight - CBC_AutoPtr<CBC_ResultPointsAndTran
sitions>(TransitionsBetween(bottomRight, c1.get()))->GetTransitions()); | |
215 FX_INT32 l2 = FXSYS_abs(dimensionTop - CBC_AutoPtr<CBC_ResultPointsAndTransi
tions>(TransitionsBetween(topLeft, c2.get()))->GetTransitions()) + | |
216 FXSYS_abs(dimensionRight - CBC_AutoPtr<CBC_ResultPointsAndTran
sitions>(TransitionsBetween(bottomRight, c2.get()))->GetTransitions()); | |
217 if (l1 <= l2) { | |
218 return c1.release(); | |
219 } | |
220 return c2.release(); | |
221 } | |
222 CBC_ResultPoint *CBC_DataMatrixDetector::CorrectTopRight(CBC_ResultPoint *bottom
Left, CBC_ResultPoint *bottomRight, CBC_ResultPoint *topLeft, CBC_ResultPoint *t
opRight, FX_INT32 dimension) | |
223 { | |
224 FX_FLOAT corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT) dimension; | |
225 FX_INT32 norm = Distance(topLeft, topRight); | |
226 FX_FLOAT cos = (topRight->GetX() - topLeft->GetX()) / norm; | |
227 FX_FLOAT sin = (topRight->GetY() - topLeft->GetY()) / norm; | |
228 CBC_AutoPtr<CBC_ResultPoint> c1(FX_NEW CBC_ResultPoint(topRight->GetX() + co
rr * cos, topRight->GetY() + corr * sin)); | |
229 corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT) dimension; | |
230 norm = Distance(bottomRight, topRight); | |
231 cos = (topRight->GetX() - bottomRight->GetX()) / norm; | |
232 sin = (topRight->GetY() - bottomRight->GetY()) / norm; | |
233 CBC_AutoPtr<CBC_ResultPoint> c2(FX_NEW CBC_ResultPoint(topRight->GetX() + co
rr * cos, topRight->GetY() + corr * sin)); | |
234 if (!IsValid(c1.get())) { | |
235 if (IsValid(c2.get())) { | |
236 return c2.release(); | |
237 } | |
238 return NULL; | |
239 } else if (!IsValid(c2.get())) { | |
240 return c1.release(); | |
241 } | |
242 FX_INT32 l1 = FXSYS_abs(CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transiti
onsBetween(topLeft, c1.get()))->GetTransitions() - | |
243 CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transiti
onsBetween(bottomRight, c1.get()))->GetTransitions()); | |
244 FX_INT32 l2 = FXSYS_abs(CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transiti
onsBetween(topLeft, c2.get()))->GetTransitions() - | |
245 CBC_AutoPtr<CBC_ResultPointsAndTransitions>(Transiti
onsBetween(bottomRight, c2.get()))->GetTransitions()); | |
246 return l1 <= l2 ? c1.release() : c2.release(); | |
247 } | |
248 FX_BOOL CBC_DataMatrixDetector::IsValid(CBC_ResultPoint *p) | |
249 { | |
250 return p->GetX() >= 0 && p->GetX() < m_image->GetWidth() && p->GetY() > 0 &&
p->GetY() < m_image->GetHeight(); | |
251 } | |
252 FX_INT32 CBC_DataMatrixDetector::Round(FX_FLOAT d) | |
253 { | |
254 return (FX_INT32) (d + 0.5f); | |
255 } | |
256 FX_INT32 CBC_DataMatrixDetector::Distance(CBC_ResultPoint *a, CBC_ResultPoint *b
) | |
257 { | |
258 return Round((FX_FLOAT) sqrt((a->GetX() - b->GetX()) | |
259 * (a->GetX() - b->GetX()) + (a->GetY() - b->Get
Y()) | |
260 * (a->GetY() - b->GetY()))); | |
261 } | |
262 void CBC_DataMatrixDetector::Increment(CFX_MapPtrTemplate<CBC_ResultPoint*, FX_I
NT32> &table, CBC_ResultPoint *key) | |
263 { | |
264 FX_INT32 value; | |
265 if(table.Lookup(key, value)) { | |
266 table.SetAt(key, INTEGERS[value + 1]); | |
267 } else { | |
268 table.SetAt(key, INTEGERS[1]); | |
269 } | |
270 } | |
271 CBC_CommonBitMatrix *CBC_DataMatrixDetector::SampleGrid(CBC_CommonBitMatrix *ima
ge, | |
272 CBC_ResultPoint *topLeft, | |
273 CBC_ResultPoint *bottomLeft, | |
274 CBC_ResultPoint *bottomRight, | |
275 CBC_ResultPoint *topRight, | |
276 FX_INT32 dimensionX, FX_INT32 dimensionY, FX_INT32 &e) | |
277 { | |
278 CBC_QRGridSampler &sampler = CBC_QRGridSampler::GetInstance(); | |
279 CBC_CommonBitMatrix* cbm = sampler.SampleGrid(image, | |
280 dimensionX, | |
281 dimensionY, | |
282 0.5f, | |
283 0.5f, | |
284 dimensionX - 0.5f, | |
285 0.5f, | |
286 dimensionX - 0.5f, | |
287 dimensionY - 0.5f, | |
288 0.5f, | |
289 dimensionY - 0.5f, | |
290 topLeft->GetX(), | |
291 topLeft->GetY(), | |
292 topRight->GetX(), | |
293 topRight->GetY(), | |
294 bottomRight->GetX(), | |
295 bottomRight->GetY(), | |
296 bottomLeft->GetX(), | |
297 bottomLeft->GetY(), e); | |
298 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
299 return cbm; | |
300 } | |
301 CBC_ResultPointsAndTransitions *CBC_DataMatrixDetector::TransitionsBetween(CBC_R
esultPoint *from, CBC_ResultPoint *to) | |
302 { | |
303 FX_INT32 fromX = (FX_INT32) from->GetX(); | |
304 FX_INT32 fromY = (FX_INT32) from->GetY(); | |
305 FX_INT32 toX = (FX_INT32) to->GetX(); | |
306 FX_INT32 toY = (FX_INT32) to->GetY(); | |
307 FX_BOOL steep = FXSYS_abs(toY - fromY) > FXSYS_abs(toX - fromX); | |
308 if (steep) { | |
309 FX_INT32 temp = fromX; | |
310 fromX = fromY; | |
311 fromY = temp; | |
312 temp = toX; | |
313 toX = toY; | |
314 toY = temp; | |
315 } | |
316 FX_INT32 dx = FXSYS_abs(toX - fromX); | |
317 FX_INT32 dy = FXSYS_abs(toY - fromY); | |
318 FX_INT32 error = -dx >> 1; | |
319 FX_INT32 ystep = fromY < toY ? 1 : -1; | |
320 FX_INT32 xstep = fromX < toX ? 1 : -1; | |
321 FX_INT32 transitions = 0; | |
322 FX_BOOL inBlack = m_image->Get(steep ? fromY : fromX, steep ? fromX : fromY)
; | |
323 for (FX_INT32 x = fromX, y = fromY; x != toX; x += xstep) { | |
324 FX_BOOL isBlack = m_image->Get(steep ? y : x, steep ? x : y); | |
325 if (isBlack != inBlack) { | |
326 transitions++; | |
327 inBlack = isBlack; | |
328 } | |
329 error += dy; | |
330 if (error > 0) { | |
331 if (y == toY) { | |
332 break; | |
333 } | |
334 y += ystep; | |
335 error -= dx; | |
336 } | |
337 } | |
338 return FX_NEW CBC_ResultPointsAndTransitions(from, to, transitions); | |
339 } | |
340 void CBC_DataMatrixDetector::OrderBestPatterns(CFX_PtrArray *patterns) | |
341 { | |
342 FX_FLOAT abDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[0], (
CBC_ResultPoint*)(*patterns)[1]); | |
343 FX_FLOAT bcDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[1], (
CBC_ResultPoint*)(*patterns)[2]); | |
344 FX_FLOAT acDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[0], (
CBC_ResultPoint*)(*patterns)[2]); | |
345 CBC_ResultPoint *topLeft, *topRight, *bottomLeft; | |
346 if (bcDistance >= abDistance && bcDistance >= acDistance) { | |
347 topLeft = (CBC_ResultPoint*)(*patterns)[0]; | |
348 topRight = (CBC_ResultPoint*)(*patterns)[1]; | |
349 bottomLeft = (CBC_ResultPoint*)(*patterns)[2]; | |
350 } else if (acDistance >= bcDistance && acDistance >= abDistance) { | |
351 topLeft = (CBC_ResultPoint*)(*patterns)[1]; | |
352 topRight = (CBC_ResultPoint*)(*patterns)[0]; | |
353 bottomLeft = (CBC_ResultPoint*)(*patterns)[2]; | |
354 } else { | |
355 topLeft = (CBC_ResultPoint*)(*patterns)[2]; | |
356 topRight = (CBC_ResultPoint*)(*patterns)[0]; | |
357 bottomLeft = (CBC_ResultPoint*)(*patterns)[1]; | |
358 } | |
359 if ((bottomLeft->GetY() - topLeft->GetY()) * (topRight->GetX() - topLeft->Ge
tX()) < (bottomLeft->GetX() | |
360 - topLeft->GetX()) * (topRight->GetY() - topLeft->GetY())) { | |
361 CBC_ResultPoint *temp = topRight; | |
362 topRight = bottomLeft; | |
363 bottomLeft = temp; | |
364 } | |
365 (*patterns)[0] = bottomLeft; | |
366 (*patterns)[1] = topLeft; | |
367 (*patterns)[2] = topRight; | |
368 } | |
OLD | NEW |