Author Topic: Image Acquisition in PixInsight (Was: When will Pixinsight...)  (Read 78870 times)

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #90 on: 2011 February 23 08:12:20 »
Quote
Personally I like this way, because it adheres much better to the object oriented design in PixInsight. Let me know if this helps you further.

I agree - here is my idea overall:

If you remember from my earlier post, the ImagingSession Process was a way to run several steps of an imaging run together.  I actually think this will be a process container itself - but with imaging specific options.  And maybe process container is the wrong terminology.  Basically, here is an example workflow I am imagining:

1.  Create new ImageSession by double clicking the ImageSession Process
2.  Create new ExposeImage process and configure for L-filter -> drag the little triangle to the ImageSession Process
3.  etc...

I've created a mockup to describe this idea.  It isn't pretty, but I wanted to capture this in case anyone wants to provide any feedback...

The reason for this separate ImageSession concept, is that we will need to orchestrate Dithering, Errors, Guiding etc... and it will allow for a nice place to manage the whole process once it is kicked off.

Cheers,
Dave
« Last Edit: 2011 February 23 08:17:50 by David Raphael »
David Raphael

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #91 on: 2011 February 23 11:37:58 »
Hi David,

Nice idea. It can be done without problems right now. Do you know how the ScreenTransferFunction and HistogramTransformation tools work together? As you probably know, you can drag a STF icon to HT's control bar, and HT imports the STF instance. Similarly, you can drag an HT icon to STF.

As long as all processes are defined in the same module, they can share/import instances. You have the full source code of the IntensityTransformations module in all PCL distributions, so you can see how this works for HT and STF; what you want to do is just the same, basically.

This is a skeleton of how you should work with several instances in your ImagingSessionInterface:

Code: [Select]
bool ImagingSessionInterface::ValidateProcess( const ProcessImplementation& p, String& whyNot ) const
{
   if ( dynamic_cast<const ExposeImageInstance*>( &p ) == 0 &&
        dynamic_cast<const AutoFocusInstance*>( &p ) == 0 )
   {
      whyNot = "Must be an instance of either ExposeImage or AutoFocus.";
      return false;
   }

   whyNot.Clear();
   return true;
}

bool ImagingSessionInterface::ImportProcess( const ProcessImplementation& p )
{
   const ExposeImageInstance* ei = dynamic_cast<const ExposeImageInstance*>( &p );
   if ( ei != 0 )
   {
      // We are importing an ExposeImage instance
      ...
   }
   else
   {
      const AutoFocusInstance* af = dynamic_cast<const AutoFocusInstance*>( &p );
      if ( af != 0 )
      {
         // We are importing an AutoFocus instance
         ...
      }
      else
      {
         // Hmmm, this is odd; this cannot happen because we have validated
         // the instance to ensure it is either ExposeImage or AutoFocus
         return false;
      }
   }

   return true;
}

Right now an instance can only be imported by a process interface by dragging it to its control bar. You cannot drag an instance to a control inside a process interface. That would be very nice because in that way the drag&drop actions would be more intuitive. I'll think on a way to overcome this limitation.

Besides that cosmetic limitation, you can import different instances as above, then allow the user to move them up and down on your interface to refine the sequence, if necessary.

HTH
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #92 on: 2011 February 23 11:43:21 »
Excelente!

One quick question regarding the Image - before, I remember having trouble creating an ImageWindow and then passing image data to it...can I create the UInt16Image and then pass it to an ImageWindow?  Or do I can I copy the data to the window?  Basically set the ImageWindow data to different images?
David Raphael

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #93 on: 2011 February 23 11:54:28 »
Nope, you must create the ImageWindow and work on the image in its main view. You cannot replace the image in a view.

However, you can assign any image to the current image in a view, which is essentially the same thing you're asking for. Recall that you get access to a main view with ImageWindow::MainView(), then you get access to the image as an ImageVariant with View::Image(); we have seen this just before your first light.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #94 on: 2011 February 23 11:58:53 »
One further question. AutoFocus and ExposeImage are executable processes? In other words, can I execute an instance of ExposeImage without needing an ImagingSession?

If the answer is yes, then why can't you rely on ProcessContainer? After all, ImagingSession is defining an ordered sequence of processes. Note that ProcessContainer is exactly that. You can execute a ProcessContainer in the global context (as long as all of its contained instances can be executed globally).

On the other hand, I understand that defining a specialized container such as ImagingSession leads to a more intuitive and easy-to-use implementation, so I am not against your idea. I just want to fix the concepts.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #95 on: 2011 February 23 12:02:45 »
Quote
One further question. AutoFocus and ExposeImage are executable processes? In other words, can I execute an instance of ExposeImage without needing an ImagingSession?

Yes.

Quote
If the answer is yes, then why can't you rely on ProcessContainer?
I think we can use ProcessContainer...
but then we won't have the nice modal dialog reporting all the progress, FWHM monitor etc...?


David Raphael

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #96 on: 2011 February 23 12:05:17 »
...you can assign any image to the current image in a view...
Would the thread be able to assign that?  It seems that would be the case by using the ExposeImageData struct?  But I thought that the thread couldn't call anything that updates the UI?
David Raphael

Offline Pleiades

  • Administrator
  • PixInsight Enthusiast
  • *****
  • Posts: 88
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #97 on: 2011 February 23 12:11:09 »
Quote
but then we won't have the nice modal dialog reporting all the progress, FWHM monitor etc...?

Correct. That's why your ImagingSession container makes a lot of sense.

Would the thread be able to assign that?

Yes, a thread can modify an image, even if it is an image living in the core application (inside a view). As long as you guarantee that two or more threads won't modify the same pixel concurrently (using mutexes if required), everything will be fine.

Quote
But I thought that the thread couldn't call anything that updates the UI?

A thread cannot perform any GUI operation. However, writing and copying pixels has nothing to do with the GUI. What a thread cannot do, for example, is call ImageWindow::Show() for example. As long as the operations that you carry out don't imply (directly or indirectly) a GUI update —which means drawing on the screen, essentially—, there should be no problems.

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #98 on: 2011 February 23 12:16:55 »
Ooops! yeah, it was me. I forgot to become myself again  :laugh:
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #99 on: 2011 February 23 12:23:32 »
Ok - so the change I just made is crashing PixInsight at startup:

Code: [Select]

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
0   libSystem.B.dylib              0x00007fff836d6616 __kill + 10
1   libSystem.B.dylib              0x00007fff83776cca abort + 83
2   libstdc++.6.dylib              0x00007fff886905d2 __tcf_0 + 0
3   libobjc.A.dylib                0x00007fff81cd4d3d _objc_terminate + 120
4   libstdc++.6.dylib              0x00007fff8868eae1 __cxxabiv1::__terminate(void (*)()) + 11
5   libstdc++.6.dylib              0x00007fff8868eb16 __cxxabiv1::__unexpected(void (*)()) + 0
6   libstdc++.6.dylib              0x00007fff8868ebfc __gxx_exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception*) + 0
7   ...iades-astrophoto.PixInsight 0x0000000100ebf4ec pcl::CriticalSignalHandler(int) + 284
8   libSystem.B.dylib              0x00007fff836e867a _sigtramp + 26
9   ImageAcquisition-pxm.dylib    0x000000012940766e pcl::Thread::IsRootThread() + 14
10  ImageAcquisition-pxm.dylib    0x00000001294066c9 pcl::StatusMonitor::__Reset() + 25
11  ImageAcquisition-pxm.dylib    0x0000000129402336 pcl::AbstractImage::AbstractImage() + 262
12  ImageAcquisition-pxm.dylib    0x0000000129400bbe pcl::Generic2DPixelData<pcl::UInt16PixelTraits>::Generic2DPixelData() + 22 (PixelData.h:192)
13  ImageAcquisition-pxm.dylib    0x0000000129400c68 pcl::Generic2DImage<pcl::UInt16PixelTraits>::Generic2DImage() + 22 (Image.h:257)
14  ImageAcquisition-pxm.dylib    0x0000000129400ce0 pcl::ExposeImageData::ExposeImageData() + 40 (ExposeImageInstance.cpp:9)
...

So it looks like there is a problem initializing that UInt16Image image - do I need to create this somewhere else?

Here is the code:

Code: [Select]
#include "ExposeImageInstance.h"

namespace pcl
{
    struct ExposeImageData
    {
       ExposeImageData() :
       mutex(), image(), imageProgress( 0 ), imageReady( false ),
       abort( false ), error( false ), paused( false ), errorMessage()
       {
       }

       Mutex       mutex;         // To protect data from concurrent accesses
       UInt16Image image;         // The image being acquired
       int         imageProgress; // Progress indicator, e.g. from 0 to 100
       bool        imageReady;    // Flag true if a new image is now ready
       bool        abort;         // Flag true if the user wants to abort
       bool        error;         // Flag true if an error occurs
       bool        paused;
       String      errorMessage;  // Error information
    };

    ExposeImageData data;
    class ExposeImageThread: public Thread
    {
...

David Raphael

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #100 on: 2011 February 23 12:33:11 »
Ah, I know why this happens :)

You are declaring an instance of ExposeImageData in this way:

static ExposeImageData data;

(with or without the static storage class). Here is the problem, because the UInt16Image constructor (called by ExposeImageData::ExposeImageData()) needs to access some core resources that aren't yet available when your module is being installed. Instead of an automatic variable, declare a pointer:

static ExposeImageData* data = 0;

and initialize it somewhere if it is zero:

if ( data == 0 )
   data = new ExposeImageData;


Does this help you?

Note— this should not lead to a crash, but to an error message, so as a bonus you've discovered a bug :)
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #101 on: 2011 February 23 13:34:31 »
Note— this should not lead to a crash, but to an error message, so as a bonus you've discovered a bug :)

Sweet!

Quote
and initialize it somewhere if it is zero:

if ( data == 0 )
   data = new ExposeImageData;


I guess it will get cleaned up when PixInsight exits?

David Raphael

Offline David Raphael

  • PixInsight Addict
  • ***
  • Posts: 226
    • Astrofactors CCD Cameras
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #102 on: 2011 February 26 13:58:56 »
I am probably beating a dead horse here ;-)

I know I keep asking questions about UI updates without occupying the rest of PixInsight...but I think this one is a little different.

I'd like to periodically update the ExposeImageInterface with the actual sensor temperature of the camera.  Is there anyway for me to do this?  It is similar to the way an interface can respond to a View event...?  The desired use case is to connect the camera, set the temperature and then the interface will display the current temperature for the camera...

Let me know what you think.

Cheers,
Dave
David Raphael

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #103 on: 2011 March 07 13:51:53 »
Quote
and initialize it somewhere if it is zero:

if ( data == 0 )
   data = new ExposeImageData;


I guess it will get cleaned up when PixInsight exits?

As a safety and good programming procedure, you should implement a destructor for your ExposeImageData class, in case it is necessary (e.g. if you have allocated some ojects dynamically in ExposeImageData's constructor).

However, since the 'data' object won't be destroyed  explicitly (because you won't call 'delete data', will you), it is unlikely that ExposeImageData's destructor will ever be called. Your object will live as long as your module is not unloaded. As PixInsight doesn't unload installed modules (a module can only be 'scheduled for uninstallation' upon the next execution of PI Core), your 'data' object will be automatically deallocated when PI exits, but its destructor won't be invoked.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Image Acquisition in PixInsight (Was: When will Pixinsight...)
« Reply #104 on: 2011 March 07 14:20:51 »
Quote
I'd like to periodically update the ExposeImageInterface with the actual sensor temperature of the camera.  Is there anyway for me to do this?  It is similar to the way an interface can respond to a View event...?  The desired use case is to connect the camera, set the temperature and then the interface will display the current temperature for the camera...

There are several ways. Perhaps the simplest and most efficient way is using a timer. A timer can work in two modes: in single-shot mode and in periodic mode. The timer generates timer events, and you can attach a member function of your interface class to capture these events. In single-shot mode, the timer generates a single tick event when the specified interval has elapsed. In periodic mode, successive timer events are generated at regular intervals. This is just what we want.

In your interface class (for example, ExposeImageInstance), you must include a Timer object as a data member, and a timer event handler as a member function:

Code: [Select]
#include <pcl/Timer.h>

class ExposeImageInstance : public ProcessImplementation
{
public:

   ...

private:

   ...

   // The timer used to update camera data at regular intervals
   Timer UpdateCameraData_Timer;

   ...

   // Timer event handler
   ExposeImageInstance::__UpdateCameraData_Timer( Timer& sender )
};

Then when you construct your GUI subobject, the timer must be initialized and the event handler connected to it:

Code: [Select]
ExposeImageInstance::GUIData::GUIData( ExposeImageInstance& w )
{
   ...
   UpdateCameraData_Timer.SetInterval( 0.5 );
   UpdateCameraData_Timer.SetPeriodic( true );
   UpdateCameraData_Timer.OnTimer( (Timer::timer_event_handler)&ExposeImageInstance::__UpdateCameraData_Timer, w );
   ...
}

Somewhere in your code you must fire the timer; for example when the user starts a new exposure, or where appropriate:

Code: [Select]
   // Start generating timer events
   GUI->GUI->UpdateCameraData_Timer.Start();

Finally, this is how your timer event handler should look like:

Code: [Select]
ExposeImageInstance::__UpdateCameraData_Timer( Timer& sender )
{
   if ( sender == GUI->UpdateCameraData_Timer )
   {
      // Will get here every 0.5 seconds

      ... perform the updates here ...

      // You'll have to stop the timer when no more updates are necessary.
      if ( no-more-updates-required )
         GUI->UpdateCameraData_Timer.Stop();
   }
}

Let me know how this works.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/