internal DmtxRegion(DmtxRegion src) { this._bottomAngle = src._bottomAngle; this._bottomKnown = src._bottomKnown; this._bottomLine = src._bottomLine; this._bottomLoc = src._bottomLoc; this._boundMax = src._boundMax; this._boundMin = src._boundMin; this._finalNeg = src._finalNeg; this._finalPos = src._finalPos; this._fit2raw = new DmtxMatrix3(src._fit2raw); this._flowBegin = src._flowBegin; this._jumpToNeg = src._jumpToNeg; this._jumpToPos = src._jumpToPos; this._leftAngle = src._leftAngle; this._leftKnown = src._leftKnown; this._leftLine = src._leftLine; this._leftLoc = src._leftLoc; this._locR = src._locR; this._locT = src._locT; this._mappingCols = src._mappingCols; this._mappingRows = src._mappingRows; this._offColor = src._offColor; this._onColor = src._onColor; this._polarity = src._polarity; this._raw2fit = new DmtxMatrix3(src._raw2fit); this._rightAngle = src._rightAngle; this._rightKnown = src._rightKnown; this._rightLoc = src._rightLoc; this._sizeIdx = src._sizeIdx; this._stepR = src._stepR; this._stepsTotal = src._stepsTotal; this._stepT = src._stepT; this._symbolCols = src._symbolCols; this._symbolRows = src._symbolRows; this._topAngle = src._topAngle; this._topKnown = src._topKnown; this._topLoc = src._topLoc; }
DmtxPointFlow FindStrongestNeighbor(DmtxPointFlow center, int sign) { int i; int strongIdx; int attempt, attemptDiff; int occupied; DmtxPixelLoc loc = new DmtxPixelLoc(); DmtxPointFlow[] flow = new DmtxPointFlow[8]; attempt = (sign < 0) ? center.Depart : (center.Depart + 4) % 8; occupied = 0; strongIdx = DmtxConstants.DmtxUndefined; for (i = 0; i < 8; i++) { loc.X = center.Loc.X + DmtxConstants.DmtxPatternX[i]; loc.Y = center.Loc.Y + DmtxConstants.DmtxPatternY[i]; int cacheIndex = DecodeGetCache(loc.X, loc.Y); if (cacheIndex == DmtxConstants.DmtxUndefined) { continue; } if ((int)(this._cache[cacheIndex] & 0x80) != 0x00) { if (++occupied > 2) return DmtxConstants.DmtxBlankEdge; else continue; } attemptDiff = Math.Abs(attempt - i); if (attemptDiff > 4) attemptDiff = 8 - attemptDiff; if (attemptDiff > 1) continue; flow[i] = GetPointFlow(center.Plane, loc, i); if (strongIdx == DmtxConstants.DmtxUndefined || flow[i].Mag > flow[strongIdx].Mag || (flow[i].Mag == flow[strongIdx].Mag && ((i & 0x01) != 0))) { strongIdx = i; } } return (strongIdx == DmtxConstants.DmtxUndefined) ? DmtxConstants.DmtxBlankEdge : flow[strongIdx]; }
bool TrailBlazeContinuous(DmtxRegion reg, DmtxPointFlow flowBegin, int maxDiagonal) { int posAssigns, negAssigns, clears; int sign; int steps; DmtxPointFlow flow, flowNext; DmtxPixelLoc boundMin, boundMax; boundMin = boundMax = flowBegin.Loc; int cacheBegIndex = DecodeGetCache(flowBegin.Loc.X, flowBegin.Loc.Y); this._cache[cacheBegIndex] = 0x80 | 0x40; reg.FlowBegin = flowBegin; posAssigns = negAssigns = 0; for (sign = 1; sign >= -1; sign -= 2) { flow = flowBegin; int cacheIndex = cacheBegIndex; for (steps = 0; ; steps++) { if (maxDiagonal != DmtxConstants.DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || boundMax.Y - boundMin.Y > maxDiagonal)) break; /* Find the strongest eligible neighbor */ flowNext = FindStrongestNeighbor(flow, sign); if (flowNext.Mag < 50) break; /* Get the neighbor's cache location */ int cacheNextIndex = DecodeGetCache(flowNext.Loc.X, flowNext.Loc.Y); if ((this._cache[cacheNextIndex] & 0x80) != 0) { throw new Exception("Error creating Trail Blaze"); } /* Mark departure from current location. If flowing downstream * (sign < 0) then departure vector here is the arrival vector * of the next location. Upstream flow uses the opposite rule. */ this._cache[cacheIndex] |= (sign < 0) ? (byte)(flowNext.Arrive) : (byte)(flowNext.Arrive << 3); /* Mark known direction for next location */ /* If testing downstream (sign < 0) then next upstream is opposite of next arrival */ /* If testing upstream (sign > 0) then next downstream is opposite of next arrival */ this._cache[cacheNextIndex] = (sign < 0) ? (byte)(((flowNext.Arrive + 4) % 8) << 3) : (byte)((flowNext.Arrive + 4) % 8); this._cache[cacheNextIndex] |= (0x80 | 0x40); /* Mark location as visited and assigned */ if (sign > 0) posAssigns++; else negAssigns++; cacheIndex = cacheNextIndex; flow = flowNext; if (flow.Loc.X > boundMax.X) boundMax.X = flow.Loc.X; else if (flow.Loc.X < boundMin.X) boundMin.X = flow.Loc.X; if (flow.Loc.Y > boundMax.Y) boundMax.Y = flow.Loc.Y; else if (flow.Loc.Y < boundMin.Y) boundMin.Y = flow.Loc.Y; /* CALLBACK_POINT_PLOT(flow.loc, (sign > 0) ? 2 : 3, 1, 2); */ } if (sign > 0) { reg.FinalPos = flow.Loc; reg.JumpToNeg = steps; } else { reg.FinalNeg = flow.Loc; reg.JumpToPos = steps; } } reg.StepsTotal = reg.JumpToPos + reg.JumpToNeg; reg.BoundMin = boundMin; reg.BoundMax = boundMax; /* Clear "visited" bit from trail */ clears = TrailClear(reg, 0x80); if (!(posAssigns + negAssigns == clears - 1)) { throw new Exception("Error cleaning after trail blaze continuous"); } /* XXX clean this up ... redundant test above */ if (maxDiagonal != DmtxConstants.DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal || boundMax.Y - boundMin.Y > maxDiagonal)) return false; return true; }
DmtxPointFlow MatrixRegionSeekEdge(DmtxPixelLoc loc) { DmtxPointFlow flow; DmtxPointFlow[] flowPlane = new DmtxPointFlow[3]; DmtxPointFlow flowPos, flowPosBack; DmtxPointFlow flowNeg, flowNegBack; int channelCount = _image.ChannelCount; /* Find whether red, green, or blue shows the strongest edge */ int strongIdx = 0; for (int i = 0; i < channelCount; i++) { flowPlane[i] = GetPointFlow(i, loc, DmtxConstants.DmtxNeighborNone); if (i > 0 && flowPlane[i].Mag > flowPlane[strongIdx].Mag) strongIdx = i; } if (flowPlane[strongIdx].Mag < 10) return DmtxConstants.DmtxBlankEdge; flow = flowPlane[strongIdx]; flowPos = FindStrongestNeighbor(flow, +1); flowNeg = FindStrongestNeighbor(flow, -1); if (flowPos.Mag != 0 && flowNeg.Mag != 0) { flowPosBack = FindStrongestNeighbor(flowPos, -1); flowNegBack = FindStrongestNeighbor(flowNeg, +1); if (flowPos.Arrive == (flowPosBack.Arrive + 4) % 8 && flowNeg.Arrive == (flowNegBack.Arrive + 4) % 8) { flow.Arrive = DmtxConstants.DmtxNeighborNone; //CALLBACK_POINT_PLOT(flow.Loc, 1, 1, 1); return flow; } } return DmtxConstants.DmtxBlankEdge; }
bool MatrixRegionOrientation(DmtxRegion reg, DmtxPointFlow begin) { int cross; int minArea; int scale; DmtxSymbolSize symbolShape; int maxDiagonal; bool err; DmtxBestLine line1x, line2x; DmtxBestLine line2n, line2p; DmtxFollow fTmp; if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolSquareAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol10x10 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol144x144)) symbolShape = DmtxSymbolSize.DmtxSymbolSquareAuto; else if (this._sizeIdxExpected == DmtxSymbolSize.DmtxSymbolRectAuto || (this._sizeIdxExpected >= DmtxSymbolSize.DmtxSymbol8x18 && this._sizeIdxExpected <= DmtxSymbolSize.DmtxSymbol16x48)) symbolShape = DmtxSymbolSize.DmtxSymbolRectAuto; else symbolShape = DmtxSymbolSize.DmtxSymbolShapeAuto; if (_edgeMax != DmtxConstants.DmtxUndefined) { if (symbolShape == DmtxSymbolSize.DmtxSymbolRectAuto) maxDiagonal = (int)(1.23 * _edgeMax + 0.5); /* sqrt(5/4) + 10% */ else maxDiagonal = (int)(1.56 * _edgeMax + 0.5); /* sqrt(2) + 10% */ } else { maxDiagonal = DmtxConstants.DmtxUndefined; } /* Follow to end in both directions */ err = TrailBlazeContinuous(reg, begin, maxDiagonal); if (err == false || reg.StepsTotal < 40) { TrailClear(reg, 0x40); return false; } /* Filter out region candidates that are smaller than expected */ if (this._edgeMin != DmtxConstants.DmtxUndefined) { scale = _scale; if (symbolShape == DmtxSymbolSize.DmtxSymbolSquareAuto) minArea = (this._edgeMin * this._edgeMin) / (scale * scale); else minArea = (2 * this._edgeMin * this._edgeMin) / (scale * scale); if ((reg.BoundMax.X - reg.BoundMin.X) * (reg.BoundMax.Y - reg.BoundMin.Y) < minArea) { TrailClear(reg, 0x40); return false; } } line1x = FindBestSolidLine(reg, 0, 0, 1, DmtxConstants.DmtxUndefined); if (line1x.Mag < 5) { TrailClear(reg, 0x40); return false; } err = FindTravelLimits(reg, ref line1x); if (line1x.DistSq < 100 || line1x.Devn * 10 >= Math.Sqrt((double)line1x.DistSq)) { TrailClear(reg, 0x40); return false; } if (!(line1x.StepPos >= line1x.StepNeg)) { throw new Exception("Error calculating matrix region orientation"); } fTmp = FollowSeek(reg, line1x.StepPos + 5); line2p = FindBestSolidLine(reg, fTmp.Step, line1x.StepNeg, 1, line1x.Angle); fTmp = FollowSeek(reg, line1x.StepNeg - 5); line2n = FindBestSolidLine(reg, fTmp.Step, line1x.StepPos, -1, line1x.Angle); if (DmtxCommon.Max<int>(line2p.Mag, line2n.Mag) < 5) return false; if (line2p.Mag > line2n.Mag) { line2x = line2p; err = FindTravelLimits(reg, ref line2x); if (line2x.DistSq < 100 || line2x.Devn * 10 >= Math.Sqrt((double)line2x.DistSq)) return false; cross = ((line1x.LocPos.X - line1x.LocNeg.X) * (line2x.LocPos.Y - line2x.LocNeg.Y)) - ((line1x.LocPos.Y - line1x.LocNeg.Y) * (line2x.LocPos.X - line2x.LocNeg.X)); if (cross > 0) { /* Condition 2 */ reg.Polarity = +1; reg.LocR = line2x.LocPos; reg.StepR = line2x.StepPos; reg.LocT = line1x.LocNeg; reg.StepT = line1x.StepNeg; reg.LeftLoc = line1x.LocBeg; reg.LeftAngle = line1x.Angle; reg.BottomLoc = line2x.LocBeg; reg.BottomAngle = line2x.Angle; reg.LeftLine = line1x; reg.BottomLine = line2x; } else { /* Condition 3 */ reg.Polarity = -1; reg.LocR = line1x.LocNeg; reg.StepR = line1x.StepNeg; reg.LocT = line2x.LocPos; reg.StepT = line2x.StepPos; reg.LeftLoc = line2x.LocBeg; reg.LeftAngle = line2x.Angle; reg.BottomLoc = line1x.LocBeg; reg.BottomAngle = line1x.Angle; reg.LeftLine = line2x; reg.BottomLine = line1x; } } else { line2x = line2n; err = FindTravelLimits(reg, ref line2x); if (line2x.DistSq < 100 || line2x.Devn / Math.Sqrt((double)line2x.DistSq) >= 0.1) return false; cross = ((line1x.LocNeg.X - line1x.LocPos.X) * (line2x.LocNeg.Y - line2x.LocPos.Y)) - ((line1x.LocNeg.Y - line1x.LocPos.Y) * (line2x.LocNeg.X - line2x.LocPos.X)); if (cross > 0) { /* Condition 1 */ reg.Polarity = -1; reg.LocR = line2x.LocNeg; reg.StepR = line2x.StepNeg; reg.LocT = line1x.LocPos; reg.StepT = line1x.StepPos; reg.LeftLoc = line1x.LocBeg; reg.LeftAngle = line1x.Angle; reg.BottomLoc = line2x.LocBeg; reg.BottomAngle = line2x.Angle; reg.LeftLine = line1x; reg.BottomLine = line2x; } else { /* Condition 4 */ reg.Polarity = +1; reg.LocR = line1x.LocPos; reg.StepR = line1x.StepPos; reg.LocT = line2x.LocNeg; reg.StepT = line2x.StepNeg; reg.LeftLoc = line2x.LocBeg; reg.LeftAngle = line2x.Angle; reg.BottomLoc = line1x.LocBeg; reg.BottomAngle = line1x.Angle; reg.LeftLine = line2x; reg.BottomLine = line1x; } } reg.LeftKnown = reg.BottomKnown = 1; return true; }
DmtxPointFlow GetPointFlow(int colorPlane, DmtxPixelLoc loc, int arrive) { int[] coefficient = new int[] { 0, 1, 2, 1, 0, -1, -2, -1 }; bool err; int patternIdx, coefficientIdx; int compass, compassMax; int[] mag = new int[4]; int xAdjust, yAdjust; int color; int[] colorPattern = new int[8]; DmtxPointFlow flow = new DmtxPointFlow(); for (patternIdx = 0; patternIdx < 8; patternIdx++) { xAdjust = loc.X + DmtxConstants.DmtxPatternX[patternIdx]; yAdjust = loc.Y + DmtxConstants.DmtxPatternY[patternIdx]; err = GetPixelValue(xAdjust, yAdjust, colorPlane, ref colorPattern[patternIdx]); if (err == false) { return DmtxConstants.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] += 2 * color; break; case 1: mag[compass] += color; break; case -2: mag[compass] -= 2 * color; break; case -1: mag[compass] -= color; break; } } /* Identify strongest compass flow */ if (compass != 0 && Math.Abs(mag[compass]) > Math.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 = Math.Abs(mag[compassMax]); flow.Loc = loc; return flow; }