def take_exposure(self, timeout: float = inf) -> np.ndarray: """Take an exposure in non-video mode. This method will poll the camera driver in a loop until the camera indicates that the exposure has completed. To avoid pegging the CPU in this loop, a sleep statement is used with a period of 10 ms. This approach should be reasonable for single exposures. Use other methods when video is desired. Args: timeout: How long to wait for exposure to complete in seconds. The default value inf can be used to disable timeout. Returns: A numpy array containing a raw camera frame. No debayering is performed. Raises: RuntimeError if the exposure failed. CameraTimeout if the timeout expires before exposure completes. """ ASICheck(asi.ASIStartExposure(self.info.CameraID, asi.ASI_FALSE)) start_time = time.perf_counter() while True: time.sleep(0.01) status = ASICheck(asi.ASIGetExpStatus(self.info.CameraID)) if status == asi.ASI_EXP_SUCCESS: break if status == asi.ASI_EXP_FAILED: raise RuntimeError('Exposure failed') if time.perf_counter() - start_time > timeout: raise CameraTimeout('Timeout waiting for exposure completion') frame = ASICheck( asi.ASIGetDataAfterExp(self.info.CameraID, self._frame_size_bytes)) return self._reshape_frame_data(frame)
def __init__( self, pixel_scale: float, binning: int = 1, video_mode: bool = False, name: str = None, ): """Initialize and configure ZWO ASI camera. Args: pixel_scale: Scale of a pixel in degrees per pixel before binning. binning: Camera binning. video_mode: False for one-shot mode, True for video mode. name: Connect only to a camera where the Name member of the info struct matches this string. If None the name is not checked and the first camera is used. Note that multiple cameras could have the same Name; when this is the case, this constructor will connect to the first camera having a Name that matches. Raises: ASIError for any camera related problems. """ num_connected = asi.ASIGetNumOfConnectedCameras() if num_connected == 0: raise ASIError('No cameras connected') # find the right camera self.info = None for idx in range(num_connected): # pylint does not seem to handle SWIG bindings perfectly # pylint: disable=no-value-for-parameter info = ASICheck(asi.ASIGetCameraProperty(idx)) if name is None or name == info.Name: self.info = info break if self.info is None: raise ASIError(f'Could not find a camera with name "{name}"') self._pixel_scale = pixel_scale self._binning = binning width = self.info.MaxWidth // binning height = self.info.MaxHeight // binning self._frame_shape = (height, width) ASICheck(asi.ASIOpenCamera(self.info.CameraID)) ASICheck(asi.ASIInitCamera(self.info.CameraID)) ASICheck( asi.ASISetControlValue(self.info.CameraID, asi.ASI_MONO_BIN, 1, asi.ASI_FALSE)) ASICheck( asi.ASISetControlValue(self.info.CameraID, asi.ASI_BANDWIDTHOVERLOAD, 94, asi.ASI_FALSE)) self.video_mode = video_mode
def video_mode(self, enabled: bool) -> None: """Enable or disable video mode""" self._bit_depth = self.BitDepth.RAW8 if enabled else self.BitDepth.RAW16 height, width = self._frame_shape self._frame_size_bytes = width * height * self._bit_depth.bytes_per_pixel( ) ASICheck( asi.ASISetROIFormat(self.info.CameraID, width, height, self._binning, self._bit_depth)) if enabled: ASICheck( asi.ASISetControlValue(self.info.CameraID, asi.ASI_HIGH_SPEED_MODE, 1, asi.ASI_FALSE)) ASICheck(asi.ASIStartVideoCapture(self.info.CameraID)) else: ASICheck( asi.ASISetControlValue(self.info.CameraID, asi.ASI_HIGH_SPEED_MODE, 0, asi.ASI_FALSE)) ASICheck(asi.ASIStopVideoCapture(self.info.CameraID)) self._video_mode = enabled
def get_dropped_frames(self) -> int: """Get number of dropped frames so far""" return ASICheck(asi.ASIGetDroppedFrames(self.info.CameraID))
def _get_ctrl(self, ctrl): return ASICheck(asi.ASIGetControlValue(self.info.CameraID, ctrl))
def _set_ctrl(self, ctrl, value: int): # auto mode always disabled since we generally don't trust it ASICheck( asi.ASISetControlValue(self.info.CameraID, ctrl, value, asi.ASI_FALSE))
def __del__(self): if hasattr(self, 'info') and self.info is not None: ASICheck(asi.ASICloseCamera(self.info.CameraID))