PCL Bitmap::Render(Image, ..., LUT, ...)

jmurphy

Well-known member
A request for more help...

I am trying to create a bitmap image from a linear PixInsight image, with the resulting bitmap stretched like an unlinked STF.
I could create a copy of the ImageVariant, calculate the STF, apply this as a histogram stretch and then convert it to a bitmap.
The Bitmap::Render() method looks like a much better option, but I don't know how to create a LUT that is similar to an unlinked STF.

The bitmap will be used to paint a ScrollBox viewport. Extra graphics will be drawn on top - for example, the PhotometricLocalNormalization sample grid. The code will be the C++ equivalent of PreviewControl, written by Andres del Pozo. Although, if the equivalent of PreviewControl has already been written in C++, that would be even better!

Thanks!
John Murphy
 
Hi John,

Take a look at the pcl::ImageView class:


ImageView encapsulates a significant part of the functionality of an image window as a control that you can embed in a top level window, such as a process interface or a dialog. ImageView derives from ScrollBox, so you don't have to care about image navigation.
 
Take a look at the pcl::ImageView class:


ImageView encapsulates a significant part of the functionality of an image window as a control that you can embed in a top level window, such as a process interface or a dialog. ImageView derives from ScrollBox, so you don't have to care about image navigation.
Hi Juan,

I am trying to make progress with the PhotometricLocalNormalization module, but I have been unable to understand how to display an image in the ImageView class, which is preventing further progress.

I am reading an image from disk:
C++:
   static Image* PLNLoadImageFile(FileFormatInstance& file, int index = 0)
   {
      // Select the image at the specified index.
      if (!file.SelectImage(index))
         throw CaughtException();

      // Create a shared image, 32-bit floating point.
      Image* image = new Image((void*)0, 0, 0);

      // Read the image.
      if (!file.ReadImage(*image))
         throw CaughtException();

      return image;
   }

The first problem is that this linear image will need to have an unliked auto STF stretch applied to it so that it becomes viewable. The existing ScreenTransferFunction works with a view, so I assume I will need to copy the relevant code from the ScreenTransferFunction. I guess I then need to apply this STF as a HistogramTransformation, ideally producing an 8 bit integer image, because its only purpose is to be displayed in the ImageView.

The next problem is how to display an the image in ImageView. Unfortunately I have been unable to figure out how to do this. I can see that it has the method Image() to return the image it is using, but I can't see a method to set the image.

Some help would be greatly appreciated.
Thanks, John Murphy
 
Hi John,

See the pcl::DisplayFunction class:


In particular, you need the DisplayFunction::ComputeAutoStretch() member function:

template <class V> void pcl::DisplayFunction::ComputeAutoStretch( const V& sigma, const V& center )

This function will compute automatic histogram stretch functions in a similar way to the STF tool. To call this function you need robust estimates of location and scale for the image. For example:

C++:
#include <DisplayFunction.h>
#include <Image.h>

void ApplyAutoStretch( Image& image, bool unlinked = true )
{
   Vector center( image.NumberOfChannels() );
   Vector sigma( image.NumberOfChannels() );
   image.PushSelections();
   for ( int c = 0; c < image.NumberOfChannels(); ++c )
   {
      image.SelectChannel( c );
      sigma[c] = 1.4826*image.MAD( center[c] = image.Median() );
   }
   image.PopSelections();
   DisplayFunction D;
   D.SetLinkedRGB( unlinked );
   D.ComputeAutoStretch( sigma, center );
   D >> image;
}

An instance of the ImageView class already owns an image. You access this image with the ImageView::Image() member function, which returns an ImageVariant object that transports the actual image being displayed in the ImageView. Then you can work with this image exactly the same as you do with any image that you can create in your code.

Extending the example that you have included in your post:

C++:
static void PLNLoadImageFileInView( ImageView& view, FileFormatInstance& file, int index = 0 )
{
   // Select the image at the specified index.
   if ( !file.SelectImage( index ) )
      throw CaughtException();

   // Read the image in the ImageView object.
   if ( !file.ReadImage( view.Image() ) )
      throw CaughtException();

   // Force the view to regenerate its screen rendition and reset the states of
   // all its interface components.
   view.Reset();
}

Let me know if this clarifies these concepts.
 
Last edited:
An instance of the ImageView class already owns an image. You access this image with the ImageView::Image() member function, which returns an ImageVariant object that transports the actual image being displayed in the ImageView. Then you can work with this image exactly the same as you do with any image that you can create in your code.

Extending the example that you have included in your post:

C++:
static void PLNLoadImageFileInView( ImageView& view, FileFormatInstance& file, int index = 0 )
{
   // Select the image at the specified index.
   if ( !file.SelectImage( index ) )
      throw CaughtException();

   // Read the image in the ImageView object.
   if ( !file.ReadImage( view.Image() ) )
      throw CaughtException();

   // Force the view to regenerate its screen rendition and reset the states of
   // all its interface components.
   view.Reset();
}

Let me know if this clarifies these concepts.
Thanks, this does help a great deal, but unfortunately I am still stuck. When I try to use ImageView, the scrollbar sizes look correct for the image size, but it displays garbage instead of the image, and an exception is thrown in the background:
*** PCL Win32 System Exception: At address 00007FF6D4B65B7B with exception code C0000005 :
Access violation: invalid memory read operation at address 0000000000000150


I have uploaded the current version of PhotometricLocalNormalization to GitLab, and will also try to explain what I have done here.

I added the ImageView just like any other GUI component in PLNInterface.h:
C++:
private:
   PLNInstance m_instance;
   struct GUIData
   {
      GUIData( PLNInterface& );
      VerticalSizer     Global_Sizer;
         //...
         SectionBar        StarDetection_SectionBar;
         Control           StarDetection_Control;
            HorizontalSizer   StarDetection_Sizer;
               NumericControl    StarDetection_NumericControl;
               PushButton        StarDetection_PushButton;
            ImageView StarDetection_ImageView;
   };

   GUIData* m_GUI = nullptr;

   void PLNLoadImageFileInView(ImageView& view, FileFormatInstance& file, int index = 0);

And added it in its default state (I assume it contains a zero sized image at this point):
C++:
Global_Sizer.Add(StarDetection_SectionBar);
Global_Sizer.Add(StarDetection_Control);
Global_Sizer.Add(StarDetection_ImageView);

When the user requests the view, I attempt to read the image from a file and display it in the ImageView:
C++:
void PLNInterface::e_StarButtonClicked(Button& sender, bool checked)
{
   if (sender == m_GUI->StarDetection_PushButton)
   {
      String targetFilename = SelectedTargetFilename(true);
      if (targetFilename.Length() == 0)
         return;

      FileFormat format(File::ExtractExtension(targetFilename), true/*read*/, false/*write*/);
      FileFormatInstance file(format);
      ImageDescriptionArray images;
      if (!file.Open(images, targetFilename))
         throw CaughtException();

      if (images.IsEmpty())
         throw Error(targetFilename + ": Empty image.");

      PLNLoadImageFileInView(m_GUI->StarDetection_ImageView, file, 0);
   }
}

void PLNInterface::PLNLoadImageFileInView(ImageView& view, FileFormatInstance& file, int index)
{
   // Select the image at the specified index.
   if (!file.SelectImage(index))
      throw CaughtException();

   // Read the image in the ImageView object.
   if (!file.ReadImage(view.Image()))
      throw CaughtException();

   // Force the view to regenerate its screen rendition and reset the states of
   // all its interface components.
   view.Reset();
}

At this point, the ImageView scrollbars correctly change for the size of the image, but garbage is displayed instead of the image and the exception is shown in the console.

1633191908308.png

(To reproduce the error, add at least one image to the Target Images list, select it and press 'Detected stars')

Help and advice would be very gratefully received.
Thanks, John Murphy
 
Back
Top