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 |
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 |
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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |