Beispiel #1
0
 def __init__(self, scene, left=None, top=None, right=None, bottom=None, all=False):
     list.__init__(self)
     self.matrix = Matrix()
     self.scene = scene
     self.parent = None
     self.properties = ORIENTATION_RELATIVE
     if all:
         # contains all points
         self.left = -float('inf')
         self.top = -float('inf')
         self.right = float('inf')
         self.bottom = float('inf')
     else:
         # contains no points
         self.left = float('inf')
         self.top = float('inf')
         self.right = -float('inf')
         self.bottom = -float('inf')
     if left is not None:
         self.left = left
     if right is not None:
         self.right = right
     if top is not None:
         self.top = top
     if bottom is not None:
         self.bottom = bottom
Beispiel #2
0
 def __init__(self):
     Module.__init__(self)
     self.hittable_elements = list()
     self.hit_chain = list()
     self.widget_root = SceneSpaceWidget(self)
     self.matrix_root = Matrix()
     self.process = self.animate_tick
     self.interval = 1.0 / 60.0  # 60fps
     self.last_position = None
     self.time = None
     self.distance = None
Beispiel #3
0
 def update_step_image(self):
     element = self.image_element
     step_value = self.spin_step_size.GetValue()
     m = element.transform
     tx = m.e
     ty = m.f
     element.transform = Matrix.scale(float(step_value), float(step_value))
     element.transform.post_translate(tx, ty)
     element.modified()
     if self.device is not None:
         self.device.signal('element_property_update', element)
         self.device.signal('refresh_scene')
Beispiel #4
0
    def rebuild_hit_chain(self, current_widget, current_matrix=None):
        # If there is a matrix for the widget concatenate it.
        if current_widget.matrix is not None:
            matrix_within_scene = Matrix(current_widget.matrix)
            matrix_within_scene.post_cat(current_matrix)
        else:
            matrix_within_scene = Matrix(current_matrix)

        # Add to list and recurse for children based on response.
        response = current_widget.hit()
        if response == HITCHAIN_HIT:
            self.hittable_elements.append(
                (current_widget, matrix_within_scene))
        elif response == HITCHAIN_DELEGATE:
            for w in current_widget:
                self.rebuild_hit_chain(w, matrix_within_scene)
        elif response == HITCHAIN_HIT_AND_DELEGATE:
            self.hittable_elements.append(
                (current_widget, matrix_within_scene))
            for w in current_widget:
                self.rebuild_hit_chain(w, matrix_within_scene)
        elif response == HITCHAIN_DELEGATE_AND_HIT:
            for w in current_widget:
                self.rebuild_hit_chain(w, matrix_within_scene)
            self.hittable_elements.append(
                (current_widget, matrix_within_scene))
Beispiel #5
0
class Widget(list):
    def __init__(self, scene, left=None, top=None, right=None, bottom=None, all=False):
        list.__init__(self)
        self.matrix = Matrix()
        self.scene = scene
        self.parent = None
        self.properties = ORIENTATION_RELATIVE
        if all:
            # contains all points
            self.left = -float('inf')
            self.top = -float('inf')
            self.right = float('inf')
            self.bottom = float('inf')
        else:
            # contains no points
            self.left = float('inf')
            self.top = float('inf')
            self.right = -float('inf')
            self.bottom = -float('inf')
        if left is not None:
            self.left = left
        if right is not None:
            self.right = right
        if top is not None:
            self.top = top
        if bottom is not None:
            self.bottom = bottom

    def __str__(self):
        return 'Widget(%f, %f, %f, %f)' % (self.left, self.top, self.right, self.bottom)

    def __repr__(self):
        return '%s(%f, %f, %f, %f)' % (type(self).__name__, self.left, self.top, self.right, self.bottom)

    def hit(self):
        return HITCHAIN_DELEGATE

    def draw(self, gc):
        # Concat if this is a thing.
        m = self.matrix
        gc.PushState()
        gc.ConcatTransform(wx.GraphicsContext.CreateMatrix(gc, ZMatrix(m)))
        self.process_draw(gc)
        for i in range(len(self) - 1, -1, -1):
            widget = self[i]
            widget.draw(gc)
        gc.PopState()

    def process_draw(self, gc):
        pass

    def contains(self, x, y=None):
        if y is None:
            y = x.y
            x = x.x
        return self.left <= x <= self.right and \
               self.top <= y <= self.bottom

    def event(self, window_pos=None, space_pos=None, event_type=None):
        return RESPONSE_CHAIN

    def notify_added_to_parent(self, parent):
        pass

    def notify_added_child(self, child):
        pass

    def notify_removed_from_parent(self, parent):
        pass

    def notify_removed_child(self, child):
        pass

    def notify_moved_child(self, child):
        pass

    def add_widget(self, index=-1, widget=None, properties=0):
        if len(self) == 0:
            last = None
        else:
            last = self[-1]
        if 0 <= index < len(self):
            self.insert(index, widget)
        else:
            self.append(widget)
        widget.parent = self
        self.layout_by_orientation(widget, last, properties)
        self.notify_added_to_parent(self)
        self.notify_added_child(widget)

    def translate(self, dx, dy):
        if dx == 0 and dy == 0:
            return
        if dx == float('nan'):
            return
        if dy == float('nan'):
            return
        if abs(dx) == float('inf'):
            return
        if abs(dy) == float('inf'):
            return
        self.translate_loop(dx, dy)

    def translate_loop(self, dx, dy):
        if self.properties & ORIENTATION_ABSOLUTE != 0:
            return  # Do not translate absolute oriented widgets.
        self.translate_self(dx, dy)
        for w in self:
            w.translate_loop(dx, dy)

    def translate_self(self, dx, dy):
        self.left += dx
        self.right += dx
        self.top += dy
        self.bottom += dy
        if self.parent is not None:
            self.notify_moved_child(self)

    def union_children_bounds(self, bounds=None):
        if bounds is None:
            bounds = [self.left, self.top, self.right, self.bottom]
        else:
            if bounds[0] > self.left:
                bounds[0] = self.left
            if bounds[1] > self.top:
                bounds[1] = self.top
            if bounds[2] < self.right:
                bounds[2] = self.left
            if bounds[3] < self.bottom:
                bounds[3] = self.bottom
        for w in self:
            w.union_children_bounds(bounds)
        return bounds

    @property
    def height(self):
        return self.bottom - self.top

    @property
    def width(self):
        return self.right - self.left

    def layout_by_orientation(self, widget, last, properties):
        if properties & ORIENTATION_ABSOLUTE != 0:
            return
        if properties & ORIENTATION_NO_BUFFER != 0:
            buffer = 0
        else:
            buffer = BUFFER
        if (properties & ORIENTATION_MODE_MASK) == ORIENTATION_RELATIVE:
            widget.translate(self.left, self.top)
            return
        elif last is None:  # orientation = origin
            widget.translate(self.left - widget.left, self.top - widget.top)
        elif (properties & ORIENTATION_GRID) != 0:
            dim = properties & ORIENTATION_DIM_MASK
            if (properties & ORIENTATION_VERTICAL) != 0:
                if dim == 0:  # Vertical
                    if self.height >= last.bottom - self.top + widget.height:
                        # add to line
                        widget.translate(last.left - widget.left, last.bottom - widget.top)
                    else:
                        # line return
                        widget.translate(last.right - widget.left + buffer, self.top - widget.top)
            else:
                if dim == 0:  # Horizontal
                    if self.width >= last.right - self.left + widget.width:
                        # add to line
                        widget.translate(last.right - widget.left + buffer, last.top - widget.top)
                    else:
                        # line return
                        widget.translate(self.left - widget.left, last.bottom - widget.top + buffer)
        elif (properties & ORIENTATION_HORIZONTAL) != 0:
            widget.translate(last.right - widget.left + buffer, last.top - widget.top)
        elif (properties & ORIENTATION_VERTICAL) != 0:
            widget.translate(last.left - widget.left, last.bottom - widget.top + buffer)
        if properties & ORIENTATION_CENTERED:
            self.center_children()

    def center_children(self):
        child_bounds = self.union_children_bounds()
        dx = self.left - (child_bounds[0] + child_bounds[2]) / 2.0
        dy = self.top - (child_bounds[1] + child_bounds[3]) / 2.0
        if dx != 0 and dy != 0:
            for w in self:
                w.translate_loop(dx, dy)

    def center_widget(self, x, y=None):
        if y is None:
            y = x.y
            x = x.x
        child_bounds = self.union_children_bounds()
        cx = (child_bounds[0] + child_bounds[2]) / 2.0
        cy = (child_bounds[1] + child_bounds[3]) / 2.0
        self.translate(x - cx, y - cy)

    def set_position(self, x, y=None):
        if y is None:
            y = x.y
            x = x.x
        dx = x - self.left
        dy = y - self.top
        self.translate(dx, dy)

    def remove_all_widgets(self):
        for w in self:
            if w is None:
                continue
            w.parent = None
            w.notify_removed_from_parent(self)
            self.notify_removed_child(w)
        self.clear()
        try:
            self.scene.notify_tree_changed()
        except AttributeError:
            pass

    def remove_widget(self, widget=None):
        if widget is None:
            return
        if isinstance(widget, Widget):
            list.remove(widget)
        elif isinstance(widget, int):
            index = widget
            widget = self[index]
            list.remove(index)
        widget.parent = None
        widget.notify_removed_from_parent(self)
        self.notify_removed_child(widget)
        try:
            self.scene.notify_tree_changed()
        except AttributeError:
            pass

    def set_widget(self, index, widget):
        w = self[index]
        self[index] = widget
        widget.parent = self
        widget.notify_added_to_parent(self)
        self.notify_removed_child(w)
        try:
            self.scene.notify_tree_changed()
        except AttributeError:
            pass

    def on_matrix_change(self):
        pass

    def scene_matrix_reset(self):
        self.matrix.reset()
        self.on_matrix_change()

    def scene_post_scale(self, sx, sy=None, ax=0, ay=0):
        self.matrix.post_scale(sx, sy, ax, ay)
        self.on_matrix_change()

    def scene_post_pan(self, px, py):
        self.matrix.post_translate(px, py)
        self.on_matrix_change()

    def scene_post_rotate(self, angle, rx=0, ry=0):
        self.matrix.post_rotate(angle, rx, ry)
        self.on_matrix_change()

    def scene_pre_scale(self, sx, sy=None, ax=0, ay=0):
        self.matrix.pre_scale(sx, sy, ax, ay)
        self.on_matrix_change()

    def scene_pre_pan(self, px, py):
        self.matrix.pre_translate(px, py)
        self.on_matrix_change()

    def scene_pre_rotate(self, angle, rx=0, ry=0):
        self.matrix.pre_rotate(angle, rx, ry)
        self.on_matrix_change()

    def get_scale_x(self):
        return self.matrix.value_scale_x()

    def get_scale_y(self):
        return self.matrix.value_scale_y()

    def get_skew_x(self):
        return self.matrix.value_skew_x()

    def get_skew_y(self):
        return self.matrix.value_skew_y()

    def get_translate_x(self):
        return self.matrix.value_trans_x()

    def get_translate_y(self):
        return self.matrix.value_trans_y()
Beispiel #6
0
        kernel.load(os.path.realpath(args.input.name))

    if args.path is not None:
        # Force the inclusion of the path.
        from svgelements import Path
        try:
            path = Path(args.path)
            path.stroke = Color('blue')
            kernel.elements.add_elem(path)
        except Exception:
            print("SVG Path Exception to: %s" % ' '.join(sys.argv))

    if args.transform:
        # Transform any data loaded data
        from svgelements import Matrix
        m = Matrix(args.transform)
        for e in kernel.elements.elems():
            e *= m
            try:
                e.modified()
            except AttributeError:
                pass

    if args.set is not None:
        # Set the variables requested here.
        for v in args.set:
            attr = v[0]
            value = v[1]
            if hasattr(device, attr):
                v = getattr(device, attr)
                if isinstance(v, bool):
    def wizard_image(svg_image, operations):
        image = svg_image.image
        matrix = Matrix(svg_image.transform)
        step = None
        mask = None
        from PIL import Image, ImageOps, ImageFilter, ImageEnhance
        for op in operations:
            name = op['name']
            if name == 'crop':
                try:
                    if op['enable'] and op['bounds'] is not None:
                        crop = op['bounds']
                        left = int(crop[0])
                        upper = int(crop[1])
                        right = int(crop[2])
                        lower = int(crop[3])
                        image = image.crop((left, upper, right, lower))
                except KeyError:
                    pass
            if name == 'resample':
                try:
                    if op['enable']:
                        image, matrix = RasterScripts.actualize(
                            image, matrix, step_level=op['step'])
                        step = op['step']
                except KeyError:
                    pass
            if name == 'grayscale':
                try:
                    if op['enable']:
                        try:
                            r = op['red'] * 0.299
                            g = op['green'] * 0.587
                            b = op['blue'] * 0.114
                            v = op['lightness']
                            c = r + g + b
                            try:
                                c /= v
                                r = r / c
                                g = g / c
                                b = b / c
                            except ZeroDivisionError:
                                pass
                            m = [r, g, b, 1.0]
                            if image.mode != "L":
                                if image.mode == "P" or image.mode == '1':
                                    image = image.convert('RGBA')
                                if op['invert']:
                                    color = 0, 0, 0
                                    c8 = 0
                                else:
                                    color = 255, 255, 255
                                    c8 = 255
                                if image.mode == 'RGBA':
                                    background = Image.new(
                                        'RGB', image.size, color)
                                    background.paste(
                                        image, mask=image.getchannel('A'))
                                    image = background
                                image = image.convert("L", matrix=m)

                                def mask_filter(e):
                                    if e == c8:
                                        return 0
                                    else:
                                        return 255

                                mask = image.point(
                                    mask_filter
                                )  # Makes a mask out of Alpha or pure mask color.
                            if op['invert']:
                                image = ImageOps.invert(image)
                        except (KeyError, OSError):
                            pass

                except KeyError:
                    pass
            if name == 'edge_enhance':
                try:
                    if op['enable']:
                        if image.mode == 'P':
                            image = image.convert('L')
                        image = image.filter(filter=ImageFilter.EDGE_ENHANCE)
                except KeyError:
                    pass
            if name == 'auto_contrast':
                try:
                    if op['enable']:
                        if image.mode != 'P':
                            image = image.convert('L')
                        image = ImageOps.autocontrast(image,
                                                      cutoff=op['cutoff'])
                except KeyError:
                    pass
            if name == 'tone':
                try:
                    if op['enable'] and op['values'] is not None:
                        if image.mode == 'L':
                            image = image.convert('P')
                            tone_values = op['values']
                            if op['type'] == 'spline':
                                spline = RasterScripts.spline(tone_values)
                            else:
                                tone_values = [
                                    q for q in tone_values if q is not None
                                ]
                                spline = RasterScripts.line(tone_values)
                            if len(spline) < 256:
                                spline.extend([255] * (256 - len(spline)))
                            if len(spline) > 256:
                                spline = spline[:256]
                            image = image.point(spline)
                            if image.mode != 'L':
                                image = image.convert('L')
                except KeyError:
                    pass
            if name == 'contrast':
                try:
                    if op['enable']:
                        if op['contrast'] is not None and op[
                                'brightness'] is not None:
                            contrast = ImageEnhance.Contrast(image)
                            c = (op['contrast'] + 128.0) / 128.0
                            image = contrast.enhance(c)

                            brightness = ImageEnhance.Brightness(image)
                            b = (op['brightness'] + 128.0) / 128.0
                            image = brightness.enhance(b)
                except KeyError:
                    pass
            if name == 'gamma':
                try:
                    if op['enable'] and op['factor'] is not None:
                        if image.mode == 'L':
                            gamma_factor = float(op['factor'])

                            def crimp(px):
                                px = int(round(px))
                                if px < 0:
                                    return 0
                                if px > 255:
                                    return 255
                                return px

                            if gamma_factor == 0:
                                gamma_lut = [0] * 256
                            else:
                                gamma_lut = [
                                    crimp(
                                        pow(i / 255,
                                            (1.0 / gamma_factor)) * 255)
                                    for i in range(256)
                                ]
                            image = image.point(gamma_lut)
                            if image.mode != 'L':
                                image = image.convert('L')
                except KeyError:
                    pass
            if name == 'unsharp_mask':
                try:
                    if op['enable'] and \
                            op['percent'] is not None and \
                            op['radius'] is not None and \
                            op['threshold'] is not None:
                        unsharp = ImageFilter.UnsharpMask(
                            radius=op['radius'],
                            percent=op['percent'],
                            threshold=op['threshold'])
                        image = image.filter(unsharp)
                except (KeyError,
                        ValueError):  # Value error if wrong type of image.
                    pass
            if name == 'dither':
                try:
                    if op['enable'] and op['type'] is not None:
                        if mask is not None:
                            background = Image.new(image.mode, image.size,
                                                   'white')
                            background.paste(image, mask=mask)
                            image = background  # Mask exists use it to remove any pixels that were pure reject.
                        if image.mode == 'RGBA':
                            pixel_data = image.load()
                            width, height = image.size
                            for y in range(height):
                                for x in range(width):
                                    if pixel_data[x, y][3] == 0:
                                        pixel_data[x, y] = (255, 255, 255, 255)
                        image = image.convert("1")
                except KeyError:
                    pass
            if name == 'halftone':
                try:
                    if op['enable']:
                        image = RasterScripts.halftone(
                            image,
                            sample=op['sample'],
                            angle=op['angle'],
                            oversample=op['oversample'],
                            black=op['black'])
                except KeyError:
                    pass

        return image, matrix, step
Beispiel #8
0
    def __init__(self, *args, **kwds):
        # begin wxGlade: CameraInterface.__init__
        kwds["style"] = kwds.get(
            "style", 0
        ) | wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL
        wx.Frame.__init__(self, *args, **kwds)
        Module.__init__(self)
        self.SetSize((608, 549))
        self.CameraInterface_menubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Perspective"), "")
        self.Bind(wx.EVT_MENU, self.reset_perspective, id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Fisheye"), "")
        self.Bind(wx.EVT_MENU, self.reset_fisheye, id=item.GetId())
        wxglade_tmp_menu.AppendSeparator()

        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 1"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu1 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 2"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu2 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-2), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 3"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu3 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-3), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 0"), "",
                                       wx.ITEM_RADIO)
        self.camera_0_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(0), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 1"), "",
                                       wx.ITEM_RADIO)
        self.camera_1_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 2"), "",
                                       wx.ITEM_RADIO)
        self.camera_2_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(2), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 3"), "",
                                       wx.ITEM_RADIO)
        self.camera_3_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(3), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 4"), "",
                                       wx.ITEM_RADIO)
        self.camera_4_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(4), id=item.GetId())
        self.CameraInterface_menubar.Append(wxglade_tmp_menu, _("Camera"))
        self.SetMenuBar(self.CameraInterface_menubar)
        # Menu Bar

        self.button_update = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_camera_50.GetBitmap())
        self.button_export = wx.BitmapButton(
            self, wx.ID_ANY,
            icons8_picture_in_picture_alternative_50.GetBitmap())
        self.check_fisheye = wx.CheckBox(self, wx.ID_ANY, _("Correct Fisheye"))
        self.check_perspective = wx.CheckBox(self, wx.ID_ANY,
                                             _("Correct Perspective"))
        self.slider_fps = wx.Slider(self,
                                    wx.ID_ANY,
                                    1,
                                    0,
                                    24,
                                    style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
                                    | wx.SL_LABELS)
        self.button_detect = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_detective_50.GetBitmap())
        self.display_camera = wx.Panel(self, wx.ID_ANY)
        self.__set_properties()
        self.__do_layout()

        self.capture = None
        self.image_width = -1
        self.image_height = -1
        self._Buffer = None

        self.frame_bitmap = None

        self.fisheye_k = None
        self.fisheye_d = None

        # Used during calibration.
        self.objpoints = []  # 3d point in real world space
        self.imgpoints = []  # 2d points in image plane.

        # Perspective Points
        self.perspective = None

        self.previous_window_position = None
        self.previous_scene_position = None

        self.corner_drag = None

        self.matrix = Matrix()

        self.Bind(wx.EVT_BUTTON, self.on_button_update, self.button_update)
        self.Bind(wx.EVT_BUTTON, self.on_button_export, self.button_export)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_fisheye, self.check_fisheye)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_perspective,
                  self.check_perspective)
        self.Bind(wx.EVT_SLIDER, self.on_slider_fps, self.slider_fps)
        self.Bind(wx.EVT_BUTTON, self.on_button_detect, self.button_detect)
        self.SetDoubleBuffered(True)
        # end wxGlade

        self.display_camera.Bind(wx.EVT_PAINT, self.on_paint)
        self.display_camera.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)
        self.display_camera.Bind(wx.EVT_MOTION, self.on_mouse_move)
        self.display_camera.Bind(wx.EVT_MOUSEWHEEL, self.on_mousewheel)
        self.display_camera.Bind(wx.EVT_MIDDLE_UP, self.on_mouse_middle_up)
        self.display_camera.Bind(wx.EVT_MIDDLE_DOWN, self.on_mouse_middle_down)

        self.display_camera.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_left_down)
        self.display_camera.Bind(wx.EVT_LEFT_UP, self.on_mouse_left_up)
        self.display_camera.Bind(wx.EVT_ENTER_WINDOW,
                                 lambda event: self.display_camera.SetFocus(
                                 ))  # Focus follows mouse.
        self.Bind(wx.EVT_CLOSE, self.on_close, self)

        self.on_size(None)
        self.Bind(wx.EVT_SIZE, self.on_size, self)
        self.camera_lock = threading.Lock()
        self.process = self.fetch_image
        self.camera_job = None
        self.fetch_job = None
Beispiel #9
0
class CameraInterface(wx.Frame, Module):
    def __init__(self, *args, **kwds):
        # begin wxGlade: CameraInterface.__init__
        kwds["style"] = kwds.get(
            "style", 0
        ) | wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL
        wx.Frame.__init__(self, *args, **kwds)
        Module.__init__(self)
        self.SetSize((608, 549))
        self.CameraInterface_menubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Perspective"), "")
        self.Bind(wx.EVT_MENU, self.reset_perspective, id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Fisheye"), "")
        self.Bind(wx.EVT_MENU, self.reset_fisheye, id=item.GetId())
        wxglade_tmp_menu.AppendSeparator()

        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 1"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu1 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 2"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu2 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-2), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera 3"), "",
                                       wx.ITEM_RADIO)
        self.camera_ip_menu3 = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-3), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 0"), "",
                                       wx.ITEM_RADIO)
        self.camera_0_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(0), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 1"), "",
                                       wx.ITEM_RADIO)
        self.camera_1_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 2"), "",
                                       wx.ITEM_RADIO)
        self.camera_2_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(2), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 3"), "",
                                       wx.ITEM_RADIO)
        self.camera_3_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(3), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 4"), "",
                                       wx.ITEM_RADIO)
        self.camera_4_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(4), id=item.GetId())
        self.CameraInterface_menubar.Append(wxglade_tmp_menu, _("Camera"))
        self.SetMenuBar(self.CameraInterface_menubar)
        # Menu Bar

        self.button_update = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_camera_50.GetBitmap())
        self.button_export = wx.BitmapButton(
            self, wx.ID_ANY,
            icons8_picture_in_picture_alternative_50.GetBitmap())
        self.check_fisheye = wx.CheckBox(self, wx.ID_ANY, _("Correct Fisheye"))
        self.check_perspective = wx.CheckBox(self, wx.ID_ANY,
                                             _("Correct Perspective"))
        self.slider_fps = wx.Slider(self,
                                    wx.ID_ANY,
                                    1,
                                    0,
                                    24,
                                    style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
                                    | wx.SL_LABELS)
        self.button_detect = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_detective_50.GetBitmap())
        self.display_camera = wx.Panel(self, wx.ID_ANY)
        self.__set_properties()
        self.__do_layout()

        self.capture = None
        self.image_width = -1
        self.image_height = -1
        self._Buffer = None

        self.frame_bitmap = None

        self.fisheye_k = None
        self.fisheye_d = None

        # Used during calibration.
        self.objpoints = []  # 3d point in real world space
        self.imgpoints = []  # 2d points in image plane.

        # Perspective Points
        self.perspective = None

        self.previous_window_position = None
        self.previous_scene_position = None

        self.corner_drag = None

        self.matrix = Matrix()

        self.Bind(wx.EVT_BUTTON, self.on_button_update, self.button_update)
        self.Bind(wx.EVT_BUTTON, self.on_button_export, self.button_export)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_fisheye, self.check_fisheye)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_perspective,
                  self.check_perspective)
        self.Bind(wx.EVT_SLIDER, self.on_slider_fps, self.slider_fps)
        self.Bind(wx.EVT_BUTTON, self.on_button_detect, self.button_detect)
        self.SetDoubleBuffered(True)
        # end wxGlade

        self.display_camera.Bind(wx.EVT_PAINT, self.on_paint)
        self.display_camera.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)
        self.display_camera.Bind(wx.EVT_MOTION, self.on_mouse_move)
        self.display_camera.Bind(wx.EVT_MOUSEWHEEL, self.on_mousewheel)
        self.display_camera.Bind(wx.EVT_MIDDLE_UP, self.on_mouse_middle_up)
        self.display_camera.Bind(wx.EVT_MIDDLE_DOWN, self.on_mouse_middle_down)

        self.display_camera.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_left_down)
        self.display_camera.Bind(wx.EVT_LEFT_UP, self.on_mouse_left_up)
        self.display_camera.Bind(wx.EVT_ENTER_WINDOW,
                                 lambda event: self.display_camera.SetFocus(
                                 ))  # Focus follows mouse.
        self.Bind(wx.EVT_CLOSE, self.on_close, self)

        self.on_size(None)
        self.Bind(wx.EVT_SIZE, self.on_size, self)
        self.camera_lock = threading.Lock()
        self.process = self.fetch_image
        self.camera_job = None
        self.fetch_job = None

    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.VERTICAL)
        sizer_2.Add(self.button_update, 0, 0, 0)
        sizer_2.Add(self.button_export, 0, 0, 0)
        sizer_3.Add(self.check_fisheye, 0, 0, 0)
        sizer_3.Add(self.check_perspective, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_2.Add(self.slider_fps, 1, wx.EXPAND, 0)
        sizer_2.Add(self.button_detect, 0, 0, 0)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        sizer_1.Add(self.display_camera, 10, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()

    def __set_properties(self):
        _icon = wx.NullIcon
        _icon.CopyFromBitmap(icons8_camera_50.GetBitmap())
        self.SetIcon(_icon)
        # begin wxGlade: CameraInterface.__set_properties
        self.SetTitle("CameraInterface")
        self.button_update.SetToolTip(_("Update Image"))
        self.button_update.SetSize(self.button_update.GetBestSize())
        self.button_export.SetToolTip(_("Export Snapsnot"))
        self.button_export.SetSize(self.button_export.GetBestSize())
        self.button_detect.SetToolTip(_("Detect Distortions/Calibration"))
        self.button_detect.SetSize(self.button_detect.GetBestSize())
        # end wxGlade

    def on_close(self, event):
        if self.state == 5:
            event.Veto()
        else:
            self.state = 5
            self.device.close('window', self.name)
            event.Skip()  # Call destroy as regular.

    def initialize(self, channel=None):
        self.device.close('window', self.name)
        self.Show()
        self.device.setting(int, 'draw_mode', 0)
        self.device.setting(int, 'camera_index', 0)
        self.device.setting(int, 'camera_fps', 1)
        self.device.setting(bool, 'mouse_zoom_invert', False)
        self.device.setting(bool, 'camera_correction_fisheye', False)
        self.device.setting(bool, 'camera_correction_perspective', False)
        self.device.setting(str, 'fisheye', '')
        self.device.setting(str, 'perspective', '')
        self.device.setting(str, 'camera_uri1', '')
        self.device.setting(str, 'camera_uri2', '')
        self.device.setting(str, 'camera_uri3', '')
        self.check_fisheye.SetValue(self.device.camera_correction_fisheye)
        self.check_perspective.SetValue(
            self.device.camera_correction_perspective)
        if self.device.fisheye is not None and len(self.device.fisheye) != 0:
            self.fisheye_k, self.fisheye_d = eval(self.device.fisheye)
        if self.device.perspective is not None and len(
                self.device.perspective) != 0:
            self.perspective = eval(self.device.perspective)
        self.slider_fps.SetValue(self.device.camera_fps)

        if self.device.camera_index == -3:
            self.camera_ip_menu3.Check(True)
        elif self.device.camera_index == -2:
            self.camera_ip_menu2.Check(True)
        elif self.device.camera_index == -1:
            self.camera_ip_menu1.Check(True)
        elif self.device.camera_index == 0:
            self.camera_0_menu.Check(True)
        elif self.device.camera_index == 1:
            self.camera_1_menu.Check(True)
        elif self.device.camera_index == 2:
            self.camera_2_menu.Check(True)
        elif self.device.camera_index == 3:
            self.camera_3_menu.Check(True)
        elif self.device.camera_index == 4:
            self.camera_4_menu.Check(True)
        if self.camera_job is not None:
            self.camera_job.cancel()
        self.camera_job = self.device.add_job(self.init_camera,
                                              times=1,
                                              interval=0.1)
        self.device.listen('camera_frame', self.on_camera_frame_update)
        self.device.listen('camera_frame_raw', self.on_camera_frame_raw)

    def finalize(self, channel=None):
        self.device.unlisten('camera_frame_raw', self.on_camera_frame_raw)
        self.device.unlisten('camera_frame', self.on_camera_frame_update)
        self.device.signal('camera_frame_raw', None)
        self.unschedule()
        self.camera_lock.acquire()
        self.close_camera()
        self.camera_lock.release()
        if self.camera_job is not None:
            self.camera_job.cancel()
        if self.fetch_job is not None:
            self.fetch_job.cancel()
        try:
            self.Close()
        except RuntimeError:
            pass

    def shutdown(self, channel=None):
        try:
            self.Close()
        except RuntimeError:
            pass

    def on_size(self, event):
        self.Layout()
        width, height = self.ClientSize
        if width <= 0:
            width = 1
        if height <= 0:
            height = 1
        self._Buffer = wx.Bitmap(width, height)
        self.update_in_gui_thread()

    def on_camera_frame_update(self, frame):
        self.on_camera_frame(frame)
        self.update_in_gui_thread()

    def on_camera_frame(self, frame):
        if frame is None:
            return
        bed_width = self.device.bed_width * 2
        bed_height = self.device.bed_height * 2

        self.image_height, self.image_width = frame.shape[:2]
        self.frame_bitmap = wx.Bitmap.FromBuffer(self.image_width,
                                                 self.image_height, frame)

        if self.device.camera_correction_perspective:
            if bed_width != self.image_width or bed_height != self.image_height:
                self.image_width = bed_width
                self.image_height = bed_height
                self.display_camera.SetSize(
                    (self.image_width, self.image_height))

    def on_camera_frame_raw(self, frame):
        if frame is None:
            return
        try:
            import cv2
            import numpy as np
        except:
            dlg = wx.MessageDialog(None,
                                   _("Could not import Camera requirements"),
                                   _("Imports Failed"), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
        CHECKERBOARD = (6, 9)
        subpix_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,
                           30, 0.1)
        calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC + cv2.fisheye.CALIB_CHECK_COND + cv2.fisheye.CALIB_FIX_SKEW
        objp = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
        objp[0, :, :2] = np.mgrid[0:CHECKERBOARD[0],
                                  0:CHECKERBOARD[1]].T.reshape(-1, 2)

        img = frame
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(
            gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH +
            cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
        # If found, add object points, image points (after refining them)

        if ret:
            self.objpoints.append(objp)
            cv2.cornerSubPix(gray, corners, (3, 3), (-1, -1), subpix_criteria)
            self.imgpoints.append(corners)
        else:
            dlg = wx.MessageDialog(None,
                                   _("Checkerboard 6x9 pattern not found."),
                                   _("Pattern not found."), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
            return
        N_OK = len(self.objpoints)
        K = np.zeros((3, 3))
        D = np.zeros((4, 1))
        rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
        tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
        try:
            rms, a, b, c, d = \
                cv2.fisheye.calibrate(
                    self.objpoints,
                    self.imgpoints,
                    gray.shape[::-1],
                    K,
                    D,
                    rvecs,
                    tvecs,
                    calibration_flags,
                    (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
                )
        except cv2.error:
            # Ill conditioned matrix for input values.
            self.objpoints = self.objpoints[:-1]  # Deleting the last entry.
            self.imgpoints = self.imgpoints[:-1]
            dlg = wx.MessageDialog(None,
                                   _("Ill-conditioned Matrix. Keep trying."),
                                   _("Matrix."), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
            return
        dlg = wx.MessageDialog(
            None, _("Success. %d images so far." % len(self.objpoints)),
            _("Image Captured"), wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
        self.device.fisheye = repr([K.tolist(), D.tolist()])
        self.fisheye_k = K.tolist()
        self.fisheye_d = D.tolist()

    def swap_camera(self, camera_index=0):
        self.camera_lock.acquire()
        self.device.camera_index = camera_index
        self.close_camera()
        if self.camera_job is not None:
            self.camera_job.cancel()
        if camera_index < 0:
            self.camera_uri_request(abs(camera_index))
            uri = self.get_camera_uri()
            if uri is None or len(uri) == 0:
                self.camera_lock.release()
                return
        self.camera_job = self.device.add_job(self.init_camera,
                                              times=1,
                                              interval=0.1)
        self.camera_lock.release()

    def close_camera(self):
        self.unschedule()
        if self.capture is not None:
            self.capture.release()
            self.capture = None

    def camera_error_requirement(self):
        try:
            for attr in dir(self):
                value = getattr(self, attr)
                if isinstance(value, wx.Control):
                    value.Enable(False)
            dlg = wx.MessageDialog(
                None,
                _("If using a precompiled binary, this was requirement was not included.\nIf using pure Python, add it with: pip install opencv-python-headless"
                  ), _("Interface Requires OpenCV."), wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        except RuntimeError:
            pass

    def camera_error_webcam(self):
        try:
            for attr in dir(self):
                value = getattr(self, attr)
                if isinstance(value, wx.Control):
                    value.Enable(False)
            dlg = wx.MessageDialog(None, _("No Webcam found."), _("Error"),
                                   wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        except RuntimeError:
            pass

    def camera_uri_request(self, index=None):
        if index is None:
            index = abs(self.device.camera_index)
        try:
            dlg = wx.TextEntryDialog(
                self,
                _("Enter the HTTP or RTSP uri for the webcam #%d") % index,
                _("Webcam URI Update"), '')
            dlg.SetValue(self.get_camera_uri())
            modal = dlg.ShowModal()
            if modal == wx.ID_OK:
                self.set_camera_uri(str(dlg.GetValue()))
                wx.CallAfter(self.init_camera)
            else:
                wx.CallAfter(self.camera_error_webcam)
            dlg.Destroy()
        except RuntimeError:
            pass

    def camera_success(self):
        try:
            for attr in dir(self):
                value = getattr(self, attr)
                if isinstance(value, wx.Control):
                    value.Enable(True)
        except RuntimeError:
            pass

    def set_camera_uri(self, uri):
        return setattr(self.device,
                       "camera_uri%d" % abs(self.device.camera_index), uri)

    def get_camera_uri(self):
        index = self.device.camera_index
        if index >= 0:
            return index
        return getattr(self.device, "camera_uri%d" % abs(index))

    def init_camera(self):
        if self.device is None:
            return
        if self.capture is not None:
            self.capture = None
        try:
            import cv2
        except ImportError:
            wx.CallAfter(self.camera_error_requirement)
            return
        if self.device.camera_index >= 0:
            self.capture = cv2.VideoCapture(self.device.camera_index)
        else:
            uri = self.get_camera_uri()
            if uri is None or len(uri) == 0:
                return
            else:
                self.capture = cv2.VideoCapture(self.get_camera_uri())
        wx.CallAfter(self.camera_success)
        try:
            self.interval = 1.0 / self.device.camera_fps
        except ZeroDivisionError:
            self.interval = 5
        except AttributeError:
            return
        self.schedule()

    def reset_perspective(self, event):
        self.perspective = None
        self.device.perspective = ''

    def reset_fisheye(self, event):
        self.fisheye_k = None
        self.fisheye_d = None
        self.device.fisheye = ''

    def on_erase(self, event):
        pass

    def on_paint(self, event):
        try:
            wx.BufferedPaintDC(self.display_camera, self._Buffer)
        except RuntimeError:
            pass

    def on_update_buffer(self, event=None):
        if self.frame_bitmap is None:
            return  # Need the bitmap to refresh.
        if self.device is None:
            return  # No window to draw in.
        dm = self.device.draw_mode
        dc = wx.MemoryDC()
        dc.SelectObject(self._Buffer)
        dc.Clear()
        w, h = dc.Size
        if dm & DRAW_MODE_FLIPXY != 0:
            dc.SetUserScale(-1, -1)
            dc.SetLogicalOrigin(w, h)
        dc.SetBackground(wx.WHITE_BRUSH)
        gc = wx.GraphicsContext.Create(dc)
        gc.SetTransform(
            wx.GraphicsContext.CreateMatrix(gc, ZMatrix(self.matrix)))
        gc.PushState()
        gc.DrawBitmap(self.frame_bitmap, 0, 0, self.image_width,
                      self.image_height)
        if not self.device.camera_correction_perspective:
            if self.perspective is None:
                self.perspective = [0, 0], \
                                   [self.image_width, 0], \
                                   [self.image_width, self.image_height], \
                                   [0, self.image_height]
            gc.SetPen(wx.BLACK_DASHED_PEN)
            gc.StrokeLines(self.perspective)
            gc.StrokeLine(self.perspective[0][0], self.perspective[0][1],
                          self.perspective[3][0], self.perspective[3][1])
            gc.SetPen(wx.BLUE_PEN)
            for p in self.perspective:
                half = CORNER_SIZE / 2
                gc.StrokeLine(p[0] - half, p[1], p[0] + half, p[1])
                gc.StrokeLine(p[0], p[1] - half, p[0], p[1] + half)
                gc.DrawEllipse(p[0] - half, p[1] - half, CORNER_SIZE,
                               CORNER_SIZE)
        gc.PopState()
        if dm & DRAW_MODE_INVERT != 0:
            dc.Blit(0, 0, w, h, dc, 0, 0, wx.SRC_INVERT)
        gc.Destroy()
        del dc

    def convert_scene_to_window(self, position):
        point = self.matrix.point_in_matrix_space(position)
        return point[0], point[1]

    def convert_window_to_scene(self, position):
        point = self.matrix.point_in_inverse_space(position)
        return point[0], point[1]

    def on_mouse_move(self, event):
        if not event.Dragging():
            return
        else:
            self.SetCursor(wx.Cursor(wx.CURSOR_HAND))
        if self.previous_window_position is None:
            return
        pos = event.GetPosition()
        window_position = pos.x, pos.y
        scene_position = self.convert_window_to_scene(
            [window_position[0], window_position[1]])
        sdx = (scene_position[0] - self.previous_scene_position[0])
        sdy = (scene_position[1] - self.previous_scene_position[1])
        wdx = (window_position[0] - self.previous_window_position[0])
        wdy = (window_position[1] - self.previous_window_position[1])
        if self.corner_drag is None:
            self.scene_post_pan(wdx, wdy)
        else:
            self.perspective[self.corner_drag][0] += sdx
            self.perspective[self.corner_drag][1] += sdy
            self.device.perspective = repr(self.perspective)
        self.previous_window_position = window_position
        self.previous_scene_position = scene_position

    def on_mousewheel(self, event):
        rotation = event.GetWheelRotation()
        mouse = event.GetPosition()
        if self.device.device_root.mouse_zoom_invert:
            rotation = -rotation
        if rotation > 1:
            self.scene_post_scale(1.1, 1.1, mouse[0], mouse[1])
        elif rotation < -1:
            self.scene_post_scale(0.9, 0.9, mouse[0], mouse[1])

    def on_mouse_left_down(self, event):
        self.previous_window_position = event.GetPosition()
        self.previous_scene_position = self.convert_window_to_scene(
            self.previous_window_position)
        self.corner_drag = None
        if self.perspective is not None:
            for i, p in enumerate(self.perspective):
                half = CORNER_SIZE / 2
                if Point.distance(self.previous_scene_position, p) < half:
                    self.corner_drag = i
                    break

    def on_mouse_left_up(self, event):
        self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        self.previous_window_position = None
        self.previous_scene_position = None
        self.corner_drag = None

    def on_mouse_middle_down(self, event):
        self.SetCursor(wx.Cursor(wx.CURSOR_HAND))
        self.previous_window_position = event.GetPosition()
        self.previous_scene_position = self.convert_window_to_scene(
            self.previous_window_position)

    def on_mouse_middle_up(self, event):
        self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        self.previous_window_position = None
        self.previous_scene_position = None

    def scene_post_pan(self, px, py):
        self.matrix.post_translate(px, py)
        self.on_update_buffer()

    def scene_post_scale(self, sx, sy=None, ax=0, ay=0):
        self.matrix.post_scale(sx, sy, ax, ay)
        self.on_update_buffer()

    def fetch_image(self, raw=False):
        if self.device is None or self.capture is None:
            return
        try:
            import cv2
        except ImportError:
            return
        if self.capture is None:
            return
        self.camera_lock.acquire()
        if self.device is None:
            self.camera_lock.release()
            return
        for i in range(10):
            ret = self.capture.grab()
            if not ret:
                if i >= 9:
                    self.capture = None
                    wx.CallAfter(self.camera_error_webcam)
                    self.camera_lock.release()
                    return
                time.sleep(0.05)
            else:
                break
        for i in range(10):
            ret, frame = self.capture.retrieve()
            if not ret or frame is None:
                if i >= 9:
                    wx.CallAfter(self.camera_error_webcam)
                    self.capture = None
                    self.camera_lock.release()
                    return
                time.sleep(0.05)
            else:
                break
        if not raw and \
                self.fisheye_k is not None and \
                self.fisheye_d is not None and \
                self.device is not None and \
                self.device.camera_correction_fisheye:
            # Unfisheye the drawing
            import numpy as np
            K = np.array(self.fisheye_k)
            D = np.array(self.fisheye_d)
            DIM = frame.shape[:2][::-1]
            map1, map2 = cv2.fisheye.initUndistortRectifyMap(
                K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
            frame = cv2.remap(frame,
                              map1,
                              map2,
                              interpolation=cv2.INTER_LINEAR,
                              borderMode=cv2.BORDER_CONSTANT)
        if not raw and self.device is not None and self.device.camera_correction_perspective:
            bed_width = self.device.bed_width * 2
            bed_height = self.device.bed_height * 2
            width, height = frame.shape[:2][::-1]
            import numpy as np
            if self.perspective is None:
                rect = np.array([[0, 0], [width - 1, 0],
                                 [width - 1, height - 1], [0, height - 1]],
                                dtype="float32")
            else:
                rect = np.array(self.perspective, dtype="float32")
            dst = np.array(
                [[0, 0], [bed_width - 1, 0], [bed_width - 1, bed_height - 1],
                 [0, bed_height - 1]],
                dtype="float32")
            M = cv2.getPerspectiveTransform(rect, dst)
            frame = cv2.warpPerspective(frame, M, (bed_width, bed_height))
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        if raw:
            self.device.signal('camera_frame_raw', frame)
        else:
            self.device.signal('camera_frame', frame)
        self.camera_lock.release()
        return frame

    def update_in_gui_thread(self):
        self.on_update_buffer()
        try:
            self.Refresh(True)
            self.Update()
        except RuntimeError:
            pass

    def on_check_perspective(self, event):
        self.device.camera_correction_perspective = self.check_perspective.GetValue(
        )

    def on_check_fisheye(self, event):
        self.device.camera_correction_fisheye = self.check_fisheye.GetValue()

    def on_button_update(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        frame = self.device.last_signal('camera_frame')
        if frame is not None:
            frame = frame[0]
            buffer = wx.Bitmap.FromBuffer(self.image_width, self.image_height,
                                          frame)
            self.device.signal('background', buffer)

    def on_button_export(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        frame = self.device.last_signal('camera_frame')
        if frame is not None:
            elements = self.device.device_root.elements
            frame = frame[0]
            from PIL import Image
            img = Image.fromarray(frame)
            obj = SVGImage()
            obj.image = img
            obj.image_width = self.image_width
            obj.image_height = self.image_height
            elements.add_elem(obj)

    def on_slider_fps(self, event):  # wxGlade: CameraInterface.<event_handler>
        fps = self.slider_fps.GetValue()
        if fps == 0:
            tick = 5
        else:
            tick = 1.0 / fps
        self.device.camera_fps = fps
        self.interval = tick

    def on_button_detect(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        if self.fetch_job is not None:
            self.fetch_job.cancel()
        self.fetch_job = self.device.add_job(self.fetch_image,
                                             args=True,
                                             times=1,
                                             interval=0)
Beispiel #10
0
    def renderLabel(self, inString):
        dwg = svgwrite.Drawing()  # SVG drawing in memory
        strIdx = 0  # Used to iterate over inString
        xOffset = 100  # Cumulative character placement offset
        yOffset = 0  # Cumulative character placement offset
        charSizeX = 8  # Character size constant
        charSizeY = 8  # Character size constant
        baseline = 170  # Y value of text baseline
        glyphBounds = [
        ]  # List of boundingBox objects to track rendered character size
        finalSegments = []  # List of output paths
        escaped = False  # Track whether the current character was preceded by a '\'
        lineover = False  # Track whether the current character needs to be lined over
        lineoverList = []

        # If we can't find the typeface that the user requested, we have to quit
        try:
            face = Face(
                os.path.dirname(os.path.abspath(__file__)) + '/typeface/' +
                self.fontName + '.ttf')
            face.set_char_size(charSizeX, charSizeY, 200, 200)
        except Exception as e:
            print(e)
            print("WARN: No Typeface found with the name " + self.fontName +
                  ".ttf")
            sys.exit(0)  # quit Python

        # If the typeface that the user requested exists, but there's no position table for it, we'll continue with a warning
        try:
            table = __import__(
                'KiBuzzard.KiBuzzard.buzzard.typeface.' + self.fontName,
                globals(), locals(), ['glyphPos'])
            glyphPos = table.glyphPos
            spaceDistance = table.spaceDistance
        except:
            glyphPos = 0
            spaceDistance = 60
            print(
                "WARN: No Position Table found for this typeface. Composition will be haphazard at best."
            )

        # If there's lineover text, drop the text down to make room for the line
        dropBaseline = False
        a = False
        x = 0
        while x < len(inString):
            if x > 0 and inString[x] == '\\':
                a = True
                if x != len(inString) - 1:
                    x += 1
            if inString[x] == '!' and not a:
                dropBaseline = True
            a = False
            x += 1
        if dropBaseline:
            baseline = 190

        # Draw and compose the glyph portion of the tag
        for charIdx in range(len(inString)):
            # Check whether this character is a space
            if inString[charIdx] == ' ':
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                xOffset += spaceDistance
                continue
            # Check whether this character is a backslash that isn't escaped
            # and isn't the first character (denoting a backslash-shaped tag)
            if inString[charIdx] == '\\' and charIdx > 0 and not escaped:
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                escaped = True
                continue
            # If this is a non-escaped '!' mark the beginning of lineover
            if inString[charIdx] == '!' and not escaped:
                glyphBounds.append(boundingBox(0, 0, 0, 0))
                lineover = True
                # If we've hit the end of the string but not the end of the lineover
                # go ahead and finish it out
                if charIdx == len(inString) - 1 and len(lineoverList) > 0:
                    linePaths = []
                    linePaths.append(
                        Line(start=complex(lineoverList[0], 10),
                             end=complex(xOffset, 10)))
                    linePaths.append(
                        Line(start=complex(xOffset, 10),
                             end=complex(xOffset, 30)))
                    linePaths.append(
                        Line(start=complex(xOffset, 30),
                             end=complex(lineoverList[0], 30)))
                    linePaths.append(
                        Line(start=complex(lineoverList[0], 30),
                             end=complex(lineoverList[0], 10)))
                    linepath = Path(*linePaths)
                    linepath = elPath(linepath.d())
                    finalSegments.append(linepath)
                    lineover = False
                    lineoverList.clear()
                continue
            # All special cases end in 'continue' so if we've gotten here we can clear our flags
            if escaped:
                escaped = False

            face.load_char(
                inString[charIdx])  # Load character curves from font
            outline = face.glyph.outline  # Save character curves to var
            y = [t[1] for t in outline.points]
            # flip the points
            outline_points = [(p[0], max(y) - p[1]) for p in outline.points]
            start, end = 0, 0
            paths = []
            box = 0
            yOffset = 0

            for i in range(len(outline.contours)):
                end = outline.contours[i]
                points = outline_points[start:end + 1]
                points.append(points[0])
                tags = outline.tags[start:end + 1]
                tags.append(tags[0])
                segments = [
                    [
                        points[0],
                    ],
                ]
                box = boundingBox(points[0][0], points[0][1], points[0][0],
                                  points[0][1])
                for j in range(1, len(points)):
                    if not tags[j]:  # if this point is off-path
                        if tags[j - 1]:  # and the last point was on-path
                            segments[-1].append(
                                points[j])  # toss this point onto the segment
                        elif not tags[j -
                                      1]:  # and the last point was off-path
                            # get center point of two
                            newPoint = ((points[j][0] + points[j - 1][0]) /
                                        2.0,
                                        (points[j][1] + points[j - 1][1]) /
                                        2.0)
                            segments[-1].append(
                                newPoint
                            )  # toss this new point onto the segment
                            segments.append(
                                [
                                    newPoint,
                                    points[j],
                                ]
                            )  # and start a new segment with the new point and this one
                    elif tags[j]:  # if this point is on-path
                        segments[-1].append(
                            points[j])  # toss this point onto the segment
                        if j < (len(points) - 1):
                            segments.append(
                                [
                                    points[j],
                                ]
                            )  # and start a new segment with this point if we're not at the end

                for segment in segments:
                    if len(segment) == 2:
                        paths.append(
                            Line(start=tuple_to_imag(segment[0]),
                                 end=tuple_to_imag(segment[1])))

                    elif len(segment) == 3:
                        paths.append(
                            QuadraticBezier(start=tuple_to_imag(segment[0]),
                                            control=tuple_to_imag(segment[1]),
                                            end=tuple_to_imag(segment[2])))
                start = end + 1

            # Derive bounding box of character
            for segment in paths:
                i = 0
                while i < 10:
                    point = segment.point(0.1 * i)
                    if point.real > box.xMax:
                        box.xMax = point.real
                    if point.imag > box.yMax:
                        box.yMax = point.imag
                    if point.real < box.xMin:
                        box.xMin = point.real
                    if point.imag < box.yMin:
                        box.yMin = point.imag
                    i += 1

            glyphBounds.append(box)
            path = Path(*paths)
            if glyphPos != 0:
                try:
                    xOffset += glyphPos[inString[charIdx]].real
                    yOffset = glyphPos[inString[charIdx]].imag
                except:
                    pass
            if lineover and len(lineoverList) == 0:
                lineoverList.append(xOffset)
                lineover = False

            if (lineover and len(lineoverList) > 0):
                linePaths = []
                linePaths.append(
                    Line(start=complex(lineoverList[0], 10),
                         end=complex(xOffset, 10)))
                linePaths.append(
                    Line(start=complex(xOffset, 10), end=complex(xOffset, 30)))
                linePaths.append(
                    Line(start=complex(xOffset, 30),
                         end=complex(lineoverList[0], 30)))
                linePaths.append(
                    Line(start=complex(lineoverList[0], 30),
                         end=complex(lineoverList[0], 10)))
                linepath = Path(*linePaths)
                linepath = elPath(linepath.d())
                finalSegments.append(linepath)
                lineover = False
                lineoverList.clear()

            pathTransform = Matrix.translate(xOffset,
                                             baseline + yOffset - box.yMax)
            path = elPath(path.d()) * pathTransform
            path = elPath(path.d())
            finalSegments.append(path)
            xOffset += 30
            if glyphPos != 0:
                try:
                    xOffset -= glyphPos[inString[charIdx]].real
                except:
                    pass
            xOffset += (glyphBounds[charIdx].xMax - glyphBounds[charIdx].xMin)
            strIdx += 1

        if self.leftCap == '' and self.rightCap == '':
            for i in range(len(finalSegments)):
                svgObj = dwg.add(dwg.path(finalSegments[i].d()))
                svgObj['fill'] = "#000000"
        else:
            #draw the outline of the label as a filled shape and
            #subtract each latter from it
            tagPaths = []
            if self.rightCap == 'round':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Arc(start=complex(xOffset, 0),
                        radius=complex(100, 100),
                        rotation=180,
                        large_arc=1,
                        sweep=1,
                        end=complex(xOffset, 200)))
            elif self.rightCap == 'square':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'pointer':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset + 100, 100)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 100),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'flagtail':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 100, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 0),
                         end=complex(xOffset + 50, 100)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 100),
                         end=complex(xOffset + 100, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 100, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'fslash':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 0),
                         end=complex(xOffset, 200)))
            elif self.rightCap == 'bslash':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0),
                         end=complex(xOffset + 50, 200)))
                tagPaths.append(
                    Line(start=complex(xOffset + 50, 200),
                         end=complex(xOffset, 200)))
            elif self.rightCap == '' and self.leftCap != '':
                tagPaths.append(
                    Line(start=complex(100, 0), end=complex(xOffset, 0)))
                tagPaths.append(
                    Line(start=complex(xOffset, 0), end=complex(xOffset, 200)))

            if self.leftCap == 'round':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Arc(start=complex(100, 200),
                        radius=complex(100, 100),
                        rotation=180,
                        large_arc=0,
                        sweep=1,
                        end=complex(100, 0)))
            elif self.leftCap == 'square':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(50, 0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == 'pointer':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(0, 100)))
                tagPaths.append(Line(start=complex(0, 100), end=complex(50,
                                                                        0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == 'flagtail':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(0, 200)))
                tagPaths.append(
                    Line(start=complex(0, 200), end=complex(50, 100)))
                tagPaths.append(Line(start=complex(50, 100), end=complex(0,
                                                                         0)))
                tagPaths.append(Line(start=complex(0, 0), end=complex(100, 0)))
            elif self.leftCap == 'fslash':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 200)))
                tagPaths.append(
                    Line(start=complex(50, 200), end=complex(100, 0)))
            elif self.leftCap == 'bslash':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(50, 0)))
                tagPaths.append(Line(start=complex(50, 0), end=complex(100,
                                                                       0)))
            elif self.leftCap == '' and self.rightCap != '':
                tagPaths.append(
                    Line(start=complex(xOffset, 200), end=complex(100, 200)))
                tagPaths.append(
                    Line(start=complex(100, 200), end=complex(100, 0)))

            path = Path(*tagPaths)
            for i in range(len(finalSegments)):
                path = elPath(path.d() + " " + finalSegments[i].reverse())
            tagObj = dwg.add(dwg.path(path.d()))
            tagObj['fill'] = "#000000"

        dwg['width'] = xOffset + 100
        dwg['height'] = 250

        #dwg.saveas('out.svg')

        print('create svg')

        return dwg
Beispiel #11
0
    def drawSVG(self, svg_attributes, attributes, paths):

        global SCALE
        global SUBSAMPLING
        global SIMPLIFY
        global SIMPLIFYHQ
        global TRACEWIDTH

        out = ''
        svgWidth = 0
        svgHeight = 0

        if 'viewBox' in svg_attributes.keys():
            if svg_attributes['viewBox'].split()[2] != '0':
                svgWidth = str(
                    round(float(svg_attributes['viewBox'].split()[2]), 2))
                svgHeight = str(
                    round(float(svg_attributes['viewBox'].split()[3]), 2))
            else:
                svgWidth = svg_attributes['width']
                svgHeight = svg_attributes['height']
        else:
            svgWidth = svg_attributes['width']
            svgHeight = svg_attributes['height']

        specifiedWidth = svg_attributes['width']
        if 'mm' in specifiedWidth:
            specifiedWidth = float(specifiedWidth.replace('mm', ''))
            SCALE = specifiedWidth / float(svgWidth)
            if self.verbose:
                print("SVG width detected in mm \\o/")
        elif 'in' in specifiedWidth:
            specifiedWidth = float(specifiedWidth.replace('in', '')) * 25.4
            SCALE = specifiedWidth / float(svgWidth)
            if self.verbose:
                print("SVG width detected in inches")
        else:
            SCALE = (self.scaleFactor * 25.4) / 150
            if self.verbose:
                print("SVG width not found, guessing based on scale factor")

        self.exportHeight = float(svgHeight) * SCALE

        if len(paths) == 0:
            print("No paths found. Did you use 'Object to path' in Inkscape?")

        i = 0
        out = []
        while i < len(paths):

            if self.verbose:
                print('Translating Path ' + str(i + 1) + ' of ' +
                      str(len(paths)))

            # Apply the tranform from this svg object to actually transform the points
            # We need the Matrix object from svgelements but we can only matrix multiply with
            # svgelements' version of the Path object so we're gonna do some dumb stuff
            # to launder the Path object from svgpathtools through a d-string into
            # svgelements' version of Path. Luckily, the Path object from svgelements has
            # backwards compatible .point methods
            pathTransform = Matrix('')
            if 'transform' in attributes[i].keys():
                pathTransform = Matrix(attributes[i]['transform'])
                if self.verbose:
                    print('...Applying Transforms')
            path = elPath(paths[i].d()) * pathTransform
            path = elPath(path.d())

            # Another stage of transforms that gets applied to all paths
            # in order to shift the label around the origin

            tx = {
                'l': 0,
                'c': 0 - (float(svgWidth) / 2),
                'r': 0 - float(svgWidth)
            }
            ty = {'t': 250, 'c': 150, 'b': 50}
            path = elPath(paths[i].d()) * Matrix.translate(
                tx[self.originPos[1]], ty[self.originPos[0]])
            path = elPath(path.d())

            style = 0

            if 'style' in attributes[i].keys():
                style = styleParse(attributes[i]['style'])

            if 'fill' in attributes[i].keys():
                filled = attributes[i]['fill'] != 'none' and attributes[i][
                    'fill'] != ''
            elif 'style' in attributes[i].keys():
                filled = style['fill'] != 'none' and style['fill'] != ''
            else:
                filled = False

            if 'stroke' in attributes[i].keys():
                stroked = attributes[i]['stroke'] != 'none' and attributes[i][
                    'stroke'] != ''
            elif 'style' in attributes[i].keys():
                stroked = style['stroke'] != 'none' and style['stroke'] != ''
            else:
                stroked = False

            if not filled and not stroked:
                i += 1
                continue  # not drawable (clip path?)

            SUBSAMPLING = self.subSampling
            TRACEWIDTH = str(self.traceWidth)
            l = path.length()
            divs = round(l * SUBSAMPLING)
            if divs < 3:
                divs = 3
            maxLen = l * 2 * SCALE / divs
            p = path.point(0)
            p = complex(p.real * SCALE, p.imag * SCALE)
            last = p
            polys = []
            points = []
            s = 0
            while s <= divs:
                p = path.point(s * 1 / divs)
                p = complex(p.real * SCALE, p.imag * SCALE)
                if dist(p, last) > maxLen:
                    if len(points) > 1:
                        points = simplify(points, SIMPLIFY, SIMPLIFYHQ)
                        polys.append(points)
                    points = [p]
                else:
                    points.append(p)

                last = p
                s += 1

            if len(points) > 1:
                points = simplify(points, SIMPLIFY, SIMPLIFYHQ)
                polys.append(points)

            if filled:
                polys = unpackPoly(polys)

            for points in polys:

                if len(points) < 2:
                    return

                _points = []
                if filled:
                    points.append(
                        points[0])  # re-add final point so we loop around

                for p in points:
                    precisionX = round(p.real, 8)
                    precisionY = round(p.imag - self.exportHeight, 8)
                    _points += [(precisionX, precisionY)]

                out += [_points]

            i += 1

        self.polys = out

        return out
class CameraInterface(wx.Frame, Module):
    def __init__(self, parent, *args, **kwds):
        wx.Frame.__init__(self,
                          parent,
                          -1,
                          "",
                          style=wx.DEFAULT_FRAME_STYLE
                          | wx.FRAME_FLOAT_ON_PARENT | wx.TAB_TRAVERSAL)
        Module.__init__(self)
        if args >= 1:
            self.settings_value = args[0]
        else:
            self.settings_value = 0
        self.SetSize((600, 600))
        self.CameraInterface_menubar = wx.MenuBar()
        wxglade_tmp_menu = wx.Menu()
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Perspective"), "")
        self.Bind(wx.EVT_MENU, self.reset_perspective, id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Reset Fisheye"), "")
        self.Bind(wx.EVT_MENU, self.reset_fisheye, id=item.GetId())
        wxglade_tmp_menu.AppendSeparator()

        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set URI"), "")
        self.Bind(wx.EVT_MENU, lambda e: self.ip_menu_edit(), id=item.GetId())

        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set IP Camera"), "",
                                       wx.ITEM_RADIO)
        self.ip_camera_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(-1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 0"), "",
                                       wx.ITEM_RADIO)
        self.camera_0_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(0), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 1"), "",
                                       wx.ITEM_RADIO)
        self.camera_1_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(1), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 2"), "",
                                       wx.ITEM_RADIO)
        self.camera_2_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(2), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 3"), "",
                                       wx.ITEM_RADIO)
        self.camera_3_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(3), id=item.GetId())
        item = wxglade_tmp_menu.Append(wx.ID_ANY, _("Set Camera 4"), "",
                                       wx.ITEM_RADIO)
        self.camera_4_menu = item
        self.Bind(wx.EVT_MENU, lambda e: self.swap_camera(4), id=item.GetId())

        self.CameraInterface_menubar.Append(wxglade_tmp_menu, _("Camera"))
        self.SetMenuBar(self.CameraInterface_menubar)
        # Menu Bar

        self.button_update = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_camera_50.GetBitmap())
        self.button_export = wx.BitmapButton(
            self, wx.ID_ANY,
            icons8_picture_in_picture_alternative_50.GetBitmap())
        self.button_reconnect = wx.BitmapButton(
            self, wx.ID_ANY, icons8_connected_50.GetBitmap())
        self.check_fisheye = wx.CheckBox(self, wx.ID_ANY, _("Correct Fisheye"))
        self.check_perspective = wx.CheckBox(self, wx.ID_ANY,
                                             _("Correct Perspective"))
        self.slider_fps = wx.Slider(self,
                                    wx.ID_ANY,
                                    24,
                                    0,
                                    60,
                                    style=wx.SL_AUTOTICKS | wx.SL_HORIZONTAL
                                    | wx.SL_LABELS)
        self.button_detect = wx.BitmapButton(self, wx.ID_ANY,
                                             icons8_detective_50.GetBitmap())
        self.display_camera = wx.Panel(self, wx.ID_ANY)
        self.__set_properties()
        self.__do_layout()

        self.camera_job = None
        self.fetch_job = None
        self.camera_setting = None
        self.setting = None

        self.current_frame = None
        self.last_frame = None

        self.current_raw = None
        self.last_raw = None

        self.capture = None
        self.image_width = -1
        self.image_height = -1
        self._Buffer = None

        self.frame_bitmap = None

        self.fisheye_k = None
        self.fisheye_d = None

        # Used during calibration.
        self.objpoints = []  # 3d point in real world space
        self.imgpoints = []  # 2d points in image plane.

        # Perspective Points
        self.perspective = None

        self.previous_window_position = None
        self.previous_scene_position = None

        self.corner_drag = None

        self.matrix = Matrix()

        self.Bind(wx.EVT_BUTTON, self.on_button_update, self.button_update)
        self.Bind(wx.EVT_BUTTON, self.on_button_export, self.button_export)
        self.Bind(wx.EVT_BUTTON, self.on_button_reconnect,
                  self.button_reconnect)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_fisheye, self.check_fisheye)
        self.Bind(wx.EVT_CHECKBOX, self.on_check_perspective,
                  self.check_perspective)
        self.Bind(wx.EVT_SLIDER, self.on_slider_fps, self.slider_fps)
        self.Bind(wx.EVT_BUTTON, self.on_button_detect, self.button_detect)
        self.SetDoubleBuffered(True)
        # end wxGlade

        self.display_camera.Bind(wx.EVT_PAINT, self.on_paint)
        self.display_camera.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)
        self.display_camera.Bind(wx.EVT_MOTION, self.on_mouse_move)
        self.display_camera.Bind(wx.EVT_MOUSEWHEEL, self.on_mousewheel)
        self.display_camera.Bind(wx.EVT_MIDDLE_UP, self.on_mouse_middle_up)
        self.display_camera.Bind(wx.EVT_MIDDLE_DOWN, self.on_mouse_middle_down)

        self.display_camera.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_left_down)
        self.display_camera.Bind(wx.EVT_LEFT_UP, self.on_mouse_left_up)
        self.display_camera.Bind(wx.EVT_ENTER_WINDOW,
                                 lambda event: self.display_camera.SetFocus(
                                 ))  # Focus follows mouse.
        self.Bind(wx.EVT_CLOSE, self.on_close, self)

        self.on_size(None)
        self.Bind(wx.EVT_SIZE, self.on_size, self)
        self.camera_lock = threading.Lock()
        self.process = self.update_view
        self.connection_attempts = 0
        self.frame_attempts = 0
        self.last_frame_index = -1
        self.frame_index = 0
        self.quit_thread = False

    def __do_layout(self):
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.VERTICAL)
        sizer_2.Add(self.button_update, 0, 0, 0)
        sizer_2.Add(self.button_export, 0, 0, 0)
        sizer_2.Add(self.button_reconnect, 0, 0, 0)
        sizer_3.Add(self.check_fisheye, 0, 0, 0)
        sizer_3.Add(self.check_perspective, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_2.Add(self.slider_fps, 1, wx.EXPAND, 0)
        sizer_2.Add(self.button_detect, 0, 0, 0)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        sizer_1.Add(self.display_camera, 10, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        self.Layout()

    def __set_properties(self):
        _icon = wx.NullIcon
        _icon.CopyFromBitmap(icons8_camera_50.GetBitmap())
        self.SetIcon(_icon)
        # begin wxGlade: CameraInterface.__set_properties
        self.SetTitle("CameraInterface")
        self.button_update.SetToolTip(_("Update Image"))
        self.button_update.SetSize(self.button_update.GetBestSize())
        self.button_export.SetToolTip(_("Export Snapsnot"))
        self.button_export.SetSize(self.button_export.GetBestSize())
        self.button_reconnect.SetToolTip(_("Reconnect Camera"))
        self.button_reconnect.SetSize(self.button_reconnect.GetBestSize())
        self.button_detect.SetToolTip(_("Detect Distortions/Calibration"))
        self.button_detect.SetSize(self.button_detect.GetBestSize())
        # end wxGlade

    @staticmethod
    def sub_register(device):
        device.register('window', "CameraURI", CameraURI)

    def on_close(self, event):
        if self.state == 5:
            event.Veto()
        else:
            self.state = 5
            self.device.close('window', self.name)
            event.Skip()  # Call destroy as regular.

    def initialize(self, channel=None):
        self.device.close('window', self.name)
        self.Show()
        self.device.setting(bool, 'mouse_zoom_invert', False)
        self.device.setting(int, 'draw_mode', 0)
        self.device.setting(int, "bed_width", 320)  # Default Value
        self.device.setting(int, "bed_height", 220)  # Default Value

        self.camera_setting = self.device.device_root.derive('camera')
        self.setting = self.camera_setting.derive(str(self.settings_value))

        self.setting.setting(int, 'index', 0)
        self.setting.setting(int, 'fps', 1)
        self.setting.setting(bool, 'correction_fisheye', False)
        self.setting.setting(bool, 'correction_perspective', False)
        self.setting.setting(str, 'fisheye', '')
        self.setting.setting(str, 'perspective', '')
        self.setting.setting(str, 'uri', '0')
        self.check_fisheye.SetValue(self.setting.correction_fisheye)
        self.check_perspective.SetValue(self.setting.correction_perspective)
        if self.setting.fisheye is not None and len(self.setting.fisheye) != 0:
            self.fisheye_k, self.fisheye_d = eval(self.setting.fisheye)
        if self.setting.perspective is not None and len(
                self.setting.perspective) != 0:
            self.perspective = eval(self.setting.perspective)
        self.slider_fps.SetValue(self.setting.fps)

        if self.camera_job is not None:
            self.camera_job.cancel()
        self.open_camera(self.setting.index)
        self.device.listen('camera_uri_changed', self.on_camera_uri_change)
        self.device.listen('camera_frame_raw', self.on_camera_frame_raw)
        self.set_camera_checks()

    def finalize(self, channel=None):
        self.setting.flush()
        self.camera_setting.flush()
        self.device.unlisten('camera_uri_changed', self.on_camera_uri_change)
        self.device.unlisten('camera_frame_raw', self.on_camera_frame_raw)
        self.quit_thread = True
        if self.camera_job is not None:
            self.camera_job.cancel()
        if self.fetch_job is not None:
            self.fetch_job.cancel()
        try:
            self.Close()
        except RuntimeError:
            pass

    def shutdown(self, channel=None):
        try:
            self.Close()
            self.quit_thread = True
        except RuntimeError:
            pass

    def on_size(self, event):
        self.Layout()
        width, height = self.ClientSize
        if width <= 0:
            width = 1
        if height <= 0:
            height = 1
        self._Buffer = wx.Bitmap(width, height)
        self.update_in_gui_thread()

    def on_camera_uri_change(self, *args):
        pass

    def ip_menu_edit(self):
        """
        Select a particular URI.
        :param uri:
        :return:
        """
        self.device.using(
            'module', 'Console').write('window open CameraURI %s %s\n' %
                                       (self.settings_value, self.setting.uri))

    def ip_menu_uri_change(self, uri):
        def function(event=None):
            self.ip_menu_uri(uri)

        return function

    def ip_menu_uri(self, uri):
        """
        Select a particular URI.
        :param uri:
        :return:
        """
        self.setting.uri = uri
        self.swap_camera(-1)

    def set_camera_checks(self):
        """
        Set the checkmarks based on the index value.

        :return:
        """

        if self.setting.index == 0:
            self.camera_0_menu.Check(True)
        elif self.setting.index == 1:
            self.camera_1_menu.Check(True)
        elif self.setting.index == 2:
            self.camera_2_menu.Check(True)
        elif self.setting.index == 3:
            self.camera_3_menu.Check(True)
        elif self.setting.index == 4:
            self.camera_4_menu.Check(True)
        else:
            self.ip_camera_menu.Check(True)

    def update_view(self):
        frame = self.last_frame
        if frame is None:
            return
        print("%d vs %d" % (self.last_frame_index, self.frame_index))
        if self.frame_index == self.last_frame_index:
            return
        else:
            self.last_frame_index = self.frame_index
        bed_width = self.device.bed_width * 2
        bed_height = self.device.bed_height * 2

        self.image_height, self.image_width = frame.shape[:2]
        self.frame_bitmap = wx.Bitmap.FromBuffer(self.image_width,
                                                 self.image_height, frame)

        if self.setting.correction_perspective:
            if bed_width != self.image_width or bed_height != self.image_height:
                self.image_width = bed_width
                self.image_height = bed_height
                self.display_camera.SetSize(
                    (self.image_width, self.image_height))
        self.update_in_gui_thread()

    def on_camera_frame_raw(self, *args):
        """
        Raw Camera frame was requested and should be processed.

        This attempts to perform checkboard detection.

        :param frame:
        :return:
        """
        frame = self.last_raw
        if frame is None:
            return
        try:
            import cv2
            import numpy as np
        except:
            dlg = wx.MessageDialog(None,
                                   _("Could not import Camera requirements"),
                                   _("Imports Failed"), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
        CHECKERBOARD = (6, 9)
        subpix_criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,
                           30, 0.1)
        calibration_flags = cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC + cv2.fisheye.CALIB_CHECK_COND + cv2.fisheye.CALIB_FIX_SKEW
        objp = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
        objp[0, :, :2] = np.mgrid[0:CHECKERBOARD[0],
                                  0:CHECKERBOARD[1]].T.reshape(-1, 2)

        img = frame
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(
            gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH +
            cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
        # If found, add object points, image points (after refining them)

        if ret:
            self.objpoints.append(objp)
            cv2.cornerSubPix(gray, corners, (3, 3), (-1, -1), subpix_criteria)
            self.imgpoints.append(corners)
        else:
            dlg = wx.MessageDialog(None,
                                   _("Checkerboard 6x9 pattern not found."),
                                   _("Pattern not found."), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
            return
        N_OK = len(self.objpoints)
        K = np.zeros((3, 3))
        D = np.zeros((4, 1))
        rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
        tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(N_OK)]
        try:
            rms, a, b, c, d = \
                cv2.fisheye.calibrate(
                    self.objpoints,
                    self.imgpoints,
                    gray.shape[::-1],
                    K,
                    D,
                    rvecs,
                    tvecs,
                    calibration_flags,
                    (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6)
                )
        except cv2.error:
            # Ill conditioned matrix for input values.
            self.objpoints = self.objpoints[:-1]  # Deleting the last entry.
            self.imgpoints = self.imgpoints[:-1]
            dlg = wx.MessageDialog(None,
                                   _("Ill-conditioned Matrix. Keep trying."),
                                   _("Matrix."), wx.OK)
            dlg.ShowModal()
            dlg.Destroy()
            return
        dlg = wx.MessageDialog(
            None, _("Success. %d images so far." % len(self.objpoints)),
            _("Image Captured"), wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
        self.setting.fisheye = repr([K.tolist(), D.tolist()])
        self.fisheye_k = K.tolist()
        self.fisheye_d = D.tolist()

    def swap_camera(self, camera_index=0):
        """
        Disconnect the current connected camera.
        Connect to the provided camera index.

        :param camera_index:
        :return:
        """
        with self.camera_lock:
            self.close_camera()
            self.open_camera(camera_index)
        self.set_camera_checks()

    def init_camera(self):
        """
        Connect to Camera.

        :return:
        """
        if self.device is None:
            return
        if self.capture is not None:
            self.capture = None
        try:
            import cv2
        except ImportError:
            wx.CallAfter(self.camera_error_requirement)
            return
        wx.CallAfter(lambda: self.set_control_enable(True))
        try:
            self.interval = 1.0 / self.setting.fps
        except ZeroDivisionError:
            self.interval = 5
        except AttributeError:
            return
        self.device.threaded(self.threaded_image_fetcher)
        self.schedule()

    def open_camera(self, camera_index=0):
        """
        Open Camera device. Prevents opening if already opening.

        :param camera_index:
        :return:
        """
        if self.camera_job is not None:
            self.camera_job.cancel()
        self.setting.index = camera_index
        uri = self.get_camera_uri()
        if uri is not None:
            self.camera_job = self.device.add_job(self.init_camera,
                                                  times=1,
                                                  interval=0.1)

    def close_camera(self):
        """
        Disconnect from the current camera.

        :return:
        """
        self.unschedule()
        if self.capture is not None:
            self.capture.release()
            self.capture = None

    def set_control_enable(self, enable=False):
        """
        Disable/Enable all the major controls within the GUI.
        :param enable:
        :return:
        """
        try:
            for attr in dir(self):
                value = getattr(self, attr)
                if isinstance(value, wx.Control):
                    if value is not self.button_reconnect:
                        value.Enable(enable)
        except RuntimeError:
            pass

    def camera_error_requirement(self):
        """
        Message Error that OpenCV is not installed and thus camera cannot run.

        Disable all Controls.

        :return:
        """
        try:
            self.set_control_enable(False)
            dlg = wx.MessageDialog(
                None,
                _("If using a precompiled binary, this was requirement was not included.\nIf using pure Python, add it with: pip install opencv-python-headless"
                  ), _("Interface Requires OpenCV."), wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        except RuntimeError:
            pass

    def camera_error_webcam(self):
        """
        Message error based on failure to connect to webcam.

        Disable all Controls.

        :return:
        """
        try:
            self.set_control_enable(False)
            dlg = wx.MessageDialog(None, _("No Webcam found."), _("Error"),
                                   wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        except RuntimeError:
            pass

    def ip_menu_new(self):
        """
        Requests and adds new IP Connection URI.

        :return:
        """
        dlg = wx.TextEntryDialog(self, _("Enter the HTTP or RTSP uri"),
                                 _("Webcam URI Update"), '')
        dlg.SetValue(str(self.get_camera_uri()))
        modal = dlg.ShowModal()
        if modal == wx.ID_OK:
            uri = str(dlg.GetValue())
            index = len(list(self.camera_setting.keylist()))
            setattr(self.camera_setting, 'uri' + str(index), uri)
            self.setting.uri = uri
            self.ip_menu_uri(uri)
            self.swap_camera(-1)
            self.set_camera_checks()

    def get_camera_uri(self):
        """
        Get the current camera URI.

        If the URI

        :return:
        """
        index = self.setting.index
        if index >= 0:
            return index
        uri = self.setting.uri
        if uri is None or len(uri) == 0:
            return None
        try:
            return int(uri)
        except ValueError:
            # URI is not a number.
            return uri

    def attempt_recovery(self):
        try:
            import cv2
        except ImportError:
            return False
        if self.quit_thread:
            return False
        if self.device is None:
            return False
        self.frame_attempts += 1
        if self.frame_attempts < 5:
            return True
        self.frame_attempts = 0

        if self.capture is not None:
            with self.camera_lock:
                self.capture.release()
                self.capture = None
        uri = self.get_camera_uri()
        if uri is None:
            return False

        self.device.signal("camera_initialize")
        with self.camera_lock:
            self.capture = cv2.VideoCapture(uri)

        if self.capture is None:
            return False
        self.connection_attempts += 1
        return True

    def threaded_image_fetcher(self):
        self.quit_thread = False
        try:
            import cv2
        except ImportError:
            return

        raw = False

        uri = self.get_camera_uri()
        if uri is None:
            return
        self.device.signal("camera_initialize")
        with self.camera_lock:
            self.capture = cv2.VideoCapture(uri)

        while not self.quit_thread:
            if self.connection_attempts > 50:
                wx.CallAfter(self.camera_error_webcam)
            with self.camera_lock:
                if self.capture is None:
                    # No capture the thread dies.
                    return
                try:
                    ret = self.capture.grab()
                except AttributeError:
                    continue

                if not ret:
                    if self.attempt_recovery():
                        continue
                    else:
                        return

                ret, frame = self.capture.retrieve()
                if not ret or frame is None:
                    if self.attempt_recovery():
                        continue
                    else:
                        return
            self.frame_attempts = 0
            self.connection_attempts = 0
            self.last_raw = self.current_raw
            self.current_raw = frame

            if not raw and \
                    self.fisheye_k is not None and \
                    self.fisheye_d is not None and \
                    self.device is not None and \
                    self.setting.correction_fisheye:
                # Unfisheye the drawing
                import numpy as np
                K = np.array(self.fisheye_k)
                D = np.array(self.fisheye_d)
                DIM = frame.shape[:2][::-1]
                map1, map2 = cv2.fisheye.initUndistortRectifyMap(
                    K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
                frame = cv2.remap(frame,
                                  map1,
                                  map2,
                                  interpolation=cv2.INTER_LINEAR,
                                  borderMode=cv2.BORDER_CONSTANT)
            if not raw and self.device is not None and self.setting.correction_perspective:
                # Perspective the drawing.
                bed_width = self.device.bed_width * 2
                bed_height = self.device.bed_height * 2
                width, height = frame.shape[:2][::-1]
                import numpy as np
                if self.perspective is None:
                    rect = np.array([[0, 0], [width - 1, 0],
                                     [width - 1, height - 1], [0, height - 1]],
                                    dtype="float32")
                else:
                    rect = np.array(self.perspective, dtype="float32")
                dst = np.array(
                    [[0, 0], [bed_width - 1, 0],
                     [bed_width - 1, bed_height - 1], [0, bed_height - 1]],
                    dtype="float32")
                M = cv2.getPerspectiveTransform(rect, dst)
                frame = cv2.warpPerspective(frame, M, (bed_width, bed_height))
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

            self.last_frame = self.current_frame
            self.current_frame = frame
            self.frame_index += 1
        if self.capture is not None:
            self.capture.release()
            self.capture = None
        if self.device is not None:
            self.device.signal("camera_finalize")

    def reset_perspective(self, event):
        """
        Reset the perspective settings.

        :param event:
        :return:
        """
        self.perspective = None
        self.setting.perspective = ''

    def reset_fisheye(self, event):
        """
        Reset the fisheye settings.

        :param event:
        :return:
        """
        self.fisheye_k = None
        self.fisheye_d = None
        self.setting.fisheye = ''

    def on_erase(self, event):
        """
        Erase camera view.
        :param event:
        :return:
        """
        pass

    def on_paint(self, event):
        """
        Paint camera view.
        :param event:
        :return:
        """
        try:
            wx.BufferedPaintDC(self.display_camera, self._Buffer)
        except RuntimeError:
            pass

    def on_update_buffer(self, event=None):
        """
        Draw Camera view.

        :param event:
        :return:
        """
        if self.frame_bitmap is None:
            return  # Need the bitmap to refresh.
        dm = self.device.draw_mode
        dc = wx.MemoryDC()
        dc.SelectObject(self._Buffer)
        dc.Clear()
        w, h = dc.Size
        if dm & DRAW_MODE_FLIPXY != 0:
            dc.SetUserScale(-1, -1)
            dc.SetLogicalOrigin(w, h)
        dc.SetBackground(wx.WHITE_BRUSH)
        gc = wx.GraphicsContext.Create(dc)  # Can crash at bitmap okay
        gc.SetTransform(
            wx.GraphicsContext.CreateMatrix(gc, ZMatrix(self.matrix)))
        gc.PushState()
        gc.DrawBitmap(self.frame_bitmap, 0, 0, self.image_width,
                      self.image_height)
        if not self.setting.correction_perspective:
            if self.perspective is None:
                self.perspective = [0, 0], \
                                   [self.image_width, 0], \
                                   [self.image_width, self.image_height], \
                                   [0, self.image_height]
            gc.SetPen(wx.BLACK_DASHED_PEN)
            gc.StrokeLines(self.perspective)
            gc.StrokeLine(self.perspective[0][0], self.perspective[0][1],
                          self.perspective[3][0], self.perspective[3][1])
            gc.SetPen(wx.BLUE_PEN)
            for p in self.perspective:
                half = CORNER_SIZE / 2
                gc.StrokeLine(p[0] - half, p[1], p[0] + half, p[1])
                gc.StrokeLine(p[0], p[1] - half, p[0], p[1] + half)
                gc.DrawEllipse(p[0] - half, p[1] - half, CORNER_SIZE,
                               CORNER_SIZE)
        gc.PopState()
        if dm & DRAW_MODE_INVERT != 0:
            dc.Blit(0, 0, w, h, dc, 0, 0, wx.SRC_INVERT)
        gc.Destroy()
        del dc

    def convert_scene_to_window(self, position):
        """
        Scene Matrix convert scene to window.
        :param position:
        :return:
        """
        point = self.matrix.point_in_matrix_space(position)
        return point[0], point[1]

    def convert_window_to_scene(self, position):
        """
        Scene Matrix convert window to scene.
        :param position:
        :return:
        """
        point = self.matrix.point_in_inverse_space(position)
        return point[0], point[1]

    def on_mouse_move(self, event):
        """
        Handle mouse movement.

        :param event:
        :return:
        """
        if not event.Dragging():
            return
        else:
            self.SetCursor(wx.Cursor(wx.CURSOR_HAND))
        if self.previous_window_position is None:
            return
        pos = event.GetPosition()
        window_position = pos.x, pos.y
        scene_position = self.convert_window_to_scene(
            [window_position[0], window_position[1]])
        sdx = (scene_position[0] - self.previous_scene_position[0])
        sdy = (scene_position[1] - self.previous_scene_position[1])
        wdx = (window_position[0] - self.previous_window_position[0])
        wdy = (window_position[1] - self.previous_window_position[1])
        if self.corner_drag is None:
            self.scene_post_pan(wdx, wdy)
        else:
            self.perspective[self.corner_drag][0] += sdx
            self.perspective[self.corner_drag][1] += sdy
            self.setting.perspective = repr(self.perspective)
        self.previous_window_position = window_position
        self.previous_scene_position = scene_position

    def on_mousewheel(self, event):
        """
        Handle mouse wheel.

        Used for zooming.

        :param event:
        :return:
        """
        rotation = event.GetWheelRotation()
        mouse = event.GetPosition()
        if self.device.device_root.mouse_zoom_invert:
            rotation = -rotation
        if rotation > 1:
            self.scene_post_scale(1.1, 1.1, mouse[0], mouse[1])
        elif rotation < -1:
            self.scene_post_scale(0.9, 0.9, mouse[0], mouse[1])

    def on_mouse_left_down(self, event):
        """
        Handle mouse left down event.

        Used for adjusting perspective items.

        :param event:
        :return:
        """
        self.previous_window_position = event.GetPosition()
        self.previous_scene_position = self.convert_window_to_scene(
            self.previous_window_position)
        self.corner_drag = None
        if self.perspective is not None:
            for i, p in enumerate(self.perspective):
                half = CORNER_SIZE / 2
                if Point.distance(self.previous_scene_position, p) < half:
                    self.corner_drag = i
                    break

    def on_mouse_left_up(self, event):
        """
        Handle Mouse Left Up.

        Drag Ends.

        :param event:
        :return:
        """
        self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        self.previous_window_position = None
        self.previous_scene_position = None
        self.corner_drag = None

    def on_mouse_middle_down(self, event):
        """
        Handle mouse middle down

        Panning.

        :param event:
        :return:
        """
        self.SetCursor(wx.Cursor(wx.CURSOR_HAND))
        self.previous_window_position = event.GetPosition()
        self.previous_scene_position = self.convert_window_to_scene(
            self.previous_window_position)

    def on_mouse_middle_up(self, event):
        """
        Handle mouse middle up.

        Pan ends.

        :param event:
        :return:
        """
        self.SetCursor(wx.Cursor(wx.CURSOR_ARROW))
        self.previous_window_position = None
        self.previous_scene_position = None

    def scene_post_pan(self, px, py):
        """
        Scene Pan.
        :param px:
        :param py:
        :return:
        """
        self.matrix.post_translate(px, py)
        self.on_update_buffer()

    def scene_post_scale(self, sx, sy=None, ax=0, ay=0):
        """
        Scene Zoom.
        :param sx:
        :param sy:
        :param ax:
        :param ay:
        :return:
        """
        self.matrix.post_scale(sx, sy, ax, ay)
        self.on_update_buffer()

    def update_in_gui_thread(self):
        """
        Redraw on the GUI thread.
        :return:
        """
        self.on_update_buffer()
        try:
            self.Refresh(True)
            self.Update()
        except RuntimeError:
            pass

    def on_check_perspective(self, event):
        """
        Perspective checked. Turns on/off
        :param event:
        :return:
        """
        self.setting.correction_perspective = self.check_perspective.GetValue()

    def on_check_fisheye(self, event):
        """
        Fisheye checked. Turns on/off.
        :param event:
        :return:
        """
        self.setting.correction_fisheye = self.check_fisheye.GetValue()

    def on_button_update(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        """
        Button update.

        Sets image background to main scene.

        :param event:
        :return:
        """
        frame = self.device.last_signal('camera_frame')
        if frame is not None:
            frame = frame[0]
            buffer = wx.Bitmap.FromBuffer(self.image_width, self.image_height,
                                          frame)
            self.device.signal('background', buffer)

    def on_button_export(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        """
        Button export.

        Sends an image to the scene as an exported object.
        :param event:
        :return:
        """
        frame = self.device.last_signal('camera_frame')
        if frame is not None:
            elements = self.device.device_root.elements
            frame = frame[0]
            from PIL import Image
            img = Image.fromarray(frame)
            obj = SVGImage()
            obj.image = img
            obj.image_width = self.image_width
            obj.image_height = self.image_height
            elements.add_elem(obj)

    def on_button_reconnect(self,
                            event):  # wxGlade: CameraInterface.<event_handler>
        self.quit_thread = True

    def on_slider_fps(self, event):  # wxGlade: CameraInterface.<event_handler>
        """
        Adjusts the camera FPS.

        If set to 0, this will be a frame each 5 seconds.

        :param event:
        :return:
        """
        fps = self.slider_fps.GetValue()
        if fps == 0:
            tick = 5
        else:
            tick = 1.0 / fps
        self.setting.fps = fps
        self.interval = tick

    def on_button_detect(self,
                         event):  # wxGlade: CameraInterface.<event_handler>
        """
        Attempts to locate 6x9 checkerboard pattern for OpenCV to correct the fisheye pattern.

        :param event:
        :return:
        """
        if self.fetch_job is not None:
            self.fetch_job.cancel()
        # TODO: This won't work anymore.
        self.device.signal('camera_frame_raw', None)

        self.fetch_job = self.device.add_job(self.on_camera_frame_raw,
                                             args=True,
                                             times=1,
                                             interval=0)
Beispiel #13
0
def drawSVG(svg_attributes, attributes, paths):

    global SCALE
    global SUBSAMPLING
    global SIMPLIFY
    global SIMPLIFYHQ
    global TRACEWIDTH

    out = ''
    svgWidth = 0
    svgHeight = 0

    if 'viewBox' in svg_attributes.keys():
        if svg_attributes['viewBox'].split()[2] != '0':
            svgWidth = str(
                round(float(svg_attributes['viewBox'].split()[2]), 2))
            svgHeight = str(
                round(float(svg_attributes['viewBox'].split()[3]), 2))
        else:
            svgWidth = svg_attributes['width']
            svgHeight = svg_attributes['height']
    else:
        svgWidth = svg_attributes['width']
        svgHeight = svg_attributes['height']

    specifiedWidth = svg_attributes.get('width')
    if specifiedWidth == None:
        specifiedWidth = "None"
    if 'mm' in specifiedWidth:
        specifiedWidth = float(specifiedWidth.replace('mm', ''))
        SCALE = specifiedWidth / float(svgWidth)
        if args.verbose:
            print("SVG width detected in mm \\o/")
    elif 'in' in specifiedWidth:
        specifiedWidth = float(specifiedWidth.replace('in', '')) * 25.4
        SCALE = specifiedWidth / float(svgWidth)
        if args.verbose:
            print("SVG width detected in inches")
    else:
        SCALE = (args.scaleFactor * 25.4) / 150
        if args.verbose:
            print("SVG width not found, guessing based on scale factor")

    exportHeight = float(svgHeight) * SCALE

    if args.outMode == "b":
        out += "CHANGE layer " + str(args.eagleLayerNumber) + \
            "; CHANGE rank 3; CHANGE pour solid; SET WIRE_BEND 2;\n"
    if args.outMode == "ls":
        out += "CHANGE layer " + str(args.eagleLayerNumber) + \
            "; CHANGE pour solid; Grid mm; SET WIRE_BEND 2;\n"

    if len(paths) == 0:
        print("No paths found. Did you use 'Object to path' in Inkscape?")
    anyVisiblePaths = False

    i = 0
    while i < len(paths):

        if args.verbose:
            print('Translating Path ' + str(i + 1) + ' of ' + str(len(paths)))

        # Apply the tranform from this svg object to actually transform the points
        # We need the Matrix object from svgelements but we can only matrix multiply with
        # svgelements' version of the Path object so we're gonna do some dumb stuff
        # to launder the Path object from svgpathtools through a d-string into
        # svgelements' version of Path. Luckily, the Path object from svgelements has
        # backwards compatible .point methods
        pathTransform = Matrix('')
        if 'transform' in attributes[i].keys():
            pathTransform = Matrix(attributes[i]['transform'])
            if args.verbose:
                print('...Applying Transforms')
        path = elPath(paths[i].d()) * pathTransform
        path = elPath(path.d())

        # Another stage of transforms that gets applied to all paths
        # in order to shift the label around the origin

        tx = {'l': 0, 'c': 0 - (float(svgWidth) / 2), 'r': 0 - float(svgWidth)}
        ty = {'t': 250, 'c': 150, 'b': 50}
        path = elPath(paths[i].d()) * Matrix.translate(tx[args.originPos[1]],
                                                       ty[args.originPos[0]])
        path = elPath(path.d())

        style = 0

        if 'style' in attributes[i].keys():
            style = styleParse(attributes[i].get('style'))

        if 'fill' in attributes[i].keys():
            filled = attributes[i].get('fill') != 'none' and attributes[i].get(
                'fill') != ''
        elif 'style' in attributes[i].keys():
            filled = style.get('fill') != 'none' and style.get('fill') != ''
        else:
            filled = False

        if 'stroke' in attributes[i].keys():
            stroked = attributes[i].get(
                'stroke') != 'none' and attributes[i].get('stroke') != ''
        elif 'style' in attributes[i].keys():
            stroked = style.get('stroke') != 'none' and style.get(
                'stroke') != ''
        else:
            stroked = False

        if not filled and not stroked:
            i += 1
            continue  # not drawable (clip path?)

        SUBSAMPLING = args.subSampling
        TRACEWIDTH = str(args.traceWidth)
        anyVisiblePaths = True
        l = path.length()
        divs = round(l * SUBSAMPLING)
        if divs < 3:
            divs = 3
        maxLen = l * 2 * SCALE / divs
        p = path.point(0)
        p = complex(p.real * SCALE, p.imag * SCALE)
        last = p
        polys = []
        points = []
        s = 0
        while s <= divs:
            p = path.point(s * 1 / divs)
            p = complex(p.real * SCALE, p.imag * SCALE)
            if dist(p, last) > maxLen:
                if len(points) > 1:
                    points = simplify(points, SIMPLIFY, SIMPLIFYHQ)
                    polys.append(points)
                points = [p]
            else:
                points.append(p)

            last = p
            s += 1

        if len(points) > 1:
            points = simplify(points, SIMPLIFY, SIMPLIFYHQ)
            polys.append(points)

        if filled:
            polys = unpackPoly(polys)

        for points in polys:

            if len(points) < 2:
                return

            scriptLine = ''
            if filled:
                points.append(
                    points[0])  # re-add final point so we loop around

            if args.outMode != "lib":

                if args.outMode == "b":
                    scriptLine += "polygon " + args.signalName + " " + TRACEWIDTH + "mm "

                if args.outMode == "ls":
                    scriptLine += "polygon " + TRACEWIDTH + "mm "

                for p in points:
                    precisionX = '{0:.2f}'.format(round(p.real, 6))
                    precisionY = '{0:.2f}'.format(
                        round(exportHeight - p.imag, 6))
                    scriptLine += '(' + precisionX + 'mm ' + precisionY + 'mm) '

                scriptLine += ';'

            else:

                scriptLine += "<polygon width=\"" + TRACEWIDTH + "\" layer=\"" + str(
                    args.eagleLayerNumber) + "\">\n"

                for p in points:
                    precisionX = '{0:.2f}'.format(round(p.real, 6))
                    precisionY = '{0:.2f}'.format(
                        round(exportHeight - p.imag, 6))
                    scriptLine += "<vertex x=\"" + precisionX + "\" y=\"" + precisionY + "\"/>\n"

                scriptLine += "</polygon>"

            out += scriptLine + '\n'

        i += 1

    if not anyVisiblePaths:
        print("No paths with fills or strokes found.")

    return out