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

Switch Painter to Pixmap

parent 2c03c3ce
......@@ -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.painting = False
self.erasing = False
self.minRadius = 10
self.maxRadius = 500
self.radius = 50
self.radius = 30
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.brect = QtCore.QRectF(0,0,1,1)
else:
self.brect.setCoords(x0,y0,x1,y1)
self.polygons = polygons
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)
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)
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)
img = np.uint8(img)
self.contours = self.imgToCnt(img, xmin, ymin, padding)
self.getBrectAndPolygon()
self.update()
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
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:
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)
......@@ -156,11 +151,10 @@ class ParticlePainter(QtWidgets.QGraphicsItem):
if self.mousePos is not None:
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)
......@@ -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)
......
......@@ -400,7 +400,8 @@ class SampleView(QtWidgets.QGraphicsView):
self.analysiswidget.setWidgetsToNewParticleIndex(cnt.particleIndex)
cnt.isSelected = True
cnt.update()
self.selectedParticleIndices.append(cnt.particleIndex)
if cnt.particleIndex not in self.selectedParticleIndices:
self.selectedParticleIndices.append(cnt.particleIndex)
def removeContourFromSelection(cnt):
cnt.isSelected = False
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment