Example #1
0
class Microscope(QWidget):
    roiClicked = Signal(int, int)

    def __init__(self, parent=None):
        super(Microscope, self).__init__(parent)

        self.setMinimumWidth(300)
        self.setMinimumHeight(300)
        self.image = QImage('image.jpg')
        self.clicks = []
        self.center = QPoint(self.image.size().width() / 2,
                             self.image.size().height() / 2)
        self.drawBoxes = False
        self.start = QPoint(0, 0)
        self.end = QPoint(1, 1)
        self.yDivs = 5
        self.xDivs = 5
        self.color = False
        self.fps = 5
        self.scaleBar = False
        self.crop = []
        self.scale = []

        self.url = 'http://localhost:9998/jpg/image.jpg'

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.updateImage)

        self.downloader = Downloader(self)
        self.downloader.imageReady.connect(self.updateImageData)

    def updatedImageSize(self):
        if self.image.size() != self.minimumSize():
            self.setMinimumSize(self.image.size())
            self.center = QPoint(self.image.size().width() / 2,
                                 self.image.size().height() / 2)

    def acquire(self, start=True):
        self.downloader.setUrl(self.url)
        if start:
            self.timer.start(1000.0 / self.fps)
        else:
            self.timer.stop()

    def paintBoxes(self, painter):
        rect = QRect(
            self.start.x(),
            self.start.y(),
            self.end.x() - self.start.x(),
            self.end.y() - self.start.y(),
        )
        painter.setPen(QColor.fromRgb(0, 255, 0))
        painter.drawRect(rect)
        # Now draw the lines for the boxes in the rectangle.
        x1 = self.start.x()
        y1 = self.start.y()
        x2 = self.end.x()
        y2 = self.end.y()
        inc_x = (x2 - x1) / self.xDivs
        inc_y = (y2 - y1) / self.yDivs
        lines = time.perf_counter()
        for i in range(1, self.xDivs):
            painter.drawLine(x1 + i * inc_x, y1, x1 + i * inc_x, y2)
        for i in range(1, self.yDivs):
            painter.drawLine(x1, y1 + i * inc_y, x2, y1 + i * inc_y)
        mid = time.perf_counter()

        # Now draw the color overlay thing if requested
        rects = time.perf_counter()
        if self.color:
            brushColor = QColor(0, 255, 0, 20)
            brush = QBrush(brushColor)
            painter.setBrush(brush)
            painter.setPen(QColor.fromRgb(0, 255, 0))
            for i in range(0, self.xDivs):
                for j in range(0, self.yDivs):
                    alpha = i / self.yDivs * 255
                    if True:  # j % 2 == 0:
                        brushColor.setAlpha(alpha / 2)
                        brushColor.setGreen(255)
                    else:
                        brushColor.setAlpha(255 / 2)
                        brushColor.setGreen(alpha)

                    brush.setColor(brushColor)
                    painter.setBrush(brush)
                    rect = QRect(x1 + i * inc_x, y1 + j * inc_y, inc_x, inc_y)
                    painter.drawRect(rect)
        rects2 = time.perf_counter()

    def paintEvent(self, event):
        tic = time.perf_counter()
        painter = QPainter(self)
        rect = event.rect()
        painter.drawImage(rect, self.image, rect)
        painter.setPen(QColor.fromRgb(255, 0, 0))
        #painter.drawPoints(self.clicks)
        if self.drawBoxes:
            self.drawBoxes(painter)
        # Draw the center mark
        painter.setPen(QColor.fromRgb(255, 0, 0))
        painter.drawLine(self.center.x() - 20, self.center.y(),
                         self.center.x() + 20, self.center.y())
        painter.drawLine(self.center.x(),
                         self.center.y() - 20, self.center.x(),
                         self.center.y() + 20)

        # Draw the scale bar
        if self.scaleBar:
            painter.setPen(QColor.fromRgb(40, 40, 40))
            painter.setFont(QFont("Arial", 30))
            scaleRect = QRect(10, 420, 200, 30)
            painter.drawText(scaleRect, Qt.AlignCenter, "10 nm")
            pen = painter.pen()
            pen.setWidth(5)
            painter.setPen(pen)
            painter.drawLine(10, 460, 210, 460)

        toc = time.perf_counter()

    def mousePressEvent(self, event):
        pos = event.pos()
        self.roiClicked.emit(pos.x(), pos.y())
        self.clicks.append(pos)
        self.start = pos
        self.end = pos
        self.update()

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def sizeHint(self):
        return QSize(400, 400)

    def updateImage(self):
        """ Request an updated image asynchronously. """
        self.downloader.downloadData()

    def updateImageData(self, image):
        """ Triggered when the new image is ready, update the view. """
        self.image.loadFromData(image, 'JPG')
        if len(self.crop) == 4:
            self.image = self.image.copy(self.crop[0], self.crop[1],
                                         self.crop[2], self.crop[3])
        if len(self.scale) == 2:
            if self.scale[0] > 0:
                self.image = self.image.scaledToWidth(self.scale[0])
            elif self.scale[1] > 0:
                self.image = self.image.scaledToHeight(self.scale[1])

        self.updatedImageSize()
        self.update()

    def resizeImage(self):
        if len(self.crop) == 4:
            self.image = self.image.copy(self.crop[0], self.crop[1],
                                         self.crop[2], self.crop[3])
        if len(self.scale) == 2:
            if self.scale[0] > 0:
                self.image = self.image.scaledToWidth(self.scale[0])
            elif self.scale[1] > 0:
                self.image = self.image.scaledToHeight(self.scale[1])

    def readFromDict(self, settings):
        """ Read the settings from a Python dict. """
        if settings.has_key('url'):
            self.url = settings['url']
        if settings.has_key('fps'):
            self.fps = settings['fps']
        if settings.has_key('xDivs'):
            self.xDivs = settings['xDivs']
        if settings.has_key('yDivs'):
            self.yDivs = settings['yDivs']
        if settings.has_key('color'):
            self.color = settings['color']
        if settings.has_key('scaleW'):
            self.scale = [settings['scaleW'], 0]
        if settings.has_key('scaleH'):
            if len(self.scale) == 2:
                self.scale[1] = settings['scaleW']
            else:
                self.scale = [0, settings['scaleW']]

    def writeToDict(self):
        """ Write the widget's settings to a Python dict. """
        settings = {
            'url': self.url,
            'fps': self.fps,
            'xDivs': self.xDivs,
            'yDivs': self.yDivs,
            'color': self.color
        }
        if len(self.scale) == 2:
            settings['scaleW'] = self.scale[0]
            settings['scaleH'] = self.scale[1]
        return settings

    def readSettings(self, settings):
        """ Read the settings for this microscope instance. """
        self.url = settings.value('url', 'http://localhost:9998/jpg/image.jpg')
        print(f'url: {self.url}')
        self.fps = settings.value('fps', 5, type=int)
        self.xDivs = settings.value('xDivs', 5, type=int)
        self.yDivs = settings.value('yDivs', 5, type=int)
        self.color = settings.value('color', False, type=bool)
        if settings.value('scaleW', -1, type=int) >= 0:
            self.scale = [
                settings.value('scaleW', 0, type=int),
                settings.value('scaleH', 0, type=int)
            ]
            self.resizeImage()

    def writeSettings(self, settings):
        """ Write the settings for this microscope instance. """
        settings.setValue('url', self.url)
        settings.setValue('fps', self.fps)
        settings.setValue('xDivs', self.xDivs)
        settings.setValue('yDivs', self.yDivs)
        settings.setValue('color', self.color)
        if len(self.scale) == 2:
            settings.setValue('scaleW', self.scale[0])
            settings.setValue('scaleH', self.scale[1])