📄 dmtxregion.c
字号:
dmtxMatrix3MultiplyBy(m, mshx); dmtxMatrix3Rotate(mphi, -phi); dmtxMatrix3MultiplyBy(m, mphi); dmtxMatrix3Translate(mtxy, -tx, -ty); dmtxMatrix3Multiply(reg->fit2raw, m, mtxy); return DMTX_SUCCESS;}/** * * */extern intdmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg){ double radians; DmtxRay2 rLeft, rBottom, rTop, rRight; DmtxVector2 p00, p10, p11, p01; assert(reg->leftKnown != 0 && reg->bottomKnown != 0); /* Build ray representing left edge */ rLeft.p.X = (double)reg->leftLoc.X; rLeft.p.Y = (double)reg->leftLoc.Y; radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES); rLeft.v.X = cos(radians); rLeft.v.Y = sin(radians); rLeft.tMin = 0.0; rLeft.tMax = dmtxVector2Norm(&rLeft.v); /* Build ray representing bottom edge */ rBottom.p.X = (double)reg->bottomLoc.X; rBottom.p.Y = (double)reg->bottomLoc.Y; radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES); rBottom.v.X = cos(radians); rBottom.v.Y = sin(radians); rBottom.tMin = 0.0; rBottom.tMax = dmtxVector2Norm(&rBottom.v); /* Build ray representing top edge */ if(reg->topKnown != 0) { rTop.p.X = (double)reg->topLoc.X; rTop.p.Y = (double)reg->topLoc.Y; radians = reg->topAngle * (M_PI/DMTX_HOUGH_RES); rTop.v.X = cos(radians); rTop.v.Y = sin(radians); rTop.tMin = 0.0; rTop.tMax = dmtxVector2Norm(&rTop.v); } else { rTop.p.X = (double)reg->locT.X; rTop.p.Y = (double)reg->locT.Y; radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES); rTop.v.X = cos(radians); rTop.v.Y = sin(radians); rTop.tMin = 0.0; rTop.tMax = rBottom.tMax; } /* Build ray representing right edge */ if(reg->rightKnown != 0) { rRight.p.X = (double)reg->rightLoc.X; rRight.p.Y = (double)reg->rightLoc.Y; radians = reg->rightAngle * (M_PI/DMTX_HOUGH_RES); rRight.v.X = cos(radians); rRight.v.Y = sin(radians); rRight.tMin = 0.0; rRight.tMax = dmtxVector2Norm(&rRight.v); } else { rRight.p.X = (double)reg->locR.X; rRight.p.Y = (double)reg->locR.Y; radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES); rRight.v.X = cos(radians); rRight.v.Y = sin(radians); rRight.tMin = 0.0; rRight.tMax = rLeft.tMax; } /* Calculate 4 corners, real or imagined */ if(dmtxRay2Intersect(&p00, &rLeft, &rBottom) == DMTX_FAILURE) return DMTX_FAILURE; if(dmtxRay2Intersect(&p10, &rBottom, &rRight) == DMTX_FAILURE) return DMTX_FAILURE; if(dmtxRay2Intersect(&p11, &rRight, &rTop) == DMTX_FAILURE) return DMTX_FAILURE; if(dmtxRay2Intersect(&p01, &rTop, &rLeft) == DMTX_FAILURE) return DMTX_FAILURE; if(dmtxRegionUpdateCorners(dec, reg, p00, p10, p11, p01) != DMTX_SUCCESS) return DMTX_FAILURE; return DMTX_SUCCESS;}/** * * */static doubleRightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle){ DmtxVector2 vA, vB; DmtxMatrix3 m; dmtxVector2Norm(dmtxVector2Sub(&vA, &c0, &c1)); dmtxVector2Norm(dmtxVector2Sub(&vB, &c2, &c1)); dmtxMatrix3Rotate(m, angle); dmtxMatrix3VMultiplyBy(&vB, m); return dmtxVector2Dot(&vA, &vB);}/** * @brief Read color of Data Matrix module location * @param image * @param reg * @param symbolRow * @param symbolCol * @param sizeIdx * @return Averaged module color */static intReadModuleColor(DmtxImage *img, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx){ int i; int symbolRows, symbolCols; int color; double sampleX[] = { 0.5, 0.4, 0.5, 0.6, 0.5 }; double sampleY[] = { 0.5, 0.5, 0.4, 0.5, 0.6 }; DmtxVector2 p; symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); color = 0; for(i = 0; i < 5; i++) { p.X = (1.0/symbolCols) * (symbolCol + sampleX[i]); p.Y = (1.0/symbolRows) * (symbolRow + sampleY[i]); dmtxMatrix3VMultiplyBy(&p, reg->fit2raw); color += dmtxImageGetColor(img, (int)(p.X + 0.5), (int)(p.Y + 0.5), reg->flowBegin.plane); } return color/5;}/** * @brief Determine barcode size, expressed in modules * @param image * @param reg * @return DMTX_SUCCESS | DMTX_FAILURE */static intMatrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg){ int row, col; int sizeIdxBeg, sizeIdxEnd; int sizeIdx, bestSizeIdx; int symbolRows, symbolCols; int jumpCount, errors; int color; int colorOnAvg, bestColorOnAvg; int colorOffAvg, bestColorOffAvg; int contrast, bestContrast; DmtxImage *img; img = dec->image; bestSizeIdx = -1; bestContrast = 0; bestColorOnAvg = bestColorOffAvg = 0; if(dec->sizeIdxExpected == DmtxSymbolShapeAuto) { sizeIdxBeg = 0; sizeIdxEnd = DMTX_SYMBOL_SQUARE_COUNT + DMTX_SYMBOL_RECT_COUNT; } else if(dec->sizeIdxExpected == DmtxSymbolSquareAuto) { sizeIdxBeg = 0; sizeIdxEnd = DMTX_SYMBOL_SQUARE_COUNT; } else if(dec->sizeIdxExpected == DmtxSymbolRectAuto) { sizeIdxBeg = DMTX_SYMBOL_SQUARE_COUNT; sizeIdxEnd = DMTX_SYMBOL_SQUARE_COUNT + DMTX_SYMBOL_RECT_COUNT; } else { sizeIdxBeg = dec->sizeIdxExpected; sizeIdxEnd = dec->sizeIdxExpected + 1; } /* Test each barcode size to find best contrast in calibration modules */ for(sizeIdx = sizeIdxBeg; sizeIdx < sizeIdxEnd; sizeIdx++) { symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx); symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx); colorOnAvg = colorOffAvg = 0; /* Sum module colors along horizontal calibration bar */ row = symbolRows - 1; for(col = 0; col < symbolCols; col++) { color = ReadModuleColor(img, reg, row, col, sizeIdx); if((col & 0x01) != 0x00) colorOffAvg += color; else colorOnAvg += color; } /* Sum module colors along vertical calibration bar */ col = symbolCols - 1; for(row = 0; row < symbolRows; row++) { color = ReadModuleColor(img, reg, row, col, sizeIdx); if((row & 0x01) != 0x00) colorOffAvg += color; else colorOnAvg += color; } colorOnAvg = (colorOnAvg * 2)/(symbolRows + symbolCols); colorOffAvg = (colorOffAvg * 2)/(symbolRows + symbolCols); contrast = abs(colorOnAvg - colorOffAvg); if(contrast < 20) continue; if(contrast > bestContrast) { bestContrast = contrast; bestSizeIdx = sizeIdx; bestColorOnAvg = colorOnAvg; bestColorOffAvg = colorOffAvg; } } /* If no sizes produced acceptable contrast then call it quits */ if(bestSizeIdx == -1 || bestContrast < 20) return DMTX_FAILURE; reg->sizeIdx = bestSizeIdx; reg->onColor = bestColorOnAvg; reg->offColor = bestColorOffAvg; reg->symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, reg->sizeIdx); reg->symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, reg->sizeIdx); reg->mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, reg->sizeIdx); reg->mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, reg->sizeIdx); /* Tally jumps on horizontal calibration bar to verify sizeIdx */ jumpCount = CountJumpTally(img, reg, 0, reg->symbolRows - 1, DmtxDirRight); errors = abs(1 + jumpCount - reg->symbolCols); if(jumpCount < 0 || errors > 2) return DMTX_FAILURE; /* Tally jumps on vertical calibration bar to verify sizeIdx */ jumpCount = CountJumpTally(img, reg, reg->symbolCols - 1, 0, DmtxDirUp); errors = abs(1 + jumpCount - reg->symbolRows); if(jumpCount < 0 || errors > 2) return DMTX_FAILURE; /* Tally jumps on horizontal finder bar to verify sizeIdx */ errors = CountJumpTally(img, reg, 0, 0, DmtxDirRight); if(jumpCount < 0 || errors > 2) return DMTX_FAILURE; /* Tally jumps on vertical finder bar to verify sizeIdx */ errors = CountJumpTally(img, reg, 0, 0, DmtxDirUp); if(errors < 0 || errors > 2) return DMTX_FAILURE; /* Tally jumps on surrounding whitespace, else fail */ errors = CountJumpTally(img, reg, 0, -1, DmtxDirRight); if(errors < 0 || errors > 2) return DMTX_FAILURE; errors = CountJumpTally(img, reg, -1, 0, DmtxDirUp); if(errors < 0 || errors > 2) return DMTX_FAILURE; errors = CountJumpTally(img, reg, 0, reg->symbolRows, DmtxDirRight); if(errors < 0 || errors > 2) return DMTX_FAILURE; errors = CountJumpTally(img, reg, reg->symbolCols, 0, DmtxDirUp); if(errors < 0 || errors > 2) return DMTX_FAILURE; return DMTX_SUCCESS;}/** * @brief Count the number of number of transitions between light and dark * @param img * @param reg * @param xStart * @param yStart * @param dir * @return Jump count */static intCountJumpTally(DmtxImage *img, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir){ int x, xInc = 0; int y, yInc = 0; int state = DMTX_MODULE_ON; int jumpCount = 0; int jumpThreshold; int tModule, tPrev; int darkOnLight; int color; assert(xStart == 0 || yStart == 0); assert(dir == DmtxDirRight || dir == DmtxDirUp); if(dir == DmtxDirRight) xInc = 1; else yInc = 1; if(xStart == -1 || xStart == reg->symbolCols || yStart == -1 || yStart == reg->symbolRows) state = DMTX_MODULE_OFF; darkOnLight = (int)(reg->offColor > reg->onColor); jumpThreshold = abs((int)(0.4 * (reg->onColor - reg->offColor) + 0.5)); color = ReadModuleColor(img, reg, yStart, xStart, reg->sizeIdx); tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; for(x = xStart + xInc, y = yStart + yInc; (dir == DmtxDirRight && x < reg->symbolCols) || (dir == DmtxDirUp && y < reg->symbolRows); x += xInc, y += yInc) { tPrev = tModule; color = ReadModuleColor(img, reg, y, x, reg->sizeIdx); tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor; if(state == DMTX_MODULE_OFF) { if(tModule > tPrev + jumpThreshold) { jumpCount++; state = DMTX_MODULE_ON; } } else { if(tModule < tPrev - jumpThreshold) { jumpCount++; state = DMTX_MODULE_OFF; } } } return jumpCount;}/** * * */static DmtxPointFlowGetPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive){ static const int coefficient[] = { 0, 1, 2, 1, 0, -1, -2, -1 }; int patternIdx, coefficientIdx; int compass, compassMax; int mag[4] = { 0 }; int xAdjust, yAdjust; int color, colorPattern[8]; DmtxPointFlow flow; for(patternIdx = 0; patternIdx < 8; patternIdx++) { xAdjust = loc.X + dmtxPatternX[patternIdx]; yAdjust = loc.Y + dmtxPatternY[patternIdx]; colorPattern[patternIdx] = dmtxImageGetColor(dec->image, xAdjust, yAdjust, colorPlane); if(colorPattern[patternIdx] == -1) return dmtxBlankEdge; } /* Calculate this pixel's flow intensity for each direction (-45, 0, 45, 90) */ compassMax = 0; for(compass = 0; compass < 4; compass++) { /* Add portion from each position in the convolution matrix pattern */ for(patternIdx = 0; patternIdx < 8; patternIdx++) { coefficientIdx = (patternIdx - compass + 8) % 8; if(coefficient[coefficientIdx] == 0) continue; color = colorPattern[patternIdx]; switch(coefficient[coefficientIdx]) { case 2: mag[compass] += color; /* Fall through */ case 1: mag[compass] += color; break; case -2: mag[compass] -= color; /* Fall through */ case -1: mag[compass] -= color; break; } } /* Identify strongest compass flow */ if(compass != 0 && abs(mag[compass]) > abs(mag[compassMax])) compassMax = compass; } /* Convert signed compass direction into unique flow directions (0-7) */ flow.plane = colorPlane; flow.arrive = arrive; flow.depart = (mag[compassMax] > 0) ? compassMax + 4 : compassMax; flow.mag = abs(mag[compassMax]); flow.loc = loc; return flow;}/** * * */static DmtxPointFlowFindStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign){ int i; int offset; int strongIdx; int attempt, attemptDiff; int occupied; unsigned char *cache; DmtxPixelLoc loc; DmtxPointFlow flow[8]; attempt = (sign < 0) ? center.depart : (center.depart+4)%8; occupied = 0; strongIdx = -1; for(i = 0; i < 8; i++) { loc.X = center.loc.X + dmtxPatternX[i]; loc.Y = center.loc.Y + dmtxPatternY[i]; offset = dmtxImageGetOffset(dec->image, loc.X, loc.Y); if(offset == DMTX_BAD_OFFSET) { loc.status = DMTX_RANGE_BAD; continue; } else { loc.status = DMTX_RANGE_GOOD; } cache = &(dec->image->cache[offset]); if((int)(*cache & 0x80) != 0x00) { if(++occupied > 2) return dmtxBlankEdge; else continue; } attemptDiff = abs(attempt - i); if(attemptDiff > 4) attemptDiff = 8 - attemptDiff; if(attemptDiff > 1) continue; flow[i] = GetPointFlow(dec, center.plane, loc, i); if(strongIdx == -1 || flow[i].mag > flow[strongIdx].mag || (flow[i].mag == flow[strongIdx].mag && ((i & 0x01) != 0))) { strongIdx = i; } } return (strongIdx == -1) ? dmtxBlankEdge : flow[strongIdx];}/** * * */static DmtxFollowFollowSeek(DmtxDecode *dec, DmtxRegion *reg, int seek)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -