1- #!/usr/bin/env python
2- # -*- coding: utf-8 -*-
1+ #!/usr/bin/env python3
32
43## Copyright (C) 2016-2017 Mick Phillips <mick.phillips@gmail.com>
54## Copyright (C) 2019 Ian Dobbie <ian.dobbie@bioch.ox.ac.uk>
2019## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
2120
2221import time
22+ from io import BytesIO
2323
24- import Pyro4
2524import numpy as np
25+ import Pyro4
2626
27- from microscope import devices
28- from microscope .devices import keep_acquiring , Binning , Roi
29-
30- #import raspberry pi specific modules
27+ # import raspberry pi specific modules
3128import picamera
3229import picamera .array
33- from io import BytesIO
34- #to allow hardware trigger.
30+ # to allow hardware trigger.
3531import RPi .GPIO as GPIO
36- GPIO_Trigger = 21
32+
33+ from microscope import devices
34+ from microscope .devices import Binning , Roi , keep_acquiring
35+
36+
37+ GPIO_Trigger = 21
3738
3839
3940# Trigger mode to type.
4041TRIGGER_MODES = {
41- ' internal' : None ,
42- ' external' : devices .TRIGGER_BEFORE ,
43- ' external start' : None ,
44- ' external exposure' : devices .TRIGGER_DURATION ,
45- ' software' : devices .TRIGGER_SOFT ,
42+ " internal" : None ,
43+ " external" : devices .TRIGGER_BEFORE ,
44+ " external start" : None ,
45+ " external exposure" : devices .TRIGGER_DURATION ,
46+ " software" : devices .TRIGGER_SOFT ,
4647}
4748
4849
4950@Pyro4 .expose
50- @Pyro4 .behavior (' single' )
51+ @Pyro4 .behavior (" single" )
5152class PiCamera (devices .CameraDevice ):
5253 def __init__ (self , * args , ** kwargs ):
5354 super (PiCamera , self ).__init__ (** kwargs )
54- # example parameter to allow setting.
55- # self.add_setting('_error_percent', 'int',
56- # lambda: self._error_percent,
57- # self._set_error_percent,
58- # lambda: (0, 100))
55+ # example parameter to allow setting.
56+ # self.add_setting('_error_percent', 'int',
57+ # lambda: self._error_percent,
58+ # self._set_error_percent,
59+ # lambda: (0, 100))
5960 self ._acquiring = False
6061 self ._exposure_time = 0.1
6162 self ._triggered = False
6263 self .camera = None
6364 # Region of interest.
6465 self .roi = Roi (None , None , None , None )
6566 # Cycle time
66- self .exposure_time = 0.001 # in seconds
67+ self .exposure_time = 0.001 # in seconds
6768 self .cycle_time = self .exposure_time
68- #initialise in soft trigger mode
69- self .trigger = devices .TRIGGER_SOFT
70- #setup hardware triggerline
69+ # initialise in soft trigger mode
70+ self .trigger = devices .TRIGGER_SOFT
71+ # setup hardware triggerline
7172 GPIO .setmode (GPIO .BCM )
7273 GPIO .setup (GPIO_Trigger .GPIO .IN )
7374
74- #when a rasing edge is detected on port GPIO_Trigger,
75- #regardless of whatever else is happening in the program, the
76- #function self._HW_trigger will be run
77- GPIO .add_event_detect (GPIO_Trigger , GPIO .RAISING ,
78- callback = self ._HW_trigger , bouncetime = 10 )
79-
80-
75+ # when a rasing edge is detected on port GPIO_Trigger,
76+ # regardless of whatever else is happening in the program, the
77+ # function self._HW_trigger will be run
78+ GPIO .add_event_detect (
79+ GPIO_Trigger ,
80+ GPIO .RAISING ,
81+ callback = self ._HW_trigger ,
82+ bouncetime = 10 ,
83+ )
8184
8285 def _HW_trigger (self ):
83- '''Function called by GPIO interupt, needs to trigger image capture'''
84- print ('PiCam HW trigger' )
85-
86+ """Function called by GPIO interupt, needs to trigger image capture"""
87+ print ("PiCam HW trigger" )
8688
8789 def _fetch_data (self ):
8890 if self ._acquiring and self ._triggered :
8991 with picamera .array .PiYUVArray (self .camera ) as output :
90- self .camera .capture (output , format = ' yuv' , use_video_port = False )
91- #just return intensity values
92- self ._logger .info (' Sending image' )
92+ self .camera .capture (output , format = " yuv" , use_video_port = False )
93+ # just return intensity values
94+ self ._logger .info (" Sending image" )
9395 self ._triggered = False
94- return ( output .array [:,:, 0 ])
96+ return output .array [:, :, 0 ]
9597
9698 def initialize (self ):
9799 """Initialise the Pi Camera camera.
98100 Open the connection, connect properties and populate settings dict.
99101 """
100102 if not self .camera :
101103 try :
102- #initialise camera in still image mode.
103- self .camera = picamera .PiCamera (sensor_mode = 2 )
104+ # initialise camera in still image mode.
105+ self .camera = picamera .PiCamera (sensor_mode = 2 )
104106 except :
105107 raise Exception ("Problem opening camera." )
106- self ._logger .info (' Initializing camera.' )
107- #create img buffer to hold images.
108- #disable camera LED by default
108+ self ._logger .info (" Initializing camera." )
109+ # create img buffer to hold images.
110+ # disable camera LED by default
109111 self .setLED (False )
110112 self ._get_sensor_shape ()
111-
113+
112114 def make_safe (self ):
113115 if self ._acquiring :
114116 self .abort ()
115-
117+
116118 def _on_disable (self ):
117119 self .abort ()
118120
@@ -121,24 +123,24 @@ def _on_enable(self):
121123 if self ._acquiring :
122124 self .abort ()
123125 self ._acquiring = True
124- #actually start camera
126+ # actually start camera
125127 self ._logger .info ("Acquisition enabled." )
126128 return True
127129
128130 def abort (self ):
129- self ._logger .info (' Disabling acquisition.' )
131+ self ._logger .info (" Disabling acquisition." )
130132 if self ._acquiring :
131133 self ._acquiring = False
132-
133134
134- def set_trigger_type (self ,trigger ):
135- if ( trigger == devices .TRIGGER_SOFT ) :
135+ def set_trigger_type (self , trigger ):
136+ if trigger == devices .TRIGGER_SOFT :
136137 GPIO .remove_event_detect (GPIO_Trigger )
137- self .trigger = devices .TRIGGER_SOFT
138- elif (trigger == devices .TRIGGER_BEFORE ):
139- GPIO .add_event_detect (GPIO_Trigger ,RISING ,
140- self .HWtrigger ,self .exposure_time )
141- self .trigger = devices .TRIGGER_BEFORE
138+ self .trigger = devices .TRIGGER_SOFT
139+ elif trigger == devices .TRIGGER_BEFORE :
140+ GPIO .add_event_detect (
141+ GPIO_Trigger , RISING , self .HWtrigger , self .exposure_time
142+ )
143+ self .trigger = devices .TRIGGER_BEFORE
142144
143145 def get_trigger_type (self ):
144146 return self .trigger
@@ -151,59 +153,52 @@ def _set_binning(self, h_bin, v_bin):
151153 return True
152154
153155 def _get_binning (self ):
154- return ( Binning (1 ,1 ) )
156+ return Binning (1 , 1 )
155157
156158 @keep_acquiring
157159 def _set_roi (self , left , top , width , height ):
158160 """Set the ROI to (left, tip, width, height)."""
159161 self .roi = Roi (left , top , width , height )
160-
161-
162- #set camera LED status, off is best for microscopy.
163- def setLED (self , state = False ):
164- print ('self.camera.led(state)' )
165162
163+ # set camera LED status, off is best for microscopy.
164+ def setLED (self , state = False ):
165+ print ("self.camera.led(state)" )
166166
167167 def set_exposure_time (self , value ):
168- #exposure times are set in us.
169- self .camera .shutter_speed = (int (value * 1.0E6 ))
170-
168+ # exposure times are set in us.
169+ self .camera .shutter_speed = int (value * 1.0e6 )
171170
172171 def get_exposure_time (self ):
173- #exposure times are in us, so multiple by 1E-6 to get seconds.
174- return (self .camera .exposure_speed * 1.0E-6 )
175-
172+ # exposure times are in us, so multiple by 1E-6 to get seconds.
173+ return self .camera .exposure_speed * 1.0e-6
176174
177175 def get_cycle_time (self ):
178- #fudge to make it work initially
179- #exposure times are in us, so multiple by 1E-6 to get seconds.
180- return ( self .camera .exposure_speed * 1.0E-6 + .1 )
176+ # fudge to make it work initially
177+ # exposure times are in us, so multiple by 1E-6 to get seconds.
178+ return self .camera .exposure_speed * 1.0e-6 + 0.1
181179
182-
183180 def _get_sensor_shape (self ):
184- res = self .camera .resolution
185- self ._set_roi (0 ,0 , res [0 ],res [1 ])
186- return ( res )
181+ res = self .camera .resolution
182+ self ._set_roi (0 , 0 , res [0 ], res [1 ])
183+ return res
187184
188185 def soft_trigger (self ):
189- self ._logger .info ('Trigger received; self._acquiring is %s.'
190- % self ._acquiring )
186+ self ._logger .info (
187+ "Trigger received; self._acquiring is %s." % self ._acquiring
188+ )
191189 if self ._acquiring :
192190 self ._triggered = True
193191
194-
195192 def HWtrigger (self , pin ):
196- self ._logger .info (' HWTrigger received' )
193+ self ._logger .info (" HWTrigger received" )
197194
198-
199- #ongoing implemetation notes
200195
201- #should be able to use rotation and hflip to set specific output image
202- # rotations
196+ # ongoing implemetation notes
203197
204- #roi's can be set with the zoom function, default is (0,0,1,1) meaning all the data.
205-
206- #Need to setup a buffer for harware triggered data aquisition so we can
207- #call the acquisition and then download the data at our leasure
198+ # should be able to use rotation and hflip to set specific output image
199+ # rotations
208200
201+ # roi's can be set with the zoom function, default is (0,0,1,1) meaning all the data.
209202
203+ # Need to setup a buffer for harware triggered data aquisition so we can
204+ # call the acquisition and then download the data at our leasure
0 commit comments