Threshold ImageProcessor

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Threshold ImageProcessor

Michael Doube
Hi all

Is there a more elegant way to threshold (using upper and lower
threshold values) an ImageProcessor than iterating over all pixels with

if(pixel > lower && pixel < upper){
   pixel = 255;
} else {
   pixel = 0;
}


I see there is a method ImageProcessor.threshold(), but it takes a
single argument which is the lower cutoff - I also need an upper cutoff.

Mike
Reply | Threaded
Open this post in threaded view
|

Re: Threshold ImageProcessor

dscho
Hi Mike,

On Fri, 19 Jun 2009, Michael Doube wrote:

> Is there a more elegant way to threshold (using upper and lower
> threshold values) an ImageProcessor than iterating over all pixels with
>
> if(pixel > lower && pixel < upper){
>   pixel = 255;
> } else {
>   pixel = 0;
> }

This is in general the method you want to use.  If you really need it
super-fast for a lot of pixels, you can construct a byte[] that holds
values 255 for everything between index "lower" and index "upper", and 0
everywhere else.  Then you can just say "pixel[i] = lut[pixel[i] & 0xff]".

This is only sensible if you really need it _super_ fast, as it
deteriorates the readability and flexibility of the code.

Ciao,
Dscho
Reply | Threaded
Open this post in threaded view
|

Re: Threshold ImageProcessor

Michael Schmid
Hi Johannes, Michael,

just a minor remark: In many cases, there is not much difference  
between the if/then and the lookup table methods; it typically needs  
maybe 10% more time with the if/then method. The value crucially  
depends on the data, however (this is a matter of branch prediction  
in the CPU): For pure noise with 50% thresholded and 50% not, branch  
prediction will fail very often, and the time needed for the if/then  
code can increase by more than a factor of 2! On the other hand, for  
extremely coarse structures, or 0% or 100% of all pixels thresholded,  
performance for the if/then and LUT codes is equal.

// LUT code
         byte[] lut = new byte[256];
         for (int i=0; i<lut.length; i++)
             lut[i] = (i<lower || i>upper) ? (byte)0 : (byte)255;

         for (int i=0; i<pixels.length; i++) {
             int v = pixels[i]&0xff;
             pixels[i] = lut[v];
         }

// if/then code
         for (int i=0; i<pixels.length; i++) {
             int v = pixels[i]&0xff;
             if (v<lower || v>upper)
                 pixels[i] = (byte)0;
             else
                 pixels[i] = (byte)255;
         }

// sometimes slightly slower than if/then code (I don't know why):
// inline conditional
         for (int i=0; i<pixels.length; i++) {
             int v = pixels[i]&0xff;
             pixels[i] = (v<lower || v>upper) ? (byte)0 : (byte)255;
         }


Michael
________________________________________________________________

On 19 Jun 2009, at 12:44, Johannes Schindelin wrote:

> Hi Mike,
>
> On Fri, 19 Jun 2009, Michael Doube wrote:
>
>> Is there a more elegant way to threshold (using upper and lower
>> threshold values) an ImageProcessor than iterating over all pixels  
>> with
>>
>> if(pixel > lower && pixel < upper){
>>   pixel = 255;
>> } else {
>>   pixel = 0;
>> }
>
> This is in general the method you want to use.  If you really need it
> super-fast for a lot of pixels, you can construct a byte[] that holds
> values 255 for everything between index "lower" and index "upper",  
> and 0
> everywhere else.  Then you can just say "pixel[i] = lut[pixel[i] &  
> 0xff]".
>
> This is only sensible if you really need it _super_ fast, as it
> deteriorates the readability and flexibility of the code.
>
> Ciao,
> Dscho
Reply | Threaded
Open this post in threaded view
|

Re: Threshold ImageProcessor

Michael Doube
In reply to this post by dscho
I ended up doing it this way, because it seems to work.  It's possible
that it's neither super-fast, nor sensible!

ImageStack sourceStack = this.imp.getImageStack();
        ImageStack binaryStack = new ImageStack(th.w, th.h);
        for (int s = 0; s < th.d; s++){
            ImageProcessor sliceIp = sourceStack.getProcessor(s+1);
            ByteProcessor binaryIp = new ByteProcessor(th.w, th.h);
            for (int y = 0; y < th.h; y++){
                for (int x = 0; x < th.w; x++){
                    if (sliceIp.get(x, y) >= this.minBoneHU &&
                            sliceIp.get(x, y) <= this.maxBoneHU){
                        binaryIp.set(x, y, 255);
                    } else {
                        binaryIp.set(x, y, 0);
                    }
                }
            }
            binaryStack.addSlice(""+s, binaryIp);
        }
        ImagePlus binaryImp = new ImagePlus("binaryImp", binaryStack);

Mike


Johannes Schindelin wrote:

> Hi Mike,
>
> On Fri, 19 Jun 2009, Michael Doube wrote:
>
>> Is there a more elegant way to threshold (using upper and lower
>> threshold values) an ImageProcessor than iterating over all pixels with
>>
>> if(pixel > lower && pixel < upper){
>>   pixel = 255;
>> } else {
>>   pixel = 0;
>> }
>
> This is in general the method you want to use.  If you really need it
> super-fast for a lot of pixels, you can construct a byte[] that holds
> values 255 for everything between index "lower" and index "upper", and 0
> everywhere else.  Then you can just say "pixel[i] = lut[pixel[i] & 0xff]".
>
> This is only sensible if you really need it _super_ fast, as it
> deteriorates the readability and flexibility of the code.
>
> Ciao,
> Dscho
>

--
Dr Michael Doube  BPhil BVSc PhD MRCVS
Research Associate
Department of Bioengineering
Imperial College London
South Kensington Campus
London  SW7 2AZ
United Kingdom
Reply | Threaded
Open this post in threaded view
|

Re: Threshold ImageProcessor

Eirinn Mackay
Just a thought- couldn't you create two binary IPs, one with the lower  
threshold and one with the upper threshold, and then create an  
intersection of them?
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
Eirinn Mackay
Research Assistant
Bartlett Group L6
Queensland Brain Institute
Brisbane, Australia
07 334 66381




On 23/06/2009, at 3:19 AM, Michael Doube wrote:

> I ended up doing it this way, because it seems to work.  It's  
> possible that it's neither super-fast, nor sensible!
>
> ImageStack sourceStack = this.imp.getImageStack();
> ImageStack binaryStack = new ImageStack(th.w, th.h);
> for (int s = 0; s < th.d; s++){
>    ImageProcessor sliceIp = sourceStack.getProcessor(s+1);
>    ByteProcessor binaryIp = new ByteProcessor(th.w, th.h);
>    for (int y = 0; y < th.h; y++){
> for (int x = 0; x < th.w; x++){
>    if (sliceIp.get(x, y) >= this.minBoneHU &&
>    sliceIp.get(x, y) <= this.maxBoneHU){
> binaryIp.set(x, y, 255);
>    } else {
> binaryIp.set(x, y, 0);
>    }
> }
>    }
>    binaryStack.addSlice(""+s, binaryIp);
> }
> ImagePlus binaryImp = new ImagePlus("binaryImp", binaryStack);
>
> Mike
>
>
> Johannes Schindelin wrote:
>> Hi Mike,
>> On Fri, 19 Jun 2009, Michael Doube wrote:
>>> Is there a more elegant way to threshold (using upper and lower  
>>> threshold values) an ImageProcessor than iterating over all pixels  
>>> with
>>>
>>> if(pixel > lower && pixel < upper){
>>>  pixel = 255;
>>> } else {
>>>  pixel = 0;
>>> }
>> This is in general the method you want to use.  If you really need  
>> it super-fast for a lot of pixels, you can construct a byte[] that  
>> holds values 255 for everything between index "lower" and index  
>> "upper", and 0 everywhere else.  Then you can just say "pixel[i] =  
>> lut[pixel[i] & 0xff]".
>> This is only sensible if you really need it _super_ fast, as it  
>> deteriorates the readability and flexibility of the code.
>> Ciao,
>> Dscho
>
> --
> Dr Michael Doube  BPhil BVSc PhD MRCVS
> Research Associate
> Department of Bioengineering
> Imperial College London
> South Kensington Campus
> London  SW7 2AZ
> United Kingdom
Reply | Threaded
Open this post in threaded view
|

Re: Threshold ImageProcessor

Michael Schmid
In reply to this post by Michael Doube
Hi Mike,

to get it faster, don't use binaryIp.set but access the pixels  
directly. For the input image you need a bit more code to get the  
pixels in case it can be different types.
This code replacing the x, y loops assumes sliceIp and binaryIp are  
same size:

binPixels = (byte[])binaryIp.getPixels();
if (sliceIp instanceof ByteProcessor) {
     pixels = (byte[]) sliceIp.binaryIp.getPixels();
     for (int i=0; i< pixels.length; i++)
         if ((pixels&0xff) >= this.minBoneHU &&
                 (pixels&0xff) <= this.maxBoneHU)
             binPixels[i] = (byte)255;     //otherwise leave it 0
} else if (sliceIp instanceof ShortProcessor) {
     pixels = (short[]) sliceIp.binaryIp.getPixels();
     for (int i=0; i< pixels.length; i++)
         if ((pixels&0xffff) >= this.minBoneHU &&
                 (pixels&0xffff) <= this.maxBoneHU)
             binPixels[i] = (byte)255;
} else if (sliceIp instanceof FloatProcessor) {
     pixels = (float[]) sliceIp.binaryIp.getPixels();
     for (int i=0; i< pixels.length; i++)
         if (pixels >= this.minBoneHU &&
                 pixels <= this.maxBoneHU)
             binPixels[i] = (byte)255;
}

Of course, if you need it only for 16-bit data, it would be enough to  
have the middle part; then it will throw a ClassCast exception when  
called with 8-bit or float.

Michael
________________________________________________________________

On 22 Jun 2009, at 19:19, Michael Doube wrote:

> I ended up doing it this way, because it seems to work.  It's  
> possible that it's neither super-fast, nor sensible!
>
> ImageStack sourceStack = this.imp.getImageStack();
> ImageStack binaryStack = new ImageStack(th.w, th.h);
> for (int s = 0; s < th.d; s++){
>    ImageProcessor sliceIp = sourceStack.getProcessor(s+1);
>    ByteProcessor binaryIp = new ByteProcessor(th.w, th.h);
>    for (int y = 0; y < th.h; y++){
> for (int x = 0; x < th.w; x++){
>    if (sliceIp.get(x, y) >= this.minBoneHU &&
>    sliceIp.get(x, y) <= this.maxBoneHU){
> binaryIp.set(x, y, 255);
>    } else {
> binaryIp.set(x, y, 0);
>    }
> }
>    }
>    binaryStack.addSlice(""+s, binaryIp);
> }
> ImagePlus binaryImp = new ImagePlus("binaryImp", binaryStack);
>
> Mike
>
>
> Johannes Schindelin wrote:
>> Hi Mike,
>> On Fri, 19 Jun 2009, Michael Doube wrote:
>>> Is there a more elegant way to threshold (using upper and lower  
>>> threshold values) an ImageProcessor than iterating over all  
>>> pixels with
>>>
>>> if(pixel > lower && pixel < upper){
>>>   pixel = 255;
>>> } else {
>>>   pixel = 0;
>>> }
>> This is in general the method you want to use.  If you really need  
>> it super-fast for a lot of pixels, you can construct a byte[] that  
>> holds values 255 for everything between index "lower" and index  
>> "upper", and 0 everywhere else.  Then you can just say "pixel[i] =  
>> lut[pixel[i] & 0xff]".
>> This is only sensible if you really need it _super_ fast, as it  
>> deteriorates the readability and flexibility of the code.
>> Ciao,
>> Dscho
>
> --
> Dr Michael Doube  BPhil BVSc PhD MRCVS
> Research Associate
> Department of Bioengineering
> Imperial College London
> South Kensington Campus
> London  SW7 2AZ
> United Kingdom