|
| 1 | +#!/usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | +## Copyright (C) 2016-2017 Mick Phillips <mick.phillips@gmail.com> |
| 5 | +## Copyright (C) 2017 Ian Dobbie <ian.dobbie@bioch.ox.ac.uk> |
| 6 | +## |
| 7 | +## This file is part of Microscope. |
| 8 | +## |
| 9 | +## Microscope is free software: you can redistribute it and/or modify |
| 10 | +## it under the terms of the GNU General Public License as published by |
| 11 | +## the Free Software Foundation, either version 3 of the License, or |
| 12 | +## (at your option) any later version. |
| 13 | +## |
| 14 | +## Microscope is distributed in the hope that it will be useful, |
| 15 | +## but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | +## GNU General Public License for more details. |
| 18 | +## |
| 19 | +## You should have received a copy of the GNU General Public License |
| 20 | +## along with Microscope. If not, see <http://www.gnu.org/licenses/>. |
| 21 | + |
| 22 | +import time |
| 23 | + |
| 24 | +import Pyro4 |
| 25 | +import numpy as np |
| 26 | + |
| 27 | +from microscope import devices |
| 28 | +from microscope.devices import keep_acquiring |
| 29 | +from microscope.filterwheel import FilterWheelBase |
| 30 | + |
| 31 | +#import ximea python module. |
| 32 | +from ximea import xiapi |
| 33 | + |
| 34 | + |
| 35 | +@Pyro4.expose |
| 36 | +@Pyro4.behavior('single') |
| 37 | +class XimaeCamera(devices.CameraDevice): |
| 38 | + def __init__(self, *args, **kwargs): |
| 39 | + super(XimaeCamera, self).__init__(**kwargs) |
| 40 | +#example parameter to allow setting. |
| 41 | +# self.add_setting('_error_percent', 'int', |
| 42 | +# lambda: self._error_percent, |
| 43 | +# self._set_error_percent, |
| 44 | +# lambda: (0, 100)) |
| 45 | + self._acquiring = False |
| 46 | + self._exposure_time = 0.1 |
| 47 | + self._triggered = False |
| 48 | + |
| 49 | + def _purge_buffers(self): |
| 50 | + """Purge buffers on both camera and PC.""" |
| 51 | + self._logger.info("Purging buffers.") |
| 52 | + |
| 53 | + def _create_buffers(self): |
| 54 | + """Create buffers and store values needed to remove padding later.""" |
| 55 | + self._purge_buffers() |
| 56 | + self._logger.info("Creating buffers.") |
| 57 | + #time.sleep(0.5) |
| 58 | + |
| 59 | + def _fetch_data(self): |
| 60 | + if self._acquiring and self._triggered: |
| 61 | + self.handle.get_image(self.img) |
| 62 | + self._logger.info('Sending image') |
| 63 | + self._triggered = False |
| 64 | + return self.img.get_image_data_raw() |
| 65 | + |
| 66 | + def abort(self): |
| 67 | + self._logger.info('Disabling acquisition.') |
| 68 | + if self._acquiring: |
| 69 | + self._acquiring = False |
| 70 | + self.handle.stop_acquisition() |
| 71 | + |
| 72 | + def initialize(self): |
| 73 | + """Initialise the camera. |
| 74 | +
|
| 75 | + Open the connection, connect properties and populate settings dict. |
| 76 | + """ |
| 77 | + |
| 78 | + try: |
| 79 | + self.handle = xiapi.Camera() |
| 80 | + self.handle.open_device() |
| 81 | + except: |
| 82 | + raise Exception("Problem opening camera.") |
| 83 | + if self.handle == None: |
| 84 | + raise Exception("No camera opened.") |
| 85 | + |
| 86 | +# for name, var in sorted(self.__dict__.items()): |
| 87 | + self._logger.info('Initializing.') |
| 88 | + #create img buffer to hold images. |
| 89 | + self.img=xiapi.Image() |
| 90 | + |
| 91 | + def make_safe(self): |
| 92 | + if self._acquiring: |
| 93 | + self.abort() |
| 94 | + |
| 95 | + def _on_disable(self): |
| 96 | + self.abort() |
| 97 | + |
| 98 | + def _on_enable(self): |
| 99 | + self._logger.info("Preparing for acquisition.") |
| 100 | + if self._acquiring: |
| 101 | + self.abort() |
| 102 | + self._create_buffers() |
| 103 | + self._acquiring = True |
| 104 | + #actually start camera |
| 105 | + self.handle.start_acquisition() |
| 106 | + self._logger.info("Acquisition enabled.") |
| 107 | + return True |
| 108 | + |
| 109 | + def set_exposure_time(self, value): |
| 110 | + #exposure times are set in us. |
| 111 | + self.handle.set_exposure(value*1.0E6) |
| 112 | + |
| 113 | + def get_exposure_time(self): |
| 114 | + #exposure times are in us, so multiple by 1E-6 to get seconds. |
| 115 | + return (self.handle.get_exposure()*1.0E-6) |
| 116 | + |
| 117 | + def get_cycle_time(self): |
| 118 | + return (self.handle.get_exposure()*1.0E-6) |
| 119 | + |
| 120 | + def _get_sensor_shape(self): |
| 121 | + return (self.img.width,self.image.height) |
| 122 | + |
| 123 | + def get_trigger_type(self): |
| 124 | + return devices.TRIGGER_SOFT |
| 125 | + |
| 126 | + def soft_trigger(self): |
| 127 | + self._logger.info('Trigger received; self._acquiring is %s.' |
| 128 | + % self._acquiring) |
| 129 | + if self._acquiring: |
| 130 | + self._triggered = True |
| 131 | + |
| 132 | + def _get_binning(self): |
| 133 | + return (1,1) |
| 134 | + |
| 135 | + @keep_acquiring |
| 136 | + def _set_binning(self, h, v): |
| 137 | + return False |
| 138 | + |
| 139 | + def _get_roi(self): |
| 140 | + return (0, 0, 512, 512) |
| 141 | + |
| 142 | + @keep_acquiring |
| 143 | + def _set_roi(self, x, y, width, height): |
| 144 | + return False |
| 145 | + |
| 146 | + def _on_shutdown(self): |
| 147 | + if self_.acquiring: |
| 148 | + self.handle.stop_acquisition() |
| 149 | + self.handle.close_device() |
| 150 | + |
0 commit comments