pixWindowedMeanSquare(PIX     *pixs,
                      l_int32  wc,
                      l_int32  hc,
                      l_int32  hasborder)
{
l_int32     i, j, w, h, wd, hd, wpl, wpld, wincr, hincr;
l_uint32    ival;
l_uint32   *datad, *lined;
l_float64   norm;
l_float64   val;
l_float64  *data, *line1, *line2;
DPIX       *dpix;
PIX        *pixb, *pixd;

    PROCNAME("pixWindowedMeanSquare");

    if (!pixs || (pixGetDepth(pixs) != 8))
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
    if (wc < 2 || hc < 2)
        return (PIX *)ERROR_PTR("wc and hc not >= 2", procName, NULL);

    pixd = NULL;

        /* Add border if requested */
    if (!hasborder)
        pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
    else
        pixb = pixClone(pixs);

    if ((dpix = pixMeanSquareAccum(pixb)) == NULL) {
        L_ERROR("dpix not made\n", procName);
        goto cleanup;
    }
    wpl = dpixGetWpl(dpix);
    data = dpixGetData(dpix);

        /* The output has wc + 1 border pixels stripped from each side
         * of pixb, and hc + 1 border pixels stripped from top and bottom. */
    pixGetDimensions(pixb, &w, &h, NULL);
    wd = w - 2 * (wc + 1);
    hd = h - 2 * (hc + 1);
    if (wd < 2 || hd < 2) {
        L_ERROR("w or h too small for kernel\n", procName);
        goto cleanup;
    }
    if ((pixd = pixCreate(wd, hd, 32)) == NULL) {
        L_ERROR("pixd not made\n", procName);
        goto cleanup;
    }
    wpld = pixGetWpl(pixd);
    datad = pixGetData(pixd);

    wincr = 2 * wc + 1;
    hincr = 2 * hc + 1;
    norm = 1.0 / ((l_float32)(wincr) * hincr);
    for (i = 0; i < hd; i++) {
        line1 = data + i * wpl;
        line2 = data + (i + hincr) * wpl;
        lined = datad + i * wpld;
        for (j = 0; j < wd; j++) {
            val = line2[j + wincr] - line2[j] - line1[j + wincr] + line1[j];
            ival = (l_uint32)(norm * val + 0.5);  /* to round up */
            lined[j] = ival;
        }
    }

cleanup:
    dpixDestroy(&dpix);
    pixDestroy(&pixb);
    return pixd;
}
pixWindowedMeanSquare(PIX     *pixs,
                      l_int32  wc,
                      l_int32  hc,
                      l_int32  hasborder)
{
l_int32     i, j, w, h, wd, hd, wpl, wpld, wincr, hincr;
l_uint32    ival;
l_uint32   *datad, *lined;
l_float64   norm;
l_float64   val;
l_float64  *data, *line1, *line2;
DPIX       *dpix;
PIX        *pixb, *pixd;

    PROCNAME("pixWindowedMeanSquare");

    if (!pixs || (pixGetDepth(pixs) != 8))
        return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
    if (wc < 2 || hc < 2)
        return (PIX *)ERROR_PTR("wc and hc not >= 2", procName, NULL);

    pixd = NULL;

         
    if (!hasborder)
        pixb = pixAddBorderGeneral(pixs, wc + 1, wc + 1, hc + 1, hc + 1, 0);
    else
        pixb = pixClone(pixs);

    if ((dpix = pixMeanSquareAccum(pixb)) == NULL) {
        L_ERROR("dpix not made\n", procName);
        goto cleanup;
    }
    wpl = dpixGetWpl(dpix);
    data = dpixGetData(dpix);

         
    pixGetDimensions(pixb, &w, &h, NULL);
    wd = w - 2 * (wc + 1);
    hd = h - 2 * (hc + 1);
    if (wd < 2 || hd < 2) {
        L_ERROR("w or h too small for kernel\n", procName);
        goto cleanup;
    }
    if ((pixd = pixCreate(wd, hd, 32)) == NULL) {
        L_ERROR("pixd not made\n", procName);
        goto cleanup;
    }
    wpld = pixGetWpl(pixd);
    datad = pixGetData(pixd);

    wincr = 2 * wc + 1;
    hincr = 2 * hc + 1;
    norm = 1.0 / ((l_float32)(wincr) * hincr);
    for (i = 0; i < hd; i++) {
        line1 = data + i * wpl;
        line2 = data + (i + hincr) * wpl;
        lined = datad + i * wpld;
        for (j = 0; j < wd; j++) {
            val = line2[j + wincr] - line2[j] - line1[j + wincr] + line1[j];
            ival = (l_uint32)(norm * val + 0.5);   
            lined[j] = ival;
        }
    }

cleanup:
    dpixDestroy(&dpix);
    pixDestroy(&pixb);
    return pixd;
}