예제 #1
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionAlignRightEdge(DmtxImage *image, DmtxRegion *reg)
{
   DmtxMatrix3 rotate, flip, shear, scale;
   DmtxMatrix3 preFit2Raw, postRaw2Fit;

   dmtxMatrix3Rotate(rotate, -M_PI_2);
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Shear(shear, 0.0, 0.5);
   dmtxMatrix3Scale(scale, 1.25, 1.0);

   dmtxMatrix3Multiply(postRaw2Fit, rotate, flip);
   dmtxMatrix3MultiplyBy(postRaw2Fit, shear);
   dmtxMatrix3MultiplyBy(postRaw2Fit, scale);

   dmtxMatrix3Scale(scale, 0.8, 1.0);
   dmtxMatrix3Shear(shear, 0.0, -0.5);
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Rotate(rotate, M_PI_2);
   dmtxMatrix3Multiply(preFit2Raw, scale, shear);
   dmtxMatrix3MultiplyBy(preFit2Raw, flip);
   dmtxMatrix3MultiplyBy(preFit2Raw, rotate);

   if(MatrixRegionAlignCalibEdge(image, reg, DmtxEdgeRight, preFit2Raw, postRaw2Fit) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   return DMTX_SUCCESS;
}
예제 #2
0
/**
 * @brief Update transformations based on known region attributes
 * @param image
 * @param reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionUpdateXfrms(DmtxImage *image, DmtxRegion *reg)
{
   DmtxVector2 vOT, vOR, vTmp;
   double tx, ty, phi, shx, scx, scy, skx, sky;
   double dimOT, dimOR, dimTX, dimRX, ratio;
   DmtxMatrix3 m, mtxy, mphi, mshx, mscxy, msky, mskx, mTmp;
   DmtxCorners corners;

   assert((reg->corners.known & DmtxCorner00) && (reg->corners.known & DmtxCorner01));

   /* Make copy of known corners to update with temporary values */
   corners = reg->corners;

   if(corners.c00.X < 0.0 || corners.c00.Y < 0.0 ||
      corners.c01.X < 0.0 || corners.c01.Y < 0.0)
      return DMTX_FAILURE;

   if(corners.c00.X > image->width - 1 || corners.c00.Y > image->height - 1 ||
      corners.c01.X > image->width - 1 || corners.c01.Y > image->height - 1)
      return DMTX_FAILURE;

   dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &corners.c01, &corners.c00)); /* XXX could use MagSquared() */
   if(dimOT < 8)
      return DMTX_FAILURE;

   /* Bottom-right corner -- validate if known or create temporary value */
   if(corners.known & DmtxCorner10) {
      if(corners.c10.X < 0.0 || corners.c10.Y < 0.0 ||
            corners.c10.X > image->width - 1 ||
            corners.c10.Y > image->height - 1)
         return DMTX_FAILURE;
   }
   else {
      dmtxMatrix3Rotate(mTmp, -M_PI_2);
      dmtxMatrix3VMultiply(&vTmp, &vOT, mTmp);
      dmtxVector2Add(&corners.c10, &corners.c00, &vTmp);
   }

   dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &corners.c10, &corners.c00)); /* XXX could use MagSquared() */
   if(dimOR < 8)
      return DMTX_FAILURE;

   /* Solid edges are both defined now */
   if(RightAngleTrueness(corners.c01, corners.c00, corners.c10, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Top-right corner -- validate if known or create temporary value */
   if(corners.known & DmtxCorner11) {
      if(corners.c11.X < 0.0 || corners.c11.Y < 0.0 ||
            corners.c11.X > image->width - 1 ||
            corners.c11.Y > image->height - 1)
         return DMTX_FAILURE;
   }
   else {
      dmtxVector2Add(&corners.c11, &corners.c01, &vOR);
   }

   /* Verify that the 4 corners define a reasonably fat quadrilateral */
   dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTmp, &corners.c11, &corners.c01)); /* XXX could use MagSquared() */
   dimRX = dmtxVector2Mag(dmtxVector2Sub(&vTmp, &corners.c11, &corners.c10)); /* XXX could use MagSquared() */
   if(dimTX < 8 || dimRX < 8)
      return DMTX_FAILURE;

   ratio = dimOT / dimRX;
   if(ratio < 0.5 || ratio > 2.0)
      return DMTX_FAILURE;

   ratio = dimOR / dimTX;
   if(ratio < 0.5 || ratio > 2.0)
      return DMTX_FAILURE;

   /* Test top-left corner for trueness */
   if(RightAngleTrueness(corners.c11, corners.c01, corners.c00, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Test bottom-right corner for trueness */
   if(RightAngleTrueness(corners.c00, corners.c10, corners.c11, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Test top-right corner for trueness */
   if(RightAngleTrueness(corners.c10, corners.c11, corners.c01, M_PI_2) < 0.7)
      return DMTX_FAILURE;

   /* Calculate values needed for transformations */
   tx = -1 * corners.c00.X;
   ty = -1 * corners.c00.Y;
   dmtxMatrix3Translate(mtxy, tx, ty);

   phi = atan2(vOT.X, vOT.Y);
   dmtxMatrix3Rotate(mphi, phi);

   /* Update transformation with values known so far */
   dmtxMatrix3Multiply(m, mtxy, mphi);

   dmtxMatrix3VMultiply(&vTmp, &corners.c10, m);

   shx = -vTmp.Y / vTmp.X;
   dmtxMatrix3Shear(mshx, 0.0, shx);

   scx = 1.0/vTmp.X;
   scy = 1.0/dmtxVector2Mag(&vOT);
   dmtxMatrix3Scale(mscxy, scx, scy);

   /* Update transformation with values known so far */
   dmtxMatrix3MultiplyBy(m, mshx);
   dmtxMatrix3MultiplyBy(m, mscxy);

   dmtxMatrix3VMultiply(&vTmp, &corners.c11, m);
   skx = vTmp.X;
   dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0);

   /* Update transformation with values known so far */
   dmtxMatrix3MultiplyBy(m, mskx);

   /* Update transformation with values known so far */
   dmtxMatrix3VMultiply(&vTmp, &corners.c11, m);
   sky = vTmp.Y;
   dmtxMatrix3LineSkewTop(msky, 1.0, sky, 1.0);

   /* Update region with final update */
   dmtxMatrix3Multiply(reg->raw2fit, m, msky);

   /* Create inverse matrix by reverse (avoid straight matrix inversion) */
   dmtxMatrix3LineSkewTopInv(msky, 1.0, sky, 1.0);
   dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0);
   dmtxMatrix3Scale(mscxy, 1.0/scx, 1.0/scy);
   dmtxMatrix3Shear(mshx, 0.0, -shx);
   dmtxMatrix3Rotate(mphi, -phi);
   dmtxMatrix3Translate(mtxy, -tx, -ty);

   dmtxMatrix3Multiply(m, msky, mskx);
   dmtxMatrix3MultiplyBy(m, mscxy);
   dmtxMatrix3MultiplyBy(m, mshx);
   dmtxMatrix3MultiplyBy(m, mphi);
   dmtxMatrix3Multiply(reg->fit2raw, m, mtxy);

   return DMTX_SUCCESS;
}
예제 #3
0
/**
 * @brief  XXX
 * @param  image
 * @param  reg
 * @return DMTX_SUCCESS | DMTX_FAILURE
 */
static int
MatrixRegionAlignSecondEdge(DmtxImage *image, DmtxRegion *reg)
{
   DmtxVector2 p0[4], p1[4], pCorner[4];
   int hitCount[4] = { 0, 0, 0, 0 };
   int weakCount[4] = { 0, 0, 0, 0 };
   DmtxMatrix3 xlate, flip, shear;
   DmtxMatrix3 preFit2Raw, postRaw2Fit;
   DmtxVector2 O, T, R;
   DmtxVector2 fitO, fitT;
   DmtxVector2 oldRawO, oldRawT;
   int i, bestFit;
   DmtxRay2 rayOT, rayNew;
   double ratio, maxRatio;

   /* Corners are named using the following layout:
    *
    *  T |
    *    |
    *    |
    *    +-----
    *  O      R
    *
    */

/*fprintf(stdout, "MatrixRegionAlignSecondEdge()\n"); */

   /* Scan top edge left-to-right (shear only)

      +---   O = intersection of known edges
      |      T = farthest known point along scanned edge
      |      R = old O
   */
   dmtxMatrix3Shear(postRaw2Fit, 0.0, 1.0);
   dmtxMatrix3Shear(preFit2Raw, 0.0, -1.0);

   hitCount[0] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[0], &p1[0], &pCorner[0], &weakCount[0]);

   /* Scan top edge right-to-left (horizontal flip and shear)

      ---+   O = intersection of known edges
         |   T = old O
         |   R = farthest known point along scanned edge
   */
   dmtxMatrix3Scale(flip, -1.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Scale(flip, -1.0, 1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, flip);

   hitCount[1] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[1], &p1[1], &pCorner[1], &weakCount[1]);

   /* Scan bottom edge left-to-right (vertical flip and shear)

      |      O = intersection of known edges
      |      T = old T
      +---   R = farthest known point along scanned edge
   */
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, xlate);
   dmtxMatrix3MultiplyBy(postRaw2Fit, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, -1.0);
   dmtxMatrix3Scale(flip, 1.0, -1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, xlate);
   dmtxMatrix3MultiplyBy(preFit2Raw, flip);

   hitCount[2] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[2], &p1[2], &pCorner[2], &weakCount[2]);

   /* Scan bottom edge right-to-left (flip flip shear)

         |   O = intersection of known edges
         |   T = farthest known point along scanned edge
      ---+   R = old T
   */
   dmtxMatrix3Scale(flip, -1.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, 1.0);
   dmtxMatrix3Shear(shear, 0.0, 1.0);
   dmtxMatrix3Multiply(postRaw2Fit, flip, xlate);
   dmtxMatrix3MultiplyBy(postRaw2Fit, shear);

   dmtxMatrix3Shear(shear, 0.0, -1.0);
   dmtxMatrix3Translate(xlate, 0.0, -1.0);
   dmtxMatrix3Scale(flip, -1.0, -1.0);
   dmtxMatrix3Multiply(preFit2Raw, shear, xlate);
   dmtxMatrix3MultiplyBy(preFit2Raw, flip);

   hitCount[3] = MatrixRegionAlignEdge(image, reg, postRaw2Fit,
         preFit2Raw, &p0[3], &p1[3], &pCorner[3], &weakCount[3]);

/**
Simplify StepAlongEdge() and avoid complicated error-prone counters.
Instead just find all 4 edges, and then prune out edges according to
early criteria:

   a) Exited based on step limit without touching anything (p0-p1
      length is <8 pixels)

   b) If length (p0-p1) of top is <1/8 of bottom (or vice versa)

For those that remain, choose the winner based on least variation
among module samples and proximity of color to initial edge

   for(each edge orientation option) {
      if(hitCount[i] < 3)
         option[i] = invalid;
      else if(length[p1-p0] < 8 pixels)
         option[i] = invalid;
   }

   if(option[0].valid && option[2].valid) {
      ratio = length[0]/length[2];
      if(ratio > 8)
         option[2] = invalid;
      else if(ration < 1/8)
         option[0] = invalid;
   }
   // XXX then also same thing for option[0] and option[1]

   // Determine winner among remaining options
   winner = NULL;
   currentMin = max or first;
   for(each sizeIdx) {
      for(each edge orientation option) {
         if(edge orientation is ruled out)
            continue;

         if(ColorDevianceSum(sizeIdx, matrix, gradient, &currentMin))
            winner = thisOrientation;
      }
   }
   if(winner == NULL)
      return FAILURE;

     - step along imaginary center (same # steps for each test),
       summing color difference between sample and ON color in known
       gradient. As soon as sum exceeds previous best, then eliminate
       from candidacy. record best minimum difference for each leg
       candidate. candidate with smallest diff wins.

     - maybe round-robin the tests, so the winning leg will get a foot
       in the door sooner, speeding things up significantly
*/

   /* choose orientation with highest hitCount/(weakCount + 1) ratio */
   for(i = 0; i < 4; i++) {
      ratio = (double)hitCount[i]/(weakCount[i] + 1);

      if(i == 0 || ratio > maxRatio) {
         bestFit = i;
         maxRatio = ratio;
      }
   }

   if(hitCount[bestFit] < 5)
      return DMTX_FAILURE;

   fitT.X = 0.0;
   fitT.Y = 1.0;
   dmtxMatrix3VMultiply(&oldRawT, &fitT, reg->fit2raw);

   fitO.X = 0.0;
   fitO.Y = 0.0;
   dmtxMatrix3VMultiply(&oldRawO, &fitO, reg->fit2raw);

   if(bestFit == 0 || bestFit == 1)
      oldRawT = pCorner[bestFit];
   else
      oldRawO = pCorner[bestFit];

   rayOT.p = oldRawO;
   dmtxVector2Sub(&rayOT.v, &oldRawT, &oldRawO);
   if(dmtxVector2Norm(&rayOT.v) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   rayNew.p = p0[bestFit];
   dmtxVector2Sub(&rayNew.v, &p1[bestFit], &p0[bestFit]);
   if(dmtxVector2Norm(&rayNew.v) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   /* New origin is always origin of both known edges */
   dmtxRay2Intersect(&O, &rayOT, &rayNew);

   if(bestFit == 0) {
      T = p1[bestFit];
      R = oldRawO;
   }
   else if(bestFit == 1) {
      T = oldRawO;
      R = p1[bestFit];
   }
   else if(bestFit == 2) {
      T = oldRawT;
      R = p1[bestFit];
   }
   else {
      assert(bestFit == 3);
      T = p1[bestFit];
      R = oldRawT;
   }

   SetCornerLoc(reg, DmtxCorner00, O);
   SetCornerLoc(reg, DmtxCorner01, T);
   SetCornerLoc(reg, DmtxCorner10, R);

   if(MatrixRegionUpdateXfrms(image, reg) != DMTX_SUCCESS)
      return DMTX_FAILURE;

   /* Skewed barcode in the bottom middle pane */
/* CALLBACK_DECODE_FUNC1(buildMatrixCallback4, dec, reg->fit2raw); */

   return DMTX_SUCCESS;
}
예제 #4
0
파일: dmtxencode.c 프로젝트: dmtx/libdmtx
/**
 * \brief  Write encoded message to image
 * \param  enc
 * \return void
 */
static void
PrintPattern(DmtxEncode *enc)
{
   int i, j;
   int symbolRow, symbolCol;
   int pixelRow, pixelCol;
   int moduleStatus;
   size_t rowSize, height;
   int rgb[3];
   double sxy, txy;
   DmtxMatrix3 m1, m2;
   DmtxVector2 vIn, vOut;

   txy = enc->marginSize;
   sxy = 1.0/enc->moduleSize;

   dmtxMatrix3Translate(m1, -txy, -txy);
   dmtxMatrix3Scale(m2, sxy, -sxy);
   dmtxMatrix3Multiply(enc->xfrm, m1, m2);

   dmtxMatrix3Translate(m1, txy, txy);
   dmtxMatrix3Scale(m2, enc->moduleSize, enc->moduleSize);
   dmtxMatrix3Multiply(enc->rxfrm, m2, m1);

   rowSize = dmtxImageGetProp(enc->image, DmtxPropRowSizeBytes);
   height = dmtxImageGetProp(enc->image, DmtxPropHeight);

   memset(enc->image->pxl, 0xff, rowSize * height);

   for(symbolRow = 0; symbolRow < enc->region.symbolRows; symbolRow++) {
      for(symbolCol = 0; symbolCol < enc->region.symbolCols; symbolCol++) {

         vIn.X = symbolCol;
         vIn.Y = symbolRow;

         dmtxMatrix3VMultiply(&vOut, &vIn, enc->rxfrm);

         pixelCol = (int)(vOut.X);
         pixelRow = (int)(vOut.Y);

         moduleStatus = dmtxSymbolModuleStatus(enc->message,
               enc->region.sizeIdx, symbolRow, symbolCol);

		 if (enc->image->bytesPerPixel == 1)
		 {
			 for(i = pixelRow; i < pixelRow + enc->moduleSize; i++) {
				for(j = pixelCol; j < pixelCol + enc->moduleSize; j++) {
				   rgb[0] = ((moduleStatus & DmtxModuleOnRed) != 0x00) ? 0 : 255;
				   dmtxImageSetPixelValue(enc->image, j, i, 0, rgb[0]);
				}
			 }
		 }
		 else
		 {
			 for(i = pixelRow; i < pixelRow + enc->moduleSize; i++) {
				 for(j = pixelCol; j < pixelCol + enc->moduleSize; j++) {
					 rgb[0] = ((moduleStatus & DmtxModuleOnRed) != 0x00) ? 0 : 255;
					 rgb[1] = ((moduleStatus & DmtxModuleOnGreen) != 0x00) ? 0 : 255;
					 rgb[2] = ((moduleStatus & DmtxModuleOnBlue) != 0x00) ? 0 : 255;
					 /*             dmtxImageSetRgb(enc->image, j, i, rgb); */
					 dmtxImageSetPixelValue(enc->image, j, i, 0, rgb[0]);
					 dmtxImageSetPixelValue(enc->image, j, i, 1, rgb[1]);
					 dmtxImageSetPixelValue(enc->image, j, i, 2, rgb[2]);
				 }
			 }
		 }
      }
   }
}