/** * \brief Convert fitted Data Matrix region into a decoded message * \param dec * \param reg * \param fix * \return Decoded message */ extern DmtxMessage * dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix) { DmtxMessage *msg; DmtxVector2 topLeft, topRight, bottomLeft, bottomRight; DmtxPixelLoc pxTopLeft, pxTopRight, pxBottomLeft, pxBottomRight; msg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMatrix); if(msg == NULL) return NULL; if(PopulateArrayFromMatrix(dec, reg, msg) != DmtxPass) { dmtxMessageDestroy(&msg); return NULL; } /* maybe place remaining logic into new dmtxDecodePopulatedArray() function so other people can pass in their own arrays */ ModulePlacementEcc200(msg->array, msg->code, reg->sizeIdx, DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue); if(RsDecode(msg->code, reg->sizeIdx, fix) == DmtxFail) { dmtxMessageDestroy(&msg); return NULL; } topLeft.X = bottomLeft.X = topLeft.Y = topRight.Y = -0.1; topRight.X = bottomRight.X = bottomLeft.Y = bottomRight.Y = 1.1; dmtxMatrix3VMultiplyBy(&topLeft, reg->fit2raw); dmtxMatrix3VMultiplyBy(&topRight, reg->fit2raw); dmtxMatrix3VMultiplyBy(&bottomLeft, reg->fit2raw); dmtxMatrix3VMultiplyBy(&bottomRight, reg->fit2raw); pxTopLeft.X = (int)(0.5 + topLeft.X); pxTopLeft.Y = (int)(0.5 + topLeft.Y); pxBottomLeft.X = (int)(0.5 + bottomLeft.X); pxBottomLeft.Y = (int)(0.5 + bottomLeft.Y); pxTopRight.X = (int)(0.5 + topRight.X); pxTopRight.Y = (int)(0.5 + topRight.Y); pxBottomRight.X = (int)(0.5 + bottomRight.X); pxBottomRight.Y = (int)(0.5 + bottomRight.Y); CacheFillQuad(dec, pxTopLeft, pxTopRight, pxBottomRight, pxBottomLeft); DecodeDataStream(msg, reg->sizeIdx, NULL); return msg; }
static double RightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle) { DmtxVector2 vA, vB; DmtxMatrix3 m; dmtxVector2Norm(dmtxVector2Sub(&vA, &c1, &c0)); dmtxVector2Norm(dmtxVector2Sub(&vB, &c2, &c1)); dmtxMatrix3Rotate(m, M_PI - angle); dmtxMatrix3VMultiplyBy(&vA, m); return dmtxVector2Dot(&vA, &vB); }
static PyObject * dmtx_decode(PyObject *self, PyObject *arglist, PyObject *kwargs) { int count=0; int found=0; int width; int height; int gap_size = DmtxUndefined; int max_count = DmtxUndefined; int timeout = DmtxUndefined; int shape = DmtxUndefined; int deviation = DmtxUndefined; int threshold = DmtxUndefined; int shrink = 1; int corrections = DmtxUndefined; int min_edge = DmtxUndefined; int max_edge = DmtxUndefined; PyObject *dataBuf = NULL; Py_ssize_t dataLen; PyObject *context = Py_None; PyObject *output = PyList_New(0); DmtxTime dmtx_timeout; DmtxImage *img; DmtxDecode *dec; DmtxRegion *reg; DmtxMessage *msg; DmtxVector2 p00, p10, p11, p01; const char *pxl; /* Input image buffer */ static char *kwlist[] = { "width", "height", "data", "gap_size", "max_count", "context", "timeout", "shape", "deviation", "threshold", "shrink", "corrections", "min_edge", "max_edge", NULL }; /* Parse out the options which are applicable */ PyObject *filtered_kwargs; filtered_kwargs = PyDict_New(); count = 3; /* Skip the first 3 keywords as they are sent in arglist */ while(kwlist[count]){ if(PyDict_GetItemString(kwargs, kwlist[count])) { PyDict_SetItemString(filtered_kwargs, kwlist[count], PyDict_GetItemString(kwargs, kwlist[count])); } count++; } /* Get parameters from Python for libdmtx */ if(!PyArg_ParseTupleAndKeywords(arglist, filtered_kwargs, "iiOi|iOiiiiiiii", kwlist, &width, &height, &dataBuf, &gap_size, &max_count, &context, &timeout, &shape, &deviation, &threshold, &shrink, &corrections, &min_edge, &max_edge)) { PyErr_SetString(PyExc_TypeError, "decode takes at least 3 arguments"); return NULL; } Py_INCREF(context); /* Reset timeout for each new page */ if(timeout != DmtxUndefined) dmtx_timeout = dmtxTimeAdd(dmtxTimeNow(), timeout); if(dataBuf == NULL) { PyErr_SetString(PyExc_TypeError, "Interleaved bitmapped data in buffer missing"); return NULL; } PyObject_AsCharBuffer(dataBuf, &pxl, &dataLen); img = dmtxImageCreate((unsigned char *)pxl, width, height, DmtxPack24bppRGB); if(img == NULL) return NULL; dec = dmtxDecodeCreate(img, shrink); if(dec == NULL) { dmtxImageDestroy(&img); return NULL; } if(gap_size != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropScanGap, gap_size); if(shape != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropSymbolSize, shape); if(deviation != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropSquareDevn, deviation); if(threshold != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropEdgeThresh, threshold); if(min_edge != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropEdgeMin, min_edge); if(max_edge != DmtxUndefined) dmtxDecodeSetProp(dec, DmtxPropEdgeMax, max_edge); for(count=1; ;count++) { Py_BEGIN_ALLOW_THREADS if(timeout == DmtxUndefined) reg = dmtxRegionFindNext(dec, NULL); else reg = dmtxRegionFindNext(dec, &dmtx_timeout); Py_END_ALLOW_THREADS /* Finished file or ran out of time before finding another region */ if(reg == NULL) break; msg = dmtxDecodeMatrixRegion(dec, reg, corrections); if(msg != NULL) { p00.X = p00.Y = p10.Y = p01.X = 0.0; p10.X = p01.Y = p11.X = p11.Y = 1.0; dmtxMatrix3VMultiplyBy(&p00, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p10, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p11, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p01, reg->fit2raw); PyList_Append(output, Py_BuildValue("s#((ii)(ii)(ii)(ii))", msg->output, msg->outputIdx, (int)((shrink * p00.X) + 0.5), height - 1 - (int)((shrink * p00.Y) + 0.5), (int)((shrink * p10.X) + 0.5), height - 1 - (int)((shrink * p10.Y) + 0.5), (int)((shrink * p11.X) + 0.5), height - 1 - (int)((shrink * p11.Y) + 0.5), (int)((shrink * p01.X) + 0.5), height - 1 - (int)((shrink * p01.Y) + 0.5))); Py_INCREF(output); dmtxMessageDestroy(&msg); found++; } dmtxRegionDestroy(®); /* Stop if we've reached maximium count */ if(max_count != DmtxUndefined) if(found >= max_count) break; } dmtxDecodeDestroy(&dec); dmtxImageDestroy(&img); Py_DECREF(context); if(output == NULL) { Py_INCREF(Py_None); return Py_None; } return output; }
/** * Decode the image, returning tags found (as DMTXTag objects) */ JNIEXPORT jobjectArray JNICALL Java_org_libdmtx_DMTXImage_getTags(JNIEnv *aEnv, jobject aImage, jint aTagCount, jint lSearchTimeout) { jclass lImageClass, lTagClass, lPointClass; jmethodID lTagConstructor, lPointConstructor; jfieldID lWidth, lHeight, lData; DmtxImage *lImage; DmtxDecode *lDecode; DmtxRegion *lRegion; DmtxTime lTimeout; int lW, lH, lI; jintArray lJavaData; jint *lPixels; jobject *lTags; jobjectArray lResult; int lTagCount = 0; /* Find DMTXImage class */ lImageClass = (*aEnv)->FindClass(aEnv, "org/libdmtx/DMTXImage"); if(lImageClass == NULL) return NULL; /* Find Tag class */ lTagClass = (*aEnv)->FindClass(aEnv, "org/libdmtx/DMTXTag"); if(lTagClass == NULL) return NULL; /* Find Point class */ lPointClass = (*aEnv)->FindClass(aEnv, "java/awt/Point"); if(lPointClass == NULL) return NULL; /* Find constructors */ lTagConstructor = (*aEnv)->GetMethodID( aEnv, lTagClass, "<init>", "(Ljava/lang/String;Ljava/awt/Point;Ljava/awt/Point;Ljava/awt/Point;Ljava/awt/Point;)V" ); lPointConstructor = (*aEnv)->GetMethodID(aEnv, lPointClass, "<init>", "(II)V"); if(lTagConstructor == NULL || lPointConstructor == NULL) return NULL; /* Find fields */ lWidth = (*aEnv)->GetFieldID(aEnv, lImageClass, "width", "I"); lHeight = (*aEnv)->GetFieldID(aEnv, lImageClass, "height", "I"); lData = (*aEnv)->GetFieldID(aEnv, lImageClass, "data", "[I"); if(lWidth == NULL || lHeight == NULL || lData == NULL) return NULL; /* Get fields */ lW = (*aEnv)->GetIntField(aEnv, aImage, lWidth); lH = (*aEnv)->GetIntField(aEnv, aImage, lHeight); lJavaData = (*aEnv)->GetObjectField(aEnv, aImage, lData); lPixels = (*aEnv)->GetIntArrayElements(aEnv, lJavaData, NULL); /* Create DmtxImage object */ lImage = dmtxImageCreate((unsigned char *)lPixels, lW, lH, DmtxPack32bppRGBX); if(lImage == NULL) return NULL; /* Create DmtxDecode object */ lDecode = dmtxDecodeCreate(lImage, 1); if(lDecode == NULL) return NULL; /* Allocate temporary Tag array */ lTags = (jobject *)malloc(aTagCount * sizeof(jobject)); if(lTags == NULL) return NULL; /* Find all tags that we can inside timeout */ lTimeout = dmtxTimeAdd(dmtxTimeNow(), lSearchTimeout); while(lTagCount < aTagCount && (lRegion = dmtxRegionFindNext(lDecode, &lTimeout))) { jstring sStringID; DmtxMessage *lMessage = dmtxDecodeMatrixRegion(lDecode, lRegion, DmtxUndefined); if(lMessage != NULL) { DmtxVector2 lCorner1, lCorner2, lCorner3, lCorner4; jobject lJCorner1, lJCorner2, lJCorner3, lJCorner4; /* Calculate position of Tag */ lCorner1.X = lCorner1.Y = lCorner2.Y = lCorner4.X = 0.0; lCorner2.X = lCorner4.Y = lCorner3.X = lCorner3.Y = 1.0; dmtxMatrix3VMultiplyBy(&lCorner1, lRegion->fit2raw); dmtxMatrix3VMultiplyBy(&lCorner2, lRegion->fit2raw); dmtxMatrix3VMultiplyBy(&lCorner3, lRegion->fit2raw); dmtxMatrix3VMultiplyBy(&lCorner4, lRegion->fit2raw); /* Create Location instances for corners */ lJCorner1 = (*aEnv)->NewObject(aEnv, lPointClass, lPointConstructor, (int) lCorner1.X, (int) (lH - lCorner1.Y - 1)); lJCorner2 = (*aEnv)->NewObject(aEnv, lPointClass, lPointConstructor, (int) lCorner2.X, (int) (lH - lCorner2.Y - 1)); lJCorner3 = (*aEnv)->NewObject(aEnv, lPointClass, lPointConstructor, (int) lCorner3.X, (int) (lH - lCorner3.Y - 1)); lJCorner4 = (*aEnv)->NewObject(aEnv, lPointClass, lPointConstructor, (int) lCorner4.X, (int) (lH - lCorner4.Y - 1)); /* Decode Message */ sStringID = (*aEnv)->NewStringUTF(aEnv, lMessage->output); /* Create Tag instance */ lTags[lTagCount] = (*aEnv)->NewObject(aEnv, lTagClass, lTagConstructor, sStringID, lJCorner1, lJCorner2, lJCorner3, lJCorner4); if(lTags[lTagCount] == NULL) return NULL; /* Increment Count */ lTagCount++; /* Free Message */ dmtxMessageDestroy(&lMessage); } /* Free Region */ dmtxRegionDestroy(&lRegion); } /* Free DMTX Structures */ dmtxDecodeDestroy(&lDecode); dmtxImageDestroy(&lImage); /* Release Image Data */ (*aEnv)->ReleaseIntArrayElements(aEnv, lJavaData, lPixels, 0); /* Create result array */ lResult = (*aEnv)->NewObjectArray(aEnv, lTagCount, lTagClass, NULL); for(lI = 0; lI < lTagCount; lI++) { (*aEnv)->SetObjectArrayElement(aEnv, lResult, lI, lTags[lI]); } /* Free local references */ (*aEnv)->DeleteLocalRef(aEnv, lJavaData); (*aEnv)->DeleteLocalRef(aEnv, lImageClass); (*aEnv)->DeleteLocalRef(aEnv, lTagClass); (*aEnv)->DeleteLocalRef(aEnv, lPointClass); return lResult; }
bool Detector::detect(cv::Mat& image, int timeout, unsigned int offsetx, unsigned int offsety){ bool detected = false; lines_.clear(); message_.clear(); polygon_.clear(); DmtxRegion *reg; DmtxDecode *dec; DmtxImage *img; DmtxMessage *msg; DmtxTime t; img = dmtxImageCreate(image.data, image.cols, image.rows, DmtxPack24bppRGB); //dmtxImageSetProp(img, DmtxPropImageFlip, DmtxFlipY); dec = dmtxDecodeCreate(img, 1); assert(dec != NULL); t = dmtxTimeAdd(dmtxTimeNow(), timeout); reg = dmtxRegionFindNext(dec, &t); if(reg != NULL) { int height; int dataWordLength; int rotateInt; double rotate; DmtxVector2 p00, p10, p11, p01; height = dmtxDecodeGetProp(dec, DmtxPropHeight); p00.X = p00.Y = p10.Y = p01.X = 0.0; p10.X = p01.Y = p11.X = p11.Y = 1.0; dmtxMatrix3VMultiplyBy(&p00, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p10, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p11, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p01, reg->fit2raw); polygon_.push_back(cv::Point(p00.X + offsetx,image.rows-p00.Y + offsety)); polygon_.push_back(cv::Point(p10.X + offsetx,image.rows-p10.Y + offsety)); polygon_.push_back(cv::Point(p11.X + offsetx,image.rows-p11.Y + offsety)); polygon_.push_back(cv::Point(p01.X + offsetx,image.rows-p01.Y + offsety)); lines_.push_back( std::pair<cv::Point,cv::Point>( cv::Point(p00.X + offsetx,image.rows-p00.Y + offsety), cv::Point(p10.X + offsetx,image.rows-p10.Y + offsety) ) ); lines_.push_back( std::pair<cv::Point,cv::Point>( cv::Point(p10.X + offsetx,image.rows-p10.Y + offsety), cv::Point(p11.X + offsetx,image.rows-p11.Y + offsety) ) ); lines_.push_back( std::pair<cv::Point,cv::Point>( cv::Point(p11.X + offsetx,image.rows-p11.Y + offsety), cv::Point(p01.X + offsetx,image.rows-p01.Y + offsety) ) ); lines_.push_back( std::pair<cv::Point,cv::Point>( cv::Point(p01.X + offsetx,image.rows-p01.Y + offsety), cv::Point(p00.X + offsetx,image.rows-p00.Y + offsety) ) ); detected = true; msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined); if(msg != NULL) { message_ = (const char*)msg->output; dmtxMessageDestroy(&msg); } dmtxRegionDestroy(®); } dmtxDecodeDestroy(&dec); dmtxImageDestroy(&img); return detected; }
bool Marker_DMTX::findPattern(const sensor_msgs::Image &img, std::vector<SMarker> &res) { int count=0; DmtxImage *dimg = dmtxImageCreate((unsigned char*)&img.data[0], img.width, img.height, DmtxPack24bppRGB); ROS_ASSERT(dimg); DmtxDecode *dec = dmtxDecodeCreate(dimg, 1); ROS_ASSERT(dec); dmtxDecodeSetProp(dec, DmtxPropEdgeThresh, 1); DmtxRegion *reg; for(count=1; ;count++) { DmtxTime timeout = dmtxTimeAdd(dmtxTimeNow(), timeout_); reg = dmtxRegionFindNext(dec, &timeout); /* Finished file or ran out of time before finding another region */ if(reg == NULL) break; if (reg != NULL) { DmtxMessage *msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined); if (msg != NULL) { SMarker m; m.code_ = std::string((const char*)msg->output,msg->outputSize); m.format_ = "datamatrix"; DmtxVector2 p00, p10, p11, p01; p00.X = p00.Y = p10.Y = p01.X = 0.0; p10.X = p01.Y = p11.X = p11.Y = 1.0; dmtxMatrix3VMultiplyBy(&p00, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p10, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p11, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p01, reg->fit2raw); Eigen::Vector2i v; v(0)=(int)((p01.X) + 0.5); v(1)=img.height - 1 - (int)((p01.Y) + 0.5); m.pts_.push_back(v); v(0)=(int)((p00.X) + 0.5); v(1)=img.height - 1 - (int)((p00.Y) + 0.5); m.pts_.push_back(v); v(0)=(int)((p11.X) + 0.5); v(1)=img.height - 1 - (int)((p11.Y) + 0.5); m.pts_.push_back(v); v(0)=(int)((p10.X) + 0.5); v(1)=img.height - 1 - (int)((p10.Y) + 0.5); m.pts_.push_back(v); res.push_back(m); dmtxMessageDestroy(&msg); } dmtxRegionDestroy(®); } } dmtxDecodeDestroy(&dec); dmtxImageDestroy(&dimg); return false; }
/** * @brief XXX * @param image * @param reg * @param edgeLoc * @param preFit2Raw * @param postRaw2Fit * @return DMTX_SUCCESS | DMTX_FAILURE */ static int MatrixRegionAlignCalibEdge(DmtxImage *image, DmtxRegion *reg, DmtxEdgeLoc edgeLoc, DmtxMatrix3 preFit2Raw, DmtxMatrix3 postRaw2Fit) { DmtxVector2 p0, p1, pCorner; double slope; int hitCount; int weakCount; assert(edgeLoc == DmtxEdgeTop || edgeLoc == DmtxEdgeRight); hitCount = MatrixRegionAlignEdge(image, reg, postRaw2Fit, preFit2Raw, &p0, &p1, &pCorner, &weakCount); if(hitCount < 2) return DMTX_FAILURE; if(edgeLoc == DmtxEdgeRight) { SetCornerLoc(reg, DmtxCorner10, pCorner); if(MatrixRegionUpdateXfrms(image, reg) != DMTX_SUCCESS) return DMTX_FAILURE; dmtxMatrix3VMultiplyBy(&p0, reg->raw2fit); dmtxMatrix3VMultiplyBy(&p1, reg->raw2fit); assert(fabs(p1.Y - p0.Y) > DMTX_ALMOST_ZERO); slope = (p1.X - p0.X) / (p1.Y - p0.Y); p0.X = p0.X - slope * p0.Y; p0.Y = 0.0; p1.X = p0.X + slope; p1.Y = 1.0; dmtxMatrix3VMultiplyBy(&p0, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p1, reg->fit2raw); SetCornerLoc(reg, DmtxCorner10, p0); SetCornerLoc(reg, DmtxCorner11, p1); } else { SetCornerLoc(reg, DmtxCorner01, pCorner); if(MatrixRegionUpdateXfrms(image, reg) != DMTX_SUCCESS) return DMTX_FAILURE; dmtxMatrix3VMultiplyBy(&p0, reg->raw2fit); dmtxMatrix3VMultiplyBy(&p1, reg->raw2fit); assert(fabs(p1.X - p0.X) > DMTX_ALMOST_ZERO); slope = (p1.Y - p0.Y) / (p1.X - p0.X); p0.Y = p0.Y - slope * p0.X; p0.X = 0.0; p1.Y = p0.Y + slope; p1.X = 1.0; dmtxMatrix3VMultiplyBy(&p0, reg->fit2raw); dmtxMatrix3VMultiplyBy(&p1, reg->fit2raw); SetCornerLoc(reg, DmtxCorner01, p0); SetCornerLoc(reg, DmtxCorner11, p1); } if(MatrixRegionUpdateXfrms(image, reg) != DMTX_SUCCESS) return DMTX_FAILURE; return DMTX_SUCCESS; }
/** * @brief XXX * @param image * @param reg * @param postRaw2Fit * @param preFit2Raw * @param p0 * @param p1 * @param pCorner * @param weakCount * @return 3 points in raw coordinates */ static int MatrixRegionAlignEdge(DmtxImage *image, DmtxRegion *reg, DmtxMatrix3 postRaw2Fit, DmtxMatrix3 preFit2Raw, DmtxVector2 *p0, DmtxVector2 *p1, DmtxVector2 *pCorner, int *weakCount) { int hitCount, edgeHit, prevEdgeHit; DmtxVector2 c00, c10, c01; DmtxMatrix3 sRaw2Fit, sFit2Raw; DmtxVector2 forward, lateral; DmtxVector2 pFitExact, pFitProgress, pRawProgress, pRawExact, pLast; double interceptTest, intercept[8]; DmtxVector2 adjust[8]; double slope[8]; int i; int stepsSinceStarAdjust; DmtxVector2 pTmp; /*fprintf(stdout, "MatrixRegionAlignEdge()\n"); */ dmtxMatrix3Multiply(sRaw2Fit, reg->raw2fit, postRaw2Fit); dmtxMatrix3Multiply(sFit2Raw, preFit2Raw, reg->fit2raw); /* Draw skewed image in bottom left pane */ /* CALLBACK_DECODE_FUNC1(buildMatrixCallback3, dec, sFit2Raw); */ /* Set starting point */ pFitProgress.X = -0.003; pFitProgress.Y = 0.9; *pCorner = pFitExact = pFitProgress; dmtxMatrix3VMultiply(&pRawProgress, &pFitProgress, sFit2Raw); /* Initialize star lines */ for(i = 0; i < 8; i++) { slope[i] = tan((M_PI_2/8.0) * i); intercept[i] = 0.9; adjust[i].X = 0.0; adjust[i].Y = 0.9; } hitCount = 0; stepsSinceStarAdjust = 0; *weakCount = 0; prevEdgeHit = edgeHit = DMTX_EDGE_STEP_EXACT; for(;;) { /* XXX technically we don't need to recalculate lateral & forward once we have left the finder bar */ dmtxMatrix3VMultiply(&pTmp, &pRawProgress, sRaw2Fit); /* XXX move this outside of this loop ? */ c00 = pTmp; c10.X = c00.X + 1; c10.Y = c00.Y; c01.X = c00.X - 0.087155743; c01.Y = c00.Y + 0.996194698; if(dmtxMatrix3VMultiplyBy(&c00, sFit2Raw) != DMTX_SUCCESS) return 0; if(dmtxMatrix3VMultiplyBy(&c10, sFit2Raw) != DMTX_SUCCESS) return 0; if(dmtxMatrix3VMultiplyBy(&c01, sFit2Raw) != DMTX_SUCCESS) return 0; if(RightAngleTrueness(c01, c00, c10, M_PI) < 0.1) { /* XXX instead of just failing here, hopefully find what happened upstream to trigger this condition. we can probably avoid this earlier on, and even avoid assertion failures elsewhere */ return 0; } /* Calculate forward and lateral directions in raw coordinates */ dmtxVector2Sub(&forward, &c10, &c00); if(dmtxVector2Norm(&forward) != DMTX_SUCCESS) return 0; dmtxVector2Sub(&lateral, &c01, &c00); if(dmtxVector2Norm(&lateral) != DMTX_SUCCESS) return 0; prevEdgeHit = edgeHit; edgeHit = StepAlongEdge(image, reg, &pRawProgress, &pRawExact, forward, lateral); dmtxMatrix3VMultiply(&pFitProgress, &pRawProgress, sRaw2Fit); if(edgeHit == DMTX_EDGE_STEP_EXACT) { /** if(prevEdgeHit == DMTX_EDGE_STEP_TOO_WEAK) <-- XXX REVIST LATER ... doesn't work hitCount++; */ hitCount++; dmtxMatrix3VMultiply(&pFitExact, &pRawExact, sRaw2Fit); /* Adjust star lines upward (non-vertical) */ for(i = 0; i < 8; i++) { interceptTest = pFitExact.Y - slope[i] * pFitExact.X; if(interceptTest > intercept[i]) { intercept[i] = interceptTest; adjust[i] = pFitExact; stepsSinceStarAdjust = 0; /* XXX still "turning corner" but not as bad anymore */ if(i == 7) { *pCorner = pFitExact; /* CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawExact, 1, 1, DMTX_DISPLAY_POINT); */ } if(i == 0) { pLast = pFitExact; /* CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawExact, 1, 1, DMTX_DISPLAY_POINT); */ } } } /* Draw edge hits along skewed edge in bottom left pane */ /* CALLBACK_DECODE_FUNC4(xfrmPlotPointCallback, dec, pFitExact, NULL, 4, DMTX_DISPLAY_POINT); */ } else if(edgeHit == DMTX_EDGE_STEP_TOO_WEAK) { stepsSinceStarAdjust++; if(prevEdgeHit == DMTX_EDGE_STEP_TOO_WEAK) (*weakCount)++; } /* XXX also change stepsSinceNear and use this in the break condition */ if(hitCount >= 20 && stepsSinceStarAdjust > hitCount) break; if(pFitProgress.X > 1.0) { /* CALLBACK_DECODE_FUNC4(plotPointCallback, dec, pRawProgress, 1, 1, DMTX_DISPLAY_SQUARE); */ break; } if(pRawProgress.X < 1 || pRawProgress.X > image->width - 1 || pRawProgress.Y < 1 || pRawProgress.Y > image->height - 1) break; } /* Find lowest available horizontal starline adjustment */ for(i = 0; i < 8; i++) { if(adjust[i].X < 0.1) break; } if(i == -1) return 0; *p0 = adjust[i]; /* Find highest available non-horizontal starline adjustment */ for(i = 7; i > 1; i--) { if(adjust[i].X > 0.8) break; } if(i == -1) return 0; *p1 = adjust[i]; if(fabs(p0->X - p1->X) < 0.1 || p0->Y < 0.2 || p1->Y < 0.2) { return 0; } dmtxMatrix3VMultiplyBy(pCorner, sFit2Raw); dmtxMatrix3VMultiplyBy(p0, sFit2Raw); dmtxMatrix3VMultiplyBy(p1, sFit2Raw); return hitCount; }