Esempio n. 1
0
 def merge_with_layer_immediately_below(self):
     """
     Merges a layer with the next lower visible layer. Does nothing
     if mode is preview or the target layer is an adjustment layer.
     """
     if not hasattr(self, 'inputImg'):
         return
     ind = self.getLowerVisibleStackIndex()
     if ind < 0:
         # no visible layer found
         return
     target = self.parentImage.layersStack[ind]
     if hasattr(target, 'inputImg') or self.parentImage.useThumb:
         info = "Uncheck Preview first" if self.parentImage.useThumb else "Target layer must be background or image"
         dlgWarn("Cannot Merge layers", info=info)
         return
     # update stack
     self.parentImage.layersStack[0].applyToStack()
     # merge
     # target.setImage(self)
     qp = QPainter(target)
     qp.setCompositionMode(self.compositionMode)
     qp.setOpacity(self.opacity)
     qp.drawImage(QRect(0, 0, self.width(), self.height()), self)
     target.updatePixmap()
     self.parentImage.layerView.clear(delete=False)
     currentIndex = self.getStackIndex()
     self.parentImage.activeLayerIndex = ind
     self.parentImage.layersStack.pop(currentIndex)
     self.parentImage.layerView.setLayers(self.parentImage)
Esempio n. 2
0
    def run(self):
        image = QImage()
        image.load(str(self.filename))

        mask = QImage(image.size(), QImage.Format_RGB32)
        mask.fill(Qt.black)

        maskfile = self.filename.parent / (self.filename.stem + ".mask")
        if maskfile.exists():
            bitmap = QImage(str(maskfile))
            if bitmap.size() != image.size():
                raise Exception("Mask %s doesn't match image size" % maskfile)
            mask.fill(QColor.fromRgbF(1.0, 0.0, 1.0))
            p = QPainter(mask)
            p.setCompositionMode(QPainter.CompositionMode_Multiply)
            p.drawImage(mask.rect(), bitmap)
            p.end()

        self.view.imagefile = self.filename
        self.view.image = image
        self.view.mask = mask
        self.view.maskfile = maskfile

        self.view.path = list()
        self.view.changed = False
        self.view.update()
 def paintEvent(self, event):
     painter = QPainter(self)
     painter.fillRect(self.rect(), QBrush(self._color_srgb))
     painter.setCompositionMode(QPainter.RasterOp_SourceXorDestination)
     pen = QPen(QBrush(Qt.white), 2., Qt.SolidLine, Qt.SquareCap,
                Qt.MiterJoin)
     painter.setPen(pen)
     painter.drawRect(self.rect().adjusted(1, 1, -1, -1))
Esempio n. 4
0
def get_icon(name, color=None):
    pixmap = QPixmap(f'icons-fontawesome/{name}.svg')
    if color != None:
        painter = QPainter(pixmap)
        painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
        painter.fillRect(pixmap.rect(), color)
        painter.end()
    return QIcon(pixmap)
Esempio n. 5
0
def pix_add_blurry(pix, transparency: float):
    temp_pix = QPixmap(pix.size())
    temp_pix.fill(Qt.transparent)
    painter = QPainter(temp_pix)
    painter.setCompositionMode(QPainter.CompositionMode_Source)
    painter.drawPixmap(0, 0, pix)
    painter.setCompositionMode(QPainter.CompositionMode_DestinationIn)
    painter.fillRect(temp_pix.rect(), QColor(0, 0, 0, int(255 * transparency)))
    painter.end()
    return temp_pix
Esempio n. 6
0
def set_rop2(op: int, painter: QPainter):
    """
    Configure a QPainter with the required binary raster operation.

    :parma op: The operation identifier.
    :param painter: The painter being used.
    :returns: The operation that will be processed.
    """
    if op < 0 or op >= len(_rop2):
        return None
    mode = _rop2[op]
    painter.setCompositionMode(mode)
    return mode
Esempio n. 7
0
    def make_compose_image(self):
        self.make_layer_image()

        self.compose_qimg = QImage(self.org_img_width, self.org_img_height,
                                   QImage.Format_RGBA8888)
        painter = QPainter(self.compose_qimg)

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        painter.drawImage(0, 0, self.org_qimg)

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        painter.drawImage(0, 0, self.layer_qimg)

        painter.end()
Esempio n. 8
0
    def erase_cursor_rect(self, pos: Tuple[int, int]):
        painter = QPainter(self.cursors_pixmap)

        cursor_rect = QRect(self.byte_rect)
        h = cursor_rect.height()
        i, j = pos

        cursor_rect.moveTopLeft(QPoint(i * self.byte_advance, j * h))

        painter.setCompositionMode(QPainter.CompositionMode_Source)
        painter.setPen(Qt.NoPen)
        painter.setBrush(Qt.transparent)
        painter.drawRect(cursor_rect)
        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
 def paintEvent(self, event):
     painter = QPainter(self)
     painter.drawPixmap(0, 0, self._pixmap)
     painter.save()
     painter.setCompositionMode(QPainter.RasterOp_SourceXorDestination)
     pen = QPen(QBrush(Qt.white), 2., Qt.SolidLine, Qt.SquareCap,
                Qt.MiterJoin)
     painter.setPen(pen)
     s = self._scale
     painter.drawRect(
         QRect(self._pos.x() * s - 1,
               (self._size.height() - 1 - self._pos.y()) * s - 1, s + 2,
               s + 2))
     painter.restore()
Esempio n. 10
0
    def join_pixmap(self, p1, p2):

        result = QPixmap(p1.size())
        result.fill(QtCore.Qt.transparent)
        painter = QPainter(result)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.setCompositionMode(QPainter.CompositionMode_Source)
        painter.drawPixmap(QtCore.QPoint(), p1)

        painter.setCompositionMode(QPainter.CompositionMode_Overlay)
        painter.drawPixmap(QtCore.QPoint(), p2)

        painter.end()
        return result
Esempio n. 11
0
    def drawCircle(self, point):
        painter = QPainter(self.image)
        painter.setCompositionMode(QPainter.CompositionMode_Source)
        painter.setRenderHint(QPainter.Antialiasing)

        brush = QBrush(QColor(0, 0, 255, 255), Qt.SolidPattern)
        pen = QPen(brush, 0.2 * self.myPenWidth / self.scaleFactor,
                   Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        painter.setPen(pen)
        radius = 1.5 * self.myPenWidth / self.scaleFactor
        rectangle = QRectF((point.x() / self.scaleFactor) - (radius / 2),
                           (point.y() / self.scaleFactor) - (radius / 2),
                           radius, radius)
        painter.drawEllipse(rectangle)

        self.update()
Esempio n. 12
0
    def paintEvent(self, event):
        p = QPainter()
        p.begin(self)
        self._normalMap.render(p, event.rect())

        p.setPen(Qt.black)
        p.drawText(
            self.rect(), Qt.AlignBottom | Qt.TextWordWrap,
            "GridCal, Map data CCBYSA 2009 "
            "OpenStreetMap.org contributors")
        p.end()

        if self.invert:
            p = QPainter(self)
            p.setCompositionMode(QPainter.CompositionMode_Difference)
            p.fillRect(event.rect(), Qt.white)
            p.end()
Esempio n. 13
0
def checkeredImage(format=QImage.Format_ARGB32):
    """
    Returns a 20x20 checker
    @param format:
    @type format:
    @return: checker
    @rtype: QImage
    """
    base = QImage(20, 20, format)
    qp = QPainter(base)
    qp.setCompositionMode(QPainter.CompositionMode_Source)
    qp.fillRect(0, 0, 10, 10, Qt.gray)
    qp.fillRect(10, 0, 10, 10, Qt.white)
    qp.fillRect(0, 10, 10, 10, Qt.white)
    qp.fillRect(10, 10, 10, 10, Qt.gray)
    qp.end()
    return base
Esempio n. 14
0
    def drawLineTo(self, endPoint):
        if not self.penMoved:
            endPoint.setX(
                endPoint.x() + 1
            )  # ensures a dot is being drawn if there was just a click and no mouse move
        painter = QPainter(self.image)
        painter.setCompositionMode(QPainter.CompositionMode_Source)
        painter.setRenderHint(QPainter.Antialiasing)

        brush = QBrush(self.myPenColor, Qt.SolidPattern)
        pen = QPen(brush, self.myPenWidth / self.scaleFactor, Qt.SolidLine,
                   Qt.RoundCap, Qt.RoundJoin)
        # pen = QPen(self.myPenColor, self.myPenWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        painter.setPen(pen)
        painter.drawLine(self.lastPoint / self.scaleFactor,
                         endPoint / self.scaleFactor)

        self.update()

        self.lastPoint = endPoint
Esempio n. 15
0
    def paintEvent(self, event):
        p = QPainter(self.mask)
        for (mode, p1, p2, weight) in self.path:
            if mode == 'add':
                p.setPen(
                    QPen(QColor.fromRgbF(1.0, 0.0, 1.0), (weight * 10.0)**2,
                         Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            else:
                p.setPen(
                    QPen(QColor.fromRgbF(0.0, 0.0, 0.0), (weight * 10.0)**2,
                         Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            p.drawLine(realCoords(p1, self.mask.rect()),
                       realCoords(p2, self.mask.rect()))
            self.changed = True
        self.path = list()
        p.end()

        p = QPainter(self)
        p.setCompositionMode(QPainter.CompositionMode_SourceOver)
        if not self.maskOnly:
            p.drawImage(self.rc, self.image)
            p.setCompositionMode(QPainter.CompositionMode_Plus)
        p.drawImage(self.rc, self.mask)
        p.end()
Esempio n. 16
0
    def paintEvent(self, event):
        painter = QPainter(self)

        brush = self.palette().window().color()
        painter.fillRect(self.rect(), brush)

        for y in range(self._rows):
            for x in range(self._cols):
                i = y * self._cols + x
                c = self._colors[i][1]
                r = QRect(self._size * x, self._size * y, self._size - 2,
                          self._size - 2)
                painter.fillRect(r, QBrush(c))

        # Draw index
        painter.setCompositionMode(QPainter.RasterOp_SourceXorDestination)
        pen = QPen(QBrush(Qt.white), 2., Qt.SolidLine, Qt.SquareCap,
                   Qt.MiterJoin)
        painter.setPen(pen)
        row = int(self._index / self._cols)
        col = int(self._index - row * self._cols)
        r = QRect(self._size * col, self._size * row, self._size - 2,
                  self._size - 2)
        painter.drawRect(r.adjusted(1, 1, -1, -1))
Esempio n. 17
0
 def getCurrentMaskedImage(self):
     """
     Reduces the layer stack up to self (included),
     taking into account the masks. if self.isClipping is True
     self.mask applies to all lower layers and to self only otherwise.
     The method uses the non color managed rPixmaps to build the masked image.
     For convenience, mainly to be able to use its color space buffers,
     the built image is of type QLayer. It is drawn on a container image,
     created only once.
     @return: masked image
     @rtype: QLayer
     """
     # init containers if needed
     if self.parentImage.useHald:
         return self.getHald()
     if self.maskedThumbContainer is None:
         self.maskedThumbContainer = QLayer.fromImage(
             self.getThumb(), parentImage=self.parentImage)
     if self.maskedImageContainer is None:
         self.maskedImageContainer = QLayer.fromImage(
             self, parentImage=self.parentImage)
     if self.parentImage.useThumb:
         img = self.maskedThumbContainer
     else:
         img = self.maskedImageContainer
     # no thumbnails for containers
     img.getThumb = lambda: img
     # draw lower stack
     qp = QPainter(img)
     top = self.parentImage.getStackIndex(self)
     bottom = 0
     for i, layer in enumerate(self.parentImage.layersStack[bottom:top +
                                                            1]):
         if layer.visible:
             if i == 0:
                 qp.setCompositionMode(QPainter.CompositionMode_Source)
             else:
                 qp.setOpacity(layer.opacity)
                 qp.setCompositionMode(layer.compositionMode)
             if layer.rPixmap is not None:
                 qp.drawPixmap(QRect(0, 0, img.width(), img.height()),
                               layer.rPixmap)
             else:
                 qp.drawImage(QRect(0, 0, img.width(), img.height()),
                              layer.getCurrentImage())
             # clipping
             if layer.isClipping and layer.maskIsEnabled:  #TODO modified 23/06/18
                 # draw mask as opacity mask
                 # mode DestinationIn (set dest opacity to source opacity)
                 qp.setCompositionMode(
                     QPainter.CompositionMode_DestinationIn)
                 omask = vImage.color2OpacityMask(layer.mask)
                 qp.drawImage(QRect(0, 0, img.width(), img.height()), omask)
     qp.end()
     return img
Esempio n. 18
0
 def getCurrentMaskedImage(self):
     """
     Blend the layer stack up to self (included),
     taking into account the masks. The method uses the
     non color managed rPixmap to build the masked image.
     For convenience, mainly to be able to use its color space buffers,
     the built image is of type bImage. It is drawn on a container image,
     instantiated only once.
     @return: masked image
     @rtype: bImage
     """
     # init containers if needed. They are instantiated only
     # once and updated by drawing.
     if self.parentImage.useHald:
         return self.getHald()
     if self.maskedThumbContainer is None:
         self.maskedThumbContainer = bImage.fromImage(
             self.getThumb(), parentImage=self.parentImage)
     if self.maskedImageContainer is None:
         self.maskedImageContainer = bImage.fromImage(
             self, parentImage=self.parentImage)
     if self.parentImage.useThumb:
         img = self.maskedThumbContainer
     else:
         img = self.maskedImageContainer
     # draw lower stack
     qp = QPainter(img)
     top = self.parentImage.getStackIndex(self)
     bottom = 0
     for i, layer in enumerate(self.parentImage.layersStack[bottom:top +
                                                            1]):
         if layer.visible:
             if i == 0:
                 qp.setCompositionMode(QPainter.CompositionMode_Source)
             else:
                 qp.setOpacity(layer.opacity)
                 qp.setCompositionMode(layer.compositionMode)
             if layer.rPixmap is None:
                 layer.rPixmap = QPixmap.fromImage(layer.getCurrentImage(
                 ))  # TODO modified 9/12/18 validate
             qp.drawPixmap(QRect(0, 0, img.width(), img.height()),
                           layer.rPixmap)
             # clipping
             if layer.isClipping and layer.maskIsEnabled:
                 # draw mask as opacity mask
                 # mode DestinationIn (set dest opacity to source opacity)
                 qp.setCompositionMode(
                     QPainter.CompositionMode_DestinationIn)
                 omask = vImage.color2OpacityMask(layer.mask)
                 qp.drawImage(QRect(0, 0, img.width(), img.height()), omask)
     qp.end()
     return img
Esempio n. 19
0
 def brushStrokePoly(pixmap, poly, brush):
     """
     Draws the brush stroke defined by a QPolygon
     @param layer:
     @type layer:
     @param x:
     @type x:
     @param y:
     @type y:
     @param r:
     @type r:
     """
     # draw the stroke
     if brush['name'] == 'eraser':
         return
     # drawing into stroke intermediate layer
     pxmp_temp = pixmap.copy()
     qp = QPainter()
     qp.begin(pxmp_temp)
     qp.setCompositionMode(qp.CompositionMode_SourceOver)
     # draw lines
     x_last, y_last = poly.first().x(), poly.first().y()
     for i in range(poly.length() - 1):
         x0, y0 = poly.at(i).x(), poly.at(i).y()
         x, y = poly.at(i + 1).x(), poly.at(i + 1).y()
         x_last, y_last = brushFamily.brushStrokeSeg(
             qp, x_last, y_last, x, y, brush)
     qp.end()
     # draw texture aligned with image
     strokeTex = pxmp_temp
     p = brush['pattern']
     if p is not None:
         if p.pxmp is not None:
             strokeTex = pxmp_temp.copy()
             qp1 = QPainter(strokeTex)
             qp1.setCompositionMode(qp.CompositionMode_DestinationIn)
             qp1.setBrush(QBrush(p.pxmp))
             qp1.fillRect(
                 QRect(0, 0, strokeTex.width(), strokeTex.height()),
                 QBrush(p.pxmp))
             qp1.end()
     # restore source image and paint
     # the whole stroke with current brush opacity
     qp.begin(pixmap)
     # qp.setCompositionMode(qp.CompositionMode_Source)
     # qp.drawImage(QPointF(), layer.strokeDest)
     qp.setOpacity(brush['opacity'])
     qp.setCompositionMode(qp.CompositionMode_SourceOver)
     qp.drawPixmap(QPointF(), strokeTex)  # pxmp_temp)
     qp.end()
Esempio n. 20
0
    def update_scene(self, meta_frame):
        """
        Updates the image_label with a new opencv image.

        Args:
            meta_frame: MetaFrame Object
        """

        # Get frame and other data from meta_frame
        frame = meta_frame.frame
        peaks = meta_frame.peaks
        tracks = meta_frame.tracks

        # Get display_options from main_window
        display_options = self.main_window.display_options

        # Get display dimensions
        self.display_height = self.image_label.height()
        self.display_width = self.image_label.width()

        # Adjust the scale factor
        scale_factor = self.display_height / 256

        # Convert frame to qt image
        pm_img = convert_cv_qt(frame, self.display_width, self.display_height)

        # Start painter
        painter = QPainter()
        painter.begin(pm_img)

        # Create pen
        pen = QtGui.QPen()
        pen.setWidth(2)
        pen.setColor(QtGui.QColor(204, 0, 0))  # r, g, b
        painter.setPen(pen)

        if display_options["show_tracks"] == True:
            # Plot peaks with centered
            for point in peaks:
                painter.drawEllipse((point[0] * scale_factor) - 4,
                                    (point[1] * scale_factor) - 4, 8, 8)

        pen.setWidth(2)
        pen.setColor(QtGui.QColor(0, 0, 255))

        if display_options["show_labels"] == True:
            # Draw tracked objects labels
            for label, trace in tracks.items():
                if len(trace) > 1:
                    # Assign random color for different tracks.
                    color = get_random_color(int(label))
                    qcolor = QColor()
                    qcolor.setNamedColor(color)
                    pen.setColor(qcolor)
                    painter.setPen(pen)
                    label = label
                    label_pos_x = trace[-1][0][0] * scale_factor + 10
                    label_pos_y = trace[-1][0][1] * scale_factor + 10
                    painter.drawText(label_pos_x, label_pos_y, label)

        if display_options["show_traces"] == True:
            # For identified object tracks draw tracking line
            # Use various colors to indicate different track_id
            for label, trace in tracks.items():
                if len(trace) > 1:
                    # Assign random color for different tracks.
                    color = get_random_color(int(label))
                    qcolor = QColor()
                    qcolor.setNamedColor(color)
                    pen.setColor(qcolor)
                    painter.setPen(pen)
                    limit = 0
                    if len(trace) > 200:
                        limit = len(trace) - 200
                    for j in range(limit, len(trace) - 1):
                        # Draw trace line
                        x1 = trace[j][0][0] * scale_factor
                        y1 = trace[j][0][1] * scale_factor
                        x2 = trace[j + 1][0][0] * scale_factor
                        y2 = trace[j + 1][0][1] * scale_factor
                        painter.drawLine(int(x1), int(y1), int(x2), int(y2))

        painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
        # painter.drawImage(0, 0, pix_map)
        painter.end()
        # label = QLabel()
        self.image_label.setPixmap(QPixmap.fromImage(pm_img))
Esempio n. 21
0
    def paintEvent(self, event):
        p = QPainter()
        p.begin(self)
        self._normalMap.render(p, event.rect())
        p.setPen(Qt.black)
        # p.drawText(self.rect(), Qt.AlignBottom | Qt.TextWordWrap, "Map data CCBYSA 2009 OpenStreetMap.org contributors")
        p.end()

        if self.zoomed:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(255, 255, 255, 0))
                g.setColorAt(0.5, QColor(128, 128, 128, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)

            if True:
                p = QPainter(self.zoomPixmap)
                p.translate(-xy)
                self._largeMap.render(p, QRect(xy, box))
                p.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            p = QPainter(self)
            p.setRenderHint(QPainter.Antialiasing)
            p.setClipPath(clipPath)
            p.drawPixmap(corner, self.zoomPixmap)
            p.setClipping(False)
            p.drawPixmap(corner, self.maskPixmap)
            p.setPen(Qt.gray)
            p.drawPath(clipPath)

        if self.invert:
            p = QPainter(self)
            p.setCompositionMode(QPainter.CompositionMode_Difference)
            p.fillRect(event.rect(), Qt.white)
            p.end()
Esempio n. 22
0
 def __strokePaint(self, layer, x, y, r):
     """
     Private drawing function. Should be called only by the mouse event handler
     @param layer:
     @type layer:
     @param x:
     @type x:
     @param y:
     @type y:
     @param r:
     @type r:
     """
     img = self.img
     State = self.State
     qp = self.qp
     # get image coordinates
     x_img = (x - img.xOffset) // r
     y_img = (y - img.yOffset) // r
     # draw the stroke
     if self.window.btnValues['brushButton']:
         # drawing onto stroke intermediate layer
         qp.begin(layer.stroke)
         qp.setCompositionMode(qp.CompositionMode_SourceOver)
         # draw move
         State['x_imagePrecPos'], State[
             'y_imagePrecPos'] = brushFamily.brushStrokeSeg(
                 qp, State['x_imagePrecPos'], State['y_imagePrecPos'],
                 x_img, y_img, State['brush'])
         qp.end()
         # draw texture aligned with image
         strokeTex = layer.stroke
         p = State['brush']['pattern']
         if p is not None:
             if p.pxmp is not None:
                 strokeTex = layer.stroke.copy()
                 qp1 = QPainter(strokeTex)
                 qp1.setCompositionMode(qp.CompositionMode_DestinationIn)
                 qp1.setBrush(QBrush(p.pxmp))
                 qp1.fillRect(
                     QRect(0, 0, strokeTex.width(), strokeTex.height()),
                     QBrush(p.pxmp))
                 qp1.end()
         # restore source image and paint
         # the whole stroke with current brush opacity.
         # Restoring source image enables iterative calls showing
         # stroke progress
         qp.begin(layer.sourceImg)
         qp.setCompositionMode(qp.CompositionMode_Source)
         qp.drawImage(QPointF(), layer.strokeDest)
         qp.setOpacity(State['brush']['opacity'])
         qp.setCompositionMode(qp.CompositionMode_SourceOver)
         qp.drawImage(QPointF(), strokeTex)  # layer.stroke)
         qp.end()
     elif self.window.btnValues['eraserButton']:
         qp.begin(layer.sourceImg)
         qp.setCompositionMode(qp.CompositionMode_DestinationIn)
         State['x_imagePrecPos'], State[
             'y_imagePrecPos'] = brushFamily.brushStrokeSeg(
                 qp, State['x_imagePrecPos'], State['y_imagePrecPos'],
                 x_img, y_img, State['brush'])
         qp.end()
     # update layer - should be layer.applyToStack() if any upper layer visible : too slow !
     layer.execute()
     img.prLayer.update()
     self.window.label.repaint()
Esempio n. 23
0
 def getBrush(self,
              size,
              opacity,
              color,
              hardness,
              flow,
              spacing=1.0,
              jitter=0.0,
              orientation=0,
              pattern=None):
     """
     initializes and returns a brush as a dictionary
     @param size: brush size
     @type size: int
     @param opacity: brush opacity, range 0..1
     @type opacity: float
     @param color:
     @type color: QColor
     @param hardness: brush hardness, range 0..1
     @type hardness: float
     @param flow: brush flow, range 0..1
     @type flow: float
     @return:
     @rtype: dict
     """
     s = float(self.baseSize) / 2
     # set brush color
     if self.name == 'eraser':
         color = QColor(0, 0, 0, 0)
     else:
         op_max = 255  # 64
         color = QColor(color.red(), color.green(), color.blue(),
                        int(op_max * flow))
     gradient = QRadialGradient(QPointF(s, s), s)
     gradient.setColorAt(0, color)
     gradient.setColorAt(hardness, color)
     if hardness < 1.0:
         # fade action to 0, starting from hardness to 1
         if self.name == 'eraser':
             gradient.setColorAt(1, QColor(0, 0, 0, 255))
         else:
             gradient.setColorAt(1, QColor(0, 0, 0, 0))
     pxmp = self.basePixmap.copy()
     qp = QPainter(pxmp)
     # fill brush contour with gradient (pxmp color is (0,0,0,0)
     # outside of contourPath)
     qp.setCompositionMode(qp.CompositionMode_Source)
     qp.fillPath(self.contourPath, QBrush(gradient))
     if self.preset is not None:
         ################################################
         # we adjust the preset pixmap to pxmp size while keeping
         # its aspect ratio and we center it into pxmp
         ################################################
         w, h = self.preset.width(), self.preset.height()
         # get the bounding rect of the scaled and centered preset
         # and the 2 complementary rects
         if w > h:
             rh = int(self.baseSize * h / w)  # height of bounding rect
             m = int((self.baseSize - rh) / 2.0)  # top and bottom margins
             r = QRect(0, m, self.baseSize, rh)
             r1 = QRect(0, 0, self.baseSize, m)
             r2 = QRect(0, rh + m, self.baseSize, m)
         else:
             rw = int(self.baseSize * w / h)  # width of bounding rect
             m = int((self.baseSize - rw) / 2.0)  # left and right margins
             r = QRect(m, 0, rw, self.baseSize)
             r1 = QRect(0, 0, m, self.baseSize)
             r2 = QRect(rw + m, 0, m, self.baseSize)
         # set opacity of r to that of preset
         qp.setCompositionMode(QPainter.CompositionMode_DestinationIn)
         qp.drawPixmap(r, self.preset)
         # paint the outside of r with transparent color
         pxmp1 = QPixmap(pxmp.size())
         pxmp1.fill(QColor(0, 0, 0, 0))
         qp.drawPixmap(r1, pxmp1)
         qp.drawPixmap(r2, pxmp1)
     qp.end()
     s = size / self.baseSize
     self.pxmp = pxmp.transformed(QTransform().scale(
         s, s).rotate(orientation))  # pxmp.scaled(size, size)
     pattern = pattern
     return {
         'family': self,
         'name': self.name,
         'pixmap': self.pxmp,
         'size': size,
         'color': color,
         'opacity': opacity,
         'hardness': hardness,
         'flow': flow,
         'spacing': spacing,
         'jitter': jitter,
         'orientation': orientation,
         'pattern': pattern,
         'cursor': self.baseCursor
     }
Esempio n. 24
0
    def histogram(self, size=QSize(200, 200), bgColor=Qt.white, range=(0, 255),
                  chans=channelValues.RGB, chanColors=Qt.gray, mode='RGB', addMode=''):
        """
        Plot the image histogram with the
        specified color mode and channels.
        Histograms are smoothed using a Savisky-Golay filter and curves are scaled individually
        to fit the height of the plot.
        @param size: size of the histogram plot
        @type size: int or QSize
        @param bgColor: background color
        @type bgColor: QColor
        @param range: plot data range
        @type range: 2-uple of int or float
        @param chans: channels to plot b=0, G=1, R=2
        @type chans: list of indices
        @param chanColors: color or 3-uple of colors
        @type chanColors: QColor or 3-uple of QColor
        @param mode: color mode ((one among 'RGB', 'HSpB', 'Lab', 'Luminosity')
        @type mode: str
        @param addMode:
        @type addMode:
        @return: histogram plot
        @rtype: QImage
        """
        # convert size to QSize
        if type(size) is int:
            size = QSize(size, size)
        # alert threshold for clipped areas
        clipping_threshold = 0.02
        # clipping threshold for black and white points
        # scaling factor for the bin edges
        spread = float(range[1] - range[0])
        scale = size.width() / spread

        # per channel histogram function
        def drawChannelHistogram(painter, hist, bin_edges, color):
            # Draw the (smoothed) histogram for a single channel.
            # param painter: QPainter
            # param hist: histogram to draw
            # smooth the histogram (first and last bins excepted) for a better visualization of clipping.
            hist = np.concatenate(([hist[0]], SavitzkyGolayFilter.filter(hist[1:-1]), [hist[-1]]))
            M = max(hist[1:-1])
            # draw histogram
            imgH = size.height()
            for i, y in enumerate(hist):
                try:
                    h = int(imgH * y / M)
                except (ValueError, ArithmeticError):
                    # don't draw the channel histogram if M is too small:
                    # It may happen when channel values are concentrated
                    # on the first and/or last bins.
                    return
                h = min(h, imgH - 1)  # height of rect must be < height of img, otherwise fillRect does nothing
                rect = QRect(int((bin_edges[i] - range[0]) * scale), max(img.height() - h, 0),
                             int((bin_edges[i + 1] - bin_edges[i]) * scale+1), h)
                painter.fillRect(rect, color)
                # clipping indicators
                if i == 0 or i == len(hist)-1:
                    left = bin_edges[0 if i == 0 else -1]
                    if range[0] < left < range[1]:
                        continue
                    left = left - (10 if i > 0 else 0)
                    percent = hist[i] * (bin_edges[i+1]-bin_edges[i])
                    if percent > clipping_threshold:
                        # calculate the color of the indicator according to percent value
                        nonlocal gPercent
                        gPercent = min(gPercent, np.clip((0.05 - percent) / 0.03, 0, 1))
                        painter.fillRect(left, 0, 10, 10, QColor(255, 255*gPercent, 0))
        # green percent for clipping indicators
        gPercent = 1.0
        bufL = cv2.cvtColor(QImageBuffer(self)[:, :, :3], cv2.COLOR_BGR2GRAY)[..., np.newaxis]  # returns Y (YCrCb) : Y = 0.299*R + 0.587*G + 0.114*B
        buf = None  # TODO added 5/11/18 validate
        if mode == 'RGB':
            buf = QImageBuffer(self)[:, :, :3][:, :, ::-1]  # RGB
        elif mode == 'HSV':
            buf = self.getHSVBuffer()
        elif mode == 'HSpB':
            buf = self.getHspbBuffer()
        elif mode == 'Lab':
            buf = self.getLabBuffer()
        elif mode == 'Luminosity':
            chans = []
        img = QImage(size.width(), size.height(), QImage.Format_ARGB32)
        img.fill(bgColor)
        qp = QPainter(img)
        try:
            if type(chanColors) is QColor or type(chanColors) is Qt.GlobalColor:
                chanColors = [chanColors]*3
            # compute histograms
            # bins='auto' sometimes causes a huge number of bins ( >= 10**9) and memory error
            # even for small data size (<=250000), so we don't use it.
            # This is a numpy bug : in the module function_base.py
            # a reasonable upper bound for bins should be chosen to prevent memory error.
            if mode == 'Luminosity' or addMode == 'Luminosity':
                hist, bin_edges = np.histogram(bufL, bins=100, density=True)
                drawChannelHistogram(qp, hist, bin_edges, Qt.gray)
            hist_L, bin_edges_L = [0]*len(chans), [0]*len(chans)
            for i, ch in enumerate(chans):
                buf0 = buf[:, :, ch]
                hist_L[i], bin_edges_L[i] = np.histogram(buf0, bins=100, density=True)
                # to prevent artifacts, the histogram bins must be drawn
                # using the composition mode source_over. So, we use
                # a fresh QImage for each channel.
                tmpimg = QImage(size, QImage.Format_ARGB32)
                tmpimg.fill(bgColor)
                tmpqp = QPainter(tmpimg)
                try:
                    drawChannelHistogram(tmpqp, hist_L[i], bin_edges_L[i], chanColors[ch])
                finally:
                    tmpqp.end()
                # add the channnel hist to img
                qp.drawImage(QPoint(0,0), tmpimg)
                # subsequent images are added using composition mode Plus
                qp.setCompositionMode(QPainter.CompositionMode_Plus)
        finally:
            qp.end()
        buf = QImageBuffer(img)
        # if len(chans) > 1, clip gray area to improve the aspect of the histogram
        if len(chans) > 1:
            buf[:, :, :3] = np.where(np.min(buf, axis=-1)[:, :, np.newaxis] >= 100,
                                     np.array((100, 100, 100))[np.newaxis, np.newaxis, :], buf[:, :, :3])
        return img
Esempio n. 25
0
class ImageSegmenterView(QGraphicsView):
    photoClicked = Signal(QPoint)

    def __init__(self, parent):
        super(ImageSegmenterView, self).__init__(parent)
        self._zoom = 0
        self.empty = True
        self._scene = QGraphicsScene(self)
        self._photo = QGraphicsPixmapItem()
        self.image_hidden = False
        self._seglayer = QGraphicsPixmapItem()
        self._seglayer.setOpacity(0.5)
        self._scene.addItem(self._photo)
        self._scene.addItem(self._seglayer)
        self.setScene(self._scene)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        # self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        # self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QBrush(QtCore.Qt.darkGray))
        self.setFrameShape(QFrame.NoFrame)

        self.seg_image = None
        self.start = False
        self.prev_point = None
        self.painter = None
        self.segmenter_pen = QPen(QtCore.Qt.green, 30, QtCore.Qt.SolidLine)
        self.segmenter_pen.setCapStyle(QtCore.Qt.RoundCap)
        self.segmenter_pen.setJoinStyle(QtCore.Qt.RoundJoin)
        self.erase = False
        self.changed = False

        self.history = collections.deque(maxlen=10)
        self.future = collections.deque(maxlen=10)

    def hasPhoto(self):
        return not self.empty

    def fitInView(self, scale=True):
        rect = QtCore.QRectF(self._photo.pixmap().rect())
        if not rect.isNull():
            self.setSceneRect(rect)
            if self.hasPhoto():
                unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
                self.scale(1 / unity.width(), 1 / unity.height())
                viewrect = self.viewport().rect()
                scenerect = self.transform().mapRect(rect)
                factor = min(viewrect.width() / scenerect.width(),
                             viewrect.height() / scenerect.height())
                self.scale(factor, factor)
            self._zoom = 0

    def setPhoto(self, pixmap=None):
        self._zoom = 0
        if pixmap and not pixmap.isNull():
            self.empty = False
            self.changed = False
            self._photo.setPixmap(pixmap)
            self.seg_image = QImage(pixmap.width(), pixmap.height(),
                                    QImage.Format_ARGB32_Premultiplied)
            self.seg_image.fill(QtCore.Qt.transparent)
            self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))
        else:
            self._empty = True
            self._photo.setPixmap(QPixmap())
        self.fitInView()

    def save_state(self):
        if self.future is not None:
            while len(self.future) > 0:
                present = self.future.pop()
                del present
        if self.seg_image is not None:
            self.history.append(self.seg_image.copy())

    def clear_history(self):
        while len(self.history) > 0:
            present = self.history.pop()
            del present

    def undo(self):
        if len(self.history) > 0:
            self.future.append(self.seg_image)
            present = self.history.pop()
            self.seg_image = present
            self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))

    def redo(self):
        if len(self.future) > 0:
            self.history.append(self.seg_image)
            present = self.future.pop()
            self.seg_image = present
            self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))

    def setSegLayer(self, pixmap=None):
        if not self._photo.pixmap().isNull():
            self.save_state()
            self.seg_image = QImage(pixmap.toImage())
            self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))

    def resetSegLayer(self):
        if not self._photo.pixmap().isNull():
            self.changed = True
            self.save_state()
            del self.seg_image
            self.seg_image = QImage(self._photo.pixmap().width(),
                                    self._photo.pixmap().height(),
                                    QImage.Format_ARGB32_Premultiplied)
            self.seg_image.fill(QtCore.Qt.transparent)
            self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))

    def wheelEvent(self, event):
        if self.hasPhoto() and not self.start:
            if event.angleDelta().y() > 0:
                factor = 1.25
                self._zoom += 1
            else:
                factor = 0.8
                self._zoom -= 1
            if self._zoom > 0:
                self.scale(factor, factor)
            elif self._zoom == 0:
                self.fitInView()
            else:
                self._zoom = 0

    def mousePressEvent(self, event):
        if not self._photo.pixmap().isNull():
            if event.button() == QtCore.Qt.LeftButton:
                self.save_state()
                self.start = True
                self.painter = QPainter(self.seg_image)
                if self.erase:
                    self.painter.setCompositionMode(
                        QPainter.CompositionMode_Clear)
                self.painter.setPen(self.segmenter_pen)
                self.paint_point(event.pos())
            elif event.button() == QtCore.Qt.RightButton:
                if not self._photo.pixmap().isNull():
                    self.setDragMode(QGraphicsView.ScrollHandDrag)
                    self.scroll_origin = self.mapToScene(event.pos())
                # if self._photo.isUnderMouse():
                #     self.photoClicked.emit(self.mapToScene(event.pos()).toPoint())
        super(ImageSegmenterView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if not self._photo.pixmap().isNull():
            if self.start:
                self.paint_point(event.pos())
            if event.buttons() & QtCore.Qt.RightButton:
                newpoint = self.mapToScene(event.pos())
                translation = newpoint - self.scroll_origin
                self.translate(translation.x(), translation.y())
                self.scroll_origin = self.mapToScene(event.pos())
        super(ImageSegmenterView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if not self._photo.pixmap().isNull():
            if self.start:
                self.start = False
                self.prev_point = None
                self.painter.end()
            if self.dragMode() == QGraphicsView.ScrollHandDrag:
                self.setDragMode(QGraphicsView.NoDrag)

    def paint_point(self, pos):
        self.changed = True
        pos = self.mapToScene(pos).toPoint()
        if self.prev_point is not None:
            self.painter.drawLine(self.prev_point, pos)
        else:
            self.painter.drawPoint(pos)
        self.prev_point = pos
        self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image))

    def set_foreground(self):
        self.erase = False
        self.segmenter_pen.setColor(QtCore.Qt.green)

    def set_possible_foreground(self):
        self.erase = False
        self.segmenter_pen.setColor(QtCore.Qt.blue)

    def set_possible_background(self):
        self.erase = True
        self.segmenter_pen.setColor(QtCore.Qt.transparent)

    def set_background(self):
        self.erase = False
        self.segmenter_pen.setColor(QtCore.Qt.red)

    def set_pen_size(self, size):
        self.segmenter_pen.setWidth(size)

    def set_opacity(self, value):
        self._seglayer.setOpacity(value / 100)

    def hide_image(self):
        if self.image_hidden:
            self._photo.setOpacity(1)
            self.image_hidden = False
        else:
            self._photo.setOpacity(0)
            self.image_hidden = True