Commit 156ef9b8 authored by Josef Brandt's avatar Josef Brandt
Browse files

Switch Painter to Pixmap

parent 2c03c3ce
Loading
Loading
Loading
Loading
+70 −76
Original line number Diff line number Diff line
@@ -25,45 +25,42 @@ import cv2


class ParticlePainter(QtWidgets.QGraphicsItem):
    def __init__(self, editorParent, contours, pos=(500,500)):
    def __init__(self, editorParent, img, topLeft):
        super(ParticlePainter, self).__init__()
        self.editorParent = editorParent
        self.viewparent = self.editorParent.viewparent
        self.setZValue(5)
        self.polygons = None
        self.contours = contours
        self.topLeft = topLeft
        self.img = img
        self.pixmap = None
        
        self.mousePos = None
        self.minRadius = 10
        self.maxRadius = 500
        self.radius = 50
        self.brect = QtCore.QRectF(0,0,1,1)
        self.getBrectAndPolygon()
        self.painting = False
        self.erasing = False
        
    def getBrectAndPolygon(self):
        polygons = []
        x0 = None
        for c in self.contours:
            polygon = QtGui.QPolygonF()
            if x0 is None:
                x0 = c[:,0,0].min()
                x1 = c[:,0,0].max()
                y0 = c[:,0,1].min()
                y1 = c[:,0,1].max()
            else:
                x0 = min(x0, c[:,0,0].min())
                x1 = max(x1, c[:,0,0].max())
                y0 = min(y0, c[:,0,1].min())
                y1 = max(y1, c[:,0,1].max())
            for ci in c:
                polygon.append(QtCore.QPointF(ci[0,0],ci[0,1]))
            polygons.append(polygon)
        if x0 is None:
        self.minRadius = 10
        self.maxRadius = 500
        self.radius = 30
        self.brect = QtCore.QRectF(0,0,1,1)
        else:
        
        self.imgToPixmap()
        self.setBrect()

    def imgToPixmap(self):
        img = self.img.repeat(3).reshape(self.img.shape[0], self.img.shape[1],3)
        height, width, channel = img.shape
        assert channel==3
        bytesPerLine = 3 * width
        pix = QtGui.QPixmap()
        pix.convertFromImage(QtGui.QImage(img.data, width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
        self.pixmap = pix

    def setBrect(self):
        x0 = self.topLeft[1]
        y0 = self.topLeft[0]
        x1 = self.topLeft[1] + self.img.shape[1]
        y1 = self.topLeft[0] + self.img.shape[0]
        self.brect.setCoords(x0,y0,x1,y1)
        self.polygons = polygons        
    
    def boundingRect(self):
        return self.brect
@@ -105,49 +102,47 @@ class ParticlePainter(QtWidgets.QGraphicsItem):
            self.editorParent.acceptPaintedResult()
    
    def drawParticle(self, pos):
        img, xmin, ymin, padding = self.contoursToImg(self.contours)
        center = (int(pos.x()+self.radius), int(pos.y()+self.radius))
        if self.painting:
            cv2.circle(img, center, self.radius, 255, -1)
        elif self.erasing:
            cv2.circle(img, center, self.radius, 0, -1)
            
        img = np.uint8(img)
        self.contours = self.imgToCnt(img, xmin, ymin, padding)
        self.getBrectAndPolygon()
        self.update()
        pixelPos = round(pos.y()-self.topLeft[0]), round(pos.x()-self.topLeft[1])
        x_min, x_max = round(pixelPos[1]-self.radius/2), round(pixelPos[1]+self.radius/2)
        y_min, y_max = round(pixelPos[0]-self.radius/2), round(pixelPos[0]+self.radius/2)
        
        x_shift = y_shift = 0
        
        if x_min < 0:
            x_shift = x_min
        elif x_min >= self.img.shape[1]:
            x_shift = x_min + 1 - self.img.shape[1]
        
        if y_min < 0:
            y_shift = y_min
        elif y_min >= self.img.shape[0]:
            y_shift = y_min + 1 - self.img.shape[0]
        
        if x_shift != 0 or y_shift != 0:
            x_range = self.img.shape[1] + abs(x_shift)
            y_range = self.img.shape[0] + abs(y_shift)
            
            newImg = np.zeros((y_range, x_range))
            if x_shift < 0:
                if y_shift == 0:
                    newImg[abs(x_shift):, :] = self.img
                elif y_shift < 0:
                
        
        
    def contoursToImg(self, contours):
        cnt = np.vstack(tuple(contours))  #combine contous
        #draw contours
        xmin, xmax = cnt[:,0,:][:, 0].min(), cnt[:,0,:][:, 0].max()
        ymin, ymax = cnt[:,0,:][:, 1].min(), cnt[:,0,:][:, 1].max()        
        padding = self.radius+2    #pixel in each direction
        rangex = int(np.round((xmax-xmin)+2*padding))
        rangey = int(np.round((ymax-ymin)+2*padding))

        img = np.zeros((rangey, rangex), dtype = np.uint8)
        for curCnt in contours:
            for i in range(len(curCnt)):
                curCnt[i][0][0] -= xmin-padding
                curCnt[i][0][1] -= ymin-padding
                
            cv2.drawContours(img, [curCnt], -1, 255, -1)
            cv2.drawContours(img, [curCnt], -1, 255, 1)
        return img, xmin, ymin, padding
    
    def imgToCnt(self, img, xmin, ymin, padding):
        if cv2.__version__ > '3.5':
            contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        else:
            temp, contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        
        for contour in contours:
            for i in range(len(contour)):
                contour[i][0][0] += xmin-padding
                contour[i][0][1] += ymin-padding
        
        return contours
#        img, xmin, ymin, padding = self.contoursToImg(self.contours)
#        center = (int(pos.x()+self.radius), int(pos.y()+self.radius))
#        if self.painting:
#            cv2.circle(img, center, self.radius, 255, -1)
#        elif self.erasing:
#            cv2.circle(img, center, self.radius, 0, -1)
#            
#        img = np.uint8(img)
#        self.contours = self.imgToCnt(img, xmin, ymin, padding)
#        self.getBrectAndPolygon()
#        self.update()
    
    def paint(self, painter, option, widget):   
        painter.setPen(QtCore.Qt.white)
@@ -157,10 +152,9 @@ class ParticlePainter(QtWidgets.QGraphicsItem):
            p = [self.mousePos.x(), self.mousePos.y(), self.radius]
            painter.drawEllipse(p[0]-p[2], p[1]-p[2], 2*p[2], 2*p[2])            
        
        if self.polygons is not None:            
            for poly in self.polygons:
                painter.setBrush(QtGui.QColor(200, 200, 255, 128))
                painter.drawPolygon(poly)
        if self.pixmap is not None:
            painter.setOpacity(0.6)
            painter.drawPixmap(self.topLeft[1], self.topLeft[0], self.pixmap)
        
                
                
+29 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ If not, see <https://www.gnu.org/licenses/>.
import numpy as np
import cv2
from PyQt5 import QtWidgets, QtCore
from copy import deepcopy

from .particlePainter import ParticlePainter

@@ -162,7 +163,7 @@ class ParticleEditor(QtCore.QObject):
        print(f'Combining particles {contourIndices} into {newAssignment}')
        contours = self.particleContainer.getParticleContoursByIndex(contourIndices)
        try:
            newContour = self.mergeContours(contours.copy()) 
            newContour = self.mergeContours(contours) 
        except NotConnectedContoursError:
            return
        
@@ -186,8 +187,13 @@ class ParticleEditor(QtCore.QObject):
        self.createSafetyBackup()
        self.storedIndices = contourIndices
        self.storedAssignmend = newAssignment
        
        contours = self.particleContainer.getParticleContoursByIndex(contourIndices)
        self.particlePainter = ParticlePainter(self, contours)
        topLeft = self.getTopLeft(contours)
        img, self.xmin, self.ymin, self.padding = self.contoursToImg(contours)
        
        self.particlePainter = ParticlePainter(self, img, topLeft)
        
        self.viewparent.normalSize()
        self.viewparent.particlePainter = self.particlePainter
        self.viewparent.scene().addItem(self.particlePainter)
@@ -195,7 +201,7 @@ class ParticleEditor(QtCore.QObject):
        
    def acceptPaintedResult(self):
        try:
            newContour = self.mergeContours(self.particlePainter.contours.copy())
            newContour = self.mergeContours(self.particlePainter.contours)
        except NotConnectedContoursError:
            self.storedIndices = []
            self.storedAssignmend = None
@@ -219,25 +225,32 @@ class ParticleEditor(QtCore.QObject):
            self.particlePainter = None
    
    def mergeContours(self, contours):
        cnt = np.vstack(tuple(contours))  #combine contous
        img, xmin, ymin, padding = self.contoursToImg(contours)
        return self.imgToCnt(img, xmin, ymin, padding)
    
    def contoursToImg(self, contours, padding=2):
        contourCopy = deepcopy(contours)
        cnt = np.vstack(tuple(contourCopy))  #combine contous
        #draw contours
        xmin, xmax = cnt[:,0,:][:, 0].min(), cnt[:,0,:][:, 0].max()
        ymin, ymax = cnt[:,0,:][:, 1].min(), cnt[:,0,:][:, 1].max()        
        padding = 2    #pixel in each direction
        padding = padding   #pixel in each direction
        rangex = int(np.round((xmax-xmin)+2*padding))
        rangey = int(np.round((ymax-ymin)+2*padding))

        img = np.zeros((rangey, rangex))
        for curCnt in contours:
        for curCnt in contourCopy:
            for i in range(len(curCnt)):
                curCnt[i][0][0] -= xmin-padding
                curCnt[i][0][1] -= ymin-padding
                
            cv2.drawContours(img, [curCnt], -1, 1, -1)
            cv2.drawContours(img, [curCnt], -1, 1, 1)
            cv2.drawContours(img, [curCnt], -1, 255, -1)
            cv2.drawContours(img, [curCnt], -1, 255, 1)
        
        img = np.uint8(cv2.morphologyEx(img, cv2.MORPH_CLOSE, np.ones((3, 3))))
        return img, xmin, ymin, padding
    
    def imgToCnt(self, img, xmin, ymin, padding):
        if cv2.__version__ > '3.5':
            contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
        else:
@@ -255,6 +268,13 @@ class ParticleEditor(QtCore.QObject):
            
        return newContour
    
    def getTopLeft(self, contours):
        cnt = np.vstack(tuple(contours))  #combine contous
        #draw contours
        xmin = cnt[:,0,:][:, 0].min()
        ymin= cnt[:,0,:][:, 1].min()
        return ymin, xmin
    
    def mergeParticlesInParticleContainerAndSampleView(self, indices, newContour, stats, assignment):
        self.viewparent.addParticleContourToIndex(newContour, len(self.viewparent.contourItems)-1)
        self.particleContainer.addMergedParticle(indices, newContour, stats, newAssignment=assignment)
+87.5 KiB

File added.

No diff preview for this file type.

+166 B

File added.

No diff preview for this file type.

+5.39 KiB

File added.

No diff preview for this file type.

Loading