Author Topic: Gradient Domain Operations, take 5  (Read 15806 times)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Gradient Domain Operations, take 5
« Reply #15 on: 2011 July 30 03:29:39 »
Try this one:

Code: [Select]
   /*
    * Shrink the mask with a fast approximation to erosion of a binary image
    * with a square structuring element of size shrinkCount_p.
    */
   void GradientsMergeMosaic::erodeMaskFast( weightImageType_t& rMask_p, int shrinkCount_p )
   {
      int w = rMask_p.Width();
      int h = rMask_p.Height();

      if ( w <= 2*shrinkCount_p || h <= 2*shrinkCount_p )
      {
         rMask_p.Zero();
         return;
      }

      weightImageType_t tmp( rMask_p );
     
      for ( int i = 0; i < shrinkCount_p; ++i )
      {
         weightImageType_t::sample* r0 = rMask_p.ScanLine( i );
         for ( int j = 0; j < w; ++j )
            *r0++ = weightImageType_t::pixel_traits::MinSampleValue();
         weightImageType_t::sample* r1 = rMask_p.ScanLine( h-i-1 );
         for ( int j = 0; j < w; ++j )
            *r1++ = weightImageType_t::pixel_traits::MinSampleValue();
      }
     
      for ( int i = shrinkCount_p, i0 = 0, i1 = 2*shrinkCount_p; i1 < h; ++i, ++i0, ++i1 )
      {
         const weightImageType_t::sample* m0 = tmp.ScanLine( i0 );
         const weightImageType_t::sample* m  = tmp.ScanLine( i );
         const weightImageType_t::sample* m1 = tmp.ScanLine( i1 );
               weightImageType_t::sample* r  = rMask_p.ScanLine( i );

         for ( int j = 0; j < shrinkCount_p; ++j )
            *r++ = weightImageType_t::pixel_traits::MinSampleValue();
               
         for ( int j = shrinkCount_p, j0 = 0, j1 = 2*shrinkCount_p; j1 < w; ++j, ++j0, ++j1, ++m0, ++m1 )
            *r++ = (*m0 && *m1 && m[j0] && m[j1]) ?
                  weightImageType_t::pixel_traits::MaxSampleValue() :
                  weightImageType_t::pixel_traits::MinSampleValue();

         for ( int j = 0; j < shrinkCount_p; ++j )
            *r++ = weightImageType_t::pixel_traits::MinSampleValue();
      }
   }

I haven't compared it, but although your convolution+binarization solution takes advantage of PCL's parallel implementations, I think this routine should be faster even without parallelization. Parallelizing it would be very easy, in fact. Worth trying.

Let me know when you have your code ready for release.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Re: Gradient Domain Operations, take 5
« Reply #16 on: 2011 July 30 10:03:44 »
Hi Juan,

thanks for the code, will try it later.

Thinking a little bit about the code in http://pixinsight.com/forum/index.php?topic=3289.msg22654#msg22654, I feel that certain morphological transforms probably are separable just as convolutions. I think for a square erosion that is certainly the case. I guess someone more versed in group theory will probably be able to explain that we can see max/min and and/or operations as equivalents to +* in this context, so the use of an outer product as in separable convolutions is possible here as well.

Maybe an opportunity to implement SeparableMorphologicalTransforms in PCL?

I hope to have some code later this weekend.

Georg
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Gradient Domain Operations, take 5
« Reply #17 on: 2011 July 30 11:34:11 »
Hi Georg,

AFAIK there is no correspondence between separability in linear operations, where an outer product can be used to transform a 2D matrix operation into two 1D vector operations, and separability in nonlinear operations such as erosion and dilation (and, by generalization, any rank-order operator).

Right now PCL implements 'brute force' morphological transformations, whose complexity is roughly O((n*N)^2), n being the size of the structuring element and N representing the size of the image. My implementations have the advantage that one can use arbitrary structuring elements; for example, circular and star-like elements, which are very useful to process astronomical images. This confers great flexibility but the problem is that these operations are extremely slow for moderately sized filters.

There exist separable morphological transformations, but AFAIK they are always restricted to square and similar kernels. The most well-known one is the van Herk/Gil-Werman algorithm (Marcel van Herk, A fast algorithm for local minimum and maximum filters on rectangular and octagonal kernels, Pattern Recognition Letters, 13, pp. 517-521, 1992). This algorithm has complexity independent on the size of the structuring element and as the paper title tells it works for rectangular and octogonal SEs. Octogonal is not too far from circular, so it sounds as a quite useful alternative for DS images.

Since your work has shown that we need better/faster morphological transformations, and I need them also for several projects (one of them is a morphological wavelet transform tool that I want to publish this Fall-Winter), I'll try to implement some variants of the van Herk/Gil-Werman algorithm in PCL ASAP.

Looking forward to your code to publish it as a development update.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Gradient Domain Operations, take 5
« Reply #18 on: 2011 July 30 11:42:52 »
Something that I've seen in your code and I'd like to comment a bit. You use to write code to generate convolution filters such as:

Code: [Select]
SeparableFilter filter( sideLength,1.0/nElements );
Note that in PCL, proper weighting of filter kernels is automatically carried out by the Convolution, SeparableConvolution and FFTConvolution classes. So the code above is equivalent to (the much easier to understand version):

Code: [Select]
SeparableFilter filter( sideLength,1.0 );
As long as all kernel elements are equal, a filter constructed this way is equivalent to a box average filter.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline georg.viehoever

  • PTeam Member
  • PixInsight Jedi Master
  • ******
  • Posts: 2132
Re: Gradient Domain Operations, take 5
« Reply #19 on: 2011 October 27 12:29:30 »
Georg (6 inch Newton, unmodified Canon EOS40D+80D, unguided EQ5 mount)