macro: convert calibrated value to raw pixel value?

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

macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
I decided to learn a bit about the macro language (usually I write everything in Java).

To start with, I thought I would write something simple.  Note that this is an exercise in
techniques.

I've hit a snag. I was trying to convert a calibrated 16-bit image to an 8-bit version, by processing it
pixel-by-pixel.  Motivated by a previous question here, I wanted to set all pixels < 0.0 to 0,
all pixels in  [0.0,10.0) to 50, those in [10.0, 20.0) to 100 ....etc.  Finally, all pixels with calibrated
values > 40.0 should be set to 255.

First, I tried going from a source image to a target image.  But...this seemed painfully slow because of the need(?)
to constantly selectImage() on every getPixel() and putPixel().

So...I switched to doing it in place.  This was speedy enough, but I ran into an issue with calibration.

To categorize the pixels, I wanted calibrated values.  OK - I found getValue(x,y) and that was fine.  But...now
I need to WRITE a calibrated value.  I can't find a function to do that.  putPixel(x,y,value) seems to accept raw pixel values.
I found a method to convert raw pixel values to calibrated values, but not the other way around.

Below is the current state of my floundering.  All hints gratefully accepted.  But please - don't try to tell me how to
perform the high-level task easier.  It's just a warm-up exercise to become familiar with all the tools.

Note that I have commented out some lines at the end - these show what I intend to do eventually.  But, right now I can't get correct calibrated values written to the image.

I would also be interested in a reasonable way to do this without modifying (or copying) the original source image).  It seems to me to be cleaner to write the new pixels to a new target image.  But, that appears to be r e a l l y   s l o w.  (or, I don' know how to do it correctly)

Be kind...
====================================================================================
function sixBins(pixelIn){
  if(pixelIn <=  0.0)
    pixelOut = 0*5;
  else if(pixelIn <= 10.0)
    pixelOut = 10*5;
  else if(pixelIn <= 20.0)
    pixelOut = 20*5;
  else if(pixelIn <= 30.0)
    pixelOut = 30*5;
  else if(pixelIn <= 40.0)
    pixelOut = 40*5;
  else if(pixelIn > 40.0)
    pixelOut =  255.0;
  return pixelOut;
 }

orig = getImageID();
title = getTitle();
w = getWidth();
h = getHeight();

print(title + " is " + w + "x" + h);

for(row=0;row<h;row++){
  for(col=0;col<w;col++) {
  pixelIn = getValue(col,row);  // gives correct calibrated values!
  pixelOut = sixBins(pixelIn);  // appears to work fine
  setPixel(col,row,pixelOut);   // does not work if the image is 16-bit calibrated
  print(pixelIn + " -> " + pixelOut); // really verbose debugging
  }
}
 
run("Histogram");
// selectImage(orig);
// setMinAndMax(0,255);
// run("8-bit");
// selectImage(orig);
// run("Histogram");
====================================================================================
--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Herbie
Good day Kenneth,

apart from the calibration problem I'd never use pixelwise operations
for the processing of whole images. Please have a look at:

"*changeValues(v1, v2, v3)*
Changes pixels in the image or selection that have a value in the range
v1-v2 to v3. For example, changeValues(0,5,5) changes all pixels less
than 5 to 5, and changeValues(0x0000ff,0x0000ff,0xff0000) changes all
blue pixels in an RGB image to red. In ImageJ 1.52d or later, use
changeValues(NaN,NaN,value) to replaces NaN values."

Regards

Herbie

:::::::::::::::::::::::::::::::::::::::::::
Am 11.11.19 um 04:31 schrieb Kenneth Sloan:

> I decided to learn a bit about the macro language (usually I write everything in Java).
>
> To start with, I thought I would write something simple.  Note that this is an exercise in
> techniques.
>
> I've hit a snag. I was trying to convert a calibrated 16-bit image to an 8-bit version, by processing it
> pixel-by-pixel.  Motivated by a previous question here, I wanted to set all pixels < 0.0 to 0,
> all pixels in  [0.0,10.0) to 50, those in [10.0, 20.0) to 100 ....etc.  Finally, all pixels with calibrated
> values > 40.0 should be set to 255.
>
> First, I tried going from a source image to a target image.  But...this seemed painfully slow because of the need(?)
> to constantly selectImage() on every getPixel() and putPixel().
>
> So...I switched to doing it in place.  This was speedy enough, but I ran into an issue with calibration.
>
> To categorize the pixels, I wanted calibrated values.  OK - I found getValue(x,y) and that was fine.  But...now
> I need to WRITE a calibrated value.  I can't find a function to do that.  putPixel(x,y,value) seems to accept raw pixel values.
> I found a method to convert raw pixel values to calibrated values, but not the other way around.
>
> Below is the current state of my floundering.  All hints gratefully accepted.  But please - don't try to tell me how to
> perform the high-level task easier.  It's just a warm-up exercise to become familiar with all the tools.
>
> Note that I have commented out some lines at the end - these show what I intend to do eventually.  But, right now I can't get correct calibrated values written to the image.
>
> I would also be interested in a reasonable way to do this without modifying (or copying) the original source image).  It seems to me to be cleaner to write the new pixels to a new target image.  But, that appears to be r e a l l y   s l o w.  (or, I don' know how to do it correctly)
>
> Be kind...
> ====================================================================================
> function sixBins(pixelIn){
>   if(pixelIn <=  0.0)
>     pixelOut = 0*5;
>   else if(pixelIn <= 10.0)
>       pixelOut = 10*5;
>   else if(pixelIn <= 20.0)
>       pixelOut = 20*5;
>   else if(pixelIn <= 30.0)
>       pixelOut = 30*5;
>   else if(pixelIn <= 40.0)
>     pixelOut = 40*5;
>   else if(pixelIn > 40.0)
>       pixelOut =  255.0;
>   return pixelOut;
>   }
>
> orig = getImageID();
> title = getTitle();
> w = getWidth();
> h = getHeight();
>
> print(title + " is " + w + "x" + h);
>
> for(row=0;row<h;row++){
>   for(col=0;col<w;col++) {
>     pixelIn = getValue(col,row);  // gives correct calibrated values!
>     pixelOut = sixBins(pixelIn);  // appears to work fine
>     setPixel(col,row,pixelOut);   // does not work if the image is 16-bit calibrated
>     print(pixelIn + " -> " + pixelOut); // really verbose debugging
>   }
> }
>  
> run("Histogram");
> // selectImage(orig);
> // setMinAndMax(0,255);
> // run("8-bit");
> // selectImage(orig);
> // run("Histogram");
> ====================================================================================
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Michael Schmid
In reply to this post by Kenneth Sloan-2
Hi Kenneth,

it might be easier to duplicate the image, then use a series of
changeValues macro commands on the copy
   https://imagej.nih.gov/ij/developer/macro/functions.html#changeValues

If you input image is not a 32-bit (floating point) image but a
calibrated 8-bit or 16-bit image, convert it to 32 bits.

If there is an overlap between input and output values such as for the
value of 0 in your case (which on the output stands input values < 0),
you could first assign -1 to negative values, e.g.
   changeValues(-1e100,-1e-100, -1);
and at the end convert all -1 values to 0.

Finally, convert to 8 bits with "Scale when converting" in the
Conversion Options off. Or set the display range to 0-255 before
converting to 8 bits, then the "Scale when converting" does not hurt.

Note that changeValues accepts double-precision arguments, but 32-bit
images have values between roughly -34e38 and +34e38, so a value like
-1e100 is guaranteed to be more negative than any 32-bit number that can
occur. Similarly, -1e-100 is more negative than 0, but more positive
than any 32-bit number (cannot be closer to 0 than +/-1.4e-45).


Michael
________________________________________________________________
On 11.11.19 04:31, Kenneth Sloan wrote:

> I decided to learn a bit about the macro language (usually I write everything in Java).
>
> To start with, I thought I would write something simple.  Note that this is an exercise in
> techniques.
>
> I've hit a snag. I was trying to convert a calibrated 16-bit image to an 8-bit version, by processing it
> pixel-by-pixel.  Motivated by a previous question here, I wanted to set all pixels < 0.0 to 0,
> all pixels in  [0.0,10.0) to 50, those in [10.0, 20.0) to 100 ....etc.  Finally, all pixels with calibrated
> values > 40.0 should be set to 255.
>
> First, I tried going from a source image to a target image.  But...this seemed painfully slow because of the need(?)
> to constantly selectImage() on every getPixel() and putPixel().
>
> So...I switched to doing it in place.  This was speedy enough, but I ran into an issue with calibration.
>
> To categorize the pixels, I wanted calibrated values.  OK - I found getValue(x,y) and that was fine.  But...now
> I need to WRITE a calibrated value.  I can't find a function to do that.  putPixel(x,y,value) seems to accept raw pixel values.
> I found a method to convert raw pixel values to calibrated values, but not the other way around.
>
> Below is the current state of my floundering.  All hints gratefully accepted.  But please - don't try to tell me how to
> perform the high-level task easier.  It's just a warm-up exercise to become familiar with all the tools.
>
> Note that I have commented out some lines at the end - these show what I intend to do eventually.  But, right now I can't get correct calibrated values written to the image.
>
> I would also be interested in a reasonable way to do this without modifying (or copying) the original source image).  It seems to me to be cleaner to write the new pixels to a new target image.  But, that appears to be r e a l l y   s l o w.  (or, I don' know how to do it correctly)
>
> Be kind...
> ====================================================================================
> function sixBins(pixelIn){
>   if(pixelIn <=  0.0)
>     pixelOut = 0*5;
>   else if(pixelIn <= 10.0)
>       pixelOut = 10*5;
>   else if(pixelIn <= 20.0)
>       pixelOut = 20*5;
>   else if(pixelIn <= 30.0)
>       pixelOut = 30*5;
>   else if(pixelIn <= 40.0)
>     pixelOut = 40*5;
>   else if(pixelIn > 40.0)
>       pixelOut =  255.0;
>   return pixelOut;
>   }
>
> orig = getImageID();
> title = getTitle();
> w = getWidth();
> h = getHeight();
>
> print(title + " is " + w + "x" + h);
>
> for(row=0;row<h;row++){
>   for(col=0;col<w;col++) {
>     pixelIn = getValue(col,row);  // gives correct calibrated values!
>     pixelOut = sixBins(pixelIn);  // appears to work fine
>     setPixel(col,row,pixelOut);   // does not work if the image is 16-bit calibrated
>     print(pixelIn + " -> " + pixelOut); // really verbose debugging
>   }
> }
>  
> run("Histogram");
> // selectImage(orig);
> // setMinAndMax(0,255);
> // run("8-bit");
> // selectImage(orig);
> // run("Histogram");
> ====================================================================================
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
Thank you for all the prompt replies.

Most seem aimed at solving the SPECIFIC application problem.  Again - this exercise was intended to
explore *mechanisms* that might be used in a more general setting.

I suppose we have established that the ImageJ macro language does not provide a way to set a specific x,y pixel
to a calibrated value (as opposed  to a raw pixel value.  Is that correct?

In this specific, toy, application, the new value depends only on the old value, and "changeValues" can be made to work.
But, I can envision many applications where the new pixel value depends on location as well as (or instead of) the current value).

For example - can I (in the macro language) draw a line in the image using a calibrated value?  I haven't checked that, so his might be trivial.

It seems odd to provide a conversion from calibrated to raw, but not the other way.  Similarly, it seems odd to include getPixel(), getValue(), and putPixel() but NOT putValue().  Is there some reason this is difficult to implement?
Is there enough information in the calibration (accessed how?) that would allow me to do the conversion myself?

From a design point of view, I would advocate adding putValue(x,y,cValue).  It is sufficient (but not as nice) to instead
add rawFromCalibrated(cValue).  Unless there is some problem I don't understand, I would add both.

======================

My second question hasn't drawn much comment: is there an efficient way to calculate a target image where every pixel is a function of x,y,value of the source image - instead of doing it "in-place" as I did.  I tried to do this by calling selectImage() before every getPixel() and putPixel(), but that seemed horribly slow.  But - I had other issues at the time, so this might not be so bad.  This doesn't matter until I have a putValue() function.

Back to full Java, for me, I suppose.

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
As long as I have pushed this exercise this far - I might as well give the OP an answer to his question.

And...also demonstrate (in Java) what I would like to be able to do in the macro language).  Java is often maligned
as being too verbose - and there is something to this criticism.  For a tiny program like this, *almost* everything
translates line-by-line into the macro language, while at the same time eliminating some of the (tedious?) type information.

I tend to argue that this verbosity is more of a feature than a bug  -  but, I can see the point that perhaps the macro
language is more suitable for such a quick-and-dirty implementation.  So, I would really like to see changes to the macro language that would allow this program to be written there.  

There are two issues:

a)[important] - add putValue(x,y,calibratedValue)

b)[not as critical] - allow easy and efficient access to more than one image at at time, at pixel-by-pixel granularity.

For the original poster, who asked for OCT images in the range -64..+64 to be mapped to an 8-bit banded grayscale image, with
counts for each category of pixel values - here is a Java plugin that does what I think you wanted.

And now a question: what type of OCT produces these values?  My OCT experience is limited to Ophthalmic devices such as
Spectralis and Nidek - which provide OCT images on a completely different scale.  I would love to hear the details of your device, and perhaps see a few images.  If interested - contact me off-list.

=================================================================================
// File: Six_Bands.java
// Author: K R Sloan
// Last Modified: 11 November 2019
// Purpose: convert an image to 8-bit
//          map values:
//              in <=  0.0 -> out =   0.0
//        0.0 < in <= 10.0 -> out =  50.0
//       10.0 < in <= 20.0 -> out = 100.0
//       20.0 < in <= 30.0 -> out = 150.0
//       30.0 < in <= 40.0 -> out = 200.0
//       40.0 < in         -> out = 250.0
import ij.*;
import ij.process.*;
import ij.plugin.*;
public class Six_Bands implements PlugIn
{
    private static int sixBands(double inValue, long[] counts)
    {
        if(inValue <=  0.0) {counts[0]++; return   0;}
        if(inValue <= 10.0) {counts[1]++; return  50;}
        if(inValue <= 20.0) {counts[2]++; return 100;}
        if(inValue <= 30.0) {counts[3]++; return 150;}
        if(inValue <= 40.0) {counts[4]++; return 200;}
  counts[5]++; return 250;
    }
    public void run(String arg)
    {
        ImagePlus ipl = IJ.getImage();
        ImageProcessor ip = ipl.getProcessor();
        int width = ip.getWidth();
        int height = ip.getHeight();
        String title = ipl.getTitle();
        String titleOut = title + "_SixBands";
        ByteProcessor bp = new ByteProcessor(width, height);
        long[] counts = new long[6];
        for(int i=0;i<counts.length;i++) counts[i]=0;
        for(int y=0;y<height;y++)
            for(int x=0;x<width;x++)
                {
                    double inValue = ip.getValue(x,y);
                    int outValue = sixBands(inValue,counts);
                    bp.putPixel(x,y,outValue);
                }
        ImagePlus iplOut = new ImagePlus(titleOut, bp);
        iplOut.show();
        IJ.log("low\thigh\tcount");
        IJ.log("-inf\t 0.0\t" + counts[0]);
        IJ.log(" 0.0\t10.0\t" + counts[1]);
        IJ.log("10.0\t20.0\t" + counts[2]);
        IJ.log("20.0\t30.0\t" + counts[3]);
        IJ.log("30.0\t40.0\t" + counts[4]);
        IJ.log("40.0\t+inf\t" + counts[5]);
    }
}
=================================================================================

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Michael Schmid
In reply to this post by Kenneth Sloan-2
Hi Kenneth,

concerning (1), why is there no macro function for calibrated -> raw
pixel value conversion, I guess that this is because it is needed only
in rare cases. One can always convert the image to 32 bits (which takes
the calibrated values) ant then work on this. Also note that raw ->
calibrated conversion is just a lookup operation in the calibration
table, whereas there can be no table for the calibrated -> raw
conversion, so it requires searching for the best fitting value (which
is slower; nothing that you want to do for each pixel, so a
setPixelValue function would be of questionable value).

I can't speak for Wayne, but I guess that he would be open to add an
inverse function for calibrate(value) in case you can provide examples
where this is needed.


Concerning (2) taking pixels of one image and setting pixels of the
other from that, pixel by pixel: I guess that you have done the obvious,
using BatchMode?

In any case, the macro language is run by an interpreter, not compiled,
so it won't be very fast for any pixel-by-pixel operations.
(I have the impression that it is comparable with python, which is also
an interpreter language).

The following macro needs about 11 seconds on my computer for a
2048x2032 pixel image. About 85% of the time are needed for switching
between the images in BatchMode (1.5 seconds without switching between
the images). This is not so bad, about 1 microsecond to switch between
the foreground images, but it is switching 8 million times...

run("Blobs (25K)");
run("Size...", "width=2048 height=2032 depth=1 constrain average
interpolation=Bilinear");
srcID=getImageID();
run("Duplicate...", "title=target");
tarID=getImageID();
setBatchMode(true);
w=getWidth();
h=getHeight();
for (y=0; y<h; y++) {
   for (x=0; x<w; x++) {
     selectImage(srcID);
     v=getPixel(x, y);
     selectImage(tarID);
     setPixel(w-1-x, y, v);
   }
}

The bottom line: for pixel-by-pixel operations, use Java or Javascript,
unless you have small images and you don't care about processing time.


Michael
________________________________________________________________
On 11.11.19 19:57, Kenneth Sloan wrote:

> Thank you for all the prompt replies.
>
> Most seem aimed at solving the SPECIFIC application problem.  Again - this exercise was intended to
> explore *mechanisms* that might be used in a more general setting.
>
> I suppose we have established that the ImageJ macro language does not provide a way to set a specific x,y pixel
> to a calibrated value (as opposed  to a raw pixel value.  Is that correct?
>
> In this specific, toy, application, the new value depends only on the old value, and "changeValues" can be made to work.
> But, I can envision many applications where the new pixel value depends on location as well as (or instead of) the current value).
>
> For example - can I (in the macro language) draw a line in the image using a calibrated value?  I haven't checked that, so his might be trivial.
>
> It seems odd to provide a conversion from calibrated to raw, but not the other way.  Similarly, it seems odd to include getPixel(), getValue(), and putPixel() but NOT putValue().  Is there some reason this is difficult to implement?
> Is there enough information in the calibration (accessed how?) that would allow me to do the conversion myself?
>
>  From a design point of view, I would advocate adding putValue(x,y,cValue).  It is sufficient (but not as nice) to instead
> add rawFromCalibrated(cValue).  Unless there is some problem I don't understand, I would add both.
>
> ======================
>
> My second question hasn't drawn much comment: is there an efficient way to calculate a target image where every pixel is a function of x,y,value of the source image - instead of doing it "in-place" as I did.  I tried to do this by calling selectImage() before every getPixel() and putPixel(), but that seemed horribly slow.  But - I had other issues at the time, so this might not be so bad.  This doesn't matter until I have a putValue() function.
>
> Back to full Java, for me, I suppose.
>
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
That’s fair.  I will consider converting to 32-bit, or BatchMode.  I hadn’t
thought about BatchMode - and I didn’t really test my multiple-selectImage
version - which looked just like yours.  That’s because I still had other
issues.

The easiest “fix” to the macro language might be an optional imageID
parameter, but perhaps BatchMode might be the answer.   Also - duplicating
the image, concerting to 32-bits, processing, and finally converting to
8-bit looks promising.  I think I can write a generic macro to handle any
pixel-by-pixel task - requiring only 1 or two localized edits to customize
it.  That was my original goal.

From a practical point of view - once you have standard boilerplate for a
full Java Plugin, I’m having a hard time seeing any advantage to the macro
version.

Philosophy ahead...feel free to skip...

I have seen this issue crop up over and over again with all sorts of
scripting and “small languages”.  They appear to be “easy entry”, but user
expectations grow over time until the users push the small language past
the point where it is useful to do so.  Currently, I usually see this in
the transition from spreadsheets to “real” databases.

I was trying to understand the lure of the macro language, and at the same
time test it’s limits.  I think I have decided that - for me - it’s more
parsimonious to simply use full Java, even for very simple tasks.  I
suspect my only exception might be for VERY simple macros used in
BatchProcessing contexts.

My bias has been confirmed - as soon as I have to think about “how can I
achieve this with a macro”, it is best to switch to full Java.  I have a
limited number of brain cells, and I’m not smart enough to learn how to
write complicated macros.  I understand that this argument works the other
way when your only programming language is macros.

Thank you for your reply - it was very helpful.


On Tue, Nov 12, 2019 at 05:19 Michael Schmid <[hidden email]>
wrote:

> Hi Kenneth,
>
> concerning (1), why is there no macro function for calibrated -> raw
> pixel value conversion, I guess that this is because it is needed only
> in rare cases. One can always convert the image to 32 bits (which takes
> the calibrated values) ant then work on this. Also note that raw ->
> calibrated conversion is just a lookup operation in the calibration
> table, whereas there can be no table for the calibrated -> raw
> conversion, so it requires searching for the best fitting value (which
> is slower; nothing that you want to do for each pixel, so a
> setPixelValue function would be of questionable value).
>
> I can't speak for Wayne, but I guess that he would be open to add an
> inverse function for calibrate(value) in case you can provide examples
> where this is needed.
>
>
> Concerning (2) taking pixels of one image and setting pixels of the
> other from that, pixel by pixel: I guess that you have done the obvious,
> using BatchMode?
>
> In any case, the macro language is run by an interpreter, not compiled,
> so it won't be very fast for any pixel-by-pixel operations.
> (I have the impression that it is comparable with python, which is also
> an interpreter language).
>
> The following macro needs about 11 seconds on my computer for a
> 2048x2032 pixel image. About 85% of the time are needed for switching
> between the images in BatchMode (1.5 seconds without switching between
> the images). This is not so bad, about 1 microsecond to switch between
> the foreground images, but it is switching 8 million times...
>
> run("Blobs (25K)");
> run("Size...", "width=2048 height=2032 depth=1 constrain average
> interpolation=Bilinear");
> srcID=getImageID();
> run("Duplicate...", "title=target");
> tarID=getImageID();
> setBatchMode(true);
> w=getWidth();
> h=getHeight();
> for (y=0; y<h; y++) {
>    for (x=0; x<w; x++) {
>      selectImage(srcID);
>      v=getPixel(x, y);
>      selectImage(tarID);
>      setPixel(w-1-x, y, v);
>    }
> }
>
> The bottom line: for pixel-by-pixel operations, use Java or Javascript,
> unless you have small images and you don't care about processing time.
>
>
> Michael
> ________________________________________________________________
> On 11.11.19 19:57, Kenneth Sloan wrote:
> > Thank you for all the prompt replies.
> >
> > Most seem aimed at solving the SPECIFIC application problem.  Again -
> this exercise was intended to
> > explore *mechanisms* that might be used in a more general setting.
> >
> > I suppose we have established that the ImageJ macro language does not
> provide a way to set a specific x,y pixel
> > to a calibrated value (as opposed  to a raw pixel value.  Is that
> correct?
> >
> > In this specific, toy, application, the new value depends only on the
> old value, and "changeValues" can be made to work.
> > But, I can envision many applications where the new pixel value depends
> on location as well as (or instead of) the current value).
> >
> > For example - can I (in the macro language) draw a line in the image
> using a calibrated value?  I haven't checked that, so his might be trivial.
> >
> > It seems odd to provide a conversion from calibrated to raw, but not the
> other way.  Similarly, it seems odd to include getPixel(), getValue(), and
> putPixel() but NOT putValue().  Is there some reason this is difficult to
> implement?
> > Is there enough information in the calibration (accessed how?) that
> would allow me to do the conversion myself?
> >
> >  From a design point of view, I would advocate adding
> putValue(x,y,cValue).  It is sufficient (but not as nice) to instead
> > add rawFromCalibrated(cValue).  Unless there is some problem I don't
> understand, I would add both.
> >
> > ======================
> >
> > My second question hasn't drawn much comment: is there an efficient way
> to calculate a target image where every pixel is a function of x,y,value of
> the source image - instead of doing it "in-place" as I did.  I tried to do
> this by calling selectImage() before every getPixel() and putPixel(), but
> that seemed horribly slow.  But - I had other issues at the time, so this
> might not be so bad.  This doesn't matter until I have a putValue()
> function.
> >
> > Back to full Java, for me, I suppose.
> >
> > --
> > Kenneth Sloan
> > [hidden email]
> > Vision is the art of seeing what is invisible to others.
> >
> > --
> > ImageJ mailing list: http://imagej.nih.gov/ij/list.html
> >
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>
--
-Kenneth Sloan

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
In reply to this post by Michael Schmid
Achieving closure.  Just in case the OP prefers a macro...  Here is my final macro version.  It is acceptably speedy, with the use of BatchMode (thanks to Michael for suggesting this).  This version appears to accept any source image type and produces an 8-bit banded image plus counts of pixels in a set of bins based on intensity, as specified by the OP.

Aside from my dinosaur (as in pre K&R C) bracketing style - I welcome comments and suggestions for improvement.

========================================================================
// File: Six_Bins.ijm
// Author: K R Sloan
// Last Modified: 12 November 2019
// Purpose: convert an image to 8-bit
//          map values:
//              in <=  0.0 -> out =   0
//        0.0 < in <= 10.0 -> out =  50
//       10.0 < in <= 20.0 -> out = 100
//       20.0 < in <= 30.0 -> out = 150
//       30.0 < in <= 40.0 -> out = 200
//       40.0 < in         -> out = 250
function sixBins(pixelIn,counts)
 {
  if(pixelIn <=  0.0) {counts[0]++; return   0;}
  if(pixelIn <= 10.0) {counts[1]++; return  50;}
  if(pixelIn <= 20.0) {counts[2]++; return 100;}
  if(pixelIn <= 30.0) {counts[3]++; return 150;}
  if(pixelIn <= 40.0) {counts[4]++; return 200;}
  counts[5]++; return 250;
 }
source = getImageID();
title = getTitle();
w = getWidth();
h = getHeight();
setBatchMode(true);
newImage(title+"_SixBins","8-bit",w,h,1);
target = getImageID();
counts = newArray(0,0,0,0,0,0);
for(y=0;y<h;y++)
 {
  for(x=0;x<w;x++)
   {
    selectImage(source); pixelIn = getValue(x,y);
    pixelOut = sixBins(pixelIn,counts);
    selectImage(target); setPixel(x,y,pixelOut);
   }
 }
setBatchMode("exit and display");
print("low\thigh\tcount");
print("-inf\t 0.0\t" + counts[0]);
print(" 0.0\t10.0\t" + counts[1]);
print("10.0\t20.0\t" + counts[2]);
print("20.0\t30.0\t" + counts[3]);
print("30.0\t40.0\t" + counts[4]);
print("40.0\t+inf\t" + counts[5]);
========================================================================
--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

George Patterson
In reply to this post by Michael Schmid
Hi Kenneth,
You could use a 1D array to store the altered pixel values based on the
source image and put them in the target image.
I don't know if it would be considered efficient since the array will use a
lot of memory depending on the size of the image.  But it is a faster
alternative than switching between images.
Editing Michael's example macro below.
George


run("Blobs (25K)");
run("Size...", "width=2048 height=2032 depth=1 constrain average
interpolation=Bilinear");
srcID=getImageID();
run("Duplicate...", "title=target");
tarID=getImageID();
//setBatchMode(true);
start=getTime();
w=getWidth();
h=getHeight();
array1=newArray(w*h);
selectImage(srcID);
for (y=0; y<h; y++) {
   for (x=0; x<w; x++) {
     array1[y*w+x]=getPixel(x, y);
   }
}

selectImage(tarID);
for (y=0; y<h; y++) {
   for (x=0; x<w; x++) {
     setPixel(w-1-x, y, array1[y*w+x]);
   }
}
print("time elapsed= "+getTime()-start);



On Tue, Nov 12, 2019 at 6:19 AM Michael Schmid <[hidden email]>
wrote:

> Hi Kenneth,
>
> concerning (1), why is there no macro function for calibrated -> raw
> pixel value conversion, I guess that this is because it is needed only
> in rare cases. One can always convert the image to 32 bits (which takes
> the calibrated values) ant then work on this. Also note that raw ->
> calibrated conversion is just a lookup operation in the calibration
> table, whereas there can be no table for the calibrated -> raw
> conversion, so it requires searching for the best fitting value (which
> is slower; nothing that you want to do for each pixel, so a
> setPixelValue function would be of questionable value).
>
> I can't speak for Wayne, but I guess that he would be open to add an
> inverse function for calibrate(value) in case you can provide examples
> where this is needed.
>
>
> Concerning (2) taking pixels of one image and setting pixels of the
> other from that, pixel by pixel: I guess that you have done the obvious,
> using BatchMode?
>
> In any case, the macro language is run by an interpreter, not compiled,
> so it won't be very fast for any pixel-by-pixel operations.
> (I have the impression that it is comparable with python, which is also
> an interpreter language).
>
> The following macro needs about 11 seconds on my computer for a
> 2048x2032 pixel image. About 85% of the time are needed for switching
> between the images in BatchMode (1.5 seconds without switching between
> the images). This is not so bad, about 1 microsecond to switch between
> the foreground images, but it is switching 8 million times...
>
> run("Blobs (25K)");
> run("Size...", "width=2048 height=2032 depth=1 constrain average
> interpolation=Bilinear");
> srcID=getImageID();
> run("Duplicate...", "title=target");
> tarID=getImageID();
> setBatchMode(true);
> w=getWidth();
> h=getHeight();
> for (y=0; y<h; y++) {
>    for (x=0; x<w; x++) {
>      selectImage(srcID);
>      v=getPixel(x, y);
>      selectImage(tarID);
>      setPixel(w-1-x, y, v);
>    }
> }
>
> The bottom line: for pixel-by-pixel operations, use Java or Javascript,
> unless you have small images and you don't care about processing time.
>
>
> Michael
> ________________________________________________________________
> On 11.11.19 19:57, Kenneth Sloan wrote:
> > Thank you for all the prompt replies.
> >
> > Most seem aimed at solving the SPECIFIC application problem.  Again -
> this exercise was intended to
> > explore *mechanisms* that might be used in a more general setting.
> >
> > I suppose we have established that the ImageJ macro language does not
> provide a way to set a specific x,y pixel
> > to a calibrated value (as opposed  to a raw pixel value.  Is that
> correct?
> >
> > In this specific, toy, application, the new value depends only on the
> old value, and "changeValues" can be made to work.
> > But, I can envision many applications where the new pixel value depends
> on location as well as (or instead of) the current value).
> >
> > For example - can I (in the macro language) draw a line in the image
> using a calibrated value?  I haven't checked that, so his might be trivial.
> >
> > It seems odd to provide a conversion from calibrated to raw, but not the
> other way.  Similarly, it seems odd to include getPixel(), getValue(), and
> putPixel() but NOT putValue().  Is there some reason this is difficult to
> implement?
> > Is there enough information in the calibration (accessed how?) that
> would allow me to do the conversion myself?
> >
> >  From a design point of view, I would advocate adding
> putValue(x,y,cValue).  It is sufficient (but not as nice) to instead
> > add rawFromCalibrated(cValue).  Unless there is some problem I don't
> understand, I would add both.
> >
> > ======================
> >
> > My second question hasn't drawn much comment: is there an efficient way
> to calculate a target image where every pixel is a function of x,y,value of
> the source image - instead of doing it "in-place" as I did.  I tried to do
> this by calling selectImage() before every getPixel() and putPixel(), but
> that seemed horribly slow.  But - I had other issues at the time, so this
> might not be so bad.  This doesn't matter until I have a putValue()
> function.
> >
> > Back to full Java, for me, I suppose.
> >
> > --
> > Kenneth Sloan
> > [hidden email]
> > Vision is the art of seeing what is invisible to others.
> >
> > --
> > ImageJ mailing list: http://imagej.nih.gov/ij/list.html
> >
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Herbie
In reply to this post by Kenneth Sloan-2
Good day Kenneth,

something like this code should do as well:

///////////////////////////////////////////
requires("1.52r");
if (bitDepth() !=8 ) exit("8bit image required.");
run("Duplicate...", "title=Copy");
run("16-bit");
changeValues( 41, 255, 250 );
changeValues( 31,   40, 200 );
changeValues( 21,   30, 150 );
changeValues( 11,   20, 100 );
changeValues(   1,   10,   50 );
getHistogram(0, counts, 6, 0, 250 );
run("8-bit");
intrv=newArray("v≤0","1≤v≤10","11≤v≤20","21≤v≤30","31≤v≤40","41≤v≤255" );
Table.setColumn("Interval", intrv);
Table.setColumn("Pixel Count", counts);
exit();
///////////////////////////////////////////

Please watch for possible line breaks introduced by the mailer.

Regards

Herbie

:::::::::::::::::::::::::::::::::::::::::::
Am 12.11.19 um 18:13 schrieb Kenneth Sloan:

> Achieving closure.  Just in case the OP prefers a macro...  Here is my final macro version.  It is acceptably speedy, with the use of BatchMode (thanks to Michael for suggesting this).  This version appears to accept any source image type and produces an 8-bit banded image plus counts of pixels in a set of bins based on intensity, as specified by the OP.
>
> Aside from my dinosaur (as in pre K&R C) bracketing style - I welcome comments and suggestions for improvement.
>
> ========================================================================
> // File: Six_Bins.ijm
> // Author: K R Sloan
> // Last Modified: 12 November 2019
> // Purpose: convert an image to 8-bit
> //          map values:
> //              in <=  0.0 -> out =   0
> //        0.0 < in <= 10.0 -> out =  50
> //       10.0 < in <= 20.0 -> out = 100
> //       20.0 < in <= 30.0 -> out = 150
> //       30.0 < in <= 40.0 -> out = 200
> //       40.0 < in         -> out = 250
> function sixBins(pixelIn,counts)
>   {
>    if(pixelIn <=  0.0) {counts[0]++; return   0;}
>    if(pixelIn <= 10.0) {counts[1]++; return  50;}
>    if(pixelIn <= 20.0) {counts[2]++; return 100;}
>    if(pixelIn <= 30.0) {counts[3]++; return 150;}
>    if(pixelIn <= 40.0) {counts[4]++; return 200;}
>    counts[5]++; return 250;
>   }
> source = getImageID();
> title = getTitle();
> w = getWidth();
> h = getHeight();
> setBatchMode(true);
> newImage(title+"_SixBins","8-bit",w,h,1);
> target = getImageID();
> counts = newArray(0,0,0,0,0,0);
> for(y=0;y<h;y++)
>   {
>    for(x=0;x<w;x++)
>     {
>      selectImage(source); pixelIn = getValue(x,y);
>      pixelOut = sixBins(pixelIn,counts);
>      selectImage(target); setPixel(x,y,pixelOut);
>     }
>   }
> setBatchMode("exit and display");
> print("low\thigh\tcount");
> print("-inf\t 0.0\t" + counts[0]);
> print(" 0.0\t10.0\t" + counts[1]);
> print("10.0\t20.0\t" + counts[2]);
> print("20.0\t30.0\t" + counts[3]);
> print("30.0\t40.0\t" + counts[4]);
> print("40.0\t+inf\t" + counts[5]);
> ========================================================================
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
In reply to this post by George Patterson
George-

Using a 1D array is exactly the kind of programming gymnastics that I try to avoid wherever possible.  I prize clarity above all else.  I *might* consider using a 2D array, if it were supported in ImageJ  - but it's not.  Note that I'm not asking for 2D arrays!  My preference is for a mechanism that allows for manipulation of multiple images without the overhead of switching the "current image".  BatchMode is a reasonable compromise, and I'm happy with it.

Duplicating the image and converting it to 32-bit...then writing new values...then converting to 8-bit is another memory-intensive method, which I would consider if I really needed speed and could afford the memory.  But, once I was reminded about BatchMode (remember, I'm a macro newbie) I found that the resulting macro was fast enough for my purposes.

What I have learned is that the macro language works well for workflows that involve a single image at a time.  Anything which needs to access multiple images on a fine-grained level (such as pixel-by-pixel) is a signal to me to switch to full Java.  This is trivial to write in full Java - especially if you create and save a template Plugin to use as boilerplate.

And, that was my goal for the current exercise.  It was triggered by yet-another query of the form "how do I transform and measure an image in a way not currently automated" - with enough detail so that (in my eyes) it differed from an actual Plugin only in he syntax.

When I taught image processing  to CS students, I took the approach of having them build toy programs which did about this amount of work - simply to get them to write the boilerplate.  THEN we moved on to more complicated processing.  Our focus was usually more on the nuts and bolts of "how to do it" rather than an application-centric approach which tends to look at what has already been implemented.  It's a question of what level of detail you want to emphasize, and whether you are behaving as a user, or a pusher.

But,  I didn't have a prototype piece of boilerplate handy.  Writing the boilerplate in Java was trivial - but  producing the macro version was challenging (for me).  So - it was worth doing.

If it's a macro - I don't care TOO MUCH about speed.  Anything that runs in less than 30 seconds is fine.  When I need speed, my preferred method is to switch to full Java.

I have many small, special purpose Java Plugins that consist mostly of calls to IJ.run().  Clearly, these could be written as macros - EXCEPT that they usually morph over time to include bells and whistles that are awkward (for me) to implement in a macro.

As I said earlier, this has been my experience with "little languages".  They are perfect at what they do, but lead developers down a slippery slope as requirements become more complex.  After a while, you can become so invested in learning the workarounds that it seems easier to continue to struggle rather than biting the bullet and switching to a more expressive language.

And now...switching subjects...what is the current state of Python compatibility with ImageJ?  Every time I am tempted to write Python code to work in ImageJ I seem to spot another complaint that the interface does not quite work properly.  If it matters, I'm interested in using Python 3 (not 2).  Is there now a robust interface?  Does it support Python 3, or just 2?  Anyone care to render either my Java or macro versions to Python 3 to  serve as a tutorial?  For that matter - is there a canonical reference tutorial I can use to get started?

But, after all...this is ImageJ, and not ImageP.

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Curtis Rueden-2
Hi Kenneth,

> what is the current state of Python compatibility with ImageJ?  Every
> time I am tempted to write Python code to work in ImageJ I seem to
> spot another complaint that the interface does not quite work
> properly.  If it matters, I'm interested in using Python 3 (not 2).
> Is there now a robust interface?  Does it support Python 3, or just 2?

The central page discussing that is here:
  https://imagej.net/Python

If you want to write scripts in Python that run directly on the JVM, you
can use Jython:
  https://imagej.net/Jython_Scripting
  https://imagej.net/Jython_Scripting_Examples#Jython_tutorials_for_ImageJ

If you want to use ImageJ from standard Python (CPython), you can use
pyimagej:
  https://github.com/imagej/pyimagej/

This approach links to Java in-process, wrapping Java objects to Python
seamlessly, giving you access to the whole ImageJ API from Python.

Finally, if you want to invoke ImageJ functionality interprocess from other
languages and/or machines, you can use the ImageJ Server:
  https://github.com/imagej/imagej-server/

The pyimagej library also includes a client for working with imagej-server.
Although the major focus lately has been on the in-process functionality of
pyimagej.

> is there a canonical reference tutorial I can use to get started?

There is a pyimagej tutorial here:

https://nbviewer.jupyter.org/github/imagej/tutorials/blob/master/notebooks/1-Using-ImageJ/6-ImageJ-with-Python-Kernel.ipynb

Regards,
Curtis

--
Curtis Rueden
Software architect, LOCI/Eliceiri lab - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden
Have you tried the Image.sc Forum? https://forum.image.sc/



On Tue, Nov 12, 2019 at 12:32 PM Kenneth Sloan <[hidden email]>
wrote:

> George-
>
> Using a 1D array is exactly the kind of programming gymnastics that I try
> to avoid wherever possible.  I prize clarity above all else.  I *might*
> consider using a 2D array, if it were supported in ImageJ  - but it's not.
> Note that I'm not asking for 2D arrays!  My preference is for a mechanism
> that allows for manipulation of multiple images without the overhead of
> switching the "current image".  BatchMode is a reasonable compromise, and
> I'm happy with it.
>
> Duplicating the image and converting it to 32-bit...then writing new
> values...then converting to 8-bit is another memory-intensive method, which
> I would consider if I really needed speed and could afford the memory.
> But, once I was reminded about BatchMode (remember, I'm a macro newbie) I
> found that the resulting macro was fast enough for my purposes.
>
> What I have learned is that the macro language works well for workflows
> that involve a single image at a time.  Anything which needs to access
> multiple images on a fine-grained level (such as pixel-by-pixel) is a
> signal to me to switch to full Java.  This is trivial to write in full Java
> - especially if you create and save a template Plugin to use as
> boilerplate.
>
> And, that was my goal for the current exercise.  It was triggered by
> yet-another query of the form "how do I transform and measure an image in a
> way not currently automated" - with enough detail so that (in my eyes) it
> differed from an actual Plugin only in he syntax.
>
> When I taught image processing  to CS students, I took the approach of
> having them build toy programs which did about this amount of work - simply
> to get them to write the boilerplate.  THEN we moved on to more complicated
> processing.  Our focus was usually more on the nuts and bolts of "how to do
> it" rather than an application-centric approach which tends to look at what
> has already been implemented.  It's a question of what level of detail you
> want to emphasize, and whether you are behaving as a user, or a pusher.
>
> But,  I didn't have a prototype piece of boilerplate handy.  Writing the
> boilerplate in Java was trivial - but  producing the macro version was
> challenging (for me).  So - it was worth doing.
>
> If it's a macro - I don't care TOO MUCH about speed.  Anything that runs
> in less than 30 seconds is fine.  When I need speed, my preferred method is
> to switch to full Java.
>
> I have many small, special purpose Java Plugins that consist mostly of
> calls to IJ.run().  Clearly, these could be written as macros - EXCEPT that
> they usually morph over time to include bells and whistles that are awkward
> (for me) to implement in a macro.
>
> As I said earlier, this has been my experience with "little languages".
> They are perfect at what they do, but lead developers down a slippery slope
> as requirements become more complex.  After a while, you can become so
> invested in learning the workarounds that it seems easier to continue to
> struggle rather than biting the bullet and switching to a more expressive
> language.
>
> And now...switching subjects...what is the current state of Python
> compatibility with ImageJ?  Every time I am tempted to write Python code to
> work in ImageJ I seem to spot another complaint that the interface does not
> quite work properly.  If it matters, I'm interested in using Python 3 (not
> 2).  Is there now a robust interface?  Does it support Python 3, or just
> 2?  Anyone care to render either my Java or macro versions to Python 3 to
> serve as a tutorial?  For that matter - is there a canonical reference
> tutorial I can use to get started?
>
> But, after all...this is ImageJ, and not ImageP.
>
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
Curtis-

Thank you for your reply.

I suspect I'm primarily interested in embedding ImageJ into a Python3 program - perhaps from inside a Jupyter notebook.

I followed your link and got as far as:

Disadvantage: Wrapping ImageJ in Python has some limitations and bugs, particularly surrounding use of ImageJ1 <https://imagej.net/ImageJ1> features, compared to using ImageJ from Java-based kernels such as BeakerX <https://beakerx.com/>

Is there a current, comprehensive discussion on the "limitations and bugs"?  The statement above is likely to dissuade me from trying this - but I'm willing to look more closely if there is clear documentation of the "limitations and bugs".

I will check out the pyimagej tutorial.

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.






--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

CARL Philippe (LBP)
In reply to this post by Kenneth Sloan-2
Dear Kenneth,

On your argument:
> From a practical point of view - once you have standard boilerplate for a
> full Java Plugin, I’m having a hard time seeing any advantage to the macro
> version.
This is more then obvious!
Macro programming is only for quick and dirty things and once you have already spend the time and work for writing a Java code it is nonsense to try to translate it back into the Macro language.

Quite similarly to you, I initially came as well from the Java world and tried to learn macro programming thinking (at least expecting) that there will be some advantages on additionally knowing this language.
And in order to learn macro programming, I had just read an excellent macro course (within authors are as well Jérôme Mutterer who's postings you may as well see from time to time on this list).
Very unfortunately this course (followed each time with examples build up in the form of exercices) is written in French not in English!

Nevertheless after completion of this course, I moved over to macro for 80-90% of my programming needs given that the development times between Java and macro are more or less 80% lower.
And over about 5 years (knowing that I write new and/or modify ImageJ codes every weeks) I only translated 4 of my codes from Macro into Java given that they started to become either too big, too slow or that I needed too fancy features.

But very honestly, I would really recommend you to try to invest some of your neurons on trying to learn macro programming further more.
Very unfortunately, the prototypical example you took was really not fitted for macros but rather for Java programming on the first place.

At last but not at least, it is way easier (with only a couple neurons required) to move from Java to Macro programming, rather than to make the inverse (taking as example a colleague in this situation).

Have a nice day.

My best regards,

Philippe


Philippe CARL
Laboratoire de Bioimagerie et Pathologies
UMR 7021 CNRS - Université de Strasbourg
Faculté de Pharmacie
74 route du Rhin
67401 ILLKIRCH
Tel : +33(0)3 68 85 41 84

----- Mail original -----
De: "Kenneth R Sloan" <[hidden email]>
À: "imagej" <[hidden email]>
Envoyé: Mardi 12 Novembre 2019 16:38:09
Objet: Re: macro: convert calibrated value to raw pixel value?

That’s fair.  I will consider converting to 32-bit, or BatchMode.  I hadn’t
thought about BatchMode - and I didn’t really test my multiple-selectImage
version - which looked just like yours.  That’s because I still had other
issues.

The easiest “fix” to the macro language might be an optional imageID
parameter, but perhaps BatchMode might be the answer.   Also - duplicating
the image, concerting to 32-bits, processing, and finally converting to
8-bit looks promising.  I think I can write a generic macro to handle any
pixel-by-pixel task - requiring only 1 or two localized edits to customize
it.  That was my original goal.

From a practical point of view - once you have standard boilerplate for a
full Java Plugin, I’m having a hard time seeing any advantage to the macro
version.

Philosophy ahead...feel free to skip...

I have seen this issue crop up over and over again with all sorts of
scripting and “small languages”.  They appear to be “easy entry”, but user
expectations grow over time until the users push the small language past
the point where it is useful to do so.  Currently, I usually see this in
the transition from spreadsheets to “real” databases.

I was trying to understand the lure of the macro language, and at the same
time test it’s limits.  I think I have decided that - for me - it’s more
parsimonious to simply use full Java, even for very simple tasks.  I
suspect my only exception might be for VERY simple macros used in
BatchProcessing contexts.

My bias has been confirmed - as soon as I have to think about “how can I
achieve this with a macro”, it is best to switch to full Java.  I have a
limited number of brain cells, and I’m not smart enough to learn how to
write complicated macros.  I understand that this argument works the other
way when your only programming language is macros.

Thank you for your reply - it was very helpful.


On Tue, Nov 12, 2019 at 05:19 Michael Schmid <[hidden email]>
wrote:

> Hi Kenneth,
>
> concerning (1), why is there no macro function for calibrated -> raw
> pixel value conversion, I guess that this is because it is needed only
> in rare cases. One can always convert the image to 32 bits (which takes
> the calibrated values) ant then work on this. Also note that raw ->
> calibrated conversion is just a lookup operation in the calibration
> table, whereas there can be no table for the calibrated -> raw
> conversion, so it requires searching for the best fitting value (which
> is slower; nothing that you want to do for each pixel, so a
> setPixelValue function would be of questionable value).
>
> I can't speak for Wayne, but I guess that he would be open to add an
> inverse function for calibrate(value) in case you can provide examples
> where this is needed.
>
>
> Concerning (2) taking pixels of one image and setting pixels of the
> other from that, pixel by pixel: I guess that you have done the obvious,
> using BatchMode?
>
> In any case, the macro language is run by an interpreter, not compiled,
> so it won't be very fast for any pixel-by-pixel operations.
> (I have the impression that it is comparable with python, which is also
> an interpreter language).
>
> The following macro needs about 11 seconds on my computer for a
> 2048x2032 pixel image. About 85% of the time are needed for switching
> between the images in BatchMode (1.5 seconds without switching between
> the images). This is not so bad, about 1 microsecond to switch between
> the foreground images, but it is switching 8 million times...
>
> run("Blobs (25K)");
> run("Size...", "width=2048 height=2032 depth=1 constrain average
> interpolation=Bilinear");
> srcID=getImageID();
> run("Duplicate...", "title=target");
> tarID=getImageID();
> setBatchMode(true);
> w=getWidth();
> h=getHeight();
> for (y=0; y<h; y++) {
>    for (x=0; x<w; x++) {
>      selectImage(srcID);
>      v=getPixel(x, y);
>      selectImage(tarID);
>      setPixel(w-1-x, y, v);
>    }
> }
>
> The bottom line: for pixel-by-pixel operations, use Java or Javascript,
> unless you have small images and you don't care about processing time.
>
>
> Michael
> ________________________________________________________________
> On 11.11.19 19:57, Kenneth Sloan wrote:
> > Thank you for all the prompt replies.
> >
> > Most seem aimed at solving the SPECIFIC application problem.  Again -
> this exercise was intended to
> > explore *mechanisms* that might be used in a more general setting.
> >
> > I suppose we have established that the ImageJ macro language does not
> provide a way to set a specific x,y pixel
> > to a calibrated value (as opposed  to a raw pixel value.  Is that
> correct?
> >
> > In this specific, toy, application, the new value depends only on the
> old value, and "changeValues" can be made to work.
> > But, I can envision many applications where the new pixel value depends
> on location as well as (or instead of) the current value).
> >
> > For example - can I (in the macro language) draw a line in the image
> using a calibrated value?  I haven't checked that, so his might be trivial.
> >
> > It seems odd to provide a conversion from calibrated to raw, but not the
> other way.  Similarly, it seems odd to include getPixel(), getValue(), and
> putPixel() but NOT putValue().  Is there some reason this is difficult to
> implement?
> > Is there enough information in the calibration (accessed how?) that
> would allow me to do the conversion myself?
> >
> >  From a design point of view, I would advocate adding
> putValue(x,y,cValue).  It is sufficient (but not as nice) to instead
> > add rawFromCalibrated(cValue).  Unless there is some problem I don't
> understand, I would add both.
> >
> > ======================
> >
> > My second question hasn't drawn much comment: is there an efficient way
> to calculate a target image where every pixel is a function of x,y,value of
> the source image - instead of doing it "in-place" as I did.  I tried to do
> this by calling selectImage() before every getPixel() and putPixel(), but
> that seemed horribly slow.  But - I had other issues at the time, so this
> might not be so bad.  This doesn't matter until I have a putValue()
> function.
> >
> > Back to full Java, for me, I suppose.
> >
> > --
> > Kenneth Sloan
> > [hidden email]
> > Vision is the art of seeing what is invisible to others.
> >
> > --
> > ImageJ mailing list: http://imagej.nih.gov/ij/list.html
> >
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>
--
-Kenneth Sloan

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
> On your argument:
>> From a practical point of view - once you have standard boilerplate for a
>> full Java Plugin, I’m having a hard time seeing any advantage to the macro
>> version.
> This is more then obvious!

I have been known to be slow.  Many things which are obvious to others puzzle me.

> Macro programming is only for quick and dirty things and once you have already spend the time and work for writing a Java code it is nonsense to try to translate it back into the Macro language.

My problem is that as soon as I start reading tutorials on the macro language I run into 5 page long programs which seem to be anything other than "quick and dirty".
 
> ...
> Nevertheless after completion of this course, I moved over to macro for 80-90% of my programming needs given that the development times between Java and macro are more or less 80% lower.

I question this.  Once you have boilerplate in hand, I find that it takes no longer to deliver a tested, working Java Plugin than it does to deliver a tested, working macro.

Now...if you are in "exploration mode" and want to try different approaches interactively, then a macro does appear to be
slightly faster to first execution.  BUT (and this is my point) - when it comes time to put a program into production use, or hand it over to someone else to use, it should not take long to produce a full Java version.  So...I tend to reject the "it's faster to write" argument.

> At last but not at least, it is way easier (with only a couple neurons required) to move from Java to Macro programming, rather than to make the inverse (taking as example a colleague in this situation).

That is more than obvious!  Only...as I have learned...it's good to be aware that the macro language is *by necessity* limited.

Which is why it is worth encouraging folks who start with macros to NOT push macros as far as they can (becoming ever more complicated and clever) and switch to full Java earlier rather than later.  This is my "beware of little languages" argument.  Little languages are VERY GOOD for small, (quick and dirty), throwaway solutions.  They tend to fail when the process becomes complicated, or involves multiple developers/users, etc.  The real trap is when a programmer becomes so invested in their macro skills that it is now expensive and painful to switch.

A competent developer should have BOTH tools in their toolbox.  Which is why I am taking your advice to learn more about the macro language.

I didn't pick the current application.  It was a request from the OP.  My first thought was "that's 10 line Java Plugin - surely it's even simpler as a macro".  When no one posted such a solution, I saw an opportunity for me to learn enough about macros to do it myself. It took longer than it should have, and required at least 2 helpful hints (mostly from Michael) - but in the end I got there.

In the end, I think this problem *is* appropriate for a macro solution.  With my existing skill set, I can (now) implement it either way, in about the same amount of time.

Along the way, I think I identified a few ways that the macro language might be improved.  But, I'm willing to tolerate the minor disadvantages of the macro solution.  I also now have the right sort of "boilerplate" for use in similar problems.
So...I'm happy.  And, since (for me) using Java is just as easy as using macros, I'm not particularly lobbying for the macro language to be "improved".  [I might even argue that making the macro language "better" might make the overall situation worse.]

Finally, I recognize that many ImageJ users may not happen to have a usable Java compiler handy.  They are *always* faced with  a rather large investment in time to write their *first* Java plugin.  My message is that this is time well spent (but NOT when you are on deadline to get the current project working, yesterday).
 
--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Curtis Rueden-2
In reply to this post by Kenneth Sloan-2
Hi Kenneth,

> Is there a current, comprehensive discussion on the "limitations and
> bugs"?  The statement above is likely to dissuade me from trying this
> - but I'm willing to look more closely if there is clear documentation
> of the "limitations and bugs".

The issue tracker covers it:
  https://github.com/imagej/pyimagej/issues

Also, since I forgot to mention it in my previous email:
* Jython is Python 2.7 only.
* pyimagej is Python 3 only.

You said you wanted Python 3, so that's another point for pyimagej.

In general: if what you want is to mix-and-match PyData stack
(NumPy/SciPy/scikit/pandas/et al.) with ImageJ, I know of no other feasible
way than pyimagej. In that case your best bet would be to suffer the
"limitations and bugs" and participate in the development to push the
project forward. On the other hand, if you are just looking for the best
script language to use _on the JVM_ then it's really in the eye of the
beholder: see https://imagej.net/Scripting#Supported_languages for a list
of possibilities.

Regards,
Curtis

--
Curtis Rueden
Software architect, LOCI/Eliceiri lab - https://loci.wisc.edu/software
ImageJ2 lead, Fiji maintainer - https://imagej.net/User:Rueden
Have you tried the Image.sc Forum? https://forum.image.sc/



On Tue, Nov 12, 2019 at 3:01 PM Kenneth Sloan <[hidden email]>
wrote:

> Curtis-
>
> Thank you for your reply.
>
> I suspect I'm primarily interested in embedding ImageJ into a Python3
> program - perhaps from inside a Jupyter notebook.
>
> I followed your link and got as far as:
>
> Disadvantage: Wrapping ImageJ in Python has some limitations and bugs,
> particularly surrounding use of ImageJ1 <https://imagej.net/ImageJ1>
> features, compared to using ImageJ from Java-based kernels such as BeakerX <
> https://beakerx.com/>
>
> Is there a current, comprehensive discussion on the "limitations and
> bugs"?  The statement above is likely to dissuade me from trying this - but
> I'm willing to look more closely if there is clear documentation of the
> "limitations and bugs".
>
> I will check out the pyimagej tutorial.
>
> --
> Kenneth Sloan
> [hidden email]
> Vision is the art of seeing what is invisible to others.
>
>
>
>
>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Kenneth Sloan-2
Thank you for your guidance.

I have no pressing need - just my usual "self-improvement" to add tools to my toolbox.

For serious use, I'm perfectly happy with Java as both a way to control ImageJ and as a generic programming language in which to do incidental image processing.

I am exploring the use of Python3 and Jupyter notebooks for other projects, and thought it would be worthwhile to find out how to include image processing in that environment.

Your links were very helpful - but...since I am not using Anaconda, the installation process for adding in ImageJ looked as if it might take a bit more time and attention than I have at the moment.  When I have a chance, I'll check back and try again.  Your notes  indicate that you are working on streamlining the process - that would be welcome.

It may also be that I will be convinced to transition to Anaconda - but right now that would interfere with projects that are on deadline.  On my first encounter with Anaconda, I was put off by its apparent desire to alter my environment in a way that was incompatible with other work.  I didn't have the time to sort this out, so I backed out of Anaconda and am proceeding happily with Python3 and pip3.

Similarly, I need to be cautious about updating Java on my development environment - to make sure I don't inadvertently cause problems for my users.  So...the apparent need to switch  to OpenJDK and Java 8 were slightly off-putting.  Nothing I can't iron out given enough free time - but not something I can do this month.

Not to mention fighting the "update to Catalina" woes.

When I return to this, I'm hoping that there is a path that involves only "brew" and "pip3" to get basic functionality working.
The fewer dependencies there are, the more likely it is that I'll be able to do it.

But, again - thank you very much for your replies.  They are most helpful.

--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

CARL Philippe (LBP)
In reply to this post by Kenneth Sloan-2
Dear Keneth,

Let me just answer to your following answer:

>> Nevertheless after completion of this course, I moved over to macro for 80-90% of my
>> programming needs given that the development times between Java and macro are more or
>> less 80% lower.
> I question this.  Once you have boilerplate in hand, I find that it takes no longer to
> deliver a tested, working Java Plugin than it does to deliver a tested, working macro.

In Java you need to import all the used libraries as well as define the used parameters.
All these definitions are not needed within Macro programming which make it's use easier and faster.

And as prototypical example, let me just describe the last macro I made for a student and for which the use of the Java language won't make a big difference on the running time but defenetly on the programming time.
So the student aquired 3 channels with 5 heights z-stack 144 pictures time lapse.
The used microscope software saved these pictures into 2 files (because too big) for each of the acquired channels.
So what needed to be done is to open the 2 files corresponding to a channel, concatenete them, reorganize the obtained stack into an ad hoc hypertstack and finally place this obtained hyperstack window at a given position within a 2 screen desktop.
And finally reproduce this same procedure with the 2 other stacks and place the obtained hyperstacks next to the previous one.
So nothing really complicated for an experienced ImageJ user, there's no doubt about it.
But believe me, way too complicated and time consuming for a beginner student to do it "by hand".
On the other side, given that there were only about 20 cells positions to open the described way, it was quite over killing to write a "squared plugin" for this (at least this is my opinion, but you may still disagree to it).
Of course from the user interface I wrote a GUI using the Dialog Macro methods which user interface result is fully indential whether it has been generated by a macro or a plugin.

So hoping I shared you now a little bit of my light, I wish you a good night!

My best regards,

Philippe

----- Mail original -----
De: "Kenneth Sloan" <[hidden email]>
À: "imagej" <[hidden email]>
Envoyé: Mercredi 13 Novembre 2019 20:09:18
Objet: Re: macro: convert calibrated value to raw pixel value?

> On your argument:
>> From a practical point of view - once you have standard boilerplate for a
>> full Java Plugin, I’m having a hard time seeing any advantage to the macro
>> version.
> This is more then obvious!

I have been known to be slow.  Many things which are obvious to others puzzle me.

> Macro programming is only for quick and dirty things and once you have already spend the time and work for writing a Java code it is nonsense to try to translate it back into the Macro language.

My problem is that as soon as I start reading tutorials on the macro language I run into 5 page long programs which seem to be anything other than "quick and dirty".
 
> ...
> Nevertheless after completion of this course, I moved over to macro for 80-90% of my programming needs given that the development times between Java and macro are more or less 80% lower.

I question this.  Once you have boilerplate in hand, I find that it takes no longer to deliver a tested, working Java Plugin than it does to deliver a tested, working macro.

Now...if you are in "exploration mode" and want to try different approaches interactively, then a macro does appear to be
slightly faster to first execution.  BUT (and this is my point) - when it comes time to put a program into production use, or hand it over to someone else to use, it should not take long to produce a full Java version.  So...I tend to reject the "it's faster to write" argument.

> At last but not at least, it is way easier (with only a couple neurons required) to move from Java to Macro programming, rather than to make the inverse (taking as example a colleague in this situation).

That is more than obvious!  Only...as I have learned...it's good to be aware that the macro language is *by necessity* limited.

Which is why it is worth encouraging folks who start with macros to NOT push macros as far as they can (becoming ever more complicated and clever) and switch to full Java earlier rather than later.  This is my "beware of little languages" argument.  Little languages are VERY GOOD for small, (quick and dirty), throwaway solutions.  They tend to fail when the process becomes complicated, or involves multiple developers/users, etc.  The real trap is when a programmer becomes so invested in their macro skills that it is now expensive and painful to switch.

A competent developer should have BOTH tools in their toolbox.  Which is why I am taking your advice to learn more about the macro language.

I didn't pick the current application.  It was a request from the OP.  My first thought was "that's 10 line Java Plugin - surely it's even simpler as a macro".  When no one posted such a solution, I saw an opportunity for me to learn enough about macros to do it myself. It took longer than it should have, and required at least 2 helpful hints (mostly from Michael) - but in the end I got there.

In the end, I think this problem *is* appropriate for a macro solution.  With my existing skill set, I can (now) implement it either way, in about the same amount of time.

Along the way, I think I identified a few ways that the macro language might be improved.  But, I'm willing to tolerate the minor disadvantages of the macro solution.  I also now have the right sort of "boilerplate" for use in similar problems.
So...I'm happy.  And, since (for me) using Java is just as easy as using macros, I'm not particularly lobbying for the macro language to be "improved".  [I might even argue that making the macro language "better" might make the overall situation worse.]

Finally, I recognize that many ImageJ users may not happen to have a usable Java compiler handy.  They are *always* faced with  a rather large investment in time to write their *first* Java plugin.  My message is that this is time well spent (but NOT when you are on deadline to get the current project working, yesterday).
 
--
Kenneth Sloan
[hidden email]
Vision is the art of seeing what is invisible to others.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Stein Rørvik
I think the tasks described by Philippe in his post is a perfect example of when it makes far more sense to write a macro than create a plugin.

I work in a quite similar way; the major thing I use ImageJ for is to export and analyze µCT data. 99% of the functions I need are already available in ImageJ. So my daily task is to run a workflow that applies for the object I scanned that day, relevant for the customer. This may be for example to import the dataset; calculate the center of gravity of the imaged object; create orthogonal views through the centre of this, add a scalebar and arrows indicating the object's coordinate system for each of the X/Y/Z axis images; import some measured physical data from a connected database, paste the relevant parameters from the object's measurement data in the corner of the image, and finally flatten the annotated image and send it as a PNG file to the customer as well as some worksheets with measured data. I think doing this in Java would require tens or maybe hundreds of hours exploring code and understand the relevant Java API's, instead of just using a the functions already available in the macro language and getting it all done in less than an hour. Most ad hoc tasks can be done in 10-20 minutes.

Since the objects I scan differ from day to day, the workflow is different from day to day. I create a set of macros for each of the tasks I typically use, and then modify them as needed. I do all improvements in a cumulative way, so that the latest version of the macro will include the new functionality included, as well as all earlier code so that it can be reused in a backwards compatible way. The flow of functionality is determined by reading attached metadata, so that the macro will know the nature of the object and decide how to process it from that. So I can use the same macros no matter the size or density of the object. The size may vary from millimeters to decimeters, the atomic density may vary from boron to neodymium.

I write plugins in java in only two cases:

1) If I need pixel-by-pixel processing in 3D, which is much faster in a plugin.
For 2D, getPixel(x,y) works okay, it only takes a few seconds per image.

2) If I need to change some function already in ImageJ that does not work for me as I need. I then extract the code, change it as I like, and recompile as a new plugin. So far I have needed to do that with only a handful of functions. I work almost exclusively with ImageJ 1.x so I can then simply use compile-and-run.

I think plugins work best for general tasks that are image independent. For workflows that are problem-dependent or object-dependent, using the macro language is far more efficient, IMHO.

Stein

-----Original Message-----
Sent: 14. november 2019 00:44
To: [hidden email]
Subject: Re: macro: convert calibrated value to raw pixel value?

Dear Keneth,

Let me just answer to your following answer:

>> Nevertheless after completion of this course, I moved over to macro
>> for 80-90% of my programming needs given that the development times
>> between Java and macro are more or less 80% lower.
> I question this.  Once you have boilerplate in hand, I find that it
> takes no longer to deliver a tested, working Java Plugin than it does to deliver a tested, working macro.

In Java you need to import all the used libraries as well as define the used parameters.
All these definitions are not needed within Macro programming which make it's use easier and faster.

And as prototypical example, let me just describe the last macro I made for a student and for which the use of the Java language won't make a big difference on the running time but defenetly on the programming time.
So the student aquired 3 channels with 5 heights z-stack 144 pictures time lapse.
The used microscope software saved these pictures into 2 files (because too big) for each of the acquired channels.
So what needed to be done is to open the 2 files corresponding to a channel, concatenete them, reorganize the obtained stack into an ad hoc hypertstack and finally place this obtained hyperstack window at a given position within a 2 screen desktop.
And finally reproduce this same procedure with the 2 other stacks and place the obtained hyperstacks next to the previous one.
So nothing really complicated for an experienced ImageJ user, there's no doubt about it.
But believe me, way too complicated and time consuming for a beginner student to do it "by hand".
On the other side, given that there were only about 20 cells positions to open the described way, it was quite over killing to write a "squared plugin" for this (at least this is my opinion, but you may still disagree to it).
Of course from the user interface I wrote a GUI using the Dialog Macro methods which user interface result is fully indential whether it has been generated by a macro or a plugin.

So hoping I shared you now a little bit of my light, I wish you a good night!

My best regards,

Philippe



--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: macro: convert calibrated value to raw pixel value?

Gabriel Landini
On Thursday, 14 November 2019 23:31:26 GMT [hidden email] wrote:

> For 2D, getPixel(x,y) works okay, it only takes a few seconds per
> image.

Plugins run in general much quicker.  Have a look at the IJ source code in
ImageProcessor.java, line 1759:
/** This is a faster version of getPixel() that does not do bounds checking.
*/
public abstract int get(int x, int y);

When processing a single image it might not make a big difference, but it may
do when using iterative loops or intensive access to image data.

I seem to remember (but I have not done any benchmarking) that 1D arrays work
faster than 2D arrays, so  this might bring some further advantage:

public abstract int get(int index);

There are also floating versions of these.

Regards

Gabriel

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html