Beispiel #1
0
 class Signals:
     layout = Signal('layout', arg_types=(object,))
     sample = Signal('sample', arg_types=(object,))
     next_port =Signal('next-port', arg_types=(object,))
     ports = Signal('ports', arg_types=(object,))
     containers = Signal('containers', arg_types=(object,))
     status = Signal('status', arg_types=(object,))
     failure = Signal('failure', arg_types=(object,))
Beispiel #2
0
 class Signals:
     temp = Signal('temp', arg_types=(float, ))
     level = Signal('level', arg_types=(float, ))
     sample = Signal('sample', arg_types=(float, ))
     shield = Signal('shield', arg_types=(float, ))
     pos = Signal('position', arg_types=(object, ))
Beispiel #3
0
 class Signals:
     result = Signal('result', arg_types=(int, object))
     grid = Signal('grid', arg_types=(object, ))
Beispiel #4
0
class ImageWidget(Gtk.DrawingArea):
    image_loaded = Signal("image-loaded", arg_types=())

    def __init__(self, size):
        super().__init__()
        self.surface = None
        self.is_rubber_banding = False
        self.is_shifting = False
        self.is_measuring = False
        self.pseudocolor = True
        self.image_loaded = False
        self.show_histogram = False
        self._canvas_is_clean = False

        self.display_gamma = 1.0
        self.gamma = 0
        self.scale = 1.0

        self.extents_back = []
        self.extents_forward = []
        self.extents = None
        self.select_reflections()

        self.set_events(Gdk.EventMask.EXPOSURE_MASK
                        | Gdk.EventMask.LEAVE_NOTIFY_MASK
                        | Gdk.EventMask.BUTTON_PRESS_MASK
                        | Gdk.EventMask.BUTTON_RELEASE_MASK
                        | Gdk.EventMask.POINTER_MOTION_MASK
                        | Gdk.EventMask.POINTER_MOTION_HINT_MASK
                        | Gdk.EventMask.VISIBILITY_NOTIFY_MASK
                        | Gdk.EventMask.SCROLL_MASK)

        self.connect('visibility-notify-event', self.on_visibility_notify)
        self.connect('unmap', self.on_unmap)
        self.connect('motion-notify-event', self.on_mouse_motion)
        self.connect('button_press_event', self.on_mouse_press)
        self.connect('scroll-event', self.on_mouse_scroll)
        self.connect('button_release_event', self.on_mouse_release)
        self.set_size_request(size, size)
        self.palettes = {
            True: color_palette(cmaps.inferno),
            False: color_palette(cmaps.binary)
        }

        self.data_loader = DataLoader()
        self.data_loader.connect('new-image', self.on_data_loaded)

    def select_reflections(self, reflections=None):
        if reflections is not None:
            diff = (reflections[:, 2] - self.frame_number)
            frame_sel = (diff >= 0) & (diff < 1)
            frame_reflections = reflections[frame_sel]
            sel = numpy.abs(frame_reflections[:, 4:]).sum(1) > 0
            indexed = frame_reflections[sel]
            unindexed = frame_reflections[~sel]

            self.indexed_spots = indexed
            self.unindexed_spots = unindexed
        else:
            self.indexed_spots = []
            self.unindexed_spots = []

    def open(self, filename):
        self.data_loader.open(filename)

    def show(self, frame):
        self.data_loader.show(frame)

    def on_data_loaded(self, obj):
        self.image_header = obj.header
        self.beam_x, self.beam_y = obj.header['beam_center']
        self.pixel_size = obj.header['pixel_size']
        self.distance = obj.header['distance']
        self.wavelength = obj.header['wavelength']
        self.pixel_data = obj.data.T
        self.raw_img = obj.image
        self.frame_number = obj.header['frame_number']
        self.filename = obj.header['filename']
        self.name = '{} [ {} ]'.format(obj.header['name'], self.frame_number)
        self.image_size = obj.header['detector_size']
        self.create_surface()
        self.emit('image-loaded')

    def create_surface(self):
        self.image_width, self.image_height = self.image_size
        width = min(self.image_width, self.image_height)
        if not self.extents:
            self.extents = (1, 1, width - 2, width - 2)
        else:
            ox, oy, ow, oh = self.extents
            nx = min(ox, self.image_width)
            ny = min(oy, self.image_height)
            nw = nh = max(
                16, min(ow, oh, self.image_width - nx, self.image_height - ny))
            self.extents = (nx, ny, nw, nh)
        self.surface = cairo.ImageSurface.create_for_data(
            self.raw_img, cairo.FORMAT_ARGB32, self.image_width,
            self.image_height)
        self.image_loaded = True
        self.queue_draw()

    def get_image_info(self):
        return self.data_loader

    def get_line_profile(self, x1, y1, x2, y2, width=1):
        x1, y1 = self.get_position(x1, y1)[:2]
        x2, y2 = self.get_position(x2, y2)[:2]
        vmin = 0
        vmax = self.image_header['saturated_value']

        coords = line(x1, y1, x2, y2)

        data = numpy.zeros((len(coords), 3))
        n = 0
        for ix, iy in coords:
            ix = max(1, ix)
            iy = max(1, iy)
            data[n][0] = n
            src = self.pixel_data[ix - width:ix + width, iy - width:iy + width]
            sel = (src > vmin) & (src < vmax)
            if sel.sum():
                val = src[sel].mean()
            else:
                val = numpy.nan
            data[n][2] = val
            data[n][1] = self.radial_distance(ix, iy, coords[0][0],
                                              coords[0][1])
            n += 1
        return data[:, 1:]

    def make_histogram(self, data, show_axis=None, distance=True):
        color = colors.Category.CAT20C[0]
        matplotlib.rcParams.update({'font.size': 9.5})
        figure = Figure(frameon=False, figsize=(4, 2), dpi=72, edgecolor=color)
        specs = matplotlib.gridspec.GridSpec(ncols=8, nrows=1, figure=figure)
        plot = figure.add_subplot(specs[0, 1:7])
        plot.patch.set_alpha(1.0)
        adjust_spines(plot, ['left'], color)
        formatter = FormatStrFormatter('%g')
        plot.yaxis.set_major_formatter(formatter)
        plot.yaxis.set_major_locator(MaxNLocator(5))

        if distance:
            plot.plot(data[:, 0], data[:, 1], lw=0.75)
        else:
            plot.vlines(data[:, 0], 0, data[:, 1])

        plot.set_xlim(min(data[:, 0]), max(data[:, 0]))

        # Ask matplotlib to render the figure to a bitmap using the Agg backend
        canvas = FigureCanvasCairo(figure)
        width, height = canvas.get_width_height()
        renderer = RendererCairo(canvas.figure.dpi)
        renderer.set_width_height(width, height)
        self.plot_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width,
                                               height)
        renderer.set_ctx_from_surface(self.plot_surface)
        canvas.figure.draw(renderer)
        self.show_histogram = True

    def draw_overlay_cairo(self, cr):
        # rubber band
        cr.set_line_width(2)
        cr.set_source_rgba(0.0, 0.5, 1.0, 1.0)
        if self.is_rubber_banding:
            x, y, w, h = bounding_box(self.rubber_x0, self.rubber_y0,
                                      self.rubber_x1, self.rubber_y1)
            cr.rectangle(x, y, w, h)
            cr.stroke()

        # cross
        x, y, w, h = self.extents
        radius = 16 * self.scale
        if (0 < (self.beam_x - x) < x + w) and (0 < (self.beam_y - y) < y + h):
            cx = int((self.beam_x - x) * self.scale)
            cy = int((self.beam_y - y) * self.scale)
            cr.move_to(cx - radius, cy)
            cr.line_to(cx + radius, cy)
            cr.stroke()
            cr.move_to(cx, cy - radius)
            cr.line_to(cx, cy + radius)
            cr.stroke()
            cr.arc(cx, cy, radius / 2, 0, 2.0 * numpy.pi)

        # measuring
        if self.is_measuring:
            cr.set_line_width(2)
            cr.move_to(self.meas_x0, self.meas_y0)
            cr.line_to(self.meas_x1, self.meas_y1)
            cr.stroke()

        # Filename
        pcontext = self.get_pango_context()
        alloc = self.get_allocation()
        font_desc = pcontext.get_font_description()
        cr.select_font_face(font_desc.get_family(), cairo.FONT_SLANT_NORMAL,
                            cairo.FONT_WEIGHT_BOLD)
        cr.set_font_size(11)
        cr.move_to(6, alloc.height - 6)
        cr.show_text(self.name)
        cr.stroke()

    def draw_spots(self, cr):
        # draw spots
        x, y, w, h = self.extents
        cr.set_line_width(0.75)
        cr.set_source_rgba(0.0, 0.5, 1.0, 1.0)
        for i, spots in enumerate([self.indexed_spots, self.unindexed_spots]):
            if i == 0:
                cr.set_source_rgba(0.0, 0.5, 1.0, 0.75)
            else:
                cr.set_source_rgba(1.0, 0.5, 0.0, 0.75)
            for spot in spots:
                sx, sy = spot[:2]
                if (0 < (sx - x) < x + w) and (0 < (sy - y) < y + h):
                    cx = int((sx - x) * self.scale)
                    cy = int((sy - y) * self.scale)
                    cr.arc(cx, cy, 16 * self.scale, 0, 2.0 * numpy.pi)
                    cr.stroke()

    def go_back(self, full=False):
        if len(self.extents_back) > 0 and not full:
            self.extents = self.extents_back.pop()
        else:
            self.extents = (1, 1, self.image_width - 2, self.image_height - 2)
            self.extents_back = []
        self.queue_draw()
        return len(self.extents_back) > 0

    def colorize(self, color=False):
        if color:
            self.data_loader.set_colormap(1)
        else:
            self.data_loader.set_colormap(0)
        self.data_loader.setup()

    def reset_filters(self):
        self.data_loader.adjust()

    def get_position(self, x, y):
        if not self.image_loaded:
            return 0, 0, 0.0, 0

        ix, iy = self.screen_to_image(x, y)
        Res = self.image_resolution(ix, iy)
        return ix, iy, Res, self.pixel_data[ix, iy]

    def save_surface(self, path):
        self.surface.write_to_png(path)
        logger.info('Image saved to PNG: {}'.format(path))

    def screen_to_image(self, x, y):
        ix = int(x / self.scale) + self.extents[0]
        iy = int(y / self.scale) + self.extents[1]
        ix = max(1, min(ix, self.image_width - 2))
        iy = max(1, min(iy, self.image_height - 2))
        return ix, iy

    def image_resolution(self, x, y):
        displacement = self.pixel_size * math.sqrt((x - self.beam_x)**2 +
                                                   (y - self.beam_y)**2)
        if self.distance == 0.0:
            angle = math.pi / 2
        else:
            angle = 0.5 * math.atan(displacement / self.distance)
        if angle < 1e-3:
            angle = 1e-3
        return self.wavelength / (2.0 * math.sin(angle))

    def radial_distance(self, x0, y0, x1, y1):
        d = math.sqrt((x0 - x1)**2 + (y0 - y1)**2) * self.pixel_size
        return d  # (self.wavelength * self.distance/d)

    def set_cursor_mode(self, cursor=None):
        window = self.get_window()
        if window is None:
            return
        if cursor is None:
            window.set_cursor(None)
        else:
            window.set_cursor(Gdk.Cursor.new(cursor))
        Gtk.main_iteration()

    # callbacks
    def on_mouse_motion(self, widget, event):
        if not self.image_loaded:
            return False

        # print event.get_state().value_names
        alloc = self.get_allocation()
        w, h = alloc.width, alloc.height
        if 'GDK_BUTTON1_MASK' in event.get_state(
        ).value_names and self.is_rubber_banding:
            self.rubber_x1 = max(min(w - 1, event.x), 0) + 0.5
            self.rubber_y1 = max(min(h - 1, event.y), 0) + 0.5
            self.queue_draw()
        elif 'GDK_BUTTON2_MASK' in event.get_state(
        ).value_names and self.is_shifting:
            self.shift_x1 = event.x
            self.shift_y1 = event.y
            ox, oy, ow, oh = self.extents
            nx = int((self.shift_x0 - self.shift_x1) / self.scale) + ox
            ny = int((self.shift_y0 - self.shift_y1) / self.scale) + oy
            nw = ow
            nh = oh
            nx = max(0, nx)
            ny = max(0, ny)
            if nx + nw > self.image_width:
                nx = self.image_width - nw
            if ny + nh > self.image_height:
                ny = self.image_height - nh
            if self.extents != (nx, ny, nw, nh):
                self.extents = (nx, ny, nw, nh)
                self.shift_x0 = self.shift_x1
                self.shift_y0 = self.shift_y1
                self.queue_draw()
        elif 'GDK_BUTTON3_MASK' in event.get_state(
        ).value_names and self.is_measuring:
            self.meas_x1 = int(max(min(w - 1, event.x), 0)) + 0.5
            self.meas_y1 = int(max(min(h - 1, event.y), 0)) + 0.5
            self.queue_draw()

        return False

    def on_mouse_scroll(self, widget, event):
        if not self.image_loaded:
            return False
        if event.direction == Gdk.ScrollDirection.UP:
            self.data_loader.adjust(1)
        elif event.direction == Gdk.ScrollDirection.DOWN:
            self.data_loader.adjust(-1)

    def on_mouse_press(self, widget, event):
        self.show_histogram = False
        if not self.image_loaded:
            return False

        alloc = self.get_allocation()
        w, h = alloc.width, alloc.height
        if event.button == 1:
            self.rubber_x0 = max(min(w, event.x), 0) + 0.5
            self.rubber_y0 = max(min(h, event.y), 0) + 0.5
            self.rubber_x1, self.rubber_y1 = self.rubber_x0, self.rubber_y0
            self.is_rubber_banding = True
            self.set_cursor_mode(Gdk.CursorType.TCROSS)
        elif event.button == 2:
            self.set_cursor_mode(Gdk.CursorType.FLEUR)
            self.shift_x0 = max(min(w, event.x), 0)
            self.shift_y0 = max(min(w, event.y), 0)
            self.shift_x1, self.shift_y1 = self.shift_x0, self.shift_y0
            self._shift_start_extents = self.extents
            self.is_shifting = True
            self.set_cursor_mode(Gdk.CursorType.FLEUR)
        elif event.button == 3:
            self.meas_x0 = int(max(min(w, event.x), 0))
            self.meas_y0 = int(max(min(h, event.y), 0))
            self.meas_x1, self.meas_y1 = self.meas_x0, self.meas_y0
            self.is_measuring = True
            self.set_cursor_mode(Gdk.CursorType.TCROSS)

    def on_mouse_release(self, widget, event):
        if not self.image_loaded:
            return False
        if self.is_rubber_banding:
            self.is_rubber_banding = False
            x0, y0 = self.screen_to_image(self.rubber_x0, self.rubber_y0)
            x1, y1 = self.screen_to_image(self.rubber_x1, self.rubber_y1)
            x, y, w, h = bounding_box(x0, y0, x1, y1)
            if min(w, h) < 10: return
            self.extents_back.append(self.extents)
            self.extents = (x, y, w, h)
            self.queue_draw()
        elif self.is_measuring:
            self.is_measuring = False
            # prevent zero-length lines
            self.histogram_data = self.get_line_profile(
                self.meas_x0, self.meas_y0, self.meas_x1, self.meas_y1, 2)
            if len(self.histogram_data) > 4:
                self.make_histogram(self.histogram_data, show_axis=[
                    'left',
                ])
                self.queue_draw()
        elif self.is_shifting:
            self.is_shifting = False
            self.extents_back.append(self._shift_start_extents)

        self.set_cursor_mode()

    def do_draw(self, cr):
        if self.surface is not None:
            alloc = self.get_allocation()
            width = min(alloc.width, alloc.height)
            self.scale = float(width) / self.extents[2]

            cr.save()
            cr.scale(self.scale, self.scale)
            cr.translate(-self.extents[0], -self.extents[1])
            cr.set_source_surface(self.surface, 0, 0)
            if self.scale >= 1:
                cr.get_source().set_filter(cairo.FILTER_FAST)
            else:
                cr.get_source().set_filter(cairo.FILTER_GOOD)
            cr.paint()
            cr.restore()

            if self.show_histogram:
                px = alloc.width - self.plot_surface.get_width() - 10
                py = alloc.height - self.plot_surface.get_height() - 10
                cr.save()
                cr.set_source_surface(self.plot_surface, px, py)
                cr.paint()
                cr.restore()

            self.draw_overlay_cairo(cr)
            self.draw_spots(cr)
            self._canvas_is_clean = True

    def on_visibility_notify(self, obj, event):
        if event.get_state() == Gdk.VisibilityState.FULLY_OBSCURED:
            self.stopped = True
        else:
            self.stopped = False

    def on_unmap(self, obj):
        self.stopped = True
Beispiel #5
0
 class Signals:
     mode = Signal("mode", arg_types=(object, ))
Beispiel #6
0
 class Signals:
     changed = Signal("changed", arg_types=(float, ))
     percent = Signal("percent", arg_types=(float, ))
Beispiel #7
0
 class Signals:
     ready = Signal("ready", arg_types=(bool, ))
Beispiel #8
0
 class Signals:
     running = Signal('running', arg_types=())
     collision = Signal('collision', arg_types=())
Beispiel #9
0
 class Signals:
     changed = Signal('samples-changed', arg_types=(object,))
     active = Signal('active-sample', arg_types=(object,))
     selected = Signal('sample-selected', arg_types=(object,))
Beispiel #10
0
 class Signals:
     changed = Signal("changed", arg_types=(bool,))
Beispiel #11
0
 class Signals:
     selected = Signal("selected", arg_types=(str, ))
Beispiel #12
0
 class Signals:
     sample_done = Signal('sample-done', arg_types=(str, ))
     sample_started = Signal('sample-started', arg_types=(str, ))
Beispiel #13
0
 class Signals:
     message = Signal('message', arg_types=(str, str))
     config = Signal('config', arg_types=(object,))
Beispiel #14
0
 class Signals:
     message = Signal('message', arg_types=(str, ))
Beispiel #15
0
 class Signals:
     updated = Signal("updated", arg_types=())
Beispiel #16
0
 class Signals:
     high = Signal('high', arg_types=(bool, ))
Beispiel #17
0
 class Signals:
     added = Signal('added', arg_types=(object, ))
     removed = Signal('removed', arg_types=(object, ))
Beispiel #18
0
 class Signals:
     state = Signal("state", arg_types=(object, ))
     new_image = Signal("new-image", arg_types=(object, ))
     progress = Signal("progress", arg_types=(float, str))
Beispiel #19
0
 class Signals:
     resized = Signal("resized", arg_types=(int, int))
Beispiel #20
0
 class Signals:
     sig_int = Signal('sig-int', arg_types=(int, ))
     sig_float = Signal('sig-float', arg_types=(float, ))
     sig_str = Signal('sig-str', arg_types=(str, ))
     sig_bool = Signal('sig-bool', arg_types=(bool, ))
Beispiel #21
0
 class Signals:
     report = Signal('new-report', arg_types=(str, object))
Beispiel #22
0
 class Signals:
     sig_multi = Signal('sig-multi', arg_types=(int, bool, float))
Beispiel #23
0
 class Signals:
     changed = Signal("changed", arg_types=(object,))
Beispiel #24
0
 class Signals:
     found = Signal("found", arg_types=(int, int, float, str))
Beispiel #25
0
 class Signals:
     changed = Signal("changed", arg_types=(object, ))
     count = Signal("count", arg_types=(float, ))
Beispiel #26
0
 class Signals:
     result = Signal('result', arg_types=(object, ))
Beispiel #27
0
 class Signals:
     new_image = Signal("new-image", arg_types=())
Beispiel #28
0
 class Signals:
     new_point = Signal('new-point', arg_types=(object, ))
     new_row = Signal('new-row', arg_types=(int, ))
     message = Signal('message', arg_types=(str, ))
Beispiel #29
0
 class Signals:
     changed = Signal("changed", arg_types=(float, ))
     starting = Signal("starting", arg_types=(bool, ))
     target = Signal("target", arg_types=(object, float))
     done = Signal("done", arg_types=())
Beispiel #30
0
 class Signals:
     deadtime = Signal("deadtime", arg_types=(float, ))