Directional dependence of re-slicing speed

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

Directional dependence of re-slicing speed

Conner Phillips
Greetings,

My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.

Thanks for your input.

Sincerely,
Conner


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

Re: Directional dependence of re-slicing speed

Stein Rørvik
I have the same problem, and discovered the same workaround (rotating first) by accident a few weeks ago when I was testing CLIJ2 for reslicing.

You may find this thread on the image.sc forum of interest:
https://forum.image.sc/t/running-clij2-macros-from-imagej-1-5x/42832/17?u=steinr

The speed using CLIJ2 (a plugin that can run selected equivalents of ImageJ commands on the GPU) is quite impressive; here are my benchmarks from the thread:
------------------------------------------------
Stack size: 2000x2000x1000
...
Time for ImageJ Reslice Left-Right:  242.763
Time for ImageJ Reslice Top-Bottom:  16.165
...
Time for CLIJ2 (Quadro M5000M) Reslice Left-Right:  0.694
Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom:  0.08
------------------------------------------------
Also, CLIJ2 now works fine as a plugin in ImageJ 1.x using a very simple workaround, please see the first posts in the thread. CLIJ2 is also much slower when reslicing left-right compared to top-bottom, but it is already so fast that it does not matter much.

Unfortunately CLIJ2 does not work for me in most cases, as the datasets I work with are normally 2000x2000x2000 16 bit voxels and are thus too large to fit in my 8GB of GPU memory. And CLIJ2 lacks the "flip vertical" option that I always need, as my data always starts (first slice) at the physical bottom of the real-world data.

So I am also interested in a "fix" for the current ImageJ reslice left-right code. I had a look at the source code some time ago but found it too complex to see where the problem is, as the reslice code is quite advanced and has a lot of options for interpolation and skewed selections. What we are lacking is some further optimization of the code in those cases when we are just moving (transposing) data without any interpolation.

Stein

-----Original Message-----
Sent: 7. oktober 2020 14:03
Subject: Directional dependence of re-slicing speed

Greetings,

My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.

Thanks for your input.

Sincerely,
Conner


--

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

Re: Directional dependence of re-slicing speed

Curtis Rueden-2
Hi,

Using ImgLib2, you can quickly create resliced views of your data. For
example, here is a Groovy script that pops up a left-right sliced view of
an image stack:

  #@ Img img
  #@ UIService ui
  import net.imglib2.view.Views
  v = Views.permute(img, 1, 2) // XYZ -> XZY
  v = Views.permute(v, 0, 2) // XZY -> YZX
  ui.show(v)

With a 1500x1500x500 8-bit ramp on my system, the Left Reslice operation
took 30 seconds, whereas popping up the view as a virtual stack took <2
seconds. If your workflow is compatible with virtual stacks, this might
save you some time and memory.

If you need a non-virtual image, you can then create a new ImagePlus, wrap
it to ImgLib2, and copy the view into the new image, which takes ~15
seconds on my system. Here is a Groovy script:

  #@ Img img
  #@output result
  import net.imglib2.view.Views
  import net.imglib2.util.ImgUtil
  import net.imglib2.img.ImagePlusAdapter
  v = Views.permute(img, 1, 2) // XYZ -> XZY
  v = Views.permute(v, 0, 2) // XZY -> YZX
  int w = v.dimension(0)
  int h = v.dimension(1)
  int d = v.dimension(2)
  result = ij.IJ.createImage("resliced", w, h, d, 8)
  dest = ImagePlusAdapter.wrap(result)
  ImgUtil.copy(v, dest)

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 Wed, Oct 7, 2020 at 5:50 PM Stein Rørvik <[hidden email]> wrote:

> I have the same problem, and discovered the same workaround (rotating
> first) by accident a few weeks ago when I was testing CLIJ2 for reslicing.
>
> You may find this thread on the image.sc forum of interest:
>
> https://forum.image.sc/t/running-clij2-macros-from-imagej-1-5x/42832/17?u=steinr
>
> The speed using CLIJ2 (a plugin that can run selected equivalents of
> ImageJ commands on the GPU) is quite impressive; here are my benchmarks
> from the thread:
> ------------------------------------------------
> Stack size: 2000x2000x1000
> ...
> Time for ImageJ Reslice Left-Right:  242.763
> Time for ImageJ Reslice Top-Bottom:  16.165
> ...
> Time for CLIJ2 (Quadro M5000M) Reslice Left-Right:  0.694
> Time for CLIJ2 (Quadro M5000M) Reslice Top-Bottom:  0.08
> ------------------------------------------------
> Also, CLIJ2 now works fine as a plugin in ImageJ 1.x using a very simple
> workaround, please see the first posts in the thread. CLIJ2 is also much
> slower when reslicing left-right compared to top-bottom, but it is already
> so fast that it does not matter much.
>
> Unfortunately CLIJ2 does not work for me in most cases, as the datasets I
> work with are normally 2000x2000x2000 16 bit voxels and are thus too large
> to fit in my 8GB of GPU memory. And CLIJ2 lacks the "flip vertical" option
> that I always need, as my data always starts (first slice) at the physical
> bottom of the real-world data.
>
> So I am also interested in a "fix" for the current ImageJ reslice
> left-right code. I had a look at the source code some time ago but found it
> too complex to see where the problem is, as the reslice code is quite
> advanced and has a lot of options for interpolation and skewed selections.
> What we are lacking is some further optimization of the code in those cases
> when we are just moving (transposing) data without any interpolation.
>
> Stein
>
> -----Original Message-----
> Sent: 7. oktober 2020 14:03
> Subject: Directional dependence of re-slicing speed
>
> Greetings,
>
> My group uses ImageJ to process TIFF optical coherence tomography data and
> we do a lot of re-slicing of stacks. One thing that is always a pain is
> that re-slicing from the right or the left takes a tremendous amount of
> time compared to re-slicing from the top or bottom. A colleague discovered
> the workaround that rotating the stack 90 degrees, slicing from the "top",
> and then de-rotating the stack has the exact same effect as slicing from
> the side at a fraction of the required time. Would it be reasonable to
> adapt this "workaround" into the actual re-slice function? Is there any
> reason why doing so might be no-go? I would generally be willing to work on
> such a change, but to be frank, I'm not a Java person and I have no
> experience with the ImageJ codebase. I would much prefer to submit the idea
> to an official wishlist if there is one.
>
> Thanks for your input.
>
> Sincerely,
> Conner
>
>
> --
>
> --
> 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: Directional dependence of re-slicing speed

Wayne Rasband-2
In reply to this post by Conner Phillips
> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>
> Greetings,
>
> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.

It appears that re-slicing from the “left” or “right” is slower because the pixels are not read consecutively from memory. I did some testing and found that this code

     for (int y=0; y<h; y++)
         for (int x=0; x<w; x++)
            sum += ip.get(x,y);

which reads the pixels along each line of the image consecutively, runs up to eight times faster (with 16000x16000 image) than this code

      for (int x=0; x<w; x++)
         for (int y=0; y<h; y++)
            sum += ip.getf(x,y);

which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.

I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.

-wayne

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

Re: Directional dependence of re-slicing speed

Stein Rørvik
I had a look at the source code today as found on https://raw.githubusercontent.com/imagej/imagej1/master/ij/plugin/Slicer.java
and compiled the file as a plugin to see what effect the reading order had on my images.

I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.

With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.

Here are some benchmarks; I scaled the T1 stack by various factors:

        [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
        Original Reslice Top... 2.222 s
        Original Reslice Left... 6.568 s
        Modified Reslice Top... 2.06 s
        Modified Reslice Left... 2.071 s

        [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
        Original Reslice Top... 2.693 s
        Original Reslice Left... 20.273 s
        Modified Reslice Top... 2.107 s
        Modified Reslice Left... 2.15 s

        [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
        Original Reslice Top... 4.789 s
        Original Reslice Left... 76.842 s
        Modified Reslice Top... 2.389 s
        Modified Reslice Left... 3.176 s

        [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
        Original Reslice Top... 13.28 s
        Original Reslice Left... 236.106 s
        Modified Reslice Top... 4.927 s
        Modified Reslice Left... 11.994 s

        [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
        Original Reslice Top... 44.946 s
        Original Reslice Left... 526.485 s
        Modified Reslice Top... 66.22 s
        Modified Reslice Left... 94.751 s

The only change I did in the java code was this, in line 436:

        //if (isStack) drawLine(x1, y1, x2, y2, imp);
        IJ.showProgress(i, outputSlices);

So there must be a bug in drawLine ?
I don't understand why drawing a vertical overlay line should be slower than a horizontal?

Stein

-----Original Message-----
Sent: 11. oktober 2020 05:18
Subject: Re: Directional dependence of re-slicing speed

> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>
> Greetings,
>
> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.

It appears that re-slicing from the “left” or “right” is slower because the pixels are not read consecutively from memory. I did some testing and found that this code

     for (int y=0; y<h; y++)
         for (int x=0; x<w; x++)
            sum += ip.get(x,y);

which reads the pixels along each line of the image consecutively, runs up to eight times faster (with 16000x16000 image) than this code

      for (int x=0; x<w; x++)
         for (int y=0; y<h; y++)
            sum += ip.getf(x,y);

which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.

I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.

-wayne

--


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

Re: Directional dependence of re-slicing speed

Wayne Rasband-2
> On Oct 11, 2020, at 8:49 AM, Stein Rørvik <[hidden email]> wrote:
>
> I had a look at the source code today as found on https://raw.githubusercontent.com/imagej/imagej1/master/ij/plugin/Slicer.java
> and compiled the file as a plugin to see what effect the reading order had on my images.
>
> I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.
>
> With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.

The Re-slice command in the ImageJ 1.53f32 daily build uses an ordinary progress bar when called from a macro, which is faster on Windows but not on MacOS.

-wayne

> Here are some benchmarks; I scaled the T1 stack by various factors:
>
> [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
> Original Reslice Top... 2.222 s
> Original Reslice Left... 6.568 s
> Modified Reslice Top... 2.06 s
> Modified Reslice Left... 2.071 s
>
> [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
> Original Reslice Top... 2.693 s
> Original Reslice Left... 20.273 s
> Modified Reslice Top... 2.107 s
> Modified Reslice Left... 2.15 s
>
> [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
> Original Reslice Top... 4.789 s
> Original Reslice Left... 76.842 s
> Modified Reslice Top... 2.389 s
> Modified Reslice Left... 3.176 s
>
> [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
> Original Reslice Top... 13.28 s
> Original Reslice Left... 236.106 s
> Modified Reslice Top... 4.927 s
> Modified Reslice Left... 11.994 s
>
> [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
> Original Reslice Top... 44.946 s
> Original Reslice Left... 526.485 s
> Modified Reslice Top... 66.22 s
> Modified Reslice Left... 94.751 s
>
> The only change I did in the java code was this, in line 436:
>
> //if (isStack) drawLine(x1, y1, x2, y2, imp);
> IJ.showProgress(i, outputSlices);
>
> So there must be a bug in drawLine ?
> I don't understand why drawing a vertical overlay line should be slower than a horizontal?
>
> Stein
>
> -----Original Message-----
> Sent: 11. oktober 2020 05:18
> Subject: Re: Directional dependence of re-slicing speed
>
>> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>>
>> Greetings,
>>
>> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.
>
> It appears that re-slicing from the “left” or “right” is slower because the pixels are not read consecutively from memory. I did some testing and found that this code
>
>     for (int y=0; y<h; y++)
>         for (int x=0; x<w; x++)
>            sum += ip.get(x,y);
>
> which reads the pixels along each line of the image consecutively, runs up to eight times faster (with 16000x16000 image) than this code
>
>      for (int x=0; x<w; x++)
>         for (int y=0; y<h; y++)
>            sum += ip.getf(x,y);
>
> which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.
>
> I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.
>
> -wayne

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

Re: Directional dependence of re-slicing speed

Stein Rørvik
Thanks, works as advertised.

You write ".. which is faster on Windows but not on MacOS"

Do you mean that it is still slow on MacOS, or that it was already fast on MacOS, so this is a Windows only problem?

For those who are used to using the "/" shortcut at the numeric keypad for reslice, this little wrapper macro in StartupMacros.ijm should do the trick, to get the faster behaviour also when using the GUI:

macro "Reslice [n/]" {
        run("Reslice [/]...", "");
}

I looked closer at the code and found that the problem is due to the transparency of the color:
                 g.setColor(new Color(1f, 1f, 0f, 0.4f));
If we replace this with a solid yellow
                 g.setColor(new Color(1f, 1f, 0f, 1f));
the yellow line progress runs as fast as without the lines, but of course covering the image.

Apparently the mechanism used to render this transparency gets slower and slower the more pixels are covered, and that this slowness increases much more in the vertical than in the horizontal direction.
Shortening the length of the transparent line also speeds up the reslice.

Anyway, the solution in 1.53f32 works fine for me, since it is macro execution time that matters, and it is easy to wrap for use in the GUI.

Stein

-----Original Message-----
Sent: 11. oktober 2020 17:21
Subject: Re: Directional dependence of re-slicing speed

> On Oct 11, 2020, at 8:49 AM, Stein Rørvik <[hidden email]> wrote:
>
> I had a look at the source code today as found on
> https://raw.githubusercontent.com/imagej/imagej1/master/ij/plugin/Slicer.java
> and compiled the file as a plugin to see what effect
> the reading order had on my images.
>
> I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.
>
> With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.

The Re-slice command in the ImageJ 1.53f32 daily build uses an ordinary progress bar when called from a macro, which is faster on Windows but not on MacOS.

-wayne

> Here are some benchmarks; I scaled the T1 stack by various factors:
>
> [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
> Original Reslice Top... 2.222 s
> Original Reslice Left... 6.568 s
> Modified Reslice Top... 2.06 s
> Modified Reslice Left... 2.071 s
>
> [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
> Original Reslice Top... 2.693 s
> Original Reslice Left... 20.273 s
> Modified Reslice Top... 2.107 s
> Modified Reslice Left... 2.15 s
>
> [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
> Original Reslice Top... 4.789 s
> Original Reslice Left... 76.842 s
> Modified Reslice Top... 2.389 s
> Modified Reslice Left... 3.176 s
>
> [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
> Original Reslice Top... 13.28 s
> Original Reslice Left... 236.106 s
> Modified Reslice Top... 4.927 s
> Modified Reslice Left... 11.994 s
>
> [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
> Original Reslice Top... 44.946 s
> Original Reslice Left... 526.485 s
> Modified Reslice Top... 66.22 s
> Modified Reslice Left... 94.751 s
>
> The only change I did in the java code was this, in line 436:
>
> //if (isStack) drawLine(x1, y1, x2, y2, imp);
> IJ.showProgress(i, outputSlices);
>
> So there must be a bug in drawLine ?
> I don't understand why drawing a vertical overlay line should be slower than a horizontal?
>
> Stein
>
> -----Original Message-----
> Sent: 11. oktober 2020 05:18
> Subject: Re: Directional dependence of re-slicing speed
>
>> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>>
>> Greetings,
>>
>> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.
>
> It appears that re-slicing from the “left” or “right” is slower
> because the pixels are not read consecutively from memory. I did some
> testing and found that this code
>
>     for (int y=0; y<h; y++)
>         for (int x=0; x<w; x++)
>            sum += ip.get(x,y);
>
> which reads the pixels along each line of the image consecutively,
> runs up to eight times faster (with 16000x16000 image) than this code
>
>      for (int x=0; x<w; x++)
>         for (int y=0; y<h; y++)
>            sum += ip.getf(x,y);
>
> which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.
>
> I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.
>
> -wayne

--
ImageJ mailing list: https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Fimagej.nih.gov%2Fij%2Flist.html&amp;data=02%7C01%7Cstein.rorvik%40sintef.no%7C61884efcc40540e41b5308d86df99f08%7Ce1f00f39604145b0b309e0210d8b32af%7C1%7C0%7C637380266183494325&amp;sdata=6BRKXeM2GjorMDpITG9BukbAa5Rd%2FPxQbC97WkYSZkI%3D&amp;reserved=0

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

Re: Directional dependence of re-slicing speed

Wayne Rasband-2
> On Oct 11, 2020, at 2:15 PM, Stein Rørvik <[hidden email]> wrote:
>
> Thanks, works as advertised.
>
> You write ".. which is faster on Windows but not on MacOS”

MacOS does not have the slow transparent line drawing problem.

> Do you mean that it is still slow on MacOS, or that it was already fast on MacOS, so this is a Windows only problem?
>
> For those who are used to using the "/" shortcut at the numeric keypad for reslice, this little wrapper macro in StartupMacros.ijm should do the trick, to get the faster behaviour also when using the GUI:

The 1.53f34 daily build always uses the standard progress bar on Windows.

-wayne

> macro "Reslice [n/]" {
> run("Reslice [/]...", "");
> }
>
> I looked closer at the code and found that the problem is due to the transparency of the color:
> g.setColor(new Color(1f, 1f, 0f, 0.4f));
> If we replace this with a solid yellow
> g.setColor(new Color(1f, 1f, 0f, 1f));
> the yellow line progress runs as fast as without the lines, but of course covering the image.
>
> Apparently the mechanism used to render this transparency gets slower and slower the more pixels are covered, and that this slowness increases much more in the vertical than in the horizontal direction.
> Shortening the length of the transparent line also speeds up the reslice.
>
> Anyway, the solution in 1.53f32 works fine for me, since it is macro execution time that matters, and it is easy to wrap for use in the GUI.
>
> Stein
>
> -----Original Message-----
> Sent: 11. oktober 2020 17:21
> Subject: Re: Directional dependence of re-slicing speed
>
>> On Oct 11, 2020, at 8:49 AM, Stein Rørvik <[hidden email]> wrote:
>>
>> I had a look at the source code today as found on
>> https://raw.githubusercontent.com/imagej/imagej1/master/ij/plugin/Slicer.java
>> and compiled the file as a plugin to see what effect
>> the reading order had on my images.
>>
>> I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.
>>
>> With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.
>
> The Re-slice command in the ImageJ 1.53f32 daily build uses an ordinary progress bar when called from a macro, which is faster on Windows but not on MacOS.
>
> -wayne
>
>> Here are some benchmarks; I scaled the T1 stack by various factors:
>>
>> [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
>> Original Reslice Top... 2.222 s
>> Original Reslice Left... 6.568 s
>> Modified Reslice Top... 2.06 s
>> Modified Reslice Left... 2.071 s
>>
>> [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
>> Original Reslice Top... 2.693 s
>> Original Reslice Left... 20.273 s
>> Modified Reslice Top... 2.107 s
>> Modified Reslice Left... 2.15 s
>>
>> [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
>> Original Reslice Top... 4.789 s
>> Original Reslice Left... 76.842 s
>> Modified Reslice Top... 2.389 s
>> Modified Reslice Left... 3.176 s
>>
>> [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
>> Original Reslice Top... 13.28 s
>> Original Reslice Left... 236.106 s
>> Modified Reslice Top... 4.927 s
>> Modified Reslice Left... 11.994 s
>>
>> [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
>> Original Reslice Top... 44.946 s
>> Original Reslice Left... 526.485 s
>> Modified Reslice Top... 66.22 s
>> Modified Reslice Left... 94.751 s
>>
>> The only change I did in the java code was this, in line 436:
>>
>> //if (isStack) drawLine(x1, y1, x2, y2, imp);
>> IJ.showProgress(i, outputSlices);
>>
>> So there must be a bug in drawLine ?
>> I don't understand why drawing a vertical overlay line should be slower than a horizontal?
>>
>> Stein
>>
>> -----Original Message-----
>> Sent: 11. oktober 2020 05:18
>> Subject: Re: Directional dependence of re-slicing speed
>>
>>> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>>>
>>> Greetings,
>>>
>>> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.
>>
>> It appears that re-slicing from the “left” or “right” is slower
>> because the pixels are not read consecutively from memory. I did some
>> testing and found that this code
>>
>>    for (int y=0; y<h; y++)
>>        for (int x=0; x<w; x++)
>>           sum += ip.get(x,y);
>>
>> which reads the pixels along each line of the image consecutively,
>> runs up to eight times faster (with 16000x16000 image) than this code
>>
>>     for (int x=0; x<w; x++)
>>        for (int y=0; y<h; y++)
>>           sum += ip.getf(x,y);
>>
>> which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.
>>
>> I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.
>>
>> -wayne

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

Re: Directional dependence of re-slicing speed

Stein Rørvik
Sorry to keep spamming you about this,

I did a web search and found this page discussing the same problem of slow drawing of transparent colors; it appears to be a java bug:
https://stackoverflow.com/questions/30861201/why-is-java-awt-graphics-drawline-exceptionally-slow

I tried the simplest solution, as presented in the last post in the thread, and it worked fine:

        Graphics2D g2 = (Graphics2D) g;
  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  RenderingHints.VALUE_ANTIALIAS_ON);

Adding the above two codelines after the call
        Graphics g = ic.getGraphics();
in the drawLine() function solves the problem of slow alpha drawing on Windows.

So if this fix is applied, the yellow transparent progress on reslice may be re-instated on Windows, at least when using the GUI. Of course it needs to be tested on MacOS and Linux too.

The other proposed fix by adding
        -Dsun.java2d.opengl=true
to the java command line also works, but that is more difficult to roll out as users must edit the ImageJ.cfg file by themselves. All image updating seems a bit faster for me with this flag on.

Stein

-----Original Message-----
Sent: 11. oktober 2020 22:11
Subject: Re: Directional dependence of re-slicing speed

> On Oct 11, 2020, at 2:15 PM, Stein Rørvik <[hidden email]> wrote:
>
> Thanks, works as advertised.
>
> You write ".. which is faster on Windows but not on MacOS”

MacOS does not have the slow transparent line drawing problem.

> Do you mean that it is still slow on MacOS, or that it was already fast on MacOS, so this is a Windows only problem?
>
> For those who are used to using the "/" shortcut at the numeric keypad for reslice, this little wrapper macro in StartupMacros.ijm should do the trick, to get the faster behaviour also when using the GUI:

The 1.53f34 daily build always uses the standard progress bar on Windows.

-wayne

> macro "Reslice [n/]" {
> run("Reslice [/]...", "");
> }
>
> I looked closer at the code and found that the problem is due to the transparency of the color:
> g.setColor(new Color(1f, 1f, 0f, 0.4f)); If we replace this with a
> solid yellow
> g.setColor(new Color(1f, 1f, 0f, 1f)); the yellow line progress
> runs as fast as without the lines, but of course covering the image.
>
> Apparently the mechanism used to render this transparency gets slower and slower the more pixels are covered, and that this slowness increases much more in the vertical than in the horizontal direction.
> Shortening the length of the transparent line also speeds up the reslice.
>
> Anyway, the solution in 1.53f32 works fine for me, since it is macro execution time that matters, and it is easy to wrap for use in the GUI.
>
> Stein
>
> -----Original Message-----
> Sent: 11. oktober 2020 17:21
> Subject: Re: Directional dependence of re-slicing speed
>
>> On Oct 11, 2020, at 8:49 AM, Stein Rørvik <[hidden email]> wrote:
>>
>> I had a look at the source code today as found on
>> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fraw
>> .githubusercontent.com%2Fimagej%2Fimagej1%2Fmaster%2Fij%2Fplugin%2FSl
>> icer.java&amp;data=02%7C01%7Cstein.rorvik%40sintef.no%7Cd4d300baccdd4
>> d67054c08d86e222519%7Ce1f00f39604145b0b309e0210d8b32af%7C1%7C0%7C6373
>> 80440237829351&amp;sdata=OBq3c42RV1mFyMZZaXAVmcrV6k5YKKGfK7abBLwDE7Q%
>> 3D&amp;reserved=0 and compiled the file as a plugin to see what
>> effect the reading order had on my images.
>>
>> I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.
>>
>> With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.
>
> The Re-slice command in the ImageJ 1.53f32 daily build uses an ordinary progress bar when called from a macro, which is faster on Windows but not on MacOS.
>
> -wayne
>
>> Here are some benchmarks; I scaled the T1 stack by various factors:
>>
>> [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
>> Original Reslice Top... 2.222 s
>> Original Reslice Left... 6.568 s
>> Modified Reslice Top... 2.06 s
>> Modified Reslice Left... 2.071 s
>>
>> [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
>> Original Reslice Top... 2.693 s
>> Original Reslice Left... 20.273 s
>> Modified Reslice Top... 2.107 s
>> Modified Reslice Left... 2.15 s
>>
>> [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
>> Original Reslice Top... 4.789 s
>> Original Reslice Left... 76.842 s
>> Modified Reslice Top... 2.389 s
>> Modified Reslice Left... 3.176 s
>>
>> [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
>> Original Reslice Top... 13.28 s
>> Original Reslice Left... 236.106 s
>> Modified Reslice Top... 4.927 s
>> Modified Reslice Left... 11.994 s
>>
>> [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
>> Original Reslice Top... 44.946 s
>> Original Reslice Left... 526.485 s
>> Modified Reslice Top... 66.22 s
>> Modified Reslice Left... 94.751 s
>>
>> The only change I did in the java code was this, in line 436:
>>
>> //if (isStack) drawLine(x1, y1, x2, y2, imp);
>> IJ.showProgress(i, outputSlices);
>>
>> So there must be a bug in drawLine ?
>> I don't understand why drawing a vertical overlay line should be slower than a horizontal?
>>
>> Stein
>>
>> -----Original Message-----
>> Sent: 11. oktober 2020 05:18
>> Subject: Re: Directional dependence of re-slicing speed
>>
>>> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>>>
>>> Greetings,
>>>
>>> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.
>>
>> It appears that re-slicing from the “left” or “right” is slower
>> because the pixels are not read consecutively from memory. I did some
>> testing and found that this code
>>
>>    for (int y=0; y<h; y++)
>>        for (int x=0; x<w; x++)
>>           sum += ip.get(x,y);
>>
>> which reads the pixels along each line of the image consecutively,
>> runs up to eight times faster (with 16000x16000 image) than this code
>>
>>     for (int x=0; x<w; x++)
>>        for (int y=0; y<h; y++)
>>           sum += ip.getf(x,y);
>>
>> which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.
>>
>> I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.
>>
>> -wayne


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

Re: Directional dependence of re-slicing speed

Wayne Rasband-2
> On Oct 12, 2020, at 9:46 AM, Stein Rørvik <[hidden email]> wrote:
>
> Sorry to keep spamming you about this,
>
> I did a web search and found this page discussing the same problem of slow drawing of transparent colors; it appears to be a java bug:
> https://stackoverflow.com/questions/30861201/why-is-java-awt-graphics-drawline-exceptionally-slow
>
> I tried the simplest solution, as presented in the last post in the thread, and it worked fine:
>
> Graphics2D g2 = (Graphics2D) g;
>   g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  RenderingHints.VALUE_ANTIALIAS_ON);

This fix for slow alpha line drawing on Windows is in the ImageJ 1.53f37 daily build.

-wayne

> Adding the above two codelines after the call
> Graphics g = ic.getGraphics();
> in the drawLine() function solves the problem of slow alpha drawing on Windows.
>
> So if this fix is applied, the yellow transparent progress on reslice may be re-instated on Windows, at least when using the GUI. Of course it needs to be tested on MacOS and Linux too.
>
> The other proposed fix by adding
> -Dsun.java2d.opengl=true
> to the java command line also works, but that is more difficult to roll out as users must edit the ImageJ.cfg file by themselves. All image updating seems a bit faster for me with this flag on.
>
> Stein
>
> -----Original Message-----
> Sent: 11. oktober 2020 22:11
> Subject: Re: Directional dependence of re-slicing speed
>
>> On Oct 11, 2020, at 2:15 PM, Stein Rørvik <[hidden email]> wrote:
>>
>> Thanks, works as advertised.
>>
>> You write ".. which is faster on Windows but not on MacOS”
>
> MacOS does not have the slow transparent line drawing problem.
>
>> Do you mean that it is still slow on MacOS, or that it was already fast on MacOS, so this is a Windows only problem?
>>
>> For those who are used to using the "/" shortcut at the numeric keypad for reslice, this little wrapper macro in StartupMacros.ijm should do the trick, to get the faster behaviour also when using the GUI:
>
> The 1.53f34 daily build always uses the standard progress bar on Windows.
>
> -wayne
>
>> macro "Reslice [n/]" {
>> run("Reslice [/]...", "");
>> }
>>
>> I looked closer at the code and found that the problem is due to the transparency of the color:
>> g.setColor(new Color(1f, 1f, 0f, 0.4f)); If we replace this with a
>> solid yellow
>> g.setColor(new Color(1f, 1f, 0f, 1f)); the yellow line progress
>> runs as fast as without the lines, but of course covering the image.
>>
>> Apparently the mechanism used to render this transparency gets slower and slower the more pixels are covered, and that this slowness increases much more in the vertical than in the horizontal direction.
>> Shortening the length of the transparent line also speeds up the reslice.
>>
>> Anyway, the solution in 1.53f32 works fine for me, since it is macro execution time that matters, and it is easy to wrap for use in the GUI.
>>
>> Stein
>>
>> -----Original Message-----
>> Sent: 11. oktober 2020 17:21
>> Subject: Re: Directional dependence of re-slicing speed
>>
>>> On Oct 11, 2020, at 8:49 AM, Stein Rørvik <[hidden email]> wrote:
>>>
>>> I had a look at the source code today as found on
>>> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fraw
>>> .githubusercontent.com%2Fimagej%2Fimagej1%2Fmaster%2Fij%2Fplugin%2FSl
>>> icer.java&amp;data=02%7C01%7Cstein.rorvik%40sintef.no%7Cd4d300baccdd4
>>> d67054c08d86e222519%7Ce1f00f39604145b0b309e0210d8b32af%7C1%7C0%7C6373
>>> 80440237829351&amp;sdata=OBq3c42RV1mFyMZZaXAVmcrV6k5YKKGfK7abBLwDE7Q%
>>> 3D&amp;reserved=0 and compiled the file as a plugin to see what
>>> effect the reading order had on my images.
>>>
>>> I tried to selectively disable the reading and writing of data per row/column, and found out that it had quite little effect; reslice left-right was equally slow compared to top-down both when returning a zero instead of a reading a pixel, and doing nothing instead of writing data to the result stack.
>>>
>>> With few possibilities left, I simply removed the fancy yellow-line-on-image-progress-update functionality, and it got _a lot_ faster, the speedup is 10-20 times.
>>
>> The Re-slice command in the ImageJ 1.53f32 daily build uses an ordinary progress bar when called from a macro, which is faster on Windows but not on MacOS.
>>
>> -wayne
>>
>>> Here are some benchmarks; I scaled the T1 stack by various factors:
>>>
>>> [128 x 128 x 65; 16-bit] t1-head.tif scaled x0.5
>>> Original Reslice Top... 2.222 s
>>> Original Reslice Left... 6.568 s
>>> Modified Reslice Top... 2.06 s
>>> Modified Reslice Left... 2.071 s
>>>
>>> [256 x 256 x 129; 16-bit] t1-head.tif scaled x1
>>> Original Reslice Top... 2.693 s
>>> Original Reslice Left... 20.273 s
>>> Modified Reslice Top... 2.107 s
>>> Modified Reslice Left... 2.15 s
>>>
>>> [512 x 512 x 258; 16-bit] t1-head.tif scaled x2
>>> Original Reslice Top... 4.789 s
>>> Original Reslice Left... 76.842 s
>>> Modified Reslice Top... 2.389 s
>>> Modified Reslice Left... 3.176 s
>>>
>>> [1024 x 1024 x 516; 16-bit] t1-head.tif scaled x4
>>> Original Reslice Top... 13.28 s
>>> Original Reslice Left... 236.106 s
>>> Modified Reslice Top... 4.927 s
>>> Modified Reslice Left... 11.994 s
>>>
>>> [2048 x 2048 x 1032; 16-bit] t1-head.tif scaled x8
>>> Original Reslice Top... 44.946 s
>>> Original Reslice Left... 526.485 s
>>> Modified Reslice Top... 66.22 s
>>> Modified Reslice Left... 94.751 s
>>>
>>> The only change I did in the java code was this, in line 436:
>>>
>>> //if (isStack) drawLine(x1, y1, x2, y2, imp);
>>> IJ.showProgress(i, outputSlices);
>>>
>>> So there must be a bug in drawLine ?
>>> I don't understand why drawing a vertical overlay line should be slower than a horizontal?
>>>
>>> Stein
>>>
>>> -----Original Message-----
>>> Sent: 11. oktober 2020 05:18
>>> Subject: Re: Directional dependence of re-slicing speed
>>>
>>>> On Oct 7, 2020, at 8:02 AM, Phillips, Conner <[hidden email]> wrote:
>>>>
>>>> Greetings,
>>>>
>>>> My group uses ImageJ to process TIFF optical coherence tomography data and we do a lot of re-slicing of stacks. One thing that is always a pain is that re-slicing from the right or the left takes a tremendous amount of time compared to re-slicing from the top or bottom. A colleague discovered the workaround that rotating the stack 90 degrees, slicing from the "top", and then de-rotating the stack has the exact same effect as slicing from the side at a fraction of the required time. Would it be reasonable to adapt this "workaround" into the actual re-slice function? Is there any reason why doing so might be no-go? I would generally be willing to work on such a change, but to be frank, I'm not a Java person and I have no experience with the ImageJ codebase. I would much prefer to submit the idea to an official wishlist if there is one.
>>>
>>> It appears that re-slicing from the “left” or “right” is slower
>>> because the pixels are not read consecutively from memory. I did some
>>> testing and found that this code
>>>
>>>   for (int y=0; y<h; y++)
>>>       for (int x=0; x<w; x++)
>>>          sum += ip.get(x,y);
>>>
>>> which reads the pixels along each line of the image consecutively,
>>> runs up to eight times faster (with 16000x16000 image) than this code
>>>
>>>    for (int x=0; x<w; x++)
>>>       for (int y=0; y<h; y++)
>>>          sum += ip.getf(x,y);
>>>
>>> which does not read the pixels consecutively. There is little difference in speed with images up to 1000x1000 in size.
>>>
>>> I would prefer not to implement the rotation work around because it would make re-slicing slower for stacks with smaller slices and it could introduce bugs.
>>>
>>> -wayne

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

Re: Directional dependence of re-slicing speed

Conner Phillips
In reply to this post by Conner Phillips
The solution works just fine on my end. Thank you for the quick fix!

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