Re: Getting the number of pixels which values are below a certain threshold

Posted by Michael Schmid on
URL: http://imagej.273.s1.nabble.com/Getting-the-number-of-pixels-which-values-are-below-a-certain-threshold-tp3688975p3688980.html

Hi Stephan,

ok, I see, it did not work correctly with 16-bit images. Funny  
enough, getRawStatistics does not give a 16-bit histogram but an 8-
bit one, restricted to the min...max range, like for float images.  
(This is different from ImageProcessor.getHistogram).

Here is a new version. Accuracy is limited because the histogram has  
only 256 steps. E.g. one step corresponds to 12 brightness units in  
an image with pixel values from -2048 to 1300. The threshold will  
have an error bar of +/- 0.5 steps, e.g. roughly +/- 6 brightness  
units in this case.
If you need better accuracy, and if it should be fast, you need a  
simple plugin.

//find number of pixels below a threshold
//does not work for images with nonlinear calibration function
threshold=-500;
getStatistics(area, mean, min, max, std, histogram);
result=0;
for (i=0; i<lengthOf(histogram); i++) {
   if (bitDepth()==32 || bitDepth()==16)
     value=min+(max-min)*i/(lengthOf(histogram)-1);
   else
     value=calibrate(i);
   if (value<threshold) result+=histogram[i];
}


Michael
________________________________________________________________

On 2 Mar 2010, at 18:57, Stephan Bender wrote:

> Hi Michael,
>
> wow, thank you!
>
> There's only one problem now:
> I tried it with a DICOM image of which I know that appr. 100000  
> pixels are in the range of -2048 --> -500.
> However, the macro returns 262144 pixels, which is 100% of the  
> pixels (the image is 512x512). Maybe it is related to the bit depth  
> you use to differ cases? Sorry, I am really a newbie with ImageJ...
> All of my images are 16bit...
>
> This is the macro how I run it:
>
> name = getArgument;
> if (name=="") exit ("No argument!");
> setBatchMode(true);
> open(name);
>
> threshold=-500;
> getStatistics(area, mean, min, max, std, histogram);
> result=0;
> for (i=0; i<lengthOf(histogram); i++) {
>   if (bitDepth()==32)
>     value=min+(max-min)*i/(lengthOf(histogram)-1);
>   else
>     value=calibrate(i);
>   if (value<threshold) result+=histogram[i];
> }
> perc=result*100/(getWidth*getHeight);
> print(getTitle+": "+getWidth+"x"+getHeight+" "+result+" "+perc+" %");
>
> As I run it from the shell, I can process the result using pipes.
> However, thank you also for the tip with the file output.
>
> Best regards,
>
> Stephan
>
>
>
> Am 02.03.2010 18:28, schrieb Michael Schmid:
>> Hi Stephan,
>>
>> loops in the macro language are like in C or Java, except that you  
>> need no type declaration.
>>
>> Also there was one problem with my idea: Using 'min, max' is  
>> correct for 32-bit images only (>90% of my images are 32 bit, so I  
>> did not think about this), and there was a 'minus 1' was missing).
>>
>> So, without trying it for all image types...
>>
>> //find number of pixels below a threshold
>> threshold=-500;
>> getStatistics(area, mean, min, max, std, histogram);
>> result=0;
>> for (i=0; i<lengthOf(histogram); i++) {
>>   if (bitDepth()==32)
>>     value=min+(max-min)*i/(lengthOf(histogram)-1);
>>   else
>>     value=calibrate(i);
>>   if (value<threshold) result+=histogram[i];
>> }
>> path=getDirectory("temp")+"ij_result.txt";
>> f = File.open(path);
>> print(f, result);
>>
>>
>> Note that your macro would print to the 'Log' window, you won't be  
>> able to access this from the shell or a Batch file. The macro  
>> above prints to a file in the temp directory (depending on the  
>> operating system, on Unix-like systems: /tmp/). Use
>>   print(getDirectory("temp"));
>> to see where it goes. You can also use getDirectory("home") or any  
>> other directory you like.
>>
>> By the way, instead of calling ImageJ from the shell (or Batch  
>> file under Windows) for each file, it might be faster to create a  
>> file with all the filenames and have ImageJ open the file and  
>> process the complete list in a loop.
>>
>>
>> Michael
>> ________________________________________________________________
>>
>> On 2 Mar 2010, at 13:34, Stephan Bender wrote:
>>
>>> Hi Michael,
>>>
>>> thanks for the advice. However, I still do not get it because of  
>>> the loop you describe.
>>>
>>> This is how I would start with the macro:
>>>
>>>    name = getArgument;
>>>    if (name=="") exit ("No argument!");
>>>    setBatchMode(true);
>>>    open(name);
>>>     // here goes the loop
>>>     print(getTitle+": "+result);
>>>
>>> Can you please help me with the loop?
>>>
>>> Thank you!
>>>
>>> Best regards,
>>>
>>> Stephan
>>>
>>> Am 02.03.2010 11:05, schrieb Michael Schmid:
>>>> Hi Stephan,
>>>>
>>>> this should be easy:
>>>>   getStatistics(area, mean, min, max, std, histogram);
>>>> In a 'for' loop, sum up all values in the histogram array from  
>>>> index 0 to
>>>>   floor(lengthOf(histogram)*(threshold-min)/(max-min))
>>>> where threshold is -500 in your case.
>>>> Write the result to a file:
>>>>  f = File.open(path);
>>>>  print(f, result);
>>>> in your shell script or batch file, you can read the value from  
>>>> the file.
>>>>
>>>>
>>>> Michael
>>>> ________________________________________________________________
>>>>
>>>> On 1 Mar 2010, at 18:18, Stephan Bender wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> I'm quite new to ImageJ, I hope someone can help me with this  
>>>>> task:
>>>>>
>>>>> I need get the number of pixels which values are below a certain
>>>>> threshold. The image format is DICOM (16 bit), and I need the  
>>>>> result
>>>>> on a Unix command line, so I guess I'll have to use a macro  
>>>>> function.
>>>>> A common image has appr. 60% of the pixel values from -2048 to  
>>>>> -500,
>>>>> I need to know the exact number of pixels below -500.
>>>>>
>>>>> Thank you very much for your help!
>>>>>
>>>>> Best regards,
>>>>>
>>>>> Stephan