måndag 27 februari 2017

star repair in PixInsight - part 2

While reprocessing old data, I came across a very instructive incidence of star over exposure. When imaging under light polluted skies, sky glow is added to any sky signal (stars, nebulae, etc). If the pollution is strong enough to over expose stars, the true star colour data is destroyed. When the sky glow is removed during post processing, this will lead to bright stars having the wrong colour.
For example, say a bright star is slightly blue in colour. Without any sky glow, it would register as RGB 0.8, 0.8, 0.95. Sky glow gives an added 0.3 in blue. This will put the star colour on sensor as RGB 0.8, 0.8, 1.0, since the maximum value for a pixel is 1.0.
When the sky glow is removed during background extraction, the value 0.2 will be subtracted, and we end up with a star's RGB values of 0.8, 0.8, 0.7. The star core has suddenly turned yellow. However, away from the core, the star will still be blue, since these areas weren't over exposed. Therefore the need to correct star colours.
During normal stretching of an image, most of the bright stars will be maximised, and have a final colour of RGB 1.0, 1.0, 1.0. However, if masked stretch is used, the stars will not be saturated, and will have a funny looking core.
Here's an example of an unstretched star, with (left) and without (right) colour repair.

When should star repair be implemented in the workflow?
Of course, before any stretch is applied, the colour must be corrected. However, there is one earlier instance where star colour matters in processing, and that is during colour calibration.
Colour calibration tries to set a white point by looking at all the stars in an image, and apply a calibration scheme that is determined by the average star colour. When the star colour is wrong due to over exposure and background extraction, the white balance after colour calibration will be off. Therefore, there is an argument for applying HSV repair prior to colour calibration. The workflow then becomes as follows:

  • cropping of edges
  • background extraction (ABE or DBE)
  • background neutralisation
  • HSV repair
  • colour calibration
This image shows the effect of doing HSV repair before (left) or after (right) colour calibration. Due to the skyglow adding mainly blue to the image, several star cores had a warmer colour after DBE. This resulted in the colour calibration routine making the blue stars more intense blue. By doing the HSV repair process prior to colour calibration, stars got a more natural blue colour after stretching.

Raspberry Pi DSLR trigger

Here's a small, simple project, a remote trigger for a DSLR.
I control my telescope mount through INDI, but unfortunately I can't control my old DSLR that way. The only way I can do "automated" exposures is if I connect an intervallometer to the camera. The problem with intervallometers is however, that they only run on small batteries, and will stop working when it's cold.
Another problem is, that it's impossible to use dithering with an intervallometer and simultaneous guiding.
Here's a partial solution to these problems. I wrote a simple Python script that will run on the Raspberry Pi, The script sends exposure signals through the RPi's GPIO bus to the remote port of my camera.
To connect the Raspberry Pi to the camera, I made a small optocoupler circuit, that will isolate the camera electronics from the RPi.
The input (left) will connect to a GPIO pin (pin 18, GPIO 24) and ground (pin 20), while the ouput (right) connects to the remote port of the camera.
Here's the code.


import RPi.GPIO as GPIO
import time
import sys

NrExposures = 1
ExposureTime = 30
TimeBetweenExposures = 6
print ' '
print 'Make sure that the camera remote port is connected to pins 18 (signal) and 20 (ground).'
print ' '
if len(sys.argv) == 1 :
   print 'No arguments provided. Will use single 30 sec exposure.'
elif len(sys.argv) == 2 :
   ExposureTime = int(sys.argv[1], 10)
   print 'Single', ExposureTime, 'seconds exposure.'
elif len(sys.argv) == 3 :
   ExposureTime = int(sys.argv[1], 10)
   NrExposures = int(sys.argv[2], 10)
   print NrExposures, 'x', ExposureTime, 'seconds exposures.'
else :
   ExposureTime = int(sys.argv[1], 10)
   NrExposures = int(sys.argv[2], 10)
   TimeBetweenExposures = int(sys.argv[3], 10)
   print NrExposures, 'x', ExposureTime, 'seconds exposures, with', TimeBetweenExposures, 'seconds delay.'

TriggerPin = 24  # Broadcom pin 24 (P1 pin 18)

GPIO.setmode(GPIO.BCM)  # Broadcom pin-numbering scheme
GPIO.setup(TriggerPin, GPIO.OUT)  # trigger pin as output

GPIO.output (TriggerPin, GPIO.LOW)

counter = NrExposures
print ' '
print 'Start : %s' % time.ctime()
while (counter > 0):
   print '  Exposure nr', counter, 'started'
   GPIO.output(TriggerPin, GPIO.HIGH)
   GPIO.output(TriggerPin, GPIO.LOW)
   print '  Exposure nr', counter, 'ended'
   counter = counter - 1
   print ' '

print 'End :  %s' % time.ctime()
GPIO.output(TriggerPin, GPIO.LOW)
print ' '
print 'Goodbye.'

The script is saved as Trigger.py and is made executable:

chmod +x Trigger.py

The script takes up to three command line arguments. The first argument is the single frame exposure time in seconds. The second argument is the number of exposures to take, and the third argument is the wait time between exposures, also in seconds.
For example

./Trigger.py 1 2 3

will take 2 exposures of 1 second each with a 3 seconds wait time after each exposure. The script will take 8 seconds to run.

If only two arguments are given, the wait time will be set to a default value of 6 seconds.
If only one argument is given, this is interpreted as exposure time. Only one exposure will be taken.
If no arguments are given, the script will do a single 30 seconds exposure.

Eventually, I may try to rewrite the INDI CCD driver to control my camera, as this will give me the possibility to dither between exposures. But for now this simple script will do the job.