Ejemplo n.º 1
0
// Compute the distance between (x, y1) and (x, y2) using the rule that
// a decrease in textline density is weighted more heavily than an increase.
// The coordinates are in source image space, ie processed by any denorm
// already, but not yet scaled by scale_factor_.
// Going from the outside of a textline to the inside should measure much
// less distance than going from the inside of a textline to the outside.
// How it works:
// An increase is cheap (getting closer to a textline).
// Constant costs unity.
// A decrease is expensive (getting further from a textline).
// Pixels in projection map Counted distance
//              2
//              3              1/x
//              3               1
//              2               x
//              5              1/x
//              7              1/x
// Total: 1 + x + 3/x where x = kWrongWayPenalty.
int TextlineProjection::VerticalDistance(bool debug, int x,
                                         int y1, int y2) const {
  x = ImageXToProjectionX(x);
  y1 = ImageYToProjectionY(y1);
  y2 = ImageYToProjectionY(y2);
  if (y1 == y2) return 0;
  int wpl = pixGetWpl(pix_);
  int step = y1 < y2 ? 1 : -1;
  uint32_t* data = pixGetData(pix_) + y1 * wpl;
  wpl *= step;
  int prev_pixel = GET_DATA_BYTE(data, x);
  int distance = 0;
  int right_way_steps = 0;
  for (int y = y1; y != y2; y += step) {
    data += wpl;
    int pixel = GET_DATA_BYTE(data, x);
    if (debug)
      tprintf("At (%d,%d), pix = %d, prev=%d\n",
              x, y + step, pixel, prev_pixel);
    if (pixel < prev_pixel)
      distance += kWrongWayPenalty;
    else if (pixel > prev_pixel)
      ++right_way_steps;
    else
      ++distance;
    prev_pixel = pixel;
  }
  return distance * scale_factor_ +
      right_way_steps * scale_factor_ / kWrongWayPenalty;
}
Ejemplo n.º 2
0
/*!
 *  pixBilateralGrayExact()
 *
 *      Input:  pixs (8 bpp gray)
 *              spatial_kel  (gaussian kernel)
 *              range_kel (<optional> 256 x 1, monotonically decreasing)
 *      Return: pixd (8 bpp bilateral filtered image)
 *
 *  Notes:
 *      (1) See pixBilateralExact().
 */
PIX *
pixBilateralGrayExact(PIX *pixs,
                      L_KERNEL *spatial_kel,
                      L_KERNEL *range_kel) {
    l_int32 i, j, id, jd, k, m, w, h, d, sx, sy, cx, cy, wplt, wpld;
    l_int32 val, center_val;
    l_uint32 *datat, *datad, *linet, *lined;
    l_float32 sum, weight_sum, weight;
    L_KERNEL *keli;
    PIX *pixt, *pixd;

    PROCNAME("pixBilateralGrayExact");

    if (!pixs)
        return (PIX *) ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 8)
        return (PIX *) ERROR_PTR("pixs must be gray", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (!spatial_kel)
        return (PIX *) ERROR_PTR("spatial kel not defined", procName, NULL);

    if (!range_kel)
        return pixConvolve(pixs, spatial_kel, 8, 1);
    if (range_kel->sx != 256 || range_kel->sy != 1)
        return (PIX *) ERROR_PTR("range kel not {256 x 1", procName, NULL);

    keli = kernelInvert(spatial_kel);
    kernelGetParameters(keli, &sy, &sx, &cy, &cx);
    if ((pixt = pixAddMirroredBorder(pixs, cx, sx - cx, cy, sy - cy)) == NULL)
        return (PIX *) ERROR_PTR("pixt not made", procName, NULL);

    pixd = pixCreate(w, h, 8);
    datat = pixGetData(pixt);
    datad = pixGetData(pixd);
    wplt = pixGetWpl(pixt);
    wpld = pixGetWpl(pixd);
    for (i = 0, id = 0; id < h; i++, id++) {
        lined = datad + id * wpld;
        for (j = 0, jd = 0; jd < w; j++, jd++) {
            center_val = GET_DATA_BYTE(datat + (i + cy) * wplt, j + cx);
            weight_sum = 0.0;
            sum = 0.0;
            for (k = 0; k < sy; k++) {
                linet = datat + (i + k) * wplt;
                for (m = 0; m < sx; m++) {
                    val = GET_DATA_BYTE(linet, j + m);
                    weight = keli->data[k][m] *
                             range_kel->data[0][L_ABS(center_val - val)];
                    weight_sum += weight;
                    sum += val * weight;
                }
            }
            SET_DATA_BYTE(lined, jd, (l_int32)(sum / weight_sum + 0.5));
        }
    }

    kernelDestroy(&keli);
    pixDestroy(&pixt);
    return pixd;
}
Ejemplo n.º 3
0
// Compute the distance between (x1, y) and (x2, y) using the rule that
// a decrease in textline density is weighted more heavily than an increase.
int TextlineProjection::HorizontalDistance(bool debug, int x1, int x2,
                                           int y) const {
  x1 = ImageXToProjectionX(x1);
  x2 = ImageXToProjectionX(x2);
  y = ImageYToProjectionY(y);
  if (x1 == x2) return 0;
  int wpl = pixGetWpl(pix_);
  int step = x1 < x2 ? 1 : -1;
  uint32_t* data = pixGetData(pix_) + y * wpl;
  int prev_pixel = GET_DATA_BYTE(data, x1);
  int distance = 0;
  int right_way_steps = 0;
  for (int x = x1; x != x2; x += step) {
    int pixel = GET_DATA_BYTE(data, x + step);
    if (debug)
      tprintf("At (%d,%d), pix = %d, prev=%d\n",
              x + step, y, pixel, prev_pixel);
    if (pixel < prev_pixel)
      distance += kWrongWayPenalty;
    else if (pixel > prev_pixel)
      ++right_way_steps;
    else
      ++distance;
    prev_pixel = pixel;
  }
  return distance * scale_factor_ +
      right_way_steps * scale_factor_ / kWrongWayPenalty;
}
/*!
 *  pixAddConstantGray()
 *
 *      Input:  pixs (8, 16 or 32 bpp)
 *              val  (amount to add to each pixel)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) In-place operation.
 *      (2) No clipping for 32 bpp.
 *      (3) For 8 and 16 bpp, if val > 0 the result is clipped
 *          to 0xff and 0xffff, rsp.
 *      (4) For 8 and 16 bpp, if val < 0 the result is clipped to 0.
 */
l_int32
pixAddConstantGray(PIX      *pixs,
                   l_int32   val)
{
l_int32    i, j, w, h, d, wpl, pval;
l_uint32  *data, *line;

    PROCNAME("pixAddConstantGray");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8 && d != 16 && d != 32)
        return ERROR_INT("pixs not 8, 16 or 32 bpp", procName, 1);

    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 8) {
            if (val < 0) {
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_BYTE(line, j);
                    pval = L_MAX(0, pval + val);
                    SET_DATA_BYTE(line, j, pval);
                }
            } else {  /* val >= 0 */
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_BYTE(line, j);
                    pval = L_MIN(255, pval + val);
                    SET_DATA_BYTE(line, j, pval);
                }
            }
        } else if (d == 16) {
            if (val < 0) {
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_TWO_BYTES(line, j);
                    pval = L_MAX(0, pval + val);
                    SET_DATA_TWO_BYTES(line, j, pval);
                }
            } else {  /* val >= 0 */
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_TWO_BYTES(line, j);
                    pval = L_MIN(0xffff, pval + val);
                    SET_DATA_TWO_BYTES(line, j, pval);
                }
            }
        } else {  /* d == 32; no check for overflow (< 0 or > 0xffffffff) */
            for (j = 0; j < w; j++)
                *(line + j) += val;
        }
    }

    return 0;
}
Ejemplo n.º 5
0
/*!
 *  bilateralApply()
 *
 *      Input:  bil
 *      Return: pixd
 */
static PIX *
bilateralApply(L_BILATERAL  *bil)
{
l_int32      i, j, k, ired, jred, w, h, wpls, wpld, ncomps, reduction;
l_int32      vals, vald, lowval, hival;
l_int32     *kindex;
l_float32    fract;
l_float32   *kfract;
l_uint32    *lines, *lined, *datas, *datad;
l_uint32  ***lineset = NULL;  /* for set of PBC */
PIX         *pixs, *pixd;
PIXA        *pixac;

    PROCNAME("bilateralApply");

    if (!bil)
        return (PIX *)ERROR_PTR("bil not defined", procName, NULL);
    pixs = bil->pixs;
    ncomps = bil->ncomps;
    kindex = bil->kindex;
    kfract = bil->kfract;
    reduction = bil->reduction;
    pixac = bil->pixac;
    lineset = bil->lineset;
    if (pixaGetCount(pixac) != ncomps)
        return (PIX *)ERROR_PTR("PBC images do not exist", procName, NULL);

    if ((pixd = pixCreateTemplate(pixs)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    datas = pixGetData(pixs);
    wpls = pixGetWpl(pixs);
    datad = pixGetData(pixd);
    wpld = pixGetWpl(pixd);
    pixGetDimensions(pixs, &w, &h, NULL);
    for (i = 0; i < h; i++) {
        lines = datas + i * wpls;
        lined = datad + i * wpld;
        ired = i / reduction;
        for (j = 0; j < w; j++) {
            jred = j / reduction;
            vals = GET_DATA_BYTE(lines, j);
            k = kindex[vals];
            lowval = GET_DATA_BYTE(lineset[k][ired], jred);
            hival = GET_DATA_BYTE(lineset[k + 1][ired], jred);
            fract = kfract[vals];
            vald = (l_int32)((1.0 - fract) * lowval + fract * hival + 0.5);
            SET_DATA_BYTE(lined, j, vald);
        }
    }

    return pixd;
}
Ejemplo n.º 6
0
/*!
 *  addConstantGrayLow()
 */
void
addConstantGrayLow(l_uint32  *data,
                   l_int32    w,
                   l_int32    h,
                   l_int32    d,
                   l_int32    wpl,
                   l_int32    val)
{
    l_int32    i, j, pval;
    l_uint32  *line;

    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 8) {
            if (val < 0) {
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_BYTE(line, j);
                    pval = L_MAX(0, pval + val);
                    SET_DATA_BYTE(line, j, pval);
                }
            }
            else {  /* val >= 0 */
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_BYTE(line, j);
                    pval = L_MIN(255, pval + val);
                    SET_DATA_BYTE(line, j, pval);
                }
            }
        }
        else if (d == 16) {
            if (val < 0) {
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_TWO_BYTES(line, j);
                    pval = L_MAX(0, pval + val);
                    SET_DATA_TWO_BYTES(line, j, pval);
                }
            }
            else {  /* val >= 0 */
                for (j = 0; j < w; j++) {
                    pval = GET_DATA_TWO_BYTES(line, j);
                    pval = L_MIN(0xffff, pval + val);
                    SET_DATA_TWO_BYTES(line, j, pval);
                }
            }
        }
        else {  /* d == 32; no check for overflow (< 0 or > 0xffffffff) */
            for (j = 0; j < w; j++)
                *(line + j) += val;
        }
    }
    return;
}
Ejemplo n.º 7
0
// Helper returns the mean pixel value over the line between the start_pt and
// end_pt (inclusive), but shifted perpendicular to the line in the projection
// image by offset pixels. For simplicity, it is assumed that the vector is
// either nearly horizontal or nearly vertical. It works on skewed textlines!
// The end points are in external coordinates, and will be denormalized with
// the denorm if not NULL before further conversion to pix coordinates.
// After all the conversions, the offset is added to the direction
// perpendicular to the line direction. The offset is thus in projection image
// coordinates, which allows the caller to get a guaranteed displacement
// between pixels used to calculate gradients.
int TextlineProjection::MeanPixelsInLineSegment(const DENORM* denorm,
                                                int offset,
                                                TPOINT start_pt,
                                                TPOINT end_pt) const {
  TransformToPixCoords(denorm, &start_pt);
  TransformToPixCoords(denorm, &end_pt);
  TruncateToImageBounds(&start_pt);
  TruncateToImageBounds(&end_pt);
  int wpl = pixGetWpl(pix_);
  uint32_t* data = pixGetData(pix_);
  int total = 0;
  int count = 0;
  int x_delta = end_pt.x - start_pt.x;
  int y_delta = end_pt.y - start_pt.y;
  if (abs(x_delta) >= abs(y_delta)) {
    if (x_delta == 0)
      return 0;
    // Horizontal line. Add the offset vertically.
    int x_step = x_delta > 0 ? 1 : -1;
    // Correct offset for rotation, keeping it anti-clockwise of the delta.
    offset *= x_step;
    start_pt.y += offset;
    end_pt.y += offset;
    TruncateToImageBounds(&start_pt);
    TruncateToImageBounds(&end_pt);
    x_delta = end_pt.x - start_pt.x;
    y_delta = end_pt.y - start_pt.y;
    count = x_delta * x_step + 1;
    for (int x = start_pt.x; x != end_pt.x; x += x_step) {
      int y = start_pt.y + DivRounded(y_delta * (x - start_pt.x), x_delta);
      total += GET_DATA_BYTE(data + wpl * y, x);
    }
  } else {
    // Vertical line. Add the offset horizontally.
    int y_step = y_delta > 0 ? 1 : -1;
    // Correct offset for rotation, keeping it anti-clockwise of the delta.
    // Pix holds the image with y=0 at the top, so the offset is negated.
    offset *= -y_step;
    start_pt.x += offset;
    end_pt.x += offset;
    TruncateToImageBounds(&start_pt);
    TruncateToImageBounds(&end_pt);
    x_delta = end_pt.x - start_pt.x;
    y_delta = end_pt.y - start_pt.y;
    count = y_delta * y_step + 1;
    for (int y = start_pt.y; y != end_pt.y; y += y_step) {
      int x = start_pt.x + DivRounded(x_delta * (y - start_pt.y), y_delta);
      total += GET_DATA_BYTE(data + wpl * y, x);
    }
  }
  return DivRounded(total, count);
}
Ejemplo n.º 8
0
/*!
 *  pixGlobalStats()
 *
 *      Input:  pixs   (8 bpp grayscale)
 *              &mean  (<optional return> pixs mean)
 *              &var   (<optional return> pixs variance)
 *              &std   (<optional return> pixs standard deviation)
 *      Return: 0 if OK; 1 on error
 */
l_int32
pixGlobalStats(PIX       *pixs,
			   l_float32 *mean,
			   l_float32 *var,
			   l_float32 *std)
{
	l_int32    w, h, d, i, j;
	l_int32    wpl;
	l_uint32  *data, *line;
	l_float32  m, v;
	
	PROCNAME("pixGlobalStats");
	
	if (!mean && !var && !std)
        return ERROR_INT("nothing to do", procName, 1);
	if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8)
        return ERROR_INT("pixs not 8 bpp", procName, 1);
	
	wpl = pixGetWpl(pixs);
	data = pixGetData(pixs);
	
	/* Calculate the global mean */
	m = 0.;
	for (i = 0; i < h; i++) {
		line = data + i * wpl;
		for (j = 0; j < w; j++)
			m += GET_DATA_BYTE(line, j);
	}
	m /= (w * h);
	
	/* Calculate the global variance */
	v = 0.;
	for (i = 0; i < h; i++) {
		line = data + i * wpl;
		for (j = 0; j < w; j++)
			v += pow((GET_DATA_BYTE(line, j) - m), 2);
	}
	v /= (w * h);
	
	if (mean)
		*mean = m;
	if (var)
		*var = v;
	if (std)
		*std = sqrt(v);
	
	return 0;
}
Ejemplo n.º 9
0
/*!
 *  pixDilateGray3h()
 *
 *      Input:  pixs (8 bpp, not cmapped)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) Special case for horizontal 3x1 brick Sel;
 *          also used as the first step for the 3x3 brick Sel.
 */
static PIX *
pixDilateGray3h(PIX  *pixs)
{
l_uint32  *datas, *datad, *lines, *lined;
l_int32    w, h, wpl, i, j;
l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
PIX       *pixd;

    PROCNAME("pixDilateGray3h");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 8)
        return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);

    pixd = pixCreateTemplateNoInit(pixs);
    pixSetBorderVal(pixd, 4, 8, 2, 8, 0);  /* only to silence valgrind */
    pixGetDimensions(pixs, &w, &h, NULL);
    datas = pixGetData(pixs);
    datad = pixGetData(pixd);
    wpl = pixGetWpl(pixs);
    for (i = 0; i < h; i++) {
        lines = datas + i * wpl;
        lined = datad + i * wpl;
        for (j = 1; j < w - 8; j += 8) {
            val0 = GET_DATA_BYTE(lines, j - 1);
            val1 = GET_DATA_BYTE(lines, j);
            val2 = GET_DATA_BYTE(lines, j + 1);
            val3 = GET_DATA_BYTE(lines, j + 2);
            val4 = GET_DATA_BYTE(lines, j + 3);
            val5 = GET_DATA_BYTE(lines, j + 4);
            val6 = GET_DATA_BYTE(lines, j + 5);
            val7 = GET_DATA_BYTE(lines, j + 6);
            val8 = GET_DATA_BYTE(lines, j + 7);
            val9 = GET_DATA_BYTE(lines, j + 8);
            maxval = L_MAX(val1, val2);
            SET_DATA_BYTE(lined, j, L_MAX(val0, maxval));
            SET_DATA_BYTE(lined, j + 1, L_MAX(maxval, val3));
            maxval = L_MAX(val3, val4);
            SET_DATA_BYTE(lined, j + 2, L_MAX(val2, maxval));
            SET_DATA_BYTE(lined, j + 3, L_MAX(maxval, val5));
            maxval = L_MAX(val5, val6);
            SET_DATA_BYTE(lined, j + 4, L_MAX(val4, maxval));
            SET_DATA_BYTE(lined, j + 5, L_MAX(maxval, val7));
            maxval = L_MAX(val7, val8);
            SET_DATA_BYTE(lined, j + 6, L_MAX(val6, maxval));
            SET_DATA_BYTE(lined, j + 7, L_MAX(maxval, val9));
        }
    }
    return pixd;
}
Ejemplo n.º 10
0
/*!
 *  pixDilateGray3v()
 *
 *      Input:  pixs (8 bpp, not cmapped)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) Special case for vertical 1x3 brick Sel;
 *          also used as the second step for the 3x3 brick Sel.
 */
static PIX *
pixDilateGray3v(PIX  *pixs)
{
l_uint32  *datas, *datad, *linesi, *linedi;
l_int32    w, h, wpl, i, j;
l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
PIX       *pixd;

    PROCNAME("pixDilateGray3v");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 8)
        return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);

    pixd = pixCreateTemplateNoInit(pixs);
    pixGetDimensions(pixs, &w, &h, NULL);
    datas = pixGetData(pixs);
    datad = pixGetData(pixd);
    wpl = pixGetWpl(pixs);
    for (j = 0; j < w; j++) {
        for (i = 1; i < h - 8; i += 8) {
            linesi = datas + i * wpl;
            linedi = datad + i * wpl;
            val0 = GET_DATA_BYTE(linesi - wpl, j);
            val1 = GET_DATA_BYTE(linesi, j);
            val2 = GET_DATA_BYTE(linesi + wpl, j);
            val3 = GET_DATA_BYTE(linesi + 2 * wpl, j);
            val4 = GET_DATA_BYTE(linesi + 3 * wpl, j);
            val5 = GET_DATA_BYTE(linesi + 4 * wpl, j);
            val6 = GET_DATA_BYTE(linesi + 5 * wpl, j);
            val7 = GET_DATA_BYTE(linesi + 6 * wpl, j);
            val8 = GET_DATA_BYTE(linesi + 7 * wpl, j);
            val9 = GET_DATA_BYTE(linesi + 8 * wpl, j);
            maxval = L_MAX(val1, val2);
            SET_DATA_BYTE(linedi, j, L_MAX(val0, maxval));
            SET_DATA_BYTE(linedi + wpl, j, L_MAX(maxval, val3));
            maxval = L_MAX(val3, val4);
            SET_DATA_BYTE(linedi + 2 * wpl, j, L_MAX(val2, maxval));
            SET_DATA_BYTE(linedi + 3 * wpl, j, L_MAX(maxval, val5));
            maxval = L_MAX(val5, val6);
            SET_DATA_BYTE(linedi + 4 * wpl, j, L_MAX(val4, maxval));
            SET_DATA_BYTE(linedi + 5 * wpl, j, L_MAX(maxval, val7));
            maxval = L_MAX(val7, val8);
            SET_DATA_BYTE(linedi + 6 * wpl, j, L_MAX(val6, maxval));
            SET_DATA_BYTE(linedi + 7 * wpl, j, L_MAX(maxval, val9));
        }
    }
    return pixd;
}
Ejemplo n.º 11
0
/*!
 *  dpixMeanSquareAccum()
 *
 *      Input:  pixs (1 bpp or 8 bpp grayscale)
 *      Return: dpix (64 bit array), or null on error
 *
 *  Notes:
 *      (1) This is an extension to the standard pixMeanSquareAccum()
 *          implementation provided by Leptonica, to handle 1bpp binary pix
 *          transparently.
 *      (1) Similar to pixBlockconvAccum(), this computes the
 *          sum of the squares of the pixel values in such a way
 *          that the value at (i,j) is the sum of all squares in
 *          the rectangle from the origin to (i,j).
 *      (2) The general recursion relation (v are squared pixel values) is
 *            a(i,j) = v(i,j) + a(i-1, j) + a(i, j-1) - a(i-1, j-1)
 *          For the first line, this reduces to the special case
 *            a(i,j) = v(i,j) + a(i, j-1)
 *          For the first column, the special case is
 *            a(i,j) = v(i,j) + a(i-1, j)
 */
DPIX *
dpixMeanSquareAccum(PIX  *pixs)
{
	l_int32     i, j, w, h, d, wpl, wpls, val;
	l_uint32   *datas, *lines;
	l_float64  *data, *line, *linep;
	DPIX       *dpix;
	
    PROCNAME("dpixMeanSquareAccum");
	
    if (!pixs)
        return (DPIX *)ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 1 && d != 8)
        return (DPIX *)ERROR_PTR("pixs not 1 bpp or 8 bpp", procName, NULL);
    if ((dpix = dpixCreate(w, h)) ==  NULL)
        return (DPIX *)ERROR_PTR("dpix not made", procName, NULL);
	
    datas = pixGetData(pixs);
    wpls = pixGetWpl(pixs);
    data = dpixGetData(dpix);
    wpl = dpixGetWpl(dpix);
	
    lines = datas;
    line = data;
    for (j = 0; j < w; j++) {   /* first line */
        val = d == 1 ? GET_DATA_BIT(lines, j) : GET_DATA_BYTE(lines, j);
        if (j == 0)
            line[0] = val * val;
        else
            line[j] = line[j - 1] + val * val;
    }
	
	/* Do the other lines */
    for (i = 1; i < h; i++) {
        lines = datas + i * wpls;
        line = data + i * wpl;  /* current dest line */
        linep = line - wpl;;  /* prev dest line */
        for (j = 0; j < w; j++) {
            val = d == 1 ? GET_DATA_BIT(lines, j) : GET_DATA_BYTE(lines, j);
            if (j == 0)
                line[0] = linep[0] + val * val;
            else
                line[j] = line[j - 1] + linep[j] - linep[j - 1] + val * val;
        }
    }
	
    return dpix;
}
Ejemplo n.º 12
0
// Helper computes the local 2-D gradient (dx, dy) from the 2x2 cell centered
// on the given (x,y). If the cell would go outside the image, it is padded
// with white.
static void ComputeGradient(const l_uint32* data, int wpl,
                            int x, int y, int width, int height,
                            ICOORD* gradient) {
  const l_uint32* line = data + y * wpl;
  int pix_x_y = x < width && y < height ?
      GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line)), x) : 255;
  int pix_x_prevy = x < width && y > 0 ?
      GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line - wpl)), x) : 255;
  int pix_prevx_prevy = x > 0 && y > 0 ?
      GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<void const*>(line - wpl)), x - 1) : 255;
  int pix_prevx_y = x > 0 && y < height ?
      GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line)), x - 1) : 255;
  gradient->set_x(pix_x_y + pix_x_prevy - (pix_prevx_y + pix_prevx_prevy));
  gradient->set_y(pix_x_prevy + pix_prevx_prevy - (pix_x_y + pix_prevx_y));
}
Ejemplo n.º 13
0
// Helper evaluates a horizontal difference, (x,y) - (x-1,y), where y is implied
// by the input image line, returning true if the difference matches diff_sign
// and updating the best_diff, best_sum, best_x if a new max.
static bool EvaluateHorizontalDiff(const l_uint32* line, int diff_sign,
                                   int x, int width,
                                   int* best_diff, int* best_sum, int* best_x) {
  if (x <= 0 || x >= width)
    return false;
  int pixel1 = GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line)), x - 1);
  int pixel2 = GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line)), x);
  int diff = (pixel2 - pixel1) * diff_sign;
  if (diff > *best_diff) {
    *best_diff = diff;
    *best_sum = pixel1 + pixel2;
    *best_x = x;
  }
  return diff > 0;
}
Ejemplo n.º 14
0
struct corners* RunFastDetector9(PIX *pix,
				 unsigned int w, 
				 unsigned int h) {

  xy *rawcorners = (xy *) malloc(sizeof(xy));
  unsigned char *im = (unsigned char*) malloc(sizeof(unsigned char) * (w*h));
  void **pix_lines = pixGetLinePtrs(pix, NULL);
  unsigned int x,y, num_corners;
  unsigned int i = 0;
  for(y=0;y<h;y++) 
    for(x=0;x<w;x++){
      im[i] = (unsigned char) GET_DATA_BYTE(pix_lines[y],x);
      i++;
    }

  free(pix_lines);
  rawcorners = fast9_detect(im, w, h, w, 88, &num_corners);
  free(im);

  unsigned int mx,my;
  mx = (unsigned int)w/2;
  my = (unsigned int)h/2;
  
  float skew_angle = 0.0;

  struct corners *corners = ParseRawCorners(rawcorners, 
					    num_corners,
					    mx,my,
					    skew_angle);
  free(rawcorners);
  return corners;
}
Ejemplo n.º 15
0
// Create a window and display the projection in it.
void TextlineProjection::DisplayProjection() const {
#ifndef GRAPHICS_DISABLED
  int width = pixGetWidth(pix_);
  int height = pixGetHeight(pix_);
  Pix* pixc = pixCreate(width, height, 32);
  int src_wpl = pixGetWpl(pix_);
  int col_wpl = pixGetWpl(pixc);
  uint32_t* src_data = pixGetData(pix_);
  uint32_t* col_data = pixGetData(pixc);
  for (int y = 0; y < height; ++y, src_data += src_wpl, col_data += col_wpl) {
    for (int x = 0; x < width; ++x) {
      int pixel = GET_DATA_BYTE(src_data, x);
      l_uint32 result;
      if (pixel <= 17)
        composeRGBPixel(0, 0, pixel * 15, &result);
      else if (pixel <= 145)
        composeRGBPixel(0, (pixel - 17) * 2, 255, &result);
      else
        composeRGBPixel((pixel - 145) * 2, 255, 255, &result);
      col_data[x] = result;
    }
  }
  ScrollView* win = new ScrollView("Projection", 0, 0,
                                   width, height, width, height);
  win->Image(pixc, 0, 0);
  win->Update();
  pixDestroy(&pixc);
#endif  // GRAPHICS_DISABLED
}
Ejemplo n.º 16
0
// Helper evaluates a vertical difference, (x,y) - (x,y-1), returning true if
// the difference, matches diff_sign and updating the best_diff, best_sum,
// best_y if a new max.
static bool EvaluateVerticalDiff(const l_uint32* data, int wpl, int diff_sign,
                                 int x, int y, int height,
                                 int* best_diff, int* best_sum, int* best_y) {
  if (y <= 0 || y >= height)
    return false;
  const l_uint32* line = data + y * wpl;
  int pixel1 = GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line - wpl)), x);
  int pixel2 = GET_DATA_BYTE(const_cast<void*> (reinterpret_cast<const void *>(line)), x);
  int diff = (pixel2 - pixel1) * diff_sign;
  if (diff > *best_diff) {
    *best_diff = diff;
    *best_sum = pixel1 + pixel2;
    *best_y = y;
  }
  return diff > 0;
}
Ejemplo n.º 17
0
/*!
 *  pixAdaptiveMeanFilter()
 *
 *      Input:  pixs   (8 bpp grayscale)
 *              wc, hc (half width/height of convolution kernel)
 *              varn   (value of overall noise variance)
 *      Return: pixd (8 bpp, filtered image)
 *
 *  Notes:
 *      (1) The filter reduces gaussian noise, achieving results similar
 *          to the arithmetic and geometric mean filters but avoiding the
 *          considerable image blurring effect introduced by those filters.
 *      (2) The filter can be expressed mathematically by:
 *            f'(x, y) = g(x, y) - varN / varL * [ g(x, y) - meanL ]
 *          where:
 *            -- g(x, y) is the pixel at the center of local region S of
 *               width (2 * wc + 1) and height (2 * wh + 1)
 *            -- varN and varL are the overall noise variance (given in input)
 *               and local variance of S, respectively
 *            -- meanL is the local mean of S
 *      (3) Typically @varn is estimated by studying the PDFs produced by
 *          the camera or equipment sensors.
 */
PIX *
pixAdaptiveMeanFilter(PIX       *pixs,
					  l_int32    wc,
					  l_int32    hc,
					  l_float32  varn)
{
	l_int32    i, j, w, h, d, wplt, wpld, wincr, hincr;
	l_uint32   val;
	l_uint32  *datat, *datad, *linet, *lined;
	l_float32  norm, meanl, varl, ratio;
	PIX       *pixt, *pixd;
	
    PROCNAME("pixAdaptiveMeanFilter");
    
    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8)
        return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
    if (wc < 1 || hc < 1)
        return (PIX *)ERROR_PTR("wc and hc not >= 1", procName, NULL);
	
	/* Add wc to each side, and hc to top and bottom of the image,
	 * mirroring for accuracy and to avoid special-casing the boundary. */
    if ((pixt = pixAddMirroredBorder(pixs, wc, wc, hc, hc)) == NULL)
        return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
	
	/* Place the filter center at (0, 0).  This is just a
	 * convenient location, because it allows us to perform
	 * the filtering over x:(0 ... w - 1) and y:(0 ... h - 1). */
	pixd = pixCreateTemplate(pixs);
	wplt = pixGetWpl(pixt);
    wpld = pixGetWpl(pixd);
	datat = pixGetData(pixt);
    datad = pixGetData(pixd);
	
    wincr = 2 * wc + 1;
    hincr = 2 * hc + 1;
	norm = 1.0 / (wincr * hincr);
	for (i = 0; i < h; i++) {
        linet = datat + (i + hc) * wplt;
		lined = datad + i * wpld;
        for (j = 0; j < w; j++) {
            /* Calculate mean intensity value */
			meanl = calculateLocalMeanLow(datat, wplt, wincr, hincr, i, j);
			/* Calculate local variance */
			varl = calculateLocalVarianceLow(datat, wplt, wincr, hincr, i, j, meanl);
			/* Account for special case in which varN is more than varL */
			ratio = (varn > varl) ? 1 : varn / varl;
			val = GET_DATA_BYTE(linet, j + wc);
			SET_DATA_BYTE(lined, j, (l_uint8) (val - ratio * (val - meanl)));
        } 
    }
	
	pixDestroy(&pixt);	
    return pixd;
}
Ejemplo n.º 18
0
void SetFourierData(void **lines,              
                    struct fouriercomponents *fc,
                    unsigned int signal_size,
                    unsigned int signal_count,
                    int scan_mode,
                    int start,
                    int end) {
  
  fc->scan_mode = scan_mode;
  fc->signal_count = signal_count;
  fc->signal_size = signal_size;
  
  fc->signals   = (double **) malloc(sizeof(double)*signal_count);  
  fc->real      = (double **) malloc(sizeof(double)*signal_count);
  fc->imag      = (double **) malloc(sizeof(double)*signal_count);
  fc->freq      = (double **) malloc(sizeof(double)*signal_count);  
  fc->magnitude = (double **) malloc(sizeof(double)*signal_count);  
  fc->phase     = (double **) malloc(sizeof(double)*signal_count);    
  
  unsigned int x,y;
  if (scan_mode==0) {
    for (y=0;y<signal_count;y++) {
      fc->signals[y] = (double*)malloc(sizeof(double)*signal_size);
      for (x=0;x<signal_size;x++) {
        fc->signals[y][x] = GET_DATA_BYTE(lines[y],x);
      }
    }
  }

  else if (scan_mode==1) {
    unsigned int i,k;
    i=k=0;
    for (x=0;x<signal_count;x++) {
      fc->signals[i] = (double*)malloc(sizeof(double)*signal_size);
      k = 0;
      for (y=start;y<end;y++) {
        fc->signals[i][k] = GET_DATA_BYTE(lines[y],x);
        k++;
      }
      i++;
    }
  }
}
Ejemplo n.º 19
0
// Sends each pixel as hex value like html, e.g. #00FF00 for green.
void ScrollView::Transfer32bppImage(PIX* image) {
  int ppL = pixGetWidth(image);
  int h = pixGetHeight(image);
  int wpl = pixGetWpl(image);
  int transfer_size= ppL * 7 + 2;
  char* pixel_data = new char[transfer_size];
  for (int y = 0; y < h; ++y) {
    l_uint32* data = pixGetData(image) + y*wpl;
    for (int x = 0; x < ppL; ++x, ++data) {
      snprintf(&pixel_data[x*7], 7, "#%.2x%.2x%.2x",
               GET_DATA_BYTE(data, COLOR_RED),
               GET_DATA_BYTE(data, COLOR_GREEN),
               GET_DATA_BYTE(data, COLOR_BLUE));
    }
    pixel_data[transfer_size - 2] = '\n';
    pixel_data[transfer_size - 1] = '\0';
    SendRawMessage(pixel_data);
  }
  delete[] pixel_data;
}
Ejemplo n.º 20
0
/*!
 *  pixApplyLocalThreshold()
 *
 *      Input:  pixs (8 bpp grayscale; not colormapped)
 *              pixth (8 bpp array of local thresholds)
 *              redfactor ( ... )
 *      Return: pixd (1 bpp, thresholded image), or null on error
 */
PIX *
pixApplyLocalThreshold(PIX     *pixs,
                       PIX     *pixth,
                       l_int32  redfactor)
{
l_int32    i, j, w, h, wpls, wplt, wpld, vals, valt;
l_uint32  *datas, *datat, *datad, *lines, *linet, *lined;
PIX       *pixd;

    PROCNAME("pixApplyLocalThreshold");

    if (!pixs || pixGetDepth(pixs) != 8)
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
    if (pixGetColormap(pixs))
        return (PIX *)ERROR_PTR("pixs is colormapped", procName, NULL);
    if (!pixth || pixGetDepth(pixth) != 8)
        return (PIX *)ERROR_PTR("pixth undefined or not 8 bpp", procName, NULL);

    pixGetDimensions(pixs, &w, &h, NULL);
    pixd = pixCreate(w, h, 1);
    datas = pixGetData(pixs);
    datat = pixGetData(pixth);
    datad = pixGetData(pixd);
    wpls = pixGetWpl(pixs);
    wplt = pixGetWpl(pixth);
    wpld = pixGetWpl(pixd);
    for (i = 0; i < h; i++) {
        lines = datas + i * wpls;
        linet = datat + i * wplt;
        lined = datad + i * wpld;
        for (j = 0; j < w; j++) {
            vals = GET_DATA_BYTE(lines, j);
            valt = GET_DATA_BYTE(linet, j);
            if (vals < valt)
                SET_DATA_BIT(lined, j);
        }
    }

    return pixd;
}
Ejemplo n.º 21
0
/*!
 *  addGrayLow()
 */
void
addGrayLow(l_uint32  *datad,
           l_int32    w,
           l_int32    h,
           l_int32    d,
           l_int32    wpld,
           l_uint32  *datas,
           l_int32    wpls)
{
    l_int32    i, j, val, sum;
    l_uint32  *lines, *lined;


    for (i = 0; i < h; i++) {
        lined = datad + i * wpld;
        lines = datas + i * wpls;
        if (d == 8) {
            for (j = 0; j < w; j++) {
                sum = GET_DATA_BYTE(lines, j) + GET_DATA_BYTE(lined, j);
                val = L_MIN(sum, 255);
                SET_DATA_BYTE(lined, j, val);
            }
        }
        else if (d == 16) {
            for (j = 0; j < w; j++) {
                sum = GET_DATA_TWO_BYTES(lines, j)
                      + GET_DATA_TWO_BYTES(lined, j);
                val = L_MIN(sum, 0xffff);
                SET_DATA_TWO_BYTES(lined, j, val);
            }
        }
        else {   /* d == 32; no clipping */
            for (j = 0; j < w; j++)
                *(lined + j) += *(lines + j);
        }
    }

    return;
}
Ejemplo n.º 22
0
// Sends for each pixel either '1' or '0'.
void ScrollView::TransferGrayImage(PIX* image) {
  char* pixel_data = new char[image->w * 2 + 2];
  for (int y = 0; y < image->h; y++) {
    l_uint32* data = pixGetData(image) + y * pixGetWpl(image);
    for (int x = 0; x < image->w; x++) {
      snprintf(&pixel_data[x*2], 2, "%.2x", (GET_DATA_BYTE(data, x)));
      pixel_data[image->w * 2] = '\n';
      pixel_data[image->w * 2 + 1] = '\0';
      SendRawMessage(pixel_data);
    }
  }
  delete [] pixel_data;
}
Ejemplo n.º 23
0
/*!
 *  subtractGrayLow()
 */
void
subtractGrayLow(l_uint32  *datad,
                l_int32    w,
                l_int32    h,
                l_int32    d,
                l_int32    wpld,
                l_uint32  *datas,
                l_int32    wpls)
{
    l_int32    i, j, val, diff;
    l_uint32  *lines, *lined;

    for (i = 0; i < h; i++) {
        lined = datad + i * wpld;
        lines = datas + i * wpls;
        if (d == 8) {
            for (j = 0; j < w; j++) {
                diff = GET_DATA_BYTE(lined, j) - GET_DATA_BYTE(lines, j);
                val = L_MAX(diff, 0);
                SET_DATA_BYTE(lined, j, val);
            }
        }
        else if (d == 16) {
            for (j = 0; j < w; j++) {
                diff = GET_DATA_TWO_BYTES(lined, j)
                       - GET_DATA_TWO_BYTES(lines, j);
                val = L_MAX(diff, 0);
                SET_DATA_TWO_BYTES(lined, j, val);
            }
        }
        else {  /* d == 32; no clipping */
            for (j = 0; j < w; j++)
                *(lined + j) -= *(lines + j);
        }
    }

    return;
}
Ejemplo n.º 24
0
// Helper function to add 1 to a rectangle in source image coords to the
// internal projection pix_.
void TextlineProjection::IncrementRectangle8Bit(const TBOX& box) {
  int scaled_left = ImageXToProjectionX(box.left());
  int scaled_top = ImageYToProjectionY(box.top());
  int scaled_right = ImageXToProjectionX(box.right());
  int scaled_bottom = ImageYToProjectionY(box.bottom());
  int wpl = pixGetWpl(pix_);
  uint32_t* data = pixGetData(pix_) + scaled_top * wpl;
  for (int y = scaled_top; y <= scaled_bottom; ++y) {
    for (int x = scaled_left; x <= scaled_right; ++x) {
      int pixel = GET_DATA_BYTE(data, x);
      if (pixel < 255)
        SET_DATA_BYTE(data, x, pixel + 1);
    }
    data += wpl;
  }
}
/*!
 *  pixMultConstantGray()
 *
 *      Input:  pixs (8, 16 or 32 bpp)
 *              val  (>= 0.0; amount to multiply by each pixel)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) In-place operation; val must be >= 0.
 *      (2) No clipping for 32 bpp.
 *      (3) For 8 and 16 bpp, the result is clipped to 0xff and 0xffff, rsp.
 */
l_int32
pixMultConstantGray(PIX       *pixs,
                    l_float32  val)
{
l_int32    i, j, w, h, d, wpl, pval;
l_uint32   upval;
l_uint32  *data, *line;

    PROCNAME("pixMultConstantGray");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 8 && d != 16 && d != 32)
        return ERROR_INT("pixs not 8, 16 or 32 bpp", procName, 1);
    if (val < 0.0)
        return ERROR_INT("val < 0.0", procName, 1);

    data = pixGetData(pixs);
    wpl = pixGetWpl(pixs);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 8) {
            for (j = 0; j < w; j++) {
                pval = GET_DATA_BYTE(line, j);
                pval = (l_int32)(val * pval);
                pval = L_MIN(255, pval);
                SET_DATA_BYTE(line, j, pval);
            }
        } else if (d == 16) {
            for (j = 0; j < w; j++) {
                pval = GET_DATA_TWO_BYTES(line, j);
                pval = (l_int32)(val * pval);
                pval = L_MIN(0xffff, pval);
                SET_DATA_TWO_BYTES(line, j, pval);
            }
        } else {  /* d == 32; no clipping */
            for (j = 0; j < w; j++) {
                upval = *(line + j);
                upval = (l_uint32)(val * upval);
                *(line + j) = upval;
            }
        }
    }

    return 0;
}
Ejemplo n.º 26
0
static L_AMAP *
BuildMapHistogram(PIX     *pix,
                  l_int32  factor,
                  l_int32  print)
{
l_int32    i, j, w, h, wpl, val;
l_uint32   val32;
l_uint32  *data, *line;
L_AMAP    *m;
PIXCMAP   *cmap;
RB_TYPE    key, value;
RB_TYPE   *pval;

    fprintf(stderr, "\n --------------- Begin building map --------------\n");
    m = l_amapCreate(L_UINT_TYPE);
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    cmap = pixGetColormap(pix);
    pixGetDimensions(pix, &w, &h, NULL);
    for (i = 0; i < h; i += factor) {
        line = data + i * wpl;
        for (j = 0; j < w; j += factor) {
            val = GET_DATA_BYTE(line, j);
            pixcmapGetColor32(cmap, val, &val32);
            key.utype = val32;
            pval = l_amapFind(m, key);
            if (!pval)
                value.itype = 1;
            else
                value.itype = 1 + pval->itype;
            if (print) {
                fprintf(stderr, "key = %llx, val = %lld\n",
                        key.utype, value.itype);
            }
            l_amapInsert(m, key, value);
        }
    }
    fprintf(stderr, "Size: %d\n", l_amapSize(m));
    if (print)
        l_rbtreePrint(stderr, m);
    fprintf(stderr, " ----------- End Building map -----------------\n");

    return m;
}
Ejemplo n.º 27
0
// Returns the maximum strokewidth in the given binary image by doubling
// the maximum of the distance function.
static int MaxStrokeWidth(Pix* pix) {
  Pix* dist_pix = pixDistanceFunction(pix, 4, 8, L_BOUNDARY_BG);
  int width = pixGetWidth(dist_pix);
  int height = pixGetHeight(dist_pix);
  int wpl = pixGetWpl(dist_pix);
  l_uint32* data = pixGetData(dist_pix);
  // Find the maximum value in the distance image.
  int max_dist = 0;
  for (int y = 0; y < height; ++y) {
    for (int x = 0; x < width; ++x) {
      int pixel = GET_DATA_BYTE(data, x);
      if (pixel > max_dist)
        max_dist = pixel;
    }
    data += wpl;
  }
  pixDestroy(&dist_pix);
  return max_dist * 2;
}
Ejemplo n.º 28
0
static L_ASET *
BuildSet(PIX     *pix,
         l_int32  factor,
         l_int32  print)
{
l_int32    i, j, w, h, wpl, val;
l_uint32   val32;
l_uint32  *data, *line;
L_ASET    *s;
PIXCMAP   *cmap;
RB_TYPE    key;
RB_TYPE   *pval;

    fprintf(stderr, "\n --------------- Begin building set --------------\n");
    s = l_asetCreate(L_UINT_TYPE);
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    cmap = pixGetColormap(pix);
    pixGetDimensions(pix, &w, &h, NULL);
    for (i = 0; i < h; i += factor) {
        line = data + i * wpl;
        for (j = 0; j < w; j += factor) {
            if (cmap) {
                val = GET_DATA_BYTE(line, j);
                pixcmapGetColor32(cmap, val, &val32);
                key.utype = val32;
            } else {
                key.utype = line[j];
            }
            pval = l_asetFind(s, key);
            if (pval && print)
                fprintf(stderr, "key = %llx\n", key.utype);
            l_asetInsert(s, key);
        }
    }
    fprintf(stderr, "Size: %d\n", l_asetSize(s));
    if (print)
        l_rbtreePrint(stderr, s);
    fprintf(stderr, " ----------- End Building set -----------------\n");

    return s;
}
Ejemplo n.º 29
0
/*!
 *  multConstantGrayLow()
 */
void
multConstantGrayLow(l_uint32  *data,
                    l_int32    w,
                    l_int32    h,
                    l_int32    d,
                    l_int32    wpl,
                    l_float32  val)
{
    l_int32    i, j, pval;
    l_uint32   upval;
    l_uint32  *line;

    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 8) {
            for (j = 0; j < w; j++) {
                pval = GET_DATA_BYTE(line, j);
                pval = (l_int32)(val * pval);
                pval = L_MIN(255, pval);
                SET_DATA_BYTE(line, j, pval);
            }
        }
        else if (d == 16) {
            for (j = 0; j < w; j++) {
                pval = GET_DATA_TWO_BYTES(line, j);
                pval = (l_int32)(val * pval);
                pval = L_MIN(0xffff, pval);
                SET_DATA_TWO_BYTES(line, j, pval);
            }
        }
        else {  /* d == 32; no clipping */
            for (j = 0; j < w; j++) {
                upval = *(line + j);
                upval = (l_uint32)(val * upval);
                *(line + j) = upval;
            }
        }
    }
    return;
}
Ejemplo n.º 30
0
/*!
 * \brief   pixToGif()
 *
 * \param[in]    pix 1, 2, 4, 8, 16 or 32 bpp
 * \param[in]    gif  opened gif stream
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This encodes the pix to the gif stream. The stream is not
 *          closes by this function.
 *      (2) It is static to make this function private.
 * </pre>
 */
static l_int32
pixToGif(PIX *pix, GifFileType *gif)
{
char            *text;
l_int32          wpl, i, j, w, h, d, ncolor, rval, gval, bval;
l_int32          gif_ncolor = 0;
l_uint32        *data, *line;
PIX             *pixd;
PIXCMAP         *cmap;
ColorMapObject  *gif_cmap;
GifByteType     *gif_line;
#if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5
int              giferr;
#endif  /* 5.1 and beyond */

    PROCNAME("pixToGif");

    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);
    if (!gif)
        return ERROR_INT("gif not defined", procName, 1);

    d = pixGetDepth(pix);
    if (d == 32) {
        pixd = pixConvertRGBToColormap(pix, 1);
    } else if (d > 1) {
        pixd = pixConvertTo8(pix, TRUE);
    } else {  /* d == 1; make sure there's a colormap */
        pixd = pixClone(pix);
        if (!pixGetColormap(pixd)) {
            cmap = pixcmapCreate(1);
            pixcmapAddColor(cmap, 255, 255, 255);
            pixcmapAddColor(cmap, 0, 0, 0);
            pixSetColormap(pixd, cmap);
        }
    }

    if (!pixd)
        return ERROR_INT("failed to convert image to indexed", procName, 1);
    d = pixGetDepth(pixd);

    if ((cmap = pixGetColormap(pixd)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("cmap is missing", procName, 1);
    }

        /* 'Round' the number of gif colors up to a power of 2 */
    ncolor = pixcmapGetCount(cmap);
    for (i = 0; i <= 8; i++) {
        if ((1 << i) >= ncolor) {
            gif_ncolor = (1 << i);
            break;
        }
    }
    if (gif_ncolor < 1) {
        pixDestroy(&pixd);
        return ERROR_INT("number of colors is invalid", procName, 1);
    }

        /* Save the cmap colors in a gif_cmap */
    if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to create GIF color map", procName, 1);
    }
    for (i = 0; i < gif_ncolor; i++) {
        rval = gval = bval = 0;
        if (ncolor > 0) {
            if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
                pixDestroy(&pixd);
                GifFreeMapObject(gif_cmap);
                return ERROR_INT("failed to get color from color map",
                                 procName, 1);
            }
            ncolor--;
        }
        gif_cmap->Colors[i].Red = rval;
        gif_cmap->Colors[i].Green = gval;
        gif_cmap->Colors[i].Blue = bval;
    }

    pixGetDimensions(pixd, &w, &h, NULL);
    if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
        != GIF_OK) {
        pixDestroy(&pixd);
        GifFreeMapObject(gif_cmap);
        return ERROR_INT("failed to write screen description", procName, 1);
    }
    GifFreeMapObject(gif_cmap); /* not needed after this point */

    if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to image screen description", procName, 1);
    }

    data = pixGetData(pixd);
    wpl = pixGetWpl(pixd);
    if (d != 1 && d != 2 && d != 4 && d != 8) {
        pixDestroy(&pixd);
        return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1);
    }

    if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w))
        == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("mem alloc fail for data line", procName, 1);
    }

    for (i = 0; i < h; i++) {
        line = data + i * wpl;
            /* Gif's way of setting the raster line up for compression */
        for (j = 0; j < w; j++) {
            switch(d)
            {
            case 8:
                gif_line[j] = GET_DATA_BYTE(line, j);
                break;
            case 4:
                gif_line[j] = GET_DATA_QBIT(line, j);
                break;
            case 2:
                gif_line[j] = GET_DATA_DIBIT(line, j);
                break;
            case 1:
                gif_line[j] = GET_DATA_BIT(line, j);
                break;
            }
        }

            /* Compress and save the line */
        if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
            LEPT_FREE(gif_line);
            pixDestroy(&pixd);
            return ERROR_INT("failed to write data line into GIF", procName, 1);
        }
    }

        /* Write a text comment.  This must be placed after writing the
         * data (!!)  Note that because libgif does not provide a function
         * for reading comments from file, you will need another way
         * to read comments. */
    if ((text = pixGetText(pix)) != NULL) {
        if (EGifPutComment(gif, text) != GIF_OK)
            L_WARNING("gif comment not written\n", procName);
    }

    LEPT_FREE(gif_line);
    pixDestroy(&pixd);
    return 0;
}