[ITK] [ITK-users] setting big spherical neighborhoods to center voxel value

Bradley Lowekamp blowekamp at mail.nih.gov
Mon Mar 30 09:06:55 EDT 2015


Hello,

Yes please check the obvious things first.

Recently I had similar requirements for an algorithm; I needed to iterate over a sparse set of neighborhoods. I ended up creating ImageScanlineImageIterators for each neighborhood. You may want to try the approach here [1] ( apologize of not having more comments there). If it works for you, I'd be quite interested if the performance comparison.

HTH,
Brad


[1] https://github.com/blowekamp/itkSuperPixel/blob/d63741c87067376f0a1e5651a7f96964974c724b/include/itkSLICImageFilter.hxx#L238-L277


On Mar 30, 2015, at 4:52 AM, Richard Beare <richard.beare at gmail.com> wrote:

> I guess the obvious common traps need to be checked - confirm you are in Release mode. Things like neighbourhood iterators can be very expensive in debug mode. Also, the neighbourhood iterator will be doing some sort of edge of image safety check, which your other code may not be doing (I haven't checked). The neighbourhood iterator isn't, I guess, really designed to be resized every time it is used. Normally you set it up once and apply it lots of times. I've no clue as to how expensive the initialisation is, but it may pay to keep a structure containing iterators that you've already allocated so that you can pick the right one and move it.
> 
> It may turn out that the design is really bad for your problem, with performance being destroyed by the creation phase, that isn't an issue in the normal use case. Continuing to use it will give you edge safety and dimension independence, but I guess you'll need to address the issue of initialization by being clever about the reuse of iterators.
> 
> One way to do that would be to use a pass to record the location and value of all of the skeleton points, sort them by brightness, then visit in order so that neighbourhoods can be reused without resizing. This assumes, of course that the skeletons contain much fewer voxels than the image.
> 
> 
> On Mon, Mar 30, 2015 at 6:51 PM, Johannes Weber <JohannesWeber at gmx.at> wrote:
> thank you for your answers!
>  
> I tried out following idea of yours: "If you use neighbourhoods, which is the appropriate ITK structure, then avoid visiting all voxels with the neighbourhood iterator. Use a standard single voxel iterator to find the skeleton voxels, then move the neighbourhood iterator to that location."
> this is fast until I use the SetRadius method of the neighborhood iterator... it goes up form about 2 seconds to 1 minute.
> for(iterator.GoToBegin(); !iterator.IsAtEnd(); iterator++)
>     {
>         if(iterator.Get() > 0)
>         {
>             neighborhoodIterator.SetLocation(iterator.GetIndex());
>             radius.Fill( (int) iterator.Get());
>             neighborhoodIterator.SetRadius(radius);
>         }
>     }
>  
> Than I implemented what I want to do by direct accessing the image array:
> float * imgArray = distanceRidge->GetBufferPointer();
>  
> and for every ridge point (value > 0) in the image I go through the desired region with 3 for loops:
>  
> for (int i1 = iStart; i1 <= iStop; i1++)
>         {
>             r1SquaredK = (i1 - i) * (i1 - i);
>             for (int j1 = jStart; j1 <= jStop; j1++)
>             {
>                 r1SquaredJK = r1SquaredK + (j1 - j) * (j1 - j);
>                 if(r1SquaredJK <= rSquared)
>                 {
>                     for (int k1 = kStart; k1 <= kStop; k1++)
>                     {                       
>                         r1Squared = r1SquaredJK + (k1 - k) * (k1 - k);
>                         if (r1Squared <= rSquared)
>                         {                            
>                             s1 = imgArray[i1 + imageSize[0] * (j1 + imageSize[1] * k1)];
>                             if(rSquared > s1)
>                             {
>                                 imgArray[i1 + imageSize[0] * (j1 + imageSize[1] * k1)] = rSquared;                                
>                             }                            
>                         }
>                     }
>                 }
>             }            
>         }
>  
> and this works fine! and it is really fast! with this approach I am getting there where I want to be.
> I am doing the same with the neighborhood iterator, or I also tried out doing it with a image region iterator and instead of going through the desired region with 3 for loops I always set the region of the iterator (see my first email).
> So what I am asking myself is now, if it is so much faster using directly the flat array where the image data is saved... is it also a proper way to do it like this? and is there a different way of implementing this, which is as fast as with flat array but using iterators from ITK or other functions/options from ITK?
>  
> Gesendet: Freitag, 27. März 2015 um 00:47 Uhr
> Von: "Richard Beare" <richard.beare at gmail.com>
> An: Richard.Beare at ieee.org
> Cc: "Johannes Weber" <JohannesWeber at gmx.at>, "Insight Users" <insight-users at itk.org>
> Betreff: Re: [ITK-users] setting big spherical neighborhoods to center voxel value
> Here's another option - I haven't thought it through completely so could be far from the mark, but I think it is close.
>  
> consider the following:
>  
> A - input mask
> B - distance transform of mask (positive values inside the mask)
> C - ridge lines in B (sort of skeleton)
>  
> You are aiming to create an image of spheres, centres on voxels in C, with size set by the "brightness" at centre location in C.
>  
> Suppose you can create the spatially variant dilation by a sphere using the parabolic tools I mentioned in the previous message - that gives you another mask:
>  
> D - spatially variant dilation of C
>  
> Now invert C and take the distance transform to give E.
> take a distance transform of D and add to E, then mask by D. The idea here is that if you add two distance transforms together you end up with a flat surface, at least in the case where the second DT is computed from peaks in the first. 
>  
> The result should be a sort of tube, of varying thickness, where the voxel value corresponds to the tube thickness (possibly with a uniform offset). Note that I don't think you will see sphere corresponding to the brightest skeleton points using this approach, but the result may be useful for your application.
> 
>  
> Also, a couple of notes regarding the direct approach.
>  
> If you use neighbourhoods, which is the appropriate ITK structure, then avoid visiting all voxels with the neighbourhood iterator. Use a standard single voxel iterator to find the skeleton voxels, then move the neighbourhood iterator to that location.
>  
>  
> There are also some optimizations you can use if you do some checks of the change in sphere size between neighbours. If the spheres were all identically sized then it is feasible to construct lists of voxels that are not in common between neighbouring spheres, and just visit those, which is a big saving. Much trickier when the sizes aren't the same, but I'd guess that for a given skeleton there'd be a relatively small number of combinations of neighbouring sizes.
>  
>  
>  
> On Fri, Mar 27, 2015 at 8:02 AM, Richard Beare <richard.beare at gmail.com> wrote:
> This isn't a complete solution, but might give you some ideas.
>  
> The part about using the skeleton points, which are distance transform voxels, as the source for the radius, can be implemented using spatially variant morphology. I have a short publication about doing this efficiently with parabolic functions. However this doesn't propagate the voxel value, only producing a mask. I have thought about combining with label dilation, to propagate a label value, but haven't done it yet.
>  
> A queue based approach to something similar is discussed in:
> "Labelled reconstruction of binary objects: a vector propagation algorithm", buckley and lagerstrom 
>  
> On Thu, Mar 26, 2015 at 11:36 PM, Bradley Lowekamp <blowekamp at mail.nih.gov> wrote:
> Hello,
>  
> If you have a 3D image and you are visiting a neighborhood of size 20^3, you are doing 8000 visits per pixel there is no way to make this efficient. You have a big O algorithm problem.
>  
> The Neighborhood iterator would be a the more ITK way of doing what you are trying to do [1] [2]. But that's is not the order of efficiency improvement you need.
>  
> You need to revise your algorithm so you only visit each pixel once. Perhaps with region growing and queues, or auxiliary images to keep track of the current distance or other data.
>  
> Hope that helps,
> Brad
>  
> [1] http://www.itk.org/Doxygen/html/classitk_1_1NeighborhoodIterator.html
> [2] http://itk.org/Wiki/ITK/Examples/Iterators/NeighborhoodIterator
>  
> On Mar 26, 2015, at 5:24 AM, JohannesWeber at gmx.at wrote:
>  
> Hello everyone,
>  
> I have the following problem: after calculating the distance map (e.g. with DanielssonDistanceMapImageFilter) I am getting rid of most of the voxels (= setting 0) after calculating a so called distance ridge (kind of a skeleton). Now I want for every voxel of this distance ridge that it is a center voxel for a spherical neighborhood with the radius equal to the distance value of the voxel, and all voxels included in this sphere are set to the distance value of the voxel of the distance ridge (the center voxel of the sphere). So that means the neighborhoods can become big, e.g. radius of 10, or 20 voxels. The problem is here the performance... I implemented it somehow, but the performance nowhere near it should be.
> e.g. going through the image with a neighborhood iterator and vor every voxel bigger than 0 creating a neighborhood with the radius with the distance value of this voxel that seems to take very long alone to create and indexing the neighborhood.
> another approach I tried is to extract all the voxels of the distance ridge, iterate through them and calculate for every ridge voxel the region and iterate through the region doing proper calculations:
>  
> for (int rp = 0; rp < nRidgePoints; rp++)
>     {
>         ImageType::IndexType s1Index;
>         const int i = ridgePointsIndex[0][rp];
>         const int j = ridgePointsIndex[1][rp];
>         const int k = ridgePointsIndex[2][rp];
>         const float r = ridgePointsValues[rp];
> 
>         rSquared = (int) ((r * r) + 0.5f);
>         rInt = (int) r;
>         if(rInt < r) rInt++;
>         iStart = i - rInt;
>         if(iStart < 0) iStart = 0;
>         iStop = i + rInt;
>         if(iStop >= imageSize[0]) iStop = imageSize[0] - 1;
>         jStart = j - rInt;
>         if(jStart < 0) jStart = 0;
>         jStop = j + rInt;
>         if(jStop >= imageSize[1]) jStop = imageSize[1] - 1;
>         kStart = k - rInt;
>         if(kStart < 0) kStart = 0;
>         kStop = k + rInt;
>         if(kStop >= imageSize[2]) kStop = imageSize[2] - 1;
>         ImageType::IndexType index;
>         ImageType::SizeType size;
>         index[0] = iStart;
>         index[1] = jStart;
>         index[2] = kStart;
>         size[0] = iStop - iStart + 1;
>         size[1] = jStop - jStart + 1;
>         size[2] = kStop - kStart + 1;
>         ImageType::RegionType region;
>         region.SetIndex(index);
>         region.SetSize(size);
>         ImageRegionIteratorWithIndexType iteratorWithIndex (distanceRidge, region);
>     
>         for (iteratorWithIndex.GoToBegin(); !iteratorWithIndex.IsAtEnd(); iteratorWithIndex++)
>         {
>             s1Index = iteratorWithIndex.GetIndex();
>             r1SquaredK = (s1Index[0] - i) * (s1Index[0] - i);
>             r1SquaredJK = r1SquaredK + (s1Index[1] - j) * (s1Index[1] - j);
>             if(r1SquaredJK <= rSquared)
>             {
>                 r1Squared = r1SquaredJK + (s1Index[2] - k) * (s1Index[2] - k);
>                 if (r1Squared <= rSquared)
>                 {                    
>                     s1 = iteratorWithIndex.Get();
>                     if (rSquared > s1)
>                     {
>                         iteratorWithIndex.Set(rSquared);                        
>                     }
>                 }               
>             }
>         }
>         
>     }
>  
> so every approach I tried until now is very slow comparing to other implementations of the algorithm I want to do... would maybe spatial objects help me somehow? But I do not really understand how they work...
> thanks for your help!
>  
> greetings,
> Johannes
> _____________________________________
> Powered by www.kitware.com
> 
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
> 
> Kitware offers ITK Training Courses, for more information visit:
> http://www.kitware.com/products/protraining.php
> 
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
> 
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/insight-users
> 
> _____________________________________
> Powered by www.kitware.com
> 
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
> 
> Kitware offers ITK Training Courses, for more information visit:
> http://www.kitware.com/products/protraining.php
> 
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
> 
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/insight-users
>  
> 
> _____________________________________
> Powered by www.kitware.com
> 
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
> 
> Kitware offers ITK Training Courses, for more information visit:
> http://www.kitware.com/products/protraining.php
> 
> Please keep messages on-topic and check the ITK FAQ at:
> http://www.itk.org/Wiki/ITK_FAQ
> 
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/insight-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/community/attachments/20150330/36c94189/attachment-0001.html>
-------------- next part --------------
_____________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html

Kitware offers ITK Training Courses, for more information visit:
http://www.kitware.com/products/protraining.php

Please keep messages on-topic and check the ITK FAQ at:
http://www.itk.org/Wiki/ITK_FAQ

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/insight-users


More information about the Community mailing list