Jump to content

Banner.jpg.b89429c566825f6ab32bcafbada449c9.jpg

Jocular: a tool for astronomical observing with a camera


Recommended Posts

Yeah CV2 does that, here's some sample code below. I'm just going to debayer and split my files as they come in then copy them to a watched folder at this point but if that could be embedded in the program even better!

#!/usr/bin/env python3                                                                                                                                                                                         
                                                                                                                                                                                                               
'''                                                                                                                                                                                                            
  Fetch RGGB data from FITS file, convert it to an RGB numpy                                                                                                                                                   
  array, with and without interpolation, and store it as                                                                                                                                                       
  uint16 PNG. This code serves as an example.                                                                                                                                                                  
                                                                                                                                                                                                               
  Variant "no interpolation" based on Osmo Systems' picamraw.                                                                                                                                                  
                                                                                                                                                                                                               
  Requires Python >= 3.5                                                                                                                                                                                       
                                                                                                                                                                                                               
  Markus Wildi, 2019                                                                                                                                                                                           
                                                                                                                                                                                                               
'''                                                                                                                                                                                                            
                                                                                                                                                                                                               
import cv2                                                                                                                                                                                                     
from astropy.io import fits                                                                                                                                                                                    
                                                                                                                                                                                                               
import numpy as np                                                                                                                                                                                             
from enum import Enum                                                                                                                                                                                          
                                                                                                                                                                                                               
# source: adapted from Osmo Systems' picamraw (https://github.com/osmosystems/picamraw).                                                                                                                       
                                                                                                                                                                                                               
class BayerOrder(Enum):                                                                                                                                                                                        
    ''' There are four supported arrangements of the R, G, G, and B pixels:                                                                                                                                    
        RGGB:                                                                                                                                                                                                  
              RG                                                                                                                                                                                               
              GB                                                                                                                                                                                               
        GBRG:                                                                                                                                                                                                  
              GB                                                                                                                                                                                               
              RG                                                                                                                                                                                               
        BGGR:                                                                                                                                                                                                  
              BG                                                                                                                                                                                               
              GR                                                                                                                                                                                               
        GRBG:                                                                                                                                                                                                  
              GR                                                                                                                                                                                               
              BG                                                                                                                                                                                               
    '''                                                                                                                                                                                                        
                                                                                                                                                                                                               
    RGGB = 'RGGB'                                                                                                                                                                                              
    GBRG = 'GBRG'                                                                                                                                                                                              
    BGGR = 'BGGR'                                                                                                                                                                                              
    GRBG = 'GRBG'                                                                                                                                                                                              
                                                                                                                                                                                                               
R_CHANNEL_INDEX, G_CHANNEL_INDEX, B_CHANNEL_INDEX = [0, 1, 2]                                                                                                                                                  
                                                                                                                                                                                                               
BAYER_ORDER_TO_RGB_CHANNEL_COORDINATES = {                                                                                                                                                                     
    # (ry, rx), (gy, gx), (Gy, Gx), (by, bx)                                                                                                                                                                   
    BayerOrder.RGGB: ((0, 0), (1, 0), (0, 1), (1, 1)),                                                                                                                                                         
    BayerOrder.GBRG: ((1, 0), (0, 0), (1, 1), (0, 1)),                                                                                                                                                         
    BayerOrder.BGGR: ((1, 1), (0, 1), (1, 0), (0, 0)),                                                                                                                                                         
    BayerOrder.GRBG: ((0, 1), (1, 1), (0, 0), (1, 0)),                                                                                                                                                         
}                                                                                                                                                                                                              
                                                                                                                                                                                                               
def _guard_attribute_is_a_multiple_of(attribute_name, attribute_value, multiple):                                                                                                                              
    if not attribute_value % multiple == 0:                                                                                                                                                                    
        raise ValueError(                                                                                                                                                                                      
            'Incoming data is the wrong shape: {attribute_name} ({attribute_value}) is not a multiple of {multiple}'                                                                                           
            .format(**locals())                                                                                                                                                                                
        )                                                                                                                                                                                                      
                                                                                                                                                                                                               
                                                                                                                                                                                                               
bggr = fits.getdata('4sec.fits')                                                                                                                                                                               
#                                                                                                                                                                                                              
# variant without interpolation                                                                                                                                                                                
#                                                                                                                                                                                                              
_guard_attribute_is_a_multiple_of('width', bggr.shape[0], 2)                                                                                                                                                   
_guard_attribute_is_a_multiple_of('height', bggr.shape[1], 2)                                                                                                                                                  
                                                                                                                                                                                                               
rgb_no_int = np.zeros((int(bggr.shape[0]/2), int(bggr.shape[1]/2), 3))                                                                                                                                         
                                                                                                                                                                                                               
((ry, rx), (gy, gx), (Gy, Gx), (by, bx)) = BAYER_ORDER_TO_RGB_CHANNEL_COORDINATES[BayerOrder.RGGB]                                                                                                             
                                                                                                                                                                                                               
rgb_no_int[:, :, R_CHANNEL_INDEX] = bggr[ry::2, rx::2]                                                                                                                                                         
rgb_no_int[:, :, G_CHANNEL_INDEX] = (bggr[gy::2, gx::2] + bggr[Gy::2, Gx::2])/2.                                                                                                                               
rgb_no_int[:, :, B_CHANNEL_INDEX] = bggr[by::2, bx::2]                                                                                                                                                         
cv2.imwrite( '4sec_no_int.png', rgb_no_int.astype(np.uint16))                                                                                                                                                  
#                                                                                                                                                                                                              
# variant with interpolation                                                                                                                                                                                   
#                                                                                                                                                                                                              
rgb = cv2.cvtColor(bggr, cv2.COLOR_BAYER_BG2RGB)                                                                                                                                                               
                                                                                                                                                                                                               
cv2.imwrite('4sec_int.png', rgb) 
Edited by GordTulloch
Link to comment
Share on other sites

I'm not using cv2 but instead this https://github.com/colour-science/colour-demosaicing/blob/master/colour_demosaicing/examples/examples_bayer.ipynb and it seems to be working fine within Jocular (not yet part of the release though). The tricky part is knowing that the incoming FITs is indeed in need of debayering... there is some inconsistency in the use of FITs header info to signal this 😉

Also considering supporting Canon/Nikon raw format but that will take a little longer. My reluctance is that handling large pixel-count sensors is pretty sluggish for compute-intensive things like live LAB colour, but I have a few ideas on that front that I want to try out.

cheers

Martin

Link to comment
Share on other sites

5 hours ago, Martin Meredith said:

I'm not using cv2 but instead this https://github.com/colour-science/colour-demosaicing/blob/master/colour_demosaicing/examples/examples_bayer.ipynb and it seems to be working fine within Jocular (not yet part of the release though). The tricky part is knowing that the incoming FITs is indeed in need of debayering... there is some inconsistency in the use of FITs header info to signal this 😉

Oh, good find, thats pretty easy to work with!  Would it not just be BAYERPAT needs to be set to something intelligent?

Link to comment
Share on other sites

  • 3 months later...

Hi Martin et al, Just wondering if you could clarify something for me.

 

My shiny new Ultrastar arrived the other day, I have yet to set it up and put it to use (bloomin' storms...)  however I noticed that the instructions refer to installing Starlight live when wanting to use the Ultra for "live viewing"

How does this differ from you software? Is yours better? or do they do different things?

Edited by Steve Loy
Link to comment
Share on other sites

Hi Steve

Starlight Live (SLL; formerly Lodestar Live) is a separate application (developed by Paul Shears of SGL) that can be used to do EEVA-like things with the SX range of cameras. SLL is excellent for EEVA and is how I got into this game in 2014, being very easy to use (and because it worked on a Mac!). I would recommend you start out with SLL with your Ultrastar, actually.

I developed Jocular because I wanted further capabilities to support my EEVA sessions, but was very much inspired by the simplicity of SLL. Jocular extends the capabilities of SLL in the following ways: automatic management & reloading of previous captures; observation planning; gradient-removal and noise reduction; greater set of stretch functions and histogram-free image manipulation; complete control of the stack; object and session logging; automatically applied calibration library; auto-flats; annotated snapshots; live LRGB and L-Ha combination; local platesolving and very deep annotation (this is in the latest version). On top of that it is open source and 100% platform-neutral, so anyone can join in on GitHub and take it forward. 

SLL and Jocular can work together, and that is how I started and how many prolific users still use Jocular. SLL is used for capture and is configured to save FITs automatically to a 'watched' folder that Jocular then automatically loads from.

I added native support for the Lodestar and the SX filter wheel in the last version and that is the way I use it now (ie without SLL). There are some issues that we are trying to sort out getting the SX cameras supported natively on Windows (it will work, just a question of the details). My intention is to support the Ultrastar natively too (this part is easy and is being held up because of the Windows issue).

If you or anyone does want to try out Jocular, please wait for a couple of days (no more) because I'll be releasing v0.4 and the installation procedure has been greatly simplified 🙂: users just need to ensure they have Python and then do a 'pip install jocular'.

cheers

Martin

  • Like 2
Link to comment
Share on other sites

3 hours ago, Martin Meredith said:

please wait for a couple of days (no more) because I'll be releasing v0.4

Oooh... super-exciting news!  I was just checking to see if there had been any updates in my absence.

Link to comment
Share on other sites

9 hours ago, Martin Meredith said:

If you or anyone does want to try out Jocular, please wait for a couple of days (no more) because I'll be releasing v0.4 and the installation procedure has been greatly simplified 🙂: users just need to ensure they have Python and then do a 'pip install jocular'.

I'm treating myself top a new laptop soon, so I'll try to install Jocular again - it does look very nice to use. :)

Link to comment
Share on other sites

Also in the process of figuring out a new laptop. I’m dithering about specs though as I’ll need it to run the software to control all the functions of the scope and obsey  remotely as well as deal with the live stacking. 

Link to comment
Share on other sites

Martin,

Will you be releasing it here or on github as could not find it on there or am i being stupid??? in searching for it sorry for the dumb question  (this is in the latest version). On top of that it is open source and 100% platform-neutral, so anyone can join in on GitHub and take it forward. 

Andy

Link to comment
Share on other sites

40 minutes ago, fozzybear said:

Martin,

Will you be releasing it here or on github as could not find it on there or am i being stupid??? in searching for it sorry for the dumb question  (this is in the latest version). On top of that it is open source and 100% platform-neutral, so anyone can join in on GitHub and take it forward. 

Andy

Hi Andy

It is already on GitHub but maybe Google hasn't picked it up yet. I'll advertise the link when I've completed the next update (this weekend).

Martin

  • Thanks 1
Link to comment
Share on other sites

Just now, Martin Meredith said:

Hi Andy

It is already on GitHub but maybe Google hasn't picked it up yet. I'll advertise the link when I've completed the next update (this weekend).

Martin

Martin

Cheers for the heads up and enjoy your weekend

Many thanks

Andy

Link to comment
Share on other sites

On 19/03/2021 at 09:05, Martin Meredith said:

I added native support for the Lodestar and the SX filter wheel in the last version and that is the way I use it now (ie without SLL). There are some issues that we are trying to sort out getting the SX cameras supported natively on Windows (it will work, just a question of the details). My intention is to support the Ultrastar natively too (this part is easy and is being held up because of the Windows issue).

Great to know I'll be able to use my Lodestar with Jocular without need for SLL (which is still a great tool in its own right!)

2 hours ago, Martin Meredith said:

You can find details here: https://transpy.eu.pythonanywhere.com/jocular 

You've done so much work on this Martin, lots of amazing  features by the look of it, very exciting, I'll have a read through the comprehensive manual to acquaint myself with its feature set. :thumbright:

  • Like 1
Link to comment
Share on other sites

Flawless installation procedure!  Can't wait to try it.

Is this fully compatible with the previous data folders?  ie. can I simply direct it towards my existing data folder (with watch list, masters, ...) ?

I hesistate (but only slightly) to ask about debayering...

Tony

Edited by AKB
Link to comment
Share on other sites

36 minutes ago, AKB said:

Flawless installation procedure!  Can't wait to try it.

Is this fully compatible with the previous data folders?  ie. can I simply direct it towards my existing data folder (with watch list, masters, ...) ?

I hesistate (but only slightly) to ask about debayering...

Tony

Yes, it ought to. The first time you start it up you need to tell it where your data folder is

jocular --datadir <your path>

(Its a long story why this is a command line option and not configured within the program itself, but it has to do with the ugly filebrowser component that was available in the toolkit I'm using...)

Debayering didn't make it into this version as I got carried away with annotation, but I can look into it again. The issue as I recall was being able to detect automatically whether a FITs needed to be debayered (and how) or not, but I could transfer that responsibility to the user...

Now the code is under proper version control I will be able to release updates much more frequently so I will see if this is something that can be done soonish.

cheers

Martin

Link to comment
Share on other sites

1 hour ago, RobertI said:

Great to know I'll be able to use my Lodestar with Jocular without need for SLL (which is still a great tool in its own right!)

You've done so much work on this Martin, lots of amazing  features by the look of it, very exciting, I'll have a read through the comprehensive manual to acquaint myself with its feature set. :thumbright:

Thanks Rob. If you're using Windows then you'll probably run into the same issues with native capture that others are having. As I'm trying to keep the code 100% platform-neutral (internally too ie no 'if Windows do this else do that'), I'm using a library for handling USB that is meant to work with OSX, Windows and Linux, but I'm having difficulties with the Windows side -- something related to permissions. As I don't have access to a Windows machine myself it is hard to work out what is going on. Annoyingly, for the 1 hour I did have access to a Windows machine it was working, so there is an existence proof, but it has proved hard to replicate!

If native capture turns out to be hard to get working, I have a plan B, which is actually turning rapidly into plan A. I've recently acquired a RPi running Astroberry and I want to be able to talk to it from Jocular, but I am determined to remain platform-neutral. The possibility I'm considering is writing a simple(?!) server running on the Pi that converts ALPACA-styled requests coming from Jocular into INDI. This then should also work on Windows using the ALPACA-ASCOM bridge. I don't intend to go the whole hog though: I'd just support a simple subset of commands for the main camera, filterwheel and mount. How difficult could that possibly be?!

Martin

  • Like 2
Link to comment
Share on other sites

39 minutes ago, Martin Meredith said:

jocular --datadir <your path>

I take it that I can run that command at any time?

41 minutes ago, Martin Meredith said:

Debayering didn't make it into this version as I got carried away with annotation, but I can look into it again.

That would be great.  I know that you had identified some possible libraries. Along these lines, can I make a suggestion, motivated by some feedback I’ve received when using Jocular for Zoom observing sessions for the local Astro club?  The folks there are really wowed by what Jocular can do, but always a bit sad when they discover that it won’t really work for their larger cameras... the trend today being for many small pixels.  So...

...if one debayer option was “super-pixel” (using the matrix of four RGGB pixels to produce just one with no processing other than averaging G) then even, say, a 24 Mpixel camera would be readily usable, since this is effectively 2x2 binning. (My current use of a mono Atik 460-EX with 6 Mpixels shows that it works well with that many pixels.). My particular interest is in using this for a ZWO ASI-294MC which has a modest 11 Mpixels.

...just a thought.   Thanks for your consideration!

Link to comment
Share on other sites

Yes, you can use that command at any time. What it does is update a file called .jocular in your home directory which simply contains the path to the data directory. BTW If you still want separate paths for the watched folder I could sort something out now that I have the mechanism in place.

I'll give the debayering/super-pixel some more thought. It is all quite new to me but yes, I have some libraries that seem to do the job. I just need to sort out the user-interaction part, to keep things simple. As you might remember we looked at the FITs headers and there was no clear/consistent convention as to whether a FITs needed debayering, and if so, with what matrix. One way would be for the user to insist on debayering everything and specify the matrix. I believe this is what other software requires.

Martin

 

Link to comment
Share on other sites

10 minutes ago, Martin Meredith said:

One way would be for the user to insist on debayering everything and specify the matrix.

Don’t see anything wrong with that approach.  Bullet proof, which is more than can be said for FITS headers from sundry capture software.  It’s not as though you change your camera that often.  Would be stored on a per-image basis?

Link to comment
Share on other sites

Martin,

I'm seeing an unexpected border around my images... something that hasan't been there before?

Edit:  I've just seen the "Frame size around image" option, and wondered if that's anything to do with it...?

 

2091050387_Screenshot2021-03-21at16_37_31.thumb.png.e8f0b4e5c1570fe74a795556e6e5f569.png

 

 

Edited by AKB
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.