Use Python to retrieve and display images from space

pyroClient.py

I've already talked about most of the libraries used in pyroClient.py (Listing 4), the display script for the interactive version of the sun display, but cherrypy and thread are new. Here, cherrypy turns a Python class into a web server, and thread allows you to start subprocesses that run concurrently with your main program. By combining cherrypy and thread, I can create a web interface that allows the display to be controlled without affecting what's currently displayed on screen.

Listing 4

pyroClient.py

01 import Pyro4
02 import pygame
03 import cPickle as pickle
04 import cherrypy
05 import thread
06
07 class web:
08   def __init__ ( self , server , display ):
09     self.server = server
10     self.display = display
11
12   @cherrypy.expose
13   def index ( self ):
14     html = "<h1>Sun Display Channel Selection</h1>"
15     channels = self.server.channelList()
16     for channel in channels:
17       html += "<div><a href='loadChannel?name=" + \
         channel + "'>" + channel + "</a></div>"
18     return html
19
20   @cherrypy.expose
21   def loadChannel ( self , name ):
22     self.display.remoteLoad = name
23     return self.index()
24
25 class sunDisplay:
26   def __init__ ( self , screen , server ):
27     self.screen = screen
28     self.server = server
29     self.remoteLoad = None
30
31   def getFiles ( self , channel , count ):
32     self.frames = list()
33     files = server.fileList ( channel )
34     for i in range ( count ):
35       if len ( self.frames ) > 0:
36         self.screen.blit ( self.frames [ -1 ] , ( 0 , 0 ) )
37         pygame.display.flip()
38
39       package = server.getFile ( channel , files \
         [ "files" ] [ i ] )
40       sun = pickle.loads ( package.encode ( "ascii" ) )
41       image = pygame.image.fromstring \
         ( sun , ( 768 , 768 ) , "RGB" )
42       self.frames.append ( image )
43       print i
44
45   def loop ( self ):
46     for frame in self.frames:
47       self.screen.blit ( frame , ( 0 , 0 ) )
48       pygame.display.flip()
49
50 uri = raw_input ( "uri" ).strip()
51 sunImages = Pyro4.Proxy ( uri )
52 channels = sunImages.channelList()
53
54 pygame.display.init()
55 screen = pygame.display.set_mode ( ( 1024 , 768 ) )
56
57 display = sunDisplay ( screen , sunImages )
58
59 thread.start_new_thread ( cherrypy.quickstart , \
   ( web ( sunImages , display ) , ) )
60
61 display.getFiles ( channels [ 0 ] , 60 )
62
63 while 1:
64   looping = True
65   while looping:
66     if display.remoteLoad != None: looping = False
67     display.loop()
68   display.getFiles ( display.remoteLoad , 60 )
69   display.remoteLoad = None

The web class (lines 7-23) creates the functions that become web pages on the interface cherrypy, which defaults to port 8080. If I visit [display ip]:8080 then, I'll get the results of the index function. In the init class, all I do is copy parameters to class objects so they are accessible in other class methods. server is the Pyro remote class that connects to pyroServer.py.

The index function creates the simple web page that you see to control the display, and @cherrypy.expose tells CherryPy to make this function accessible via the web interface. Without it, the function won't be accessible as a web page.

On line 15, self.server.channelList is a remote call to pyroServer.py, which will get a list of available channels. Lines 16 and 17 create a <div> and a link for each channel, and line 18 returns the generated HTML.

Next, the loadChannel function accepts one parameter – name – the channel name to load. Because this is a cherrypy function, the parameter must be provided by the web browser as either a GET or POST variable. Line 22 sets remoteLoad in the display class and then returns index again to continue to provide the selection list (line 23).

In the sunDisplay class (lines 25-48), I start by creating class variables from parameters and initializing self.remoteLoad to None.

Again, getFiles retrieves sun images from the server, and self.frames is the list where I store them. After getting the list of file names of the selected channel from the server, the loop starting on line 34 gets the images and uses PyGame to display the most recent frame. Lines 39-42 retrieve the image package from the server, unpack the pickle string, convert the string back to a PyGame surface, and add the unpacked image to the list of current frames.

The short loop function (lines 45-48) shows each frame in the list on the display. Once it's run, the function returns, allowing the display to check whether it needs to change the channel currently being shown.

On line 50, the program asks for the URL of the Pyro server. Once obtained, the connection is established and sunImages.channelList() fetches a list of available channels.

Lines 54-57 start PyGame, save a 1024x768 graphics window to the screen variable, and create the sunDisplay class, passing screen and sunImages to it so that it can access the display and the server.

Line 59 uses threading to start the web server in a separate process. Thus, it runs concurrently with the display and doesn't prevent the screen from updating. Line 61 fetches images from the first channel in the list so that the display will show something immediately; then, the main loop starts.

Lines 63-69 set up an infinite loop and another loop that exits if a new channel has been requested; otherwise, it loops through the images (line 67). If a new channel is requested, lines 68 and 69 fetch the new channel images and set remoteLoad to None so the loop continues, beginning the process again!

Conclusion

The sun display project has become an interesting conglomeration of Python modules as I searched for the best way to handle all of the requirements. The end result, however, is a unique set of displays that offer control and flexibility beyond what is immediately obvious. That flexibility allows planetarium presenters to educate guests more freely and have more options in how they present the SDO materials.

Infos

  1. Fort Worth Museum of Science and History: http://www.fwmsh.org
  2. Solar Dynamics Observatory: https://www.nasa.gov/mission_pages/sdo/main/index.html
  3. SDO data repository: http://sdo.gsfc.nasa.gov/
  4. Listings for this article: ftp://ftp.linux-magazine.com/pub/listings/raspberry-pi-geek.com/13

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content