Javascript Bradley自适应阈值实现

时间:2015-08-11 13:42:21

标签: javascript adaptive-threshold

我一直在努力实现Bradley自适应阈值处理。我知道其中一个堆栈溢出问题中有一个python代码。但是我正努力在JS中实现相同的目标。谁能帮帮我吗?到目前为止,我的代码是:

function computeAdaptiveThreshold (imagetest,imageWidth,imageHeight,callback) 
{

    var   size = imageWidth*imageHeight*4;
    var  s = imageWidth/8;
    var s2=s>>1;
    var t=0.15;
    var it=1.0-t;
    var i,j,diff,x1,y1,x2,y2,ind1,ind2,ind3;
    var sum=0;
    var ind=0;
    var integralImg = [];

    var canvas = document.createElement('canvas');
    var bin = canvas.getContext('2d').createImageData(imageWidth, imageHeight);

    for(i=0;i<imageWidth;i++)
    {
        sum = 0;

        for(j=0;j<imageHeight;j++)
        {
            index = i *imageHeight + j;
            sum += imagetest.data[index];

            if(i== 0)
            {
                integralImg[index] = sum;
            }
            else
            {
                //index = (i-1) * height + j;
                integralImg[index] = integralImg[(i-1) * imageHeight + j] + sum;
            }
        }
    }

    x1=0;

    for(i=1;i<imageWidth;++i)
    {
        sum=0;
        ind=i;
        ind3=ind-s2;
        if(i>s)
        {
            x1=i-s;
        }
        diff=i-x1;
        for(j=0;j<imageHeight;++j)
        {
            sum+=imagetest.data[ind];// & 0xFF;
            integralImg[ind] = integralImg[(ind-1)]+sum;
            ind+=imageWidth;
            if(i<s2)continue;
            if(j<s2)continue;
            y1=(j<s ? 0 : j-s);
            ind1=y1*imageWidth;
            ind2=j*imageWidth;

            if (((imagetest.data[ind3])*(diff * (j - y1))) < ((integralImg[(ind2 + i)] - integralImg[(ind1 + i)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
                bin.data[ind3] = 0;
            } else {
                bin.data[ind3] = 255;
            }
            ind3 += imageWidth;
        }
    }


    y1 = 0;
    for( j = 0; j < imageHeight; ++j )
    {
        i = 0;
        y2 =imageHeight- 1;
        if( j <imageHeight- s2 )
        {
            i = imageWidth - s2;
            y2 = j + s2;
        }

        ind = j * imageWidth + i;
        if( j > s2 ) y1 = j - s2;
        ind1 = y1 * imageWidth;
        ind2 = y2 * imageWidth;
        diff = y2 - y1;
        for( ; i < imageWidth; ++i, ++ind )
        {

            x1 = ( i < s2 ? 0 : i - s2);
            x2 = i + s2;

            // check the border
            if (x2 >= imageWidth) x2 = imageWidth - 1;

            if (((imagetest.data[ind])*((x2 - x1) * diff)) < ((integralImg[(ind2 + x2)] - integralImg[(ind1 + x2)] - integralImg[(ind2 + x1)] + integralImg[(ind1 + x1)])*it)) {
                bin.data[ind] = 0;
            } else {
                bin.data[ind] = 255;
            }
        }
    }

    callback(bin);`

我的图像非常糟糕。我应该说我不能把它称为图像。

1 个答案:

答案 0 :(得分:1)

我认为你的第一个努力应该是重构代码:处理索引要容易得多 然后你会发现你的索引有问题:一个图像 - 即使是灰色的 - 是一个RGBA数组,意思是4个字节=每个像素32位。
你可以通过转换RGBA->处理这个问题。 b&amp; W图像,然后进行阈值处理,然后进行b&amp; w - &gt; RGBA回来。
...或者随时处理RGBA组件。请注意,这里您只想输出黑色或白色,因此您可以在数组上创建一个Int32视图,并为每个像素立即写入R,G,B,A。

所以有些代码(在这里工作:http://jsfiddle.net/gamealchemist/3zuopz19/8/):

function computeAdaptiveThreshold(sourceImageData, ratio, callback) {
    var integral = buildIntegral_Gray(sourceImageData);

    var width = sourceImageData.width;
    var height = sourceImageData.height;
    var s = width >> 4; // in fact it's s/2, but since we never use s...

    var sourceData = sourceImageData.data;
    var result = createImageData(width, height);
    var resultData = result.data;
    var resultData32 = new Uint32Array(resultData.buffer);

    var x = 0,
        y = 0,
        lineIndex = 0;

    for (y = 0; y < height; y++, lineIndex += width) {
        for (x = 0; x < width; x++) {

            var value = sourceData[(lineIndex + x) << 2];
            var x1 = Math.max(x - s, 0);
            var y1 = Math.max(y - s, 0);
            var x2 = Math.min(x + s, width - 1);
            var y2 = Math.min(y + s, height - 1);
            var area = (x2 - x1 + 1) * (y2 - y1 + 1);
            var localIntegral = getIntegralAt(integral, width, x1, y1, x2, y2);
            if (value * area > localIntegral * ratio) {
                resultData32[lineIndex + x] = 0xFFFFFFFF;
            } else {
                resultData32[lineIndex + x] = 0xFF000000;
            }
        }
    }
    return result;
}

function createImageData(width, height) {
    var canvas = document.createElement('canvas');
    return canvas.getContext('2d').createImageData(width, height);
}

function buildIntegral_Gray(sourceImageData) {
    var sourceData = sourceImageData.data;
    var width = sourceImageData.width;
    var height = sourceImageData.height;
    // should it be Int64 Array ??
    // Sure for big images 
    var integral = new Int32Array(width * height)
    // ... for loop
    var x = 0,
        y = 0,
        lineIndex = 0,
        sum = 0;
    for (x = 0; x < width; x++) {
        sum += sourceData[x << 2];
        integral[x] = sum;
    }

    for (y = 1, lineIndex = width; y < height; y++, lineIndex += width) {
        sum = 0;
        for (x = 0; x < width; x++) {
            sum += sourceData[(lineIndex + x) << 2];
            integral[lineIndex + x] = integral[lineIndex - width + x] + sum;
        }
    }
    return integral;
}

function getIntegralAt(integral, width, x1, y1, x2, y2) {
    var result = integral[x2 + y2 * width];
    if (y1 > 0) {
        result -= integral[x2 + (y1 - 1) * width];
        if (x1 > 0) {
            result += integral[(x1 - 1) + (y1 - 1) * width];
        }
    }
    if (x1 > 0) {
        result -= integral[(x1 - 1) + (y2) * width];
    }
    return result;
}