libdmtx 0.7.8.7
libdmtx is a software library that enables programs to read and write Data Matrix barcodes of the modern ECC200 variety.
Loading...
Searching...
No Matches
dmtxregion.c
Go to the documentation of this file.
1
18#include <assert.h>
19#include <math.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "dmtx.h"
24#include "dmtxstatic.h"
25
26#define DMTX_HOUGH_RES 180
27
33{
34 DmtxRegion *regCopy;
35
36 regCopy = (DmtxRegion *)malloc(sizeof(DmtxRegion));
37 if (regCopy == NULL) {
38 return NULL;
39 }
40
41 memcpy(regCopy, reg, sizeof(DmtxRegion));
42
43 return regCopy;
44}
45
52{
53 if (reg == NULL || *reg == NULL) {
54 return DmtxFail;
55 }
56
57 free(*reg);
58
59 *reg = NULL;
60
61 return DmtxPass;
62}
63
70{
71 int locStatus;
72 DmtxPixelLoc loc;
73 DmtxRegion *reg;
74
75 /* Continue until we find a region or run out of chances */
76 for (;;) {
77 locStatus = popGridLocation(&(dec->grid), &loc);
78 if (locStatus == DmtxRangeEnd) {
79 break;
80 }
81
82 /* 扫描确认loc坐标位置是否存在二维码区域 */
83 reg = dmtxRegionScanPixel(dec, loc.x, loc.y);
84 if (reg != NULL) {
85 return reg; // 成功找到一个二维码区域
86 }
87
88 /* 超时检测 */
89 if (timeout != NULL && dmtxTimeExceeded(*timeout)) {
90 break;
91 }
92 }
93
94 return NULL;
95}
96
100extern DmtxRegion *dmtxRegionScanPixel(DmtxDecode *dec, int x, int y)
101{
102 unsigned char *cache;
103 DmtxRegion reg;
104 DmtxPointFlow flowBegin;
105 DmtxPixelLoc loc;
106
107 loc.x = x;
108 loc.y = y;
109
110 cache = dmtxDecodeGetCache(dec, loc.x, loc.y);
111 if (cache == NULL) {
112 return NULL;
113 }
114
115 if ((int)(*cache & 0x80) != 0x00) {
116 return NULL;
117 }
118
119 /* Test for presence of any reasonable edge at this location */
120 flowBegin = matrixRegionSeekEdge(dec, loc);
121 if (flowBegin.mag < (int)(dec->edgeThresh * 7.65 + 0.5)) {
122 return NULL;
123 }
124
125 memset(&reg, 0x00, sizeof(DmtxRegion));
126
127 /* Determine barcode orientation */
128 if (matrixRegionOrientation(dec, &reg, flowBegin) == DmtxFail) {
129 return NULL;
130 }
131 if (dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail) {
132 return NULL;
133 }
134
135 /* 匹配顶部点线 */
137 return NULL;
138 }
139 if (dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail) {
140 return NULL;
141 }
142
143 /* 匹配右侧点线 */
145 return NULL;
146 }
147 if (dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail) {
148 return NULL;
149 }
150
153 }
154
155 /* 计算最匹配的二维码符号尺寸 */
156 if (matrixRegionFindSize(dec, &reg) == DmtxFail) {
157 return NULL;
158 }
159
160 /* Found a valid matrix region */
161 return dmtxRegionCreate(&reg);
162}
163
177{
178 int i;
179 int strongIdx;
180 int channelCount;
181 DmtxPointFlow flow, flowPlane[3] = {};
182 DmtxPointFlow flowPos, flowPosBack;
183 DmtxPointFlow flowNeg, flowNegBack;
184
185 channelCount = dec->image->channelCount;
186
187 /* Find whether red, green, or blue shows the strongest edge */
188 strongIdx = 0;
189 for (i = 0; i < channelCount; i++) {
190 flowPlane[i] = getPointFlow(dec, i, loc, dmtxNeighborNone);
191 if (i > 0 && flowPlane[i].mag > flowPlane[strongIdx].mag) {
192 strongIdx = i;
193 }
194 }
195
196 if (flowPlane[strongIdx].mag < 10) { // 如果最强边缘的幅度小于阈值,返回空白边缘
197 return dmtxBlankEdge;
198 }
199
200 flow = flowPlane[strongIdx];
201
202 // 寻找正负方向上的最强邻近边缘
203 flowPos = findStrongestNeighbor(dec, flow, +1);
204 flowNeg = findStrongestNeighbor(dec, flow, -1);
205
206 // 来回验证是否该起点的能不能按照相同的位置原路返回
207 //
208 // 这个机制是为了保证选取的起始点位在规定的搜索时间内能够闭合:
209 // 闭合的自然条件是按照原来的方向返回该点位如果这个机制无法通过,
210 // 则说明选择的点位在返回时和出发时有两个不同的方向,这种情况在一个闭合的轮廓边界中是不允许的
211 if (flowPos.mag != 0 && flowNeg.mag != 0) {
212 flowPosBack = findStrongestNeighbor(dec, flowPos, -1);
213 flowNegBack = findStrongestNeighbor(dec, flowNeg, +1);
214 if (flowPos.arrive == (flowPosBack.arrive + 4) % 8 && flowNeg.arrive == (flowNegBack.arrive + 4) % 8) {
215 // 如果沿着flow点往正负方向走,如果下一个点能够通过同样的方式走回到flow点,那么认为这个点是有可能形成一个闭合的形状的
217 if (cbPlotPoint) {
218 cbPlotPoint(flow.loc, 0.0F, 1, 1);
219 }
220 return flow;
221 }
222 }
223
224 return dmtxBlankEdge;
225}
226
241{
242 int cross;
243 int minArea;
244 int scale;
245 int symbolShape;
246 int maxDiagonal;
247 DmtxPassFail err;
248 DmtxBestLine line1x, line2x;
249 DmtxBestLine line2n, line2p;
250 DmtxFollow fTmp;
251
252 if (dec->sizeIdxExpected == DmtxSymbolSquareAuto ||
253 (dec->sizeIdxExpected >= DmtxSymbol10x10 && dec->sizeIdxExpected <= DmtxSymbol144x144)) {
254 symbolShape = DmtxSymbolSquareAuto;
255 } else if (dec->sizeIdxExpected == DmtxSymbolRectAuto ||
256 (dec->sizeIdxExpected >= DmtxSymbol8x18 && dec->sizeIdxExpected <= DmtxSymbol16x48)) {
257 symbolShape = DmtxSymbolRectAuto;
258 } else {
259 symbolShape = DmtxSymbolShapeAuto;
260 }
261
262 if (dec->edgeMax != DmtxUndefined) {
263 if (symbolShape == DmtxSymbolRectAuto) {
264 maxDiagonal = (int)(1.23 * dec->edgeMax + 0.5); /* sqrt(5/4) + 10% */
265 } else {
266 maxDiagonal = (int)(1.56 * dec->edgeMax + 0.5); /* sqrt(2) + 10% */
267 }
268 } else {
269 maxDiagonal = DmtxUndefined;
270 }
271
272 /* 以十字搜索像素点为起点,分别从正负方向寻边 */
273 err = trailBlazeContinuous(dec, reg, begin, maxDiagonal);
274 if (err == DmtxFail || reg->stepsTotal < 40) {
275 trailClear(dec, reg, 0x40);
276 return DmtxFail;
277 }
278
279 /* Filter out region candidates that are smaller than expected */
280 if (dec->edgeMin != DmtxUndefined) {
281 scale = dmtxDecodeGetProp(dec, DmtxPropScale);
282
283 if (symbolShape == DmtxSymbolSquareAuto) {
284 minArea = (dec->edgeMin * dec->edgeMin) / (scale * scale);
285 } else {
286 minArea = (2 * dec->edgeMin * dec->edgeMin) / (scale * scale);
287 }
288
289 if ((reg->boundMax.x - reg->boundMin.x) * (reg->boundMax.y - reg->boundMin.y) < minArea) {
290 trailClear(dec, reg, 0x40);
291 return DmtxFail;
292 }
293 }
294
295 /* 寻找第一条直线 */
296 line1x = findBestSolidLine(dec, reg, 0, 0, +1, DmtxUndefined);
297 if (line1x.mag < 5) {
298 trailClear(dec, reg, 0x40);
299 return DmtxFail;
300 }
301
302 err = findTravelLimits(dec, reg, &line1x);
303 if (err == DmtxFail || line1x.distSq < 100 || line1x.devn * 10 >= sqrt((double)line1x.distSq)) {
304 trailClear(dec, reg, 0x40);
305 return DmtxFail;
306 }
307 DmtxAssert(line1x.stepPos >= line1x.stepNeg);
308
309 /* 第一条直线正向搜索另一条直线 */
310 fTmp = followSeek(dec, reg, line1x.stepPos + 5);
311 line2p = findBestSolidLine(dec, reg, fTmp.step, line1x.stepNeg, +1, line1x.angle);
312
313 /* 第一条直线负向搜索另一条直线 */
314 fTmp = followSeek(dec, reg, line1x.stepNeg - 5);
315 line2n = findBestSolidLine(dec, reg, fTmp.step, line1x.stepPos, -1, line1x.angle);
316 if (max(line2p.mag, line2n.mag) < 5) {
317 return DmtxFail;
318 }
319
320 if (line2p.mag > line2n.mag) {
321 line2x = line2p;
322 err = findTravelLimits(dec, reg, &line2x);
323 if (err == DmtxFail || line2x.distSq < 100 || line2x.devn * 10 >= sqrt((double)line2x.distSq)) {
324 return DmtxFail;
325 }
326
327 cross = ((line1x.locPos.x - line1x.locNeg.x) * (line2x.locPos.y - line2x.locNeg.y)) -
328 ((line1x.locPos.y - line1x.locNeg.y) * (line2x.locPos.x - line2x.locNeg.x));
329 if (cross > 0) {
330 /* Condition 2 */
331 reg->polarity = +1;
332 reg->locR = line2x.locPos;
333 reg->stepR = line2x.stepPos;
334 reg->locT = line1x.locNeg;
335 reg->stepT = line1x.stepNeg;
336 reg->leftLoc = line1x.locBeg;
337 reg->leftAngle = line1x.angle;
338 reg->bottomLoc = line2x.locBeg;
339 reg->bottomAngle = line2x.angle;
340 reg->leftLine = line1x;
341 reg->bottomLine = line2x;
342 } else {
343 /* Condition 3 */
344 reg->polarity = -1;
345 reg->locR = line1x.locNeg;
346 reg->stepR = line1x.stepNeg;
347 reg->locT = line2x.locPos;
348 reg->stepT = line2x.stepPos;
349 reg->leftLoc = line2x.locBeg;
350 reg->leftAngle = line2x.angle;
351 reg->bottomLoc = line1x.locBeg;
352 reg->bottomAngle = line1x.angle;
353 reg->leftLine = line2x;
354 reg->bottomLine = line1x;
355 }
356 } else {
357 line2x = line2n;
358 err = findTravelLimits(dec, reg, &line2x);
359 if (err == DmtxFail || line2x.distSq < 100 || line2x.devn / sqrt((double)line2x.distSq) >= 0.1) {
360 return DmtxFail;
361 }
362
363 cross = ((line1x.locNeg.x - line1x.locPos.x) * (line2x.locNeg.y - line2x.locPos.y)) -
364 ((line1x.locNeg.y - line1x.locPos.y) * (line2x.locNeg.x - line2x.locPos.x));
365 if (cross > 0) {
366 /* Condition 1 */
367 reg->polarity = -1;
368 reg->locR = line2x.locNeg;
369 reg->stepR = line2x.stepNeg;
370 reg->locT = line1x.locPos;
371 reg->stepT = line1x.stepPos;
372 reg->leftLoc = line1x.locBeg;
373 reg->leftAngle = line1x.angle;
374 reg->bottomLoc = line2x.locBeg;
375 reg->bottomAngle = line2x.angle;
376 reg->leftLine = line1x;
377 reg->bottomLine = line2x;
378 } else {
379 /* Condition 4 */
380 reg->polarity = +1;
381 reg->locR = line1x.locPos;
382 reg->stepR = line1x.stepPos;
383 reg->locT = line2x.locNeg;
384 reg->stepT = line2x.stepNeg;
385 reg->leftLoc = line2x.locBeg;
386 reg->leftAngle = line2x.angle;
387 reg->bottomLoc = line1x.locBeg;
388 reg->bottomAngle = line1x.angle;
389 reg->leftLine = line2x;
390 reg->bottomLine = line1x;
391 }
392 }
393
394 if (cbPlotPoint) {
395 cbPlotPoint(reg->locR, 180.0F /*青*/, 1, 1);
396 cbPlotPoint(reg->locT, 180.0F /*青*/, 1, 1);
397 }
398
399 reg->leftKnown = reg->bottomKnown = 1;
400
401 return DmtxPass;
402}
403
408{
409 long xDelta, yDelta;
410
411 xDelta = a.x - b.x;
412 yDelta = a.y - b.y;
413
414 return (xDelta * xDelta) + (yDelta * yDelta);
415}
416
422 DmtxVector2 p11, DmtxVector2 p01)
423{
424 double xMax, yMax;
425 double tx, ty, phi, shx, scx, scy, skx, sky;
426 double dimOT, dimOR, dimTX, dimRX, ratio;
427 DmtxVector2 vOT, vOR, vTX, vRX, vTmp;
428 DmtxMatrix3 m, mtxy, mphi, mshx, mscx, mscy, mscxy, msky, mskx;
429
430 xMax = (double)(dmtxDecodeGetProp(dec, DmtxPropWidth) - 1);
431 yMax = (double)(dmtxDecodeGetProp(dec, DmtxPropHeight) - 1);
432
433 if (p00.x < 0.0 || p00.y < 0.0 || p00.x > xMax || p00.y > yMax || p01.x < 0.0 || p01.y < 0.0 || p01.x > xMax ||
434 p01.y > yMax || p10.x < 0.0 || p10.y < 0.0 || p10.x > xMax || p10.y > yMax) {
435 return DmtxFail;
436 }
437
438 dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &p01, &p00)); /* XXX could use MagSquared() */
439 dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &p10, &p00));
440 dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTX, &p11, &p01));
441 dimRX = dmtxVector2Mag(dmtxVector2Sub(&vRX, &p11, &p10));
442
443 /* Verify that sides are reasonably long */
444 if (dimOT <= 8.0 || dimOR <= 8.0 || dimTX <= 8.0 || dimRX <= 8.0) {
445 return DmtxFail;
446 }
447
448 /* Verify that the 4 corners define a reasonably fat quadrilateral */
449 ratio = dimOT / dimRX;
450 if (ratio <= 0.5 || ratio >= 2.0) {
451 return DmtxFail;
452 }
453
454 ratio = dimOR / dimTX;
455 if (ratio <= 0.5 || ratio >= 2.0) {
456 return DmtxFail;
457 }
458
459 /* Verify this is not a bowtie shape */
460 if (dmtxVector2Cross(&vOR, &vRX) <= 0.0 || dmtxVector2Cross(&vOT, &vTX) >= 0.0) {
461 return DmtxFail;
462 }
463
464 if (rightAngleTrueness(p00, p10, p11, M_PI_2) <= dec->squareDevn) {
465 return DmtxFail;
466 }
467 if (rightAngleTrueness(p10, p11, p01, M_PI_2) <= dec->squareDevn) {
468 return DmtxFail;
469 }
470
471 /* Calculate values needed for transformations */
472 tx = -1 * p00.x;
473 ty = -1 * p00.y;
474 dmtxMatrix3Translate(mtxy, tx, ty);
475
476 phi = atan2(vOT.x, vOT.y);
477 dmtxMatrix3Rotate(mphi, phi);
478 dmtxMatrix3Multiply(m, mtxy, mphi);
479
480 dmtxMatrix3VMultiply(&vTmp, &p10, m);
481 shx = -vTmp.y / vTmp.x;
482 dmtxMatrix3Shear(mshx, 0.0, shx);
483 dmtxMatrix3MultiplyBy(m, mshx);
484
485 scx = 1.0 / vTmp.x;
486 dmtxMatrix3Scale(mscx, scx, 1.0);
487 dmtxMatrix3MultiplyBy(m, mscx);
488
489 dmtxMatrix3VMultiply(&vTmp, &p11, m);
490 scy = 1.0 / vTmp.y;
491 dmtxMatrix3Scale(mscy, 1.0, scy);
492 dmtxMatrix3MultiplyBy(m, mscy);
493
494 dmtxMatrix3VMultiply(&vTmp, &p11, m);
495 skx = vTmp.x;
496 dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0);
497 dmtxMatrix3MultiplyBy(m, mskx);
498
499 dmtxMatrix3VMultiply(&vTmp, &p01, m);
500 sky = vTmp.y;
501 dmtxMatrix3LineSkewTop(msky, sky, 1.0, 1.0);
502 dmtxMatrix3Multiply(reg->raw2fit, m, msky);
503
504 /* Create inverse matrix by reverse (avoid straight matrix inversion) */
505 dmtxMatrix3LineSkewTopInv(msky, sky, 1.0, 1.0);
506 dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0);
507 dmtxMatrix3Multiply(m, msky, mskx);
508
509 dmtxMatrix3Scale(mscxy, 1.0 / scx, 1.0 / scy);
510 dmtxMatrix3MultiplyBy(m, mscxy);
511
512 dmtxMatrix3Shear(mshx, 0.0, -shx);
513 dmtxMatrix3MultiplyBy(m, mshx);
514
515 dmtxMatrix3Rotate(mphi, -phi);
516 dmtxMatrix3MultiplyBy(m, mphi);
517
518 dmtxMatrix3Translate(mtxy, -tx, -ty);
519 dmtxMatrix3Multiply(reg->fit2raw, m, mtxy);
520
521 return DmtxPass;
522}
523
529{
530 double radians;
531 DmtxRay2 rLeft, rBottom, rTop, rRight;
532 DmtxVector2 p00, p10, p11, p01;
533
534 DmtxAssert(reg->leftKnown != 0 && reg->bottomKnown != 0);
535
536 /* Build ray representing left edge */
537 rLeft.p.x = (double)reg->leftLoc.x;
538 rLeft.p.y = (double)reg->leftLoc.y;
539 radians = reg->leftAngle * (M_PI / DMTX_HOUGH_RES);
540 rLeft.v.x = cos(radians);
541 rLeft.v.y = sin(radians);
542 rLeft.tMin = 0.0;
543 rLeft.tMax = dmtxVector2Norm(&rLeft.v);
544
545 /* Build ray representing bottom edge */
546 rBottom.p.x = (double)reg->bottomLoc.x;
547 rBottom.p.y = (double)reg->bottomLoc.y;
548 radians = reg->bottomAngle * (M_PI / DMTX_HOUGH_RES);
549 rBottom.v.x = cos(radians);
550 rBottom.v.y = sin(radians);
551 rBottom.tMin = 0.0;
552 rBottom.tMax = dmtxVector2Norm(&rBottom.v);
553
554 /* Build ray representing top edge */
555 if (reg->topKnown != 0) {
556 rTop.p.x = (double)reg->topLoc.x;
557 rTop.p.y = (double)reg->topLoc.y;
558 radians = reg->topAngle * (M_PI / DMTX_HOUGH_RES);
559 rTop.v.x = cos(radians);
560 rTop.v.y = sin(radians);
561 rTop.tMin = 0.0;
562 rTop.tMax = dmtxVector2Norm(&rTop.v);
563 } else {
564 rTop.p.x = (double)reg->locT.x;
565 rTop.p.y = (double)reg->locT.y;
566 radians = reg->bottomAngle * (M_PI / DMTX_HOUGH_RES);
567 rTop.v.x = cos(radians);
568 rTop.v.y = sin(radians);
569 rTop.tMin = 0.0;
570 rTop.tMax = rBottom.tMax;
571 }
572
573 /* Build ray representing right edge */
574 if (reg->rightKnown != 0) {
575 rRight.p.x = (double)reg->rightLoc.x;
576 rRight.p.y = (double)reg->rightLoc.y;
577 radians = reg->rightAngle * (M_PI / DMTX_HOUGH_RES);
578 rRight.v.x = cos(radians);
579 rRight.v.y = sin(radians);
580 rRight.tMin = 0.0;
581 rRight.tMax = dmtxVector2Norm(&rRight.v);
582 } else {
583 rRight.p.x = (double)reg->locR.x;
584 rRight.p.y = (double)reg->locR.y;
585 radians = reg->leftAngle * (M_PI / DMTX_HOUGH_RES);
586 rRight.v.x = cos(radians);
587 rRight.v.y = sin(radians);
588 rRight.tMin = 0.0;
589 rRight.tMax = rLeft.tMax;
590 }
591
592 /* Calculate 4 corners, real or imagined */
593 if (dmtxRay2Intersect(&p00, &rLeft, &rBottom) == DmtxFail) {
594 return DmtxFail;
595 }
596
597 if (dmtxRay2Intersect(&p10, &rBottom, &rRight) == DmtxFail) {
598 return DmtxFail;
599 }
600
601 if (dmtxRay2Intersect(&p11, &rRight, &rTop) == DmtxFail) {
602 return DmtxFail;
603 }
604
605 if (dmtxRay2Intersect(&p01, &rTop, &rLeft) == DmtxFail) {
606 return DmtxFail;
607 }
608
609 if (dmtxRegionUpdateCorners(dec, reg, p00, p10, p11, p01) != DmtxPass) {
610 return DmtxFail;
611 }
612
613 return DmtxPass;
614}
615
620static double rightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle)
621{
622 DmtxVector2 vA, vB;
623 DmtxMatrix3 m;
624
625 dmtxVector2Norm(dmtxVector2Sub(&vA, &c0, &c1));
626 dmtxVector2Norm(dmtxVector2Sub(&vB, &c2, &c1));
627
628 dmtxMatrix3Rotate(m, angle);
630
631 return dmtxVector2Dot(&vA, &vB);
632}
633
646static int readModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx, int colorPlane)
647{
648 int i;
649 int symbolRows, symbolCols;
650 int color, colorTmp;
651 double sampleX[] = {0.5, 0.4, 0.5, 0.6, 0.5};
652 double sampleY[] = {0.5, 0.5, 0.4, 0.5, 0.6};
653 DmtxVector2 p;
654
655 symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
656 symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);
657
658 /* 从给定坐标及其周围共5个点位获取图像像素并求平均值 */
659 color = 0;
660 for (i = 0; i < 5; i++) {
661 p.x = (1.0 / symbolCols) * (symbolCol + sampleX[i]);
662 p.y = (1.0 / symbolRows) * (symbolRow + sampleY[i]);
663
664 dmtxMatrix3VMultiplyBy(&p, reg->fit2raw); // 从二维码坐标转换到图像坐标
665
666 // dmtxLogDebug("%dx%d", (int)(p.x + 0.5), (int)(p.y + 0.5));
667
668 if (cbPlotModule) {
669 cbPlotModule(dec, reg, (int)(p.x + 0.5), (int)(p.y + 0.5), 0);
670 }
671
672 dmtxDecodeGetPixelValue(dec, (int)(p.x + 0.5), (int)(p.y + 0.5), colorPlane, &colorTmp);
673 color += colorTmp;
674 }
675 // printf("\n");
676 return color / 5;
677}
678
689{
690 int row, col;
691 int sizeIdxBeg, sizeIdxEnd;
692 int sizeIdx, bestSizeIdx;
693 int symbolRows, symbolCols;
694 int jumpCount, errors;
695 int color;
696 int colorOnAvg, bestColorOnAvg;
697 int colorOffAvg, bestColorOffAvg;
698 int contrast, bestContrast;
699 // DmtxImage *img;
700
701 // img = dec->image;
702 bestSizeIdx = DmtxUndefined;
703 bestContrast = 0;
704 bestColorOnAvg = bestColorOffAvg = 0;
705
706 if (dec->sizeIdxExpected == DmtxSymbolShapeAuto) {
707 sizeIdxBeg = 0;
709 } else if (dec->sizeIdxExpected == DmtxSymbolSquareAuto) {
710 sizeIdxBeg = 0;
711 sizeIdxEnd = DmtxSymbolSquareCount;
712 } else if (dec->sizeIdxExpected == DmtxSymbolRectAuto) {
713 sizeIdxBeg = DmtxSymbolSquareCount;
715 } else {
716 sizeIdxBeg = dec->sizeIdxExpected;
717 sizeIdxEnd = dec->sizeIdxExpected + 1;
718 }
719
720 /* 遍历每种DataMatrix种类模板,通过顶部和右侧的点线取颜色计算寻找对比度最大的模板 */
721 for (sizeIdx = sizeIdxBeg; sizeIdx < sizeIdxEnd; sizeIdx++) {
722 symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
723 symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);
724 colorOnAvg = colorOffAvg = 0;
725
726 /* 对DataMatrix顶部点线黑白码元分别求和 */
727 row = symbolRows - 1;
728 for (col = 0; col < symbolCols; col++) {
729 color = readModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane);
730 if ((col & 0x01) != 0x00) {
731 colorOffAvg += color;
732 } else {
733 colorOnAvg += color;
734 }
735 }
736
737 /* 对DataMatrix右侧点线黑白码元分别求和 */
738 col = symbolCols - 1;
739 for (row = 0; row < symbolRows; row++) {
740 color = readModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane);
741 if ((row & 0x01) != 0x00) {
742 colorOffAvg += color;
743 } else {
744 colorOnAvg += color;
745 }
746 }
747
748 colorOnAvg = (colorOnAvg * 2) / (symbolRows + symbolCols);
749 colorOffAvg = (colorOffAvg * 2) / (symbolRows + symbolCols);
750
751 contrast = abs(colorOnAvg - colorOffAvg);
752 if (contrast < 20) {
753 continue; // bit1码元与bit0码元的差值小于20直接认为该模板无效
754 }
755
756 /* 遍历所有类型,寻找效果最好的 */
757 if (contrast > bestContrast) {
758 bestContrast = contrast;
759 bestSizeIdx = sizeIdx;
760 bestColorOnAvg = colorOnAvg;
761 bestColorOffAvg = colorOffAvg;
762 }
763 }
764
765 /* 如果所有的模板都不是很匹配,直接返回错误 */
766 if (bestSizeIdx == DmtxUndefined || bestContrast < 20) {
767 return DmtxFail;
768 }
769
770 reg->sizeIdx = bestSizeIdx; // 最佳DataMatrix种类模板的索引号,共30种
771 reg->onColor = bestColorOnAvg; // bit1的码元颜色值
772 reg->offColor = bestColorOffAvg; // bit0的码元颜色值
773
778
789 jumpCount = countJumpTally(dec, reg, 0, reg->symbolRows - 1, DmtxDirRight);
790 errors = abs(1 + jumpCount - reg->symbolCols);
791 if (jumpCount < 0 || errors > 2) {
792 return DmtxFail;
793 }
794
807 jumpCount = countJumpTally(dec, reg, reg->symbolCols - 1, 0, DmtxDirUp);
808 errors = abs(1 + jumpCount - reg->symbolRows);
809 if (jumpCount < 0 || errors > 2) {
810 return DmtxFail;
811 }
812
823 errors = countJumpTally(dec, reg, 0, 0, DmtxDirRight);
824 if (jumpCount < 0 || errors > 2) {
825 return DmtxFail;
826 }
827
840 errors = countJumpTally(dec, reg, 0, 0, DmtxDirUp);
841 if (errors < 0 || errors > 2) {
842 return DmtxFail;
843 }
844
856 errors = countJumpTally(dec, reg, 0, -1, DmtxDirRight);
857 if (errors < 0 || errors > 2) {
858 return DmtxFail;
859 }
860
871 errors = countJumpTally(dec, reg, -1, 0, DmtxDirUp);
872 if (errors < 0 || errors > 2) {
873 return DmtxFail;
874 }
875
885 errors = countJumpTally(dec, reg, 0, reg->symbolRows, DmtxDirRight);
886 if (errors < 0 || errors > 2) {
887 return DmtxFail;
888 }
889
900 errors = countJumpTally(dec, reg, reg->symbolCols, 0, DmtxDirUp);
901 if (errors < 0 || errors > 2) {
902 return DmtxFail;
903 }
904
905 return DmtxPass;
906}
907
919static int countJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir)
920{
921 int x, xInc = 0;
922 int y, yInc = 0;
923 int state = DmtxModuleOn;
924 int jumpCount = 0;
925 int jumpThreshold;
926 int tModule, tPrev;
927 int darkOnLight; // 白底黑码:1,黑底白码:0
928 int color;
929
930 DmtxAssert(xStart == 0 || yStart == 0);
931 DmtxAssert(dir == DmtxDirRight || dir == DmtxDirUp);
932
933 if (dir == DmtxDirRight) {
934 xInc = 1;
935 } else {
936 yInc = 1;
937 }
938
939 if (xStart == -1 || xStart == reg->symbolCols || yStart == -1 || yStart == reg->symbolRows) {
940 state = DmtxModuleOff;
941 }
942
943 darkOnLight = (int)(reg->offColor > reg->onColor);
944 jumpThreshold = abs((int)(0.4 * (reg->onColor - reg->offColor) + 0.5));
945 color = readModuleColor(dec, reg, yStart, xStart, reg->sizeIdx, reg->flowBegin.plane);
946 tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;
947
948 for (x = xStart + xInc, y = yStart + yInc;
949 (dir == DmtxDirRight && x < reg->symbolCols) || (dir == DmtxDirUp && y < reg->symbolRows);
950 x += xInc, y += yInc) {
951 tPrev = tModule;
952 color = readModuleColor(dec, reg, y, x, reg->sizeIdx, reg->flowBegin.plane);
953 tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;
954
955 if (state == DmtxModuleOff) {
956 if (tModule > tPrev + jumpThreshold) {
957 jumpCount++;
958 state = DmtxModuleOn;
959 }
960 } else {
961 if (tModule < tPrev - jumpThreshold) {
962 jumpCount++;
963 state = DmtxModuleOff;
964 }
965 }
966 }
967
968 return jumpCount;
969}
970
974static DmtxPointFlow getPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive)
975{
976 static const int coefficient[] = {0, 1, 2, 1, 0, -1, -2, -1};
977 unsigned int err;
978 int patternIdx, coefficientIdx;
979 int compass, compassMax;
980 int mag[4] = {0};
981 int xAdjust, yAdjust;
982 int color, colorPattern[8];
983 DmtxPointFlow flow;
984
985 // 以loc坐标为中心按照如下所示顺序获取周边的8个像素值
986 // \ref dmtxNeighborNone
987 // Y+
988 // |
989 // 6 5 4
990 // —— 7 8 3 ——> X+
991 // 0 1 2
992 // |
993 for (patternIdx = 0; patternIdx < 8; patternIdx++) {
994 xAdjust = loc.x + dmtxPatternX[patternIdx];
995 yAdjust = loc.y + dmtxPatternY[patternIdx];
996 err = dmtxDecodeGetPixelValue(dec, xAdjust, yAdjust, colorPlane, &colorPattern[patternIdx]);
997 if (err == DmtxFail) {
998 return dmtxBlankEdge;
999 }
1000 }
1001
1002 /* 计算四个方向上的流动强度 (-45, 0, 45, 90) */
1003 compassMax = 0;
1004 for (compass = 0; compass < 4; compass++) {
1005 /* Add portion from each position in the convolution matrix pattern */
1006 for (patternIdx = 0; patternIdx < 8; patternIdx++) {
1007 coefficientIdx = (patternIdx - compass + 8) % 8;
1008 if (coefficient[coefficientIdx] == 0) {
1009 continue;
1010 }
1011
1012 color = colorPattern[patternIdx];
1013
1014 switch (coefficient[coefficientIdx]) {
1015 case 2:
1016 mag[compass] += color;
1017 /* Fall through */
1018 case 1:
1019 mag[compass] += color;
1020 break;
1021 case -2:
1022 mag[compass] -= color;
1023 /* Fall through */
1024 case -1:
1025 mag[compass] -= color;
1026 break;
1027 }
1028 }
1029
1030 /* 确定最强的梯度流动方向 */
1031 if (compass != 0 && abs(mag[compass]) > abs(mag[compassMax])) {
1032 compassMax = compass;
1033 }
1034 }
1035
1036 /* Convert signed compass direction into unique flow directions (0-7) */
1037 flow.plane = colorPlane; // 颜色平面(彩色RGB三个平面中的一个)
1038 flow.arrive = arrive; // 抵达方向 8
1039 flow.depart = (mag[compassMax] > 0) ? compassMax + 4
1040 : compassMax; // 离开方向 假设是水平方向就需要判断是向左(<-),还是向右(->)
1041 flow.mag = abs(mag[compassMax]); // 梯度强度
1042 flow.loc = loc; // 原始像素位置
1043
1044 return flow;
1045}
1046
1052{
1053 int i;
1054 int strongIdx;
1055 int attempt, attemptDiff;
1056 int occupied;
1057 unsigned char *cache;
1058 DmtxPixelLoc loc;
1059 DmtxPointFlow flow[8];
1060
1061 attempt = (sign < 0) ? center.depart : (center.depart + 4) % 8;
1062
1063 occupied = 0;
1064 strongIdx = DmtxUndefined;
1065 for (i = 0; i < 8; i++) {
1066 loc.x = center.loc.x + dmtxPatternX[i];
1067 loc.y = center.loc.y + dmtxPatternY[i];
1068
1069 cache = dmtxDecodeGetCache(dec, loc.x, loc.y);
1070 if (cache == NULL) {
1071 continue;
1072 }
1073
1074 if ((int)(*cache & 0x80) != 0x00) {
1075 if (++occupied > 2) {
1076 return dmtxBlankEdge;
1077 }
1078 continue;
1079 }
1080
1081 attemptDiff = abs(attempt - i);
1082 if (attemptDiff > 4) {
1083 attemptDiff = 8 - attemptDiff;
1084 }
1085 if (attemptDiff > 1) {
1086 continue;
1087 }
1088
1089 flow[i] = getPointFlow(dec, center.plane, loc, i);
1090
1091 if (strongIdx == DmtxUndefined || flow[i].mag > flow[strongIdx].mag ||
1092 (flow[i].mag == flow[strongIdx].mag && ((i & 0x01) != 0))) {
1093 strongIdx = i;
1094 }
1095 }
1096
1097 return (strongIdx == DmtxUndefined) ? dmtxBlankEdge : flow[strongIdx];
1098}
1099
1113static DmtxFollow followSeek(DmtxDecode *dec, DmtxRegion *reg, int seek)
1114{
1115 int i;
1116 int sign;
1117 DmtxFollow follow;
1118
1119 follow.loc = reg->flowBegin.loc;
1120 follow.step = 0;
1121 follow.ptr = dmtxDecodeGetCache(dec, follow.loc.x, follow.loc.y);
1122 DmtxAssert(follow.ptr != NULL);
1123 follow.neighbor = *follow.ptr;
1124
1125 sign = (seek > 0) ? +1 : -1;
1126 for (i = 0; i != seek; i += sign) {
1127 follow = followStep(dec, reg, follow, sign);
1128 DmtxAssert(follow.ptr != NULL);
1129 DmtxAssert(abs(follow.step) <= reg->stepsTotal);
1130 }
1131
1132 return follow;
1133}
1134
1139{
1140 DmtxFollow follow;
1141
1142 follow.loc = loc;
1143 follow.step = 0;
1144 follow.ptr = dmtxDecodeGetCache(dec, follow.loc.x, follow.loc.y);
1145 DmtxAssert(follow.ptr != NULL);
1146 follow.neighbor = *follow.ptr;
1147
1148 return follow;
1149}
1150
1159static DmtxFollow followStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign)
1160{
1161 int patternIdx;
1162 int stepMod;
1163 int factor;
1164 DmtxFollow follow;
1165
1166 DmtxAssert(abs(sign) == 1);
1167 DmtxAssert((int)(followBeg.neighbor & 0x40) != 0x00);
1168
1169 factor = reg->stepsTotal + 1;
1170 if (sign > 0) {
1171 stepMod = (factor + (followBeg.step % factor)) % factor;
1172 } else {
1173 stepMod = (factor - (followBeg.step % factor)) % factor;
1174 }
1175
1176 /* End of positive trail -- magic jump */
1177 if (sign > 0 && stepMod == reg->jumpToNeg) {
1178 follow.loc = reg->finalNeg;
1179 }
1180 /* End of negative trail -- magic jump */
1181 else if (sign < 0 && stepMod == reg->jumpToPos) {
1182 follow.loc = reg->finalPos;
1183 }
1184 /* Trail in progress -- normal jump */
1185 else {
1186 patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3);
1187 follow.loc.x = followBeg.loc.x + dmtxPatternX[patternIdx];
1188 follow.loc.y = followBeg.loc.y + dmtxPatternY[patternIdx];
1189 }
1190
1191 follow.step = followBeg.step + sign;
1192 follow.ptr = dmtxDecodeGetCache(dec, follow.loc.x, follow.loc.y);
1193 DmtxAssert(follow.ptr != NULL);
1194 follow.neighbor = *follow.ptr;
1195
1196 return follow;
1197}
1198
1203static DmtxFollow followStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign)
1204{
1205 int patternIdx;
1206 DmtxFollow follow;
1207
1208 DmtxAssert(abs(sign) == 1);
1209 DmtxAssert((int)(followBeg.neighbor & 0x40) != 0x00);
1210
1211 patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3);
1212 follow.loc.x = followBeg.loc.x + dmtxPatternX[patternIdx];
1213 follow.loc.y = followBeg.loc.y + dmtxPatternY[patternIdx];
1214
1215 follow.step = followBeg.step + sign;
1216 follow.ptr = dmtxDecodeGetCache(dec, follow.loc.x, follow.loc.y);
1217 DmtxAssert(follow.ptr != NULL);
1218 follow.neighbor = *follow.ptr;
1219
1220 return follow;
1221}
1222
1234static DmtxPassFail trailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal)
1235{
1236 int posAssigns, negAssigns, clears;
1237 int sign; // 方向标志,+1为正向,-1为负向
1238 int steps;
1239 unsigned char *cache, *cacheNext, *cacheBeg;
1240 DmtxPointFlow flow, flowNext;
1241 DmtxPixelLoc boundMin, boundMax;
1242
1243 boundMin = boundMax = flowBegin.loc;
1244 cacheBeg = dmtxDecodeGetCache(dec, flowBegin.loc.x, flowBegin.loc.y);
1245 if (cacheBeg == NULL) {
1246 return DmtxFail;
1247 }
1248 *cacheBeg = (0x80 | 0x40); /* Mark location as visited and assigned */
1249
1250 reg->flowBegin = flowBegin;
1251
1252 posAssigns = negAssigns = 0;
1253 for (sign = 1; sign >= -1; sign -= 2) { // 分别进行正向和负向探索
1254 flow = flowBegin;
1255 cache = cacheBeg;
1256
1257 for (steps = 0;; steps++) {
1258 // 检查是否超过最大对角线限制
1259 if (maxDiagonal != DmtxUndefined &&
1260 (boundMax.x - boundMin.x > maxDiagonal || boundMax.y - boundMin.y > maxDiagonal)) {
1261 break;
1262 }
1263
1264 /* 寻找梯度最大的下一个点 */
1265 flowNext = findStrongestNeighbor(dec, flow, sign);
1266 if (flowNext.mag < 50) {
1267 break;
1268 }
1269
1270 /* Get the neighbor's cache location */
1271 cacheNext = dmtxDecodeGetCache(dec, flowNext.loc.x, flowNext.loc.y);
1272 if (cacheNext == NULL) {
1273 break;
1274 }
1275 DmtxAssert(!(*cacheNext & 0x80));
1276
1277 /* Mark departure from current location. If flowing downstream
1278 * (sign < 0) then departure vector here is the arrival vector
1279 * of the next location. Upstream flow uses the opposite rule. */
1280 *cache |= (sign < 0) ? flowNext.arrive : flowNext.arrive << 3;
1281
1282 /* Mark known direction for next location */
1283 /* If testing downstream (sign < 0) then next upstream is opposite of next arrival */
1284 /* If testing upstream (sign > 0) then next downstream is opposite of next arrival */
1285 *cacheNext = (sign < 0) ? (((flowNext.arrive + 4) % 8) << 3) : ((flowNext.arrive + 4) % 8);
1286 *cacheNext |= (0x80 | 0x40); /* Mark location as visited and assigned */
1287 if (sign > 0) {
1288 posAssigns++;
1289 } else {
1290 negAssigns++;
1291 }
1292 cache = cacheNext;
1293 flow = flowNext;
1294
1295 if (flow.loc.x > boundMax.x) {
1296 boundMax.x = flow.loc.x;
1297 } else if (flow.loc.x < boundMin.x) {
1298 boundMin.x = flow.loc.x;
1299 }
1300 if (flow.loc.y > boundMax.y) {
1301 boundMax.y = flow.loc.y;
1302 } else if (flow.loc.y < boundMin.y) {
1303 boundMin.y = flow.loc.y;
1304 }
1305
1306 if (cbPlotPoint) {
1307 cbPlotPoint(flow.loc, (sign > 0) ? 0.0F /*红*/ : 180.0F /*青*/, 1, 2);
1308 }
1309 }
1310
1311 if (sign > 0) {
1312 reg->finalPos = flow.loc;
1313 reg->jumpToNeg = steps;
1314 } else {
1315 reg->finalNeg = flow.loc;
1316 reg->jumpToPos = steps;
1317 }
1318 }
1319 reg->stepsTotal = reg->jumpToPos + reg->jumpToNeg;
1320 reg->boundMin = boundMin;
1321 reg->boundMax = boundMax;
1322
1323 /* Clear "visited" bit from trail */
1324 clears = trailClear(dec, reg, 0x80);
1325 DmtxAssert(posAssigns + negAssigns == clears - 1);
1326
1327 /* XXX clean this up ... redundant test above */
1328 if (maxDiagonal != DmtxUndefined &&
1329 (boundMax.x - boundMin.x > maxDiagonal || boundMax.y - boundMin.y > maxDiagonal)) {
1330 return DmtxFail;
1331 }
1332
1333 return DmtxPass;
1334}
1335
1341static int trailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir)
1342{
1343 unsigned char *beforeCache, *afterCache;
1344 DmtxBoolean onEdge;
1345 int distSq, distSqMax;
1346 int travel, outward;
1347 int xDiff, yDiff;
1348 int steps;
1349 int stepDir, dirMap[] = {0, 1, 2, 7, 8, 3, 6, 5, 4};
1350 DmtxPassFail err;
1351 DmtxPixelLoc beforeStep, afterStep;
1352 DmtxPointFlow flow, flowNext;
1353 DmtxPixelLoc loc0;
1354 int xStep, yStep;
1355
1356 loc0 = line.loc;
1357 flow = getPointFlow(dec, reg->flowBegin.plane, loc0, dmtxNeighborNone);
1358 distSqMax = (line.xDelta * line.xDelta) + (line.yDelta * line.yDelta);
1359 steps = 0;
1360 onEdge = DmtxTrue;
1361
1362 beforeStep = loc0;
1363 beforeCache = dmtxDecodeGetCache(dec, loc0.x, loc0.y);
1364 if (beforeCache == NULL) {
1365 return DmtxFail;
1366 }
1367 *beforeCache = 0x00; /* probably should just overwrite one direction */
1368
1369 do {
1370 if (onEdge == DmtxTrue) {
1371 flowNext = findStrongestNeighbor(dec, flow, streamDir);
1372 if (flowNext.mag == DmtxUndefined) {
1373 break;
1374 }
1375
1376 err = bresLineGetStep(line, flowNext.loc, &travel, &outward);
1377 if (err == DmtxFail) {
1378 return DmtxFail;
1379 }
1380
1381 if (flowNext.mag < 50 || outward < 0 || (outward == 0 && travel < 0)) {
1382 onEdge = DmtxFalse;
1383 } else {
1384 bresLineStep(&line, travel, outward);
1385 flow = flowNext;
1386 }
1387 }
1388
1389 if (onEdge == DmtxFalse) {
1390 bresLineStep(&line, 1, 0);
1391 flow = getPointFlow(dec, reg->flowBegin.plane, line.loc, dmtxNeighborNone);
1392 if (flow.mag > 50) {
1393 onEdge = DmtxTrue;
1394 }
1395 }
1396
1397 afterStep = line.loc;
1398 afterCache = dmtxDecodeGetCache(dec, afterStep.x, afterStep.y);
1399 if (afterCache == NULL) {
1400 break;
1401 }
1402
1403 /* Determine step direction using pure magic */
1404 xStep = afterStep.x - beforeStep.x;
1405 yStep = afterStep.y - beforeStep.y;
1406 DmtxAssert(abs(xStep) <= 1 && abs(yStep) <= 1);
1407 stepDir = dirMap[3 * yStep + xStep + 4];
1408 DmtxAssert(stepDir != 8);
1409
1410 if (streamDir < 0) {
1411 *beforeCache |= (0x40 | stepDir);
1412 *afterCache = (((stepDir + 4) % 8) << 3);
1413 } else {
1414 *beforeCache |= (0x40 | (stepDir << 3));
1415 *afterCache = ((stepDir + 4) % 8);
1416 }
1417
1418 /* Guaranteed to have taken one step since top of loop */
1419 xDiff = line.loc.x - loc0.x;
1420 yDiff = line.loc.y - loc0.y;
1421 distSq = (xDiff * xDiff) + (yDiff * yDiff);
1422
1423 beforeStep = line.loc;
1424 beforeCache = afterCache;
1425 steps++;
1426
1427 } while (distSq < distSqMax);
1428
1429 return steps;
1430}
1431
1436static int trailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask)
1437{
1438 int clears;
1439 DmtxFollow follow;
1440
1441 DmtxAssert((clearMask | 0xff) == 0xff);
1442
1443 /* Clear "visited" bit from trail */
1444 clears = 0;
1445 follow = followSeek(dec, reg, 0);
1446 while (abs(follow.step) <= reg->stepsTotal) {
1447 DmtxAssert((int)(*follow.ptr & clearMask) != 0x00);
1448 *follow.ptr &= (clearMask ^ 0xff);
1449 follow = followStep(dec, reg, follow, +1);
1450 clears++;
1451 }
1452
1453 return clears;
1454}
1455
1471static DmtxBestLine findBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir,
1472 int houghAvoid)
1473{
1474 int hough[3][DMTX_HOUGH_RES] = {{0}};
1475 int houghMin, houghMax;
1476 char houghTest[DMTX_HOUGH_RES];
1477 int i;
1478 int step;
1479 int sign;
1480 int tripSteps;
1481 int angleBest;
1482 int hOffset, hOffsetBest;
1483 int xDiff, yDiff;
1484 int dH;
1485 DmtxRay2 rH;
1486 DmtxFollow follow;
1487 DmtxBestLine line;
1488 DmtxPixelLoc rHp;
1489
1490 memset(&line, 0x00, sizeof(DmtxBestLine));
1491 memset(&rH, 0x00, sizeof(DmtxRay2));
1492 angleBest = 0;
1493 hOffset = hOffsetBest = 0;
1494
1495 sign = 0;
1496
1497 /* Always follow path flowing away from the trail start */
1498 if (step0 != 0) {
1499 if (step0 > 0) {
1500 sign = +1;
1501 tripSteps = (step1 - step0 + reg->stepsTotal) % reg->stepsTotal;
1502 } else {
1503 sign = -1;
1504 tripSteps = (step0 - step1 + reg->stepsTotal) % reg->stepsTotal;
1505 }
1506 if (tripSteps == 0) {
1507 tripSteps = reg->stepsTotal;
1508 }
1509 } else if (step1 != 0) {
1510 sign = (step1 > 0) ? +1 : -1;
1511 tripSteps = abs(step1);
1512 } else if (step1 == 0) {
1513 sign = +1;
1514 tripSteps = reg->stepsTotal;
1515 }
1516 DmtxAssert(sign == streamDir);
1517
1518 follow = followSeek(dec, reg, step0);
1519 rHp = follow.loc;
1520
1521 line.stepBeg = line.stepPos = line.stepNeg = step0;
1522 line.locBeg = follow.loc;
1523 line.locPos = follow.loc;
1524 line.locNeg = follow.loc;
1525
1526 /* Predetermine which angles to test */
1527 for (i = 0; i < DMTX_HOUGH_RES; i++) {
1528 if (houghAvoid == DmtxUndefined) {
1529 houghTest[i] = 1;
1530 } else {
1531 houghMin = (houghAvoid + DMTX_HOUGH_RES / 6) % DMTX_HOUGH_RES;
1532 houghMax = (houghAvoid - DMTX_HOUGH_RES / 6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES;
1533 if (houghMin > houghMax) {
1534 houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0;
1535 } else {
1536 houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0;
1537 }
1538 }
1539 }
1540
1541 /* Test each angle for steps along path */
1542 for (step = 0; step < tripSteps; step++) {
1543 xDiff = follow.loc.x - rHp.x;
1544 yDiff = follow.loc.y - rHp.y;
1545
1546 /* Increment Hough accumulator */
1547 for (i = 0; i < DMTX_HOUGH_RES; i++) {
1548 if ((int)houghTest[i] == 0) {
1549 continue;
1550 }
1551
1552 dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff);
1553 if (dH >= -384 && dH <= 384) {
1554 if (dH > 128) {
1555 hOffset = 2;
1556 } else if (dH >= -128) {
1557 hOffset = 1;
1558 } else {
1559 hOffset = 0;
1560 }
1561
1562 hough[hOffset][i]++;
1563
1564 /* New angle takes over lead */
1565 if (hough[hOffset][i] > hough[hOffsetBest][angleBest]) {
1566 angleBest = i;
1567 hOffsetBest = hOffset;
1568 }
1569 }
1570 }
1571
1572 if (cbPlotPoint) {
1573 cbPlotPoint(follow.loc, (sign > 1) ? 120.0F + step : 300.0F + step, 1, 2);
1574 }
1575
1576 follow = followStep(dec, reg, follow, sign);
1577 }
1578
1579 line.angle = angleBest;
1580 line.hOffset = hOffsetBest;
1581 line.mag = hough[hOffsetBest][angleBest];
1582
1583 return line;
1584}
1585
1590static DmtxBestLine findBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid)
1591{
1592 int hough[3][DMTX_HOUGH_RES] = {{0}};
1593 int houghMin, houghMax;
1594 char houghTest[DMTX_HOUGH_RES];
1595 int i;
1596 int step;
1597 int angleBest;
1598 int hOffset, hOffsetBest;
1599 int xDiff, yDiff;
1600 int dH;
1601 DmtxRay2 rH;
1602 DmtxBestLine line;
1603 DmtxPixelLoc rHp;
1604 DmtxFollow follow;
1605
1606 memset(&line, 0x00, sizeof(DmtxBestLine));
1607 memset(&rH, 0x00, sizeof(DmtxRay2));
1608 angleBest = 0;
1609 hOffset = hOffsetBest = 0;
1610
1611 follow = followSeekLoc(dec, loc0);
1612 rHp = line.locBeg = line.locPos = line.locNeg = follow.loc;
1613 line.stepBeg = line.stepPos = line.stepNeg = 0;
1614
1615 /* Predetermine which angles to test */
1616 for (i = 0; i < DMTX_HOUGH_RES; i++) {
1617 if (houghAvoid == DmtxUndefined) {
1618 houghTest[i] = 1;
1619 } else {
1620 houghMin = (houghAvoid + DMTX_HOUGH_RES / 6) % DMTX_HOUGH_RES;
1621 houghMax = (houghAvoid - DMTX_HOUGH_RES / 6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES;
1622 if (houghMin > houghMax) {
1623 houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0;
1624 } else {
1625 houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0;
1626 }
1627 }
1628 }
1629
1630 /* Test each angle for steps along path */
1631 for (step = 0; step < tripSteps; step++) {
1632 xDiff = follow.loc.x - rHp.x;
1633 yDiff = follow.loc.y - rHp.y;
1634
1635 /* Increment Hough accumulator */
1636 for (i = 0; i < DMTX_HOUGH_RES; i++) {
1637 if ((int)houghTest[i] == 0) {
1638 continue;
1639 }
1640
1641 dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff);
1642 if (dH >= -384 && dH <= 384) {
1643 if (dH > 128) {
1644 hOffset = 2;
1645 } else if (dH >= -128) {
1646 hOffset = 1;
1647 } else {
1648 hOffset = 0;
1649 }
1650
1651 hough[hOffset][i]++;
1652
1653 /* New angle takes over lead */
1654 if (hough[hOffset][i] > hough[hOffsetBest][angleBest]) {
1655 angleBest = i;
1656 hOffsetBest = hOffset;
1657 }
1658 }
1659 }
1660
1661 if (cbPlotPoint) {
1662 cbPlotPoint(follow.loc, (sign > 1) ? 300.0F /*品红*/ : 120.0F /*绿*/, 1, 2);
1663 }
1664
1665 follow = followStep2(dec, follow, sign);
1666 }
1667
1668 line.angle = angleBest;
1669 line.hOffset = hOffsetBest;
1670 line.mag = hough[hOffsetBest][angleBest];
1671
1672 return line;
1673}
1674
1680{
1681 int i;
1682 int distSq, distSqMax;
1683 int xDiff, yDiff;
1684 int posRunning, negRunning;
1685 int posTravel, negTravel;
1686 int posWander, posWanderMin, posWanderMax, posWanderMinLock, posWanderMaxLock;
1687 int negWander, negWanderMin, negWanderMax, negWanderMinLock, negWanderMaxLock;
1688 int cosAngle, sinAngle;
1689 DmtxFollow followPos, followNeg;
1690 DmtxPixelLoc loc0, posMax, negMax;
1691
1692 /* line->stepBeg is already known to sit on the best Hough line */
1693 followPos = followNeg = followSeek(dec, reg, line->stepBeg);
1694 loc0 = followPos.loc;
1695
1696 cosAngle = rHvX[line->angle];
1697 sinAngle = rHvY[line->angle];
1698
1699 distSqMax = 0;
1700 posMax = negMax = followPos.loc;
1701
1702 posTravel = negTravel = 0;
1703 posWander = posWanderMin = posWanderMax = posWanderMinLock = posWanderMaxLock = 0;
1704 negWander = negWanderMin = negWanderMax = negWanderMinLock = negWanderMaxLock = 0;
1705
1706 for (i = 0; i < reg->stepsTotal / 2; i++) {
1707 posRunning = (int)(i < 10 || abs(posWander) < abs(posTravel));
1708 negRunning = (int)(i < 10 || abs(negWander) < abs(negTravel));
1709
1710 if (posRunning != 0) {
1711 xDiff = followPos.loc.x - loc0.x;
1712 yDiff = followPos.loc.y - loc0.y;
1713 posTravel = (cosAngle * xDiff) + (sinAngle * yDiff);
1714 posWander = (cosAngle * yDiff) - (sinAngle * xDiff);
1715
1716 if (posWander >= -3 * 256 && posWander <= 3 * 256) {
1717 distSq = (int)distanceSquared(followPos.loc, negMax);
1718 if (distSq > distSqMax) {
1719 posMax = followPos.loc; // 更新
1720 distSqMax = distSq;
1721 line->stepPos = followPos.step;
1722 line->locPos = followPos.loc;
1723 posWanderMinLock = posWanderMin;
1724 posWanderMaxLock = posWanderMax;
1725 }
1726 } else {
1727 posWanderMin = min(posWanderMin, posWander);
1728 posWanderMax = max(posWanderMax, posWander);
1729 }
1730 } else if (!negRunning) {
1731 break;
1732 }
1733
1734 if (negRunning != 0) {
1735 xDiff = followNeg.loc.x - loc0.x;
1736 yDiff = followNeg.loc.y - loc0.y;
1737 negTravel = (cosAngle * xDiff) + (sinAngle * yDiff);
1738 negWander = (cosAngle * yDiff) - (sinAngle * xDiff);
1739
1740 if (negWander >= -3 * 256 && negWander < 3 * 256) {
1741 distSq = (int)distanceSquared(followNeg.loc, posMax);
1742 if (distSq > distSqMax) {
1743 negMax = followNeg.loc; // 更新
1744 distSqMax = distSq;
1745 line->stepNeg = followNeg.step;
1746 line->locNeg = followNeg.loc;
1747 negWanderMinLock = negWanderMin;
1748 negWanderMaxLock = negWanderMax;
1749 }
1750 } else {
1751 negWanderMin = min(negWanderMin, negWander);
1752 negWanderMax = max(negWanderMax, negWander);
1753 }
1754 } else if (!posRunning) {
1755 break;
1756 }
1757
1758 if (cbPlotPoint) {
1759 cbPlotPoint(followPos.loc, 60.0F /*黄*/, 1, 2);
1760 cbPlotPoint(followNeg.loc, 240.0F /*蓝*/, 1, 2);
1761 }
1762
1763 followPos = followStep(dec, reg, followPos, +1);
1764 followNeg = followStep(dec, reg, followNeg, -1);
1765 }
1766 line->devn = max(posWanderMaxLock - posWanderMinLock, negWanderMaxLock - negWanderMinLock) / 256;
1767 line->distSq = distSqMax;
1768
1769 if (cbPlotPoint) {
1770 cbPlotPoint(posMax, 120.0F /*绿*/, 1, 1);
1771 cbPlotPoint(negMax, 120.0F /*绿*/, 1, 1);
1772 }
1773
1774 return DmtxPass;
1775}
1776
1782{
1783 int streamDir;
1784 int steps;
1785 int avoidAngle;
1786 int symbolShape;
1787 DmtxVector2 pTmp;
1788 DmtxPixelLoc loc0, loc1, locOrigin;
1789 DmtxBresLine line;
1790 DmtxFollow follow;
1791 DmtxBestLine bestLine;
1792
1793 /* 确定原点的像素坐标 */
1794 pTmp.x = 0.0;
1795 pTmp.y = 0.0;
1796 dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw);
1797 locOrigin.x = (int)(pTmp.x + 0.5);
1798 locOrigin.y = (int)(pTmp.y + 0.5);
1799
1800 if (dec->sizeIdxExpected == DmtxSymbolSquareAuto ||
1801 (dec->sizeIdxExpected >= DmtxSymbol10x10 && dec->sizeIdxExpected <= DmtxSymbol144x144)) {
1802 symbolShape = DmtxSymbolSquareAuto;
1803 } else if (dec->sizeIdxExpected == DmtxSymbolRectAuto ||
1804 (dec->sizeIdxExpected >= DmtxSymbol8x18 && dec->sizeIdxExpected <= DmtxSymbol16x48)) {
1805 symbolShape = DmtxSymbolRectAuto;
1806 } else {
1807 symbolShape = DmtxSymbolShapeAuto;
1808 }
1809
1810 /* Determine end locations of test line */
1811 if (edgeLoc == DmtxEdgeTop) {
1812 streamDir = reg->polarity * -1;
1813 avoidAngle = reg->leftLine.angle;
1814 follow = followSeekLoc(dec, reg->locT);
1815 pTmp.x = 0.8;
1816 pTmp.y = (symbolShape == DmtxSymbolRectAuto) ? 0.2 : 0.6;
1817 } else {
1818 DmtxAssert(edgeLoc == DmtxEdgeRight);
1819 streamDir = reg->polarity;
1820 avoidAngle = reg->bottomLine.angle;
1821 follow = followSeekLoc(dec, reg->locR);
1822 pTmp.x = (symbolShape == DmtxSymbolSquareAuto) ? 0.7 : 0.9;
1823 pTmp.y = 0.8;
1824 }
1825
1826 dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw);
1827 loc1.x = (int)(pTmp.x + 0.5);
1828 loc1.y = (int)(pTmp.y + 0.5);
1829
1830 loc0 = follow.loc;
1831 line = bresLineInit(loc0, loc1, locOrigin);
1832 steps = trailBlazeGapped(dec, reg, line, streamDir);
1833
1834 bestLine = findBestSolidLine2(dec, loc0, steps, streamDir, avoidAngle);
1835 if (bestLine.mag < 5) {
1836 ;
1837 }
1838
1839 if (edgeLoc == DmtxEdgeTop) {
1840 reg->topKnown = 1;
1841 reg->topAngle = bestLine.angle;
1842 reg->topLoc = bestLine.locBeg;
1843 } else {
1844 reg->rightKnown = 1;
1845 reg->rightAngle = bestLine.angle;
1846 reg->rightLoc = bestLine.locBeg;
1847 }
1848
1849 return DmtxPass;
1850}
1851
1857{
1858 int cp;
1859 DmtxBresLine line;
1860 DmtxPixelLoc *locBeg, *locEnd;
1861
1862 /* XXX Verify that loc0 and loc1 are inbounds */
1863
1864 /* Values that stay the same after initialization */
1865 line.loc0 = loc0;
1866 line.loc1 = loc1;
1867 line.xStep = (loc0.x < loc1.x) ? +1 : -1;
1868 line.yStep = (loc0.y < loc1.y) ? +1 : -1;
1869 line.xDelta = abs(loc1.x - loc0.x);
1870 line.yDelta = abs(loc1.y - loc0.y);
1871 line.steep = (int)(line.yDelta > line.xDelta);
1872
1873 /* Take cross product to determine outward step */
1874 if (line.steep != 0) {
1875 /* Point first vector up to get correct sign */
1876 if (loc0.y < loc1.y) {
1877 locBeg = &loc0;
1878 locEnd = &loc1;
1879 } else {
1880 locBeg = &loc1;
1881 locEnd = &loc0;
1882 }
1883 cp = (((locEnd->x - locBeg->x) * (locInside.y - locEnd->y)) -
1884 ((locEnd->y - locBeg->y) * (locInside.x - locEnd->x)));
1885
1886 line.xOut = (cp > 0) ? +1 : -1;
1887 line.yOut = 0;
1888 } else {
1889 /* Point first vector left to get correct sign */
1890 if (loc0.x > loc1.x) {
1891 locBeg = &loc0;
1892 locEnd = &loc1;
1893 } else {
1894 locBeg = &loc1;
1895 locEnd = &loc0;
1896 }
1897 cp = (((locEnd->x - locBeg->x) * (locInside.y - locEnd->y)) -
1898 ((locEnd->y - locBeg->y) * (locInside.x - locEnd->x)));
1899
1900 line.xOut = 0;
1901 line.yOut = (cp > 0) ? +1 : -1;
1902 }
1903
1904 /* Values that change while stepping through line */
1905 line.loc = loc0;
1906 line.travel = 0;
1907 line.outward = 0;
1908 line.error = (line.steep) ? line.yDelta / 2 : line.xDelta / 2;
1909
1910 if (cbPlotPoint) {
1911 cbPlotPoint(loc0, 240.0F /*蓝*/, 1, 1);
1912 cbPlotPoint(loc1, 240.0F /*蓝*/, 1, 1);
1913 }
1914
1915 return line;
1916}
1917
1922static DmtxPassFail bresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward)
1923{
1924 /* Determine necessary step along and outward from Bresenham line */
1925 if (line.steep != 0) {
1926 *travel = (line.yStep > 0) ? target.y - line.loc.y : line.loc.y - target.y;
1927 bresLineStep(&line, *travel, 0);
1928 *outward = (line.xOut > 0) ? target.x - line.loc.x : line.loc.x - target.x;
1929 DmtxAssert(line.yOut == 0);
1930 } else {
1931 *travel = (line.xStep > 0) ? target.x - line.loc.x : line.loc.x - target.x;
1932 bresLineStep(&line, *travel, 0);
1933 *outward = (line.yOut > 0) ? target.y - line.loc.y : line.loc.y - target.y;
1934 DmtxAssert(line.xOut == 0);
1935 }
1936
1937 return DmtxPass;
1938}
1939
1944static DmtxPassFail bresLineStep(DmtxBresLine *line, int travel, int outward)
1945{
1946 int i;
1947 DmtxBresLine lineNew;
1948
1949 lineNew = *line;
1950
1951 DmtxAssert(abs(travel) < 2);
1952 DmtxAssert(abs(outward) >= 0);
1953
1954 /* Perform forward step */
1955 if (travel > 0) {
1956 lineNew.travel++;
1957 if (lineNew.steep != 0) {
1958 lineNew.loc.y += lineNew.yStep;
1959 lineNew.error -= lineNew.xDelta;
1960 if (lineNew.error < 0) {
1961 lineNew.loc.x += lineNew.xStep;
1962 lineNew.error += lineNew.yDelta;
1963 }
1964 } else {
1965 lineNew.loc.x += lineNew.xStep;
1966 lineNew.error -= lineNew.yDelta;
1967 if (lineNew.error < 0) {
1968 lineNew.loc.y += lineNew.yStep;
1969 lineNew.error += lineNew.xDelta;
1970 }
1971 }
1972 } else if (travel < 0) {
1973 lineNew.travel--;
1974 if (lineNew.steep != 0) {
1975 lineNew.loc.y -= lineNew.yStep;
1976 lineNew.error += lineNew.xDelta;
1977 if (lineNew.error >= lineNew.yDelta) {
1978 lineNew.loc.x -= lineNew.xStep;
1979 lineNew.error -= lineNew.yDelta;
1980 }
1981 } else {
1982 lineNew.loc.x -= lineNew.xStep;
1983 lineNew.error += lineNew.yDelta;
1984 if (lineNew.error >= lineNew.xDelta) {
1985 lineNew.loc.y -= lineNew.yStep;
1986 lineNew.error -= lineNew.xDelta;
1987 }
1988 }
1989 }
1990
1991 for (i = 0; i < outward; i++) {
1992 /* Outward steps */
1993 lineNew.outward++;
1994 lineNew.loc.x += lineNew.xOut;
1995 lineNew.loc.y += lineNew.yOut;
1996 }
1997
1998 *line = lineNew;
1999
2000 return DmtxPass;
2001}
2002
2007#ifdef NOTDEFINED
2008static void WriteDiagnosticImage(DmtxDecode *dec, DmtxRegion *reg, char *imagePath)
2009{
2010 int row, col;
2011 int width, height;
2012 unsigned char *cache;
2013 int rgb[3];
2014 FILE *fp;
2015 DmtxVector2 p;
2016 DmtxImage *img;
2017
2018 DmtxAssert(reg != NULL);
2019
2020 fp = fopen(imagePath, "wb");
2021 if (fp == NULL) {
2022 exit(3);
2023 }
2024
2025 width = dmtxDecodeGetProp(dec, DmtxPropWidth);
2026 height = dmtxDecodeGetProp(dec->image, DmtxPropHeight);
2027
2028 img = dmtxImageCreate(NULL, width, height, DmtxPack24bppRGB);
2029
2030 /* Populate image */
2031 for (row = 0; row < height; row++) {
2032 for (col = 0; col < width; col++) {
2033 cache = dmtxDecodeGetCache(dec, col, row);
2034 if (cache == NULL) {
2035 rgb[0] = 0;
2036 rgb[1] = 0;
2037 rgb[2] = 128;
2038 } else {
2039 dmtxDecodeGetPixelValue(dec, col, row, 0, &rgb[0]);
2040 dmtxDecodeGetPixelValue(dec, col, row, 1, &rgb[1]);
2041 dmtxDecodeGetPixelValue(dec, col, row, 2, &rgb[2]);
2042
2043 p.X = col;
2044 p.Y = row;
2046
2047 if (p.X < 0.0 || p.X > 1.0 || p.Y < 0.0 || p.Y > 1.0) {
2048 rgb[0] = 0;
2049 rgb[1] = 0;
2050 rgb[2] = 128;
2051 } else if (p.X + p.Y > 1.0) {
2052 rgb[0] += (0.4 * (255 - rgb[0]));
2053 rgb[1] += (0.4 * (255 - rgb[1]));
2054 rgb[2] += (0.4 * (255 - rgb[2]));
2055 }
2056 }
2057
2058 dmtxImageSetRgb(img, col, row, rgb);
2059 }
2060 }
2061
2062 /* Write additional markers */
2063 rgb[0] = 255;
2064 rgb[1] = 0;
2065 rgb[2] = 0;
2066 dmtxImageSetRgb(img, reg->toploc.x, reg->toploc.y, rgb);
2067 dmtxImageSetRgb(img, reg->rightloc.x, reg->rightloc.y, rgb);
2068
2069 /* Write image to PNM file */
2070 fprintf(fp, "P6\n%d %d\n255\n", width, height);
2071 for (row = height - 1; row >= 0; row--) {
2072 for (col = 0; col < width; col++) {
2073 dmtxImageGetRgb(img, col, row, rgb);
2074 fwrite(rgb, sizeof(char), 3, fp);
2075 }
2076 }
2077
2078 dmtxImageDestroy(&img);
2079
2080 fclose(fp);
2081}
2082#endif
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
DmtxPassFail dmtxMatrix3VMultiply(OUT DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m)
将向量与矩阵相乘
#define DmtxPassFail
Definition dmtx.h:42
double dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2)
二维向量叉积
Definition dmtxvector2.c:89
@ DmtxPropWidth
图像宽度
Definition dmtx.h:196
@ DmtxPropHeight
图像高度
Definition dmtx.h:197
@ DmtxPropScale
图像缩放比例
Definition dmtx.h:211
void dmtxMatrix3LineSkewSide(OUT DmtxMatrix3 m, double b0, double b1, double sz)
Generate side line skew transformation.
int dmtxGetSymbolAttribute(int attribute, int sizeIdx)
根据规格索引返回二维码规格各个参数
Definition dmtxsymbol.c:45
enum DmtxDirection_enum DmtxDirection
int dmtxTimeExceeded(DmtxTime timeout)
Determine whether the received timeout has been exceeded.
Definition dmtxtime.c:139
#define DmtxTrue
Definition dmtx.h:47
double DmtxMatrix3[3][3]
DmtxMatrix3 类型定义,表示一个3x3的双精度浮点数矩阵
Definition dmtx.h:262
void dmtxMatrix3Multiply(OUT DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1)
矩阵相乘
@ DmtxPack24bppRGB
Definition dmtx.h:231
@ DmtxSymAttribSymbolRows
二维码码元总行数(包括L形框和点线)
Definition dmtx.h:154
@ DmtxSymAttribSymbolCols
二维码码元总列数(包括L形框和点线)
Definition dmtx.h:155
@ DmtxSymAttribMappingMatrixRows
二维码数据区码元总行数(不包括L形框和点线)
Definition dmtx.h:160
@ DmtxSymAttribMappingMatrixCols
二维码数据区码元总列数(不包括L形框和点线)
Definition dmtx.h:161
void dmtxMatrix3LineSkewTop(OUT DmtxMatrix3 m, double b0, double b1, double sz)
生成顶部线倾斜变换矩阵
#define DmtxBoolean
Definition dmtx.h:46
#define DmtxPass
Definition dmtx.h:43
DmtxPassFail dmtxImageDestroy(DmtxImage **img)
Free libdmtx image memory.
Definition dmtximage.c:167
#define DmtxUndefined
Definition dmtx.h:40
double dmtxVector2Mag(const DmtxVector2 *v)
二维向量的模
void dmtxMatrix3Rotate(OUT DmtxMatrix3 m, double angle)
生成旋转变换矩阵
@ DmtxDirRight
Definition dmtx.h:145
@ DmtxDirUp
Definition dmtx.h:142
DmtxPassFail dmtxMatrix3VMultiplyBy(INOUT DmtxVector2 *v, DmtxMatrix3 m)
将向量与矩阵相乘
#define DmtxFalse
Definition dmtx.h:48
DmtxPassFail dmtxRay2Intersect(OUT DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1)
判断两条直线是否相交,并计算交点。
void dmtxMatrix3Translate(OUT DmtxMatrix3 m, double tx, double ty)
生成平移变换矩阵
Definition dmtxmatrix3.c:82
double dmtxVector2Norm(DmtxVector2 *v)
DmtxImage * dmtxImageCreate(unsigned char *pxl, int width, int height, int pack)
libdmtx stores image data as a large one-dimensional array of packed pixels, reading from the array w...
Definition dmtximage.c:78
#define DmtxSymbolRectCount
长方形二维码种类个数
Definition dmtx.h:54
#define M_PI_2
Definition dmtx.h:37
void dmtxMatrix3LineSkewSideInv(OUT DmtxMatrix3 m, double b0, double b1, double sz)
Generate side line skew transformation (inverse)
void dmtxMatrix3Shear(OUT DmtxMatrix3 m, double shx, double shy)
生成剪切变换矩阵
#define DmtxSymbolSquareCount
正方形二维码种类个数
Definition dmtx.h:53
#define DmtxModuleOn
bit1
Definition dmtx.h:61
DmtxVector2 * dmtxVector2Sub(OUT DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2)
向量相减
Definition dmtxvector2.c:58
#define DmtxFail
Definition dmtx.h:44
void dmtxMatrix3MultiplyBy(INOUT DmtxMatrix3 m0, DmtxMatrix3 m1)
矩阵相乘
double dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2)
二维向量点积
void dmtxMatrix3Scale(OUT DmtxMatrix3 m, double sx, double sy)
生成缩放变换矩阵
#define M_PI
Definition dmtx.h:33
#define DmtxModuleOff
bit0
Definition dmtx.h:56
void dmtxMatrix3LineSkewTopInv(OUT DmtxMatrix3 m, double b0, double b1, double sz)
Generate top line skew transformation (inverse)
@ DmtxSymbol10x10
Definition dmtx.h:105
@ DmtxSymbol144x144
Definition dmtx.h:128
@ DmtxSymbolRectAuto
Definition dmtx.h:100
@ DmtxSymbol8x18
Definition dmtx.h:131
@ DmtxSymbolShapeAuto
Definition dmtx.h:102
@ DmtxSymbolSquareAuto
Definition dmtx.h:101
@ DmtxSymbol16x48
Definition dmtx.h:136
unsigned char * dmtxDecodeGetCache(DmtxDecode *dec, int x, int y)
Returns xxx.
Definition dmtxdecode.c:211
DmtxPassFail dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, OUT int *value)
获取图像像素
Definition dmtxdecode.c:233
int dmtxDecodeGetProp(DmtxDecode *dec, int prop)
Get decoding behavior property.
Definition dmtxdecode.c:166
DmtxRegion * dmtxRegionScanPixel(DmtxDecode *dec, int x, int y)
将坐标点(x,y)作为二维码L型框的边缘点去匹配二维码包围框
Definition dmtxregion.c:100
DmtxPassFail dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg)
Definition dmtxregion.c:528
static DmtxPointFlow findStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign)
static DmtxPassFail matrixRegionAlignCalibEdge(DmtxDecode *dec, DmtxRegion *reg, int edgeLoc)
static DmtxPassFail matrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg)
确定二维码尺寸(点线中黑白点的总数)
Definition dmtxregion.c:688
DmtxRegion * dmtxRegionFindNext(DmtxDecode *dec, DmtxTime *timeout)
寻找下一个二维码区域
Definition dmtxregion.c:69
static double rightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle)
Definition dmtxregion.c:620
static DmtxBestLine findBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid)
DmtxPassFail dmtxRegionDestroy(DmtxRegion **reg)
Destroy region struct.
Definition dmtxregion.c:51
#define DMTX_HOUGH_RES
Definition dmtxregion.c:26
static DmtxBestLine findBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir, int houghAvoid)
查找最佳实线
static DmtxPointFlow getPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive)
从像素坐标寻找其在指定颜色平面的梯度方向
Definition dmtxregion.c:974
static DmtxPassFail bresLineStep(DmtxBresLine *line, int travel, int outward)
static DmtxFollow followSeek(DmtxDecode *dec, DmtxRegion *reg, int seek)
根据指定步数从当前区域的起始点追踪到新位置
DmtxRegion * dmtxRegionCreate(DmtxRegion *reg)
Create copy of existing region struct.
Definition dmtxregion.c:32
static DmtxPassFail trailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal)
从flowBegin点出发,分别从正负方向寻找连续的边界线
static DmtxPassFail findTravelLimits(DmtxDecode *dec, DmtxRegion *reg, DmtxBestLine *line)
static DmtxFollow followStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign)
DmtxPassFail dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00, DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01)
Definition dmtxregion.c:421
static long distanceSquared(DmtxPixelLoc a, DmtxPixelLoc b)
计算两个像素点之间的欧几里得距离的平方
Definition dmtxregion.c:407
static int readModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx, int colorPlane)
读取模块(码元)颜色值
Definition dmtxregion.c:646
static DmtxFollow followSeekLoc(DmtxDecode *dec, DmtxPixelLoc loc)
根据指定像素坐标初始化追踪起始信息
static int trailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask)
static DmtxBresLine bresLineInit(DmtxPixelLoc loc0, DmtxPixelLoc loc1, DmtxPixelLoc locInside)
static int countJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir)
计算一个方向上颜色跳变次数
Definition dmtxregion.c:919
static int trailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir)
recives bresline, and follows strongest neighbor unless it involves ratcheting bresline inward or bac...
static DmtxPassFail bresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward)
static DmtxFollow followStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign)
寻找followBeg的下一个点
static DmtxPassFail matrixRegionOrientation(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow begin)
确定数据矩阵区域的方向和关键边界
Definition dmtxregion.c:240
static DmtxPointFlow matrixRegionSeekEdge(DmtxDecode *dec, DmtxPixelLoc loc)
寻找指定像素位置梯度流向,并检查该点是否能形成闭环。如果成功暂定该点在DataMatrix的'L'型边上
Definition dmtxregion.c:176
static int popGridLocation(DmtxScanGrid *grid, DmtxPixelLoc *locPtr)
Return the next good location (which may be the current location), and advance grid progress one posi...
libdmtx - Data Matrix Encoding/Decoding Library Copyright 2008, 2009 Mike Laughton.
static const DmtxPointFlow dmtxBlankEdge
Definition dmtxstatic.h:357
static const int dmtxPatternX[]
Definition dmtxstatic.h:355
static int rHvY[]
Definition dmtxstatic.h:380
static int rHvX[]
Definition dmtxstatic.h:368
#define DmtxAssert(expr)
Definition dmtxstatic.h:96
#define min(X, Y)
Definition dmtxstatic.h:62
static const int dmtxPatternY[]
Definition dmtxstatic.h:356
@ DmtxEdgeRight
Definition dmtxstatic.h:124
@ DmtxEdgeTop
Definition dmtxstatic.h:121
static const int dmtxNeighborNone
Definition dmtxstatic.h:354
#define max(X, Y)
Definition dmtxstatic.h:65
static DmtxCallbackPlotModule cbPlotModule
Definition dmtxstatic.h:363
static DmtxCallbackPlotPoint cbPlotPoint
Definition dmtxstatic.h:361
static DmtxCallbackBuildMatrixRegion cbBuildMatrixRegion
Definition dmtxstatic.h:359
@ DmtxRangeEnd
Definition dmtxstatic.h:116
DmtxPixelLoc locPos
正方向点(线段端点)
Definition dmtx.h:361
DmtxPixelLoc locBeg
起始位置点
Definition dmtx.h:360
int mag
幅值
Definition dmtx.h:354
int stepPos
正方向步进位置
Definition dmtx.h:356
DmtxPixelLoc locNeg
负方向点(线段端点)
Definition dmtx.h:362
int angle
线条的角度,单位:度
Definition dmtx.h:352
int stepNeg
负方向步进位置
Definition dmtx.h:357
DmtxBresLine.
DmtxDecode.
DmtxFollow.
像素坐标
Definition dmtx.h:268
图像像素点及其梯度流动方向
Definition dmtx.h:342
int mag
梯度幅值
Definition dmtx.h:346
int arrive
梯度方向起点
Definition dmtx.h:344
int plane
多通道平面索引
Definition dmtx.h:343
DmtxPixelLoc loc
像素的坐标
Definition dmtx.h:347
int depart
梯度方向终点
Definition dmtx.h:345
向量表示的直线(线段)
Definition dmtx.h:286
DmtxVector2 p
Definition dmtx.h:289
double tMin
Definition dmtx.h:287
double tMax
Definition dmtx.h:288
DmtxVector2 v
Definition dmtx.h:290
二维码区域(包围框)
Definition dmtx.h:369
int leftAngle
hough angle of left edge
Definition dmtx.h:389
int bottomKnown
known == 1; unknown == 0
Definition dmtx.h:392
int offColor
代表bit0的颜色值
Definition dmtx.h:405
int bottomAngle
hough angle of bottom edge
Definition dmtx.h:393
DmtxPixelLoc finalNeg
Definition dmtx.h:375
int rightKnown
known == 1; unknown == 0
Definition dmtx.h:399
DmtxPixelLoc rightLoc
known (arbitrary) location on right edge
Definition dmtx.h:401
DmtxMatrix3 raw2fit
3x3 变换矩阵,从图像坐标系到二维码坐标系
Definition dmtx.h:413
DmtxBestLine bottomLine
Definition dmtx.h:395
int mappingCols
二维码数据区码元列数
Definition dmtx.h:410
int sizeIdx
二维码类型索引,总共有 DmtxSymbolSquareCount + DmtxSymbolRectCount 种
Definition dmtx.h:406
DmtxPixelLoc finalPos
Definition dmtx.h:374
int mappingRows
二维码数据区码元行数
Definition dmtx.h:409
int leftKnown
known == 1; unknown == 0
Definition dmtx.h:388
DmtxPointFlow flowBegin
搜索起点,十字搜索抛出的点
Definition dmtx.h:378
int symbolRows
二维码码元行数(包括L形框和点线)
Definition dmtx.h:407
int symbolCols
二维码码元列数(包括L形框和点线)
Definition dmtx.h:408
DmtxPixelLoc boundMax
Definition dmtx.h:377
DmtxPixelLoc boundMin
Definition dmtx.h:376
int onColor
代表bit1的颜色值
Definition dmtx.h:404
DmtxPixelLoc bottomLoc
known (arbitrary) location on bottom edge
Definition dmtx.h:394
int topKnown
known == 1; unknown == 0
Definition dmtx.h:396
int rightAngle
hough angle of right edge
Definition dmtx.h:400
DmtxBestLine leftLine
Definition dmtx.h:391
DmtxPixelLoc leftLoc
known (arbitrary) location on left edge
Definition dmtx.h:390
DmtxPixelLoc locT
remove if stepT works above
Definition dmtx.h:385
DmtxPixelLoc topLoc
known (arbitrary) location on top edge
Definition dmtx.h:398
int topAngle
hough angle of top edge
Definition dmtx.h:397
DmtxPixelLoc locR
remove if stepR works above
Definition dmtx.h:384
DmtxMatrix3 fit2raw
3x3 变换矩阵,从二维码坐标系到图像坐标系
Definition dmtx.h:414
DmtxTime.
二维向量
Definition dmtx.h:277