...
 
Commits (5)
......@@ -23,10 +23,6 @@ from PyQt5 import QtWidgets, QtGui, QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import os
import numpy as np
from analysis import importSpectra
class ParticleIndicator(QtWidgets.QPushButton):
......@@ -132,31 +128,8 @@ class SpectraPlot(QtWidgets.QGroupBox):
self.setLayout(layout)
def loadSpectraAndInitializeSpecPlot(self): #formerly updateData(self)....
# def tryLoadingNumpySpecFile():
# specPath = self.dataset.getSpectraFileName()
# if os.path.exists(specPath):
# return np.load(specPath)
# else:
# raise ImportError
# try:
# self.spectra = tryLoadingNumpySpecFile()
# except ImportError:
#
# fname = QtWidgets.QFileDialog.getOpenFileName(QtWidgets.QWidget(), 'Select Spectra File', self.dataset.path, 'text file (*.txt)')[0]
#
# try:
# self.spectra, spectraNames = importSpectra.importWITecSpectra(fname)
# except ImportError:
# try:
# self.spectra, spectraNames = importSpectra.importRenishawSpectra(fname)
# except ImportError:
# self.spectra, spectraNames = importSpectra.importPerkinElmerSpectra(fname)
#
# if self.spectra is None:
# raise ImportError
# else:
# np.save(self.dataset.getSpectraFileName(), self.spectra)
self.spectra = self.dataset.particleContainer.spectra
assert self.spectra is not None
self.canvas.draw()
def updateParticleSpectrum(self, specIndex, particleSize, hqi):
......
......@@ -32,7 +32,6 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio
from .analysiswidgets import ExpExcelDialog
from .analysisplots import TypeHistogramView, SpectraPlot
from .loadresults import LoadTrueMatchResults
from .particleeditor import ParticleEditor
from .database import DataBaseWindow
from .colorlegend import getColorFromNameWithSeed
......@@ -56,7 +55,6 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.viewparent = viewparent
self.dataset = dataset
self.particleContainer = dataset.particleContainer
self.editor = ParticleEditor(self.particleContainer, self)
# self.additivePlot = None
self.importWindow = None
......@@ -221,6 +219,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.createMenus()
self.applyHQIThresholdToResults()
self.createHistogramData()
self.particleContainer.loadSpectra()
self.initializeSpecPlot()
self.setTypeSelector()
self.updateHistogramsAndContours()
......@@ -556,7 +555,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow):
self.currentParticleIndex = particleIndex
partIndices = self.particleContainer.getIndicesOfParticleType(assignment)
self.particleSelector.setMaximum(len(partIndices))
self.particleNumberLabel.setText(f'of {len(partIndices)} particles; ')
self.particleSelector.setValue(partIndices.index(particleIndex)+1)
......
......@@ -19,7 +19,7 @@ along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
import numpy as np
from viewitems import SegmentationContour, RamanScanIndicator
class Particle(object):
def __init__(self):
......@@ -35,23 +35,9 @@ class Particle(object):
self.viewItem = None
def addMeasurement(self, refToMeasurement):
refToMeasurement.assignedParticle = self
self.measurements.append(refToMeasurement)
# def addExistingMeasurement(self, meas):
# self.measurements.append(meas)
#
# def addEmptyMeasurement(self):
# self.measurements.append(Measurement())
# indexOfNewMeasurment = len(self.measurements)-1
# return indexOfNewMeasurment
# def setMeasurementScanIndex(self, indexOfMeasurment, scanIndex):
# self.measurements[indexOfMeasurment].ramanScanIndex = scanIndex
#
# def setMeasurementPixelCoords(self, indexOfMeasurment, x, y):
# self.measurements[indexOfMeasurment].pixelcoord_x= x
# self.measurements[indexOfMeasurment].pixelcoord_y = y
#
def setAllSpectraToNewAssignment(self, newAssignment):
for meas in self.measurements:
meas.setAssignment(newAssignment)
......@@ -127,8 +113,8 @@ class Particle(object):
for measurement in self.measurements:
measurement.applyHQIThreshold(minHQI)
# def recreateViewItem(self):
# pass
def recreateViewItem(self):
self.viewItem = SegmentationContour()
class Measurement(object):
......@@ -141,6 +127,8 @@ class Measurement(object):
self.assignment_orig = 'Not Evaluated'
self.assignment_afterHQI = None
self.hqi = None
self.assignedParticle = None
def setAssignment(self, assignment):
self.assignment_orig = assignment
......
......@@ -42,7 +42,13 @@ class ParticleContainer(object):
self.measurements.append(Measurement())
indexOfNewMeas = len(self.measurements)-1
return indexOfNewMeas
def clearParticles(self):
self.particles = []
def clearMeasurements(self):
self.measurements = []
def setMeasurementScanIndex(self, indexOfMeasurment, scanIndex):
self.measurements[indexOfMeasurment].ramanScanIndex = scanIndex
......@@ -178,9 +184,8 @@ class ParticleContainer(object):
def getMeasurementPixelCoords(self):
coords = []
for particle in self.particles:
for measurement in particle.getMeasurements():
coords.append([measurement.pixelcoord_x, measurement.pixelcoord_y])
for meas in self.measurements:
coords.append([meas.pixelcoord_x, meas.pixelcoord_y])
return coords
def getNumberOfParticlesOfAssignment(self, assignment):
......@@ -269,7 +274,7 @@ class ParticleContainer(object):
if newAssignment is not None:
meas.setAssignment(newAssignment)
meas.setHQI(100)
newParticle.addExistingMeasurement(meas)
newParticle.addMeasurement(meas)
#set Particle Stats
long, short, longellipse, shortellipse, area = newStats
......
......@@ -23,47 +23,41 @@ from PyQt5 import QtWidgets, QtCore, QtGui
import numpy as np
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.brect = QtCore.QRectF(0,0,1,1)
else:
self.brect.setCoords(x0,y0,x1,y1)
self.polygons = polygons
self.minRadius = 5
self.maxRadius = 500
self.radius = 30
self.brect = QtCore.QRectF(0,0,1,1)
self.setPixmap()
self.setBrect()
def setPixmap(self):
img = self.img.repeat(3).reshape(self.img.shape[0], self.img.shape[1], 3)
height, width, channel = img.shape
bytesPerLine = 3 * width
self.pixmap = QtGui.QPixmap()
self.pixmap.convertFromImage(QtGui.QImage(img.data, width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
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
......@@ -104,51 +98,65 @@ class ParticlePainter(QtWidgets.QGraphicsItem):
elif event.key() == QtCore.Qt.Key_Return:
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))
def drawParticle(self, pixelPos):
x_min, x_max = round(pixelPos.x()-self.radius), round(pixelPos.x()+self.radius)
y_min, y_max = round(pixelPos.y()-self.radius), round(pixelPos.y()+self.radius)
x_shift = y_shift = int(0)
if x_min < 0:
x_shift = int(x_min)
self.topLeft[1] -= abs(x_min)
elif x_max >= self.img.shape[1]:
x_shift = int(x_max + 1 - self.img.shape[1])
if y_min < 0:
self.topLeft[0] -= abs(y_min)
y_shift = int(y_min)
elif y_max >= self.img.shape[0]:
y_shift = int(y_max + 1 - self.img.shape[0])
if x_shift != 0 or y_shift != 0:
x_range = int(self.img.shape[1] + abs(x_shift))
y_range = int(self.img.shape[0] + abs(y_shift))
newImg = np.zeros((y_range, x_range))
if x_shift < 0:
if y_shift < 0:
newImg[abs(y_shift):, abs(x_shift):] = self.img
elif y_shift == 0:
newImg[:, abs(x_shift):] = self.img
elif y_shift > 0:
newImg[:self.img.shape[0], abs(x_shift):] = self.img
elif x_shift == 0:
if y_shift < 0:
newImg[abs(y_shift):, :] = self.img
elif y_shift == 0:
newImg[:, :] = self.img
elif y_shift > 0:
newImg[:self.img.shape[0], :] = self.img
elif x_shift > 0:
if y_shift < 0:
newImg[abs(y_shift):, :self.img.shape[1]] = self.img
elif y_shift == 0:
newImg[:, :self.img.shape[1]] = self.img
elif y_shift > 0:
newImg[:y_shift, :self.img.shape[1]] = self.img
self.img = np.uint8(newImg)
self.setBrect()
center = (int(pixelPos.x()), int(pixelPos.y()))
if self.painting:
cv2.circle(img, center, self.radius, 255, -1)
cv2.circle(self.img, center, self.radius, 255, -1)
elif self.erasing:
cv2.circle(img, center, self.radius, 0, -1)
cv2.circle(self.img, center, self.radius, 0, -1)
img = np.uint8(img)
self.contours = self.imgToCnt(img, xmin, ymin, padding)
self.getBrectAndPolygon()
self.setPixmap()
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
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
def paint(self, painter, option, widget):
painter.setPen(QtCore.Qt.white)
painter.drawRect(self.brect)
......@@ -156,11 +164,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,14 @@ 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, padding=0)
img, xmin, ymin, self.padding = self.contoursToImg(contours, padding=0)
topLeft = [ymin, xmin]
self.particlePainter = ParticlePainter(self, img, topLeft)
self.viewparent.normalSize()
self.viewparent.particlePainter = self.particlePainter
self.viewparent.scene().addItem(self.particlePainter)
......@@ -195,7 +202,10 @@ class ParticleEditor(QtCore.QObject):
def acceptPaintedResult(self):
try:
newContour = self.mergeContours(self.particlePainter.contours.copy())
img = self.particlePainter.img
xmin = self.particlePainter.topLeft[1]
ymin = self.particlePainter.topLeft[0]
newContour = self.imgToCnt(img, xmin, ymin, 0)
except NotConnectedContoursError:
self.storedIndices = []
self.storedAssignmend = None
......@@ -219,25 +229,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:
......@@ -245,7 +262,7 @@ class ParticleEditor(QtCore.QObject):
if len(contours)>1:
QtWidgets.QMessageBox.critical(self.viewparent, 'ERROR!',
'Particle contours are not connected and cannot be combined!')
'Particle contours are not connected or have holes.\nThat is currently not supported!')
raise NotConnectedContoursError
newContour = contours[0]
......@@ -255,6 +272,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)
......
......@@ -24,7 +24,7 @@ import numpy as np
import cv2
from helperfunctions import cv2imread_fix, cv2imwrite_fix
from copy import copy
from analysis.particleInfo import ParticleContainer
from analysis.particleContainer import ParticleContainer
currentversion = 3
......@@ -149,6 +149,7 @@ class DataSet(object):
# self.particlestats = []
# self.ramanscansortindex = None
self.particleContainer = ParticleContainer(self)
self.particleDetectionDone = False
self.ramanscandone = False
# self.results = {'polymers': None,
......@@ -246,40 +247,30 @@ class DataSet(object):
self.imagedim_bf = self.imagedim
self.imagedim_df = self.imagedim
del self.imagedim
if not hasattr(self, 'particles2spectra'):
self.particles2spectra = [[int(np.where(self.ramanscansortindex == i)[0])] for i in range(len(self.ramanscansortindex))]
self.version = 2
if self.version == 2:
self.particleContainer = ParticleContainer(self)
def recreateMeasurement2ParticleFromScanIndices():
measurements2particles = [[int(np.where(self.ramanscansortindex == i)[0])] for i in range(len(self.ramanscansortindex))]
return measurements2particles
self.particleContainer.initializeParticles(len(self.particlestats))
self.particleContainer.setParticleContours(self.particlecontours)
self.particleContainer.setParticleStats(self.particlestats)
self.particleContainer.applyPixelScaleToParticleStats(self.getPixelScale())
if hasattr(self, 'particles2spectra'):
if self.particles2spectra is not None:
measurements2particles = self.particles2spectra
else:
measurements2particles = recreateMeasurement2ParticleFromScanIndices()
else:
measurements2particles = recreateMeasurement2ParticleFromScanIndices()
for particleIndex, listOfScanIndices in enumerate(measurements2particles):
curParticle = self.particleContainer.getParticleOfIndex(particleIndex)
for scanIndex in listOfScanIndices:
# curParticle.addEmptyMeasurement()
# curParticle.setMeasurementPixelCoords(measIndex, x, y)
# curParticle.setMeasurementScanIndex(measIndex, scanIndex)
indexOfNewMeas = self.particleContainer.addEmptyMeasurement()
x, y = self.ramanpoints[particleIndex][0], self.ramanpoints[particleIndex][1]
self.particleContainer.setMeasurementPixelCoords(indexOfNewMeas, x, y)
self.particleContainer.setMeasurementScanIndex(indexOfNewMeas, scanIndex)
curParticle.addMeasurement(self.particleContainer.measurements[indexOfNewMeas])
if len(self.particlestats) > 0: #i.e., particle detection was completed and particle data is there
for particleIndex, listOfScanIndices in enumerate(self.particles2spectra):
curParticle = self.particleContainer.getParticleOfIndex(particleIndex)
for scanIndex in listOfScanIndices:
indexOfNewMeas = self.particleContainer.addEmptyMeasurement()
x, y = self.ramanpoints[particleIndex][0], self.ramanpoints[particleIndex][1]
self.particleContainer.setMeasurementPixelCoords(indexOfNewMeas, x, y)
self.particleContainer.setMeasurementScanIndex(indexOfNewMeas, scanIndex)
curParticle.addMeasurement(self.particleContainer.measurements[indexOfNewMeas])
for particle in self.particleContainer.particles:
for meas in particle.measurements:
......@@ -292,8 +283,6 @@ class DataSet(object):
# self.version = 3
# add later conversion for higher version numbers here
def getSubImage(self, img, index, draw=True):
contour = self.particlecontours[index]
x0, x1 = contour[:,0,0].min(), contour[:,0,0].max()
......@@ -395,28 +384,14 @@ class DataSet(object):
def getLegacyDetectImageName(self):
return os.path.join(self.path, "detectimage.png")
def getBackgroundImageName(self):
return os.path.join(self.path, "background.bmp")
def getDetectImageName(self):
raise NotImplementedError("No longer implemented due to change in API")
def getTmpImageName(self):
return os.path.join(self.path, "tmp.bmp")
def saveParticleData(self):
print('Not saving ParticleData into text file...:\nThe current output format might be wrong, if multiple spectra per particle are present...')
# if len(self.ramanscansortindex)>0:
# data = []
# pixelscale = (self.pixelscale_df if self.imagescanMode == 'df' else self.pixelscale_bf)
# for i in self.ramanscansortindex:
# data.append(list(self.ramanpoints[i])+list(self.particlestats[i]))
# data = np.array(data)
# data[:,0], data[:,1], z = self.mapToLengthRaman((data[:,0], data[:,1]), microscopeMode=self.imagescanMode, noz=True)
# data[:,2:7] *= pixelscale
# header = "x [µm], y [µm], length [µm], height [µm], length_ellipse [µm], height_ellipse [µm]"
# if data.shape[1]>6:
# header = header + ", area [µm^2]"
# data[:,6] *= pixelscale
# np.savetxt(os.path.join(self.path, "particledata.txt"), data,
# header=header)
def save(self):
saveData(self, self.fname)
......
......@@ -20,7 +20,7 @@ If not, see <https://www.gnu.org/licenses/>.
"""
import numpy as np
from PyQt5 import QtCore, QtWidgets, QtGui
from segmentation import Segmentation
from segmentation import Segmentation, MeasurementPoint
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
import matplotlib.pyplot as plt
from threading import Thread
......@@ -248,7 +248,9 @@ class ImageView(QtWidgets.QLabel):
painter.setPen(QtCore.Qt.red)
painter.setBrush(QtCore.Qt.red)
for p in self.measpoints:
painter.drawEllipse(p[0]-2, p[1]-2, 5, 5)
for point in self.measpoints[p]:
# painter.drawEllipse(p[0]-2, p[1]-2, 5, 5)
painter.drawEllipse(point.x-2, point.y-2, 5, 5)
if self.showseedpoints:
painter.setPen(QtCore.Qt.white)
......@@ -581,10 +583,9 @@ class ParticleDetectionView(QtWidgets.QWidget):
@QtCore.pyqtSlot()
def clearDetection(self):
if self.dataset is not None:
self.dataset.ramanpoints = []
self.dataset.particlecontours = []
self.dataset.particlestats = []
self.dataset.ramanscansortindex = []
self.dataset.particleContainer.clearParticles()
self.dataset.particleContainer.clearMeasurements()
self.dataset.particleDetectionDone = False
self.dataset.ramanscandone = False
self.dataset.mode = "opticalscan"
self.dataset.save()
......@@ -676,8 +677,8 @@ class ParticleDetectionView(QtWidgets.QWidget):
curParticle.addMeasurement(particleContainer.measurements[indexOfNewMeas])
self.dataset.ramanpoints = measurementPoints #consider moving that to particleContainer
self.dataset.particleDetectionDone = True
# self.dataset.ramanpoints = measurementPoints #consider moving that to particleContainer
# self.dataset.particlecontours = contours
# self.dataset.particlestats = particlestats
# self.dataset.ramanscansortindex = []
......
......@@ -100,13 +100,24 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
fileName = QtWidgets.QFileDialog.getSaveFileName(self, "Create New Project",
defaultPath, "*.pkl")[0]
if fileName:
# if fileName.find(' ') < 0:
self.fname = str(fileName) #TODO: No spaces for Renishaw Interface!!
self.view.new(self.fname)
self.scalingChanged(1.)
# else:
# QtWidgets.QMessageBox.critical(self, "Error", "File path must not contain spaces.")
isValid, msg = self.testFilename(fileName)
if isValid:
self.fname = str(fileName)
self.view.new(self.fname)
self.scalingChanged(1.)
else:
QtWidgets.QMessageBox.critical(self, "Error", msg)
@QtCore.pyqtSlot()
def testFilename(self, fileName):
if self.view.ramanctrl.name == 'RenishawCOM': #the renishawCom does not allow Spaces within filePath
if fileName.find(' ') == 0:
return False, "File path must not contain spaces."
else:
return True, ""
else:
return True, ""
@QtCore.pyqtSlot()
def about(self):
QtWidgets.QMessageBox.about(self, 'GEPARD',
......@@ -192,7 +203,7 @@ class GEPARDMainWindow(QtWidgets.QMainWindow):
self.configRamanCtrlAct.triggered.connect(self.view.configureRamanControl)
if self.view.simulatedRaman:
self.configRamanCtrlAct.setDisabled(True)
def updateModes(self, active=None, maxenabled=None):
ose, osc, pde, pdc, rse, rsc, pae, pac = [False]*8
if maxenabled=="OpticalScan":
......@@ -316,12 +327,11 @@ if __name__ == '__main__':
if not os.path.exists(logpath):
os.mkdir(logpath)
logname = os.path.join(logpath, 'logfile.txt')
#
# fp = open(logname, "a")
# sys.stderr = fp
# sys.stdout = fp
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()),
flush=True)
fp = open(logname, "a")
sys.stderr = fp
sys.stdout = fp
print("starting GEPARD at: " + strftime("%d %b %Y %H:%M:%S", localtime()), flush=True)
gepard = GEPARDMainWindow(logpath)
gepard.showMaximized()
......
......@@ -48,15 +48,17 @@ def imageStacking(colimgs):
return im, zval
def combineImages(path, nx, ny, nk, width, height, angle):
imgs = []
full = None
for i in range(nx):
for j in range(ny):
colimgs = []
for k in range(nk):
colimgs.append(cv2.imread(path + f'test_{i}_{j}_{k}.bmp'))
img = imageStacking(colimgs)
imgs.append(img)
if nk > 1:
colimgs = []
for k in range(nk):
colimgs.append(cv2.imread(path + f'test_{i}_{j}_{k}.bmp'))
img = imageStacking(colimgs)
else:
img = cv2.imread(path + f'test_{i}_{j}_1.bmp')
dx = i*.9*img.shape[1]
dy = j*.8*img.shape[0]
c, s = np.cos(np.radians(angle)), np.sin(np.radians(angle))
......@@ -67,6 +69,7 @@ def combineImages(path, nx, ny, nk, width, height, angle):
full = dst
else:
full = cv2.max(full,dst)
cv2.imwrite("full_dunkel.png", full)
......
# -*- coding: utf-8 -*-
"""
GEPARD - Gepard-Enabled PARticle Detection
Copyright (C) 2018 Lars Bittrich and Josef Brandt, Leibniz-Institut für
Polymerforschung Dresden e. V. <bittrich-lars@ipfdd.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program, see COPYING.
If not, see <https://www.gnu.org/licenses/>.
"""
from PyQt5 import QtCore, QtWidgets, QtGui
import cv2
import numpy as np
import os
from helperfunctions import cv2imread_fix
class BackGroundManager(QtWidgets.QWidget):
managerClosed = QtCore.pyqtSignal()
readBackground = QtCore.pyqtSignal(int)
def __init__(self, parentOSwidget):
super(BackGroundManager, self).__init__()
self.setFixedSize(1500, 900)
self.setWindowTitle('Optical Background Manager')
self.parentOSwidget = parentOSwidget
self.parentOSwidget.backGroundSavedToPath.connect(self.updateChildImage)
self.ramanctrl = self.parentOSwidget.ramanctrl
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
self.imagesGroup = QtWidgets.QGroupBox('Current Background Images')
self.imagesLayout = QtWidgets.QGridLayout()
self.imgContainers = []
self.avgImg = None
self.presetIndividualImages()
self.previewImage = QtWidgets.QGraphicsView()
self.setupGraphicsView(self.previewImage, scaleFactor=0.8)
previewGroup = QtWidgets.QGroupBox()
previewLayout = QtWidgets.QVBoxLayout()
self.blurspinbox = QtWidgets.QSpinBox(self)
self.blurspinbox.setMinimum(3)
self.blurspinbox.setMaximum(99)
self.blurspinbox.setSingleStep(2)
self.blurspinbox.setValue(5)
self.blurspinbox.valueChanged.connect(self.calculateAverageImage)
self.blurspinbox.setMaximumWidth(150)
self.previewCurrentViewBtn = QtWidgets.QPushButton('Acquire 3x3 area and preview subtracted result')
self.previewCurrentViewBtn.clicked.connect(self.previewStitchedArea)
self.previewArea = QtWidgets.QGraphicsView()
self.setupGraphicsView(self.previewArea, scaleFactor=0.5)
previewLayout.addWidget(QtWidgets.QLabel('Radius for blur'))
previewLayout.addWidget(self.blurspinbox)
previewLayout.addWidget(QtWidgets.QLabel('Preview of averaged and smoothed image'))
previewLayout.addWidget(self.previewImage)
previewLayout.addWidget(self.previewCurrentViewBtn)
previewLayout.addWidget(self.previewArea)
previewGroup.setLayout(previewLayout)
layout.addWidget(self.imagesGroup)
layout.addWidget(previewGroup)
def presetIndividualImages(self, nrows=3, ncols=2):
index = 0
for row in range(nrows):
for col in range(ncols):
self.imgContainers.append(SingleImageContainer(self, index))
self.imagesLayout.addWidget(self.imgContainers[-1], row, col)
index += 1
self.imagesGroup.setLayout(self.imagesLayout)
def previewStitchedArea(self):
if self.avgImg is None:
QtWidgets.QMessageBox.about(self, 'Warning', 'No Background Image is aquired')
return
else:
from opticalscan import loadAndPasteImage
self.dataset = self.parentOSwidget.dataset
#acquire images in 3x3 area to preview quality of background subtraction
x, y, z = self.ramanctrl.getPosition()
micMode = self.parentOSwidget.view.microscopeMode
width, height, angle = self.ramanctrl.getImageDimensions(micMode)
startPoint = [x-width, y-height]
endPoint = [x+width, y+height]
points = np.concatenate(([startPoint], [endPoint]), axis=0)
p0 = [points[:,0].min(), points[:,1].max()]
p1 = [points[:,0].max(), points[:,1].min()]
reply = QtWidgets.QMessageBox.question(self, 'Message',f"The stage will move {round(3*width)} in x and {round(3*height)} in y.\nContinue?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
fullimg = None
zimg = None
for row in range(3):
for col in range(3):
curPoint = [startPoint[0] + row*width, startPoint[1] + col*height]
self.ramanctrl.moveToAbsolutePosition(curPoint[0], curPoint[1])
self.ramanctrl.saveImage(self.dataset.getTmpImageName())
fullimg, zimg = loadAndPasteImage([self.dataset.getTmpImageName()], fullimg, zimg, width, height, angle, p0, p1, curPoint, background=self.avgImg)
self.updateGraphicsView(self.previewArea, fullimg, convertColors=True)
def setupGraphicsView(self, graphView, scaleFactor=1.):
graphView.item = QtWidgets.QGraphicsPixmapItem()
scene = QtWidgets.QGraphicsScene(graphView)
scene.addItem(graphView.item)
graphView.setScene(scene)
graphView.scale(scaleFactor, scaleFactor)
def updateGraphicsView(self, graphView, img, convertColors=False):
if img is not None:
prevImg = img
else:
prevImg = np.zeros((300, 300))
if convertColors:
prevImg = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
height, width = prevImg.shape[:2]
bytesPerLine = 3 * width
pix = QtGui.QPixmap()
pix.convertFromImage(QtGui.QImage(prevImg, width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
graphView.item.setPixmap(pix)
@QtCore.pyqtSlot(int, str)
def updateChildImage(self, index, path):
self.imgContainers[index].updateImage(path)
self.calculateAverageImage()
def calculateAverageImage(self):
curImgs = [i.getImage() for i in self.imgContainers if i.getImage() is not None]
if len(curImgs) > 0:
curImgs = np.array(curImgs)
self.avgImg = np.sum(curImgs, axis=0)/len(curImgs)
radius = self.blurspinbox.value()
if radius %2 == 0:
radius += 1
if radius < 0:
radius = 1
self.avgImg = cv2.GaussianBlur(self.avgImg, (radius, radius), 0)
self.avgImg = np.uint8(self.avgImg)
self.parentOSwidget.writeBackGroundImage(self.avgImg)
else:
self.avgImg = None
self.parentOSwidget.deleteBackGroundImage()
self.updateGraphicsView(self.previewImage, self.avgImg)
def closeEvent(self, event):
self.managerClosed.emit()
event.accept()
class SingleImageContainer(QtWidgets.QGroupBox):
def __init__(self, parent, index):
super(SingleImageContainer, self).__init__()
self.index = index
self.parent = parent
layout = QtWidgets.QVBoxLayout()
layout.addWidget(QtWidgets.QLabel(f'Background {index+1}'))
readBtn = QtWidgets.QPushButton('ReadImage')
readBtn.clicked.connect(self.readImage)
self.image = ImagePixmap()
delBtn = QtWidgets.QPushButton('Delete Image')
delBtn.clicked.connect(self.clearImage)
layout.addWidget(readBtn)
layout.addWidget(self.image)
layout.addWidget(delBtn)
self.setLayout(layout)
def readImage(self):
self.parent.readBackground.emit(self.index)
def updateImage(self, path):
self.image.updateImage(path)
def clearImage(self):
self.image.clearImage()
self.parent.calculateAverageImage()
def getImage(self):
return self.image.imgdata
class ImagePixmap(QtWidgets.QGraphicsView):
def __init__(self):
super(ImagePixmap, self).__init__()
self.item = QtWidgets.QGraphicsPixmapItem()
self.item.setPos(0, 0)
self.item.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.imgdata = None
scene = QtWidgets.QGraphicsScene(self)
scene.addItem(self.item)
self.setScene(scene)
self.scale(0.4, 0.4)
self.updateImage()
def updateImage(self, img_path=None):
if img_path is None:
self.loadImageIntoPixmap(self.createBlancImage())
elif os.path.exists(img_path):
self.imgdata = cv2.cvtColor(cv2imread_fix(img_path), cv2.COLOR_BGR2RGB)
self.loadImageIntoPixmap(self.imgdata)
def createBlancImage(self):
blancImg = np.zeros((300, 500, 3))
cv2.putText(blancImg, 'None selected', (150, 150), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255), 2)
return blancImg
def loadImageIntoPixmap(self, img):
height, width = img.shape[:2]
bytesPerLine = 3 * width
pix = QtGui.QPixmap()
pix.convertFromImage(QtGui.QImage(img, width, height, bytesPerLine, QtGui.QImage.Format_RGB888))
self.item.setPixmap(pix)
def clearImage(self):
self.imgdata = None
self.updateImage()
This diff is collapsed.
......@@ -47,6 +47,7 @@ class WITecCOM(RamanBase):
def __init__(self, hostname=None):
super().__init__()
self.name = 'WITecCOM'
if hostname is None:
hostname = gethostname()
self.IBUCSAccess = win32com.client.DispatchEx(self.CLSID, machine=hostname,
......@@ -210,9 +211,22 @@ class WITecCOM(RamanBase):
# move only if new position is really different; repeat if new position is ignored (happens some times)
while max(abs(initpos[0]-x), abs(initpos[1]-y))>epsxy:
t0 = time()
self.PosXFloatMan.SetValue(x)
self.PosYFloatMan.SetValue(y)
self.GoToTrigger.OperateTrigger()
numFails = 0
maxFails = 50
positionSubmitted = False
while numFails < maxFails and not positionSubmitted:
try:
self.PosXFloatMan.SetValue(x)
self.PosYFloatMan.SetValue(y)
self.GoToTrigger.OperateTrigger()
positionSubmitted = True
except pythoncom.com_error:
numFails += 1
sleep(.1)
if numFails > 0:
print(f'{numFails} of max. {maxFails} unsuccessfull position submits to Position: {x}, {y}', flush=True)
if not positionSubmitted:
print(f'Error setting Position: {x}, {y}\nExpecting \"signal ignored\" warning', flush=True)
# wait till position is found within accuracy of epsxy; check if position changes at all
distance = 2*epsxy
......@@ -296,7 +310,6 @@ class WITecCOM(RamanBase):
print("Waiting for measurement ready...")
t1 = time()
def triggerMeasurement(self, num):
assert self.timeseries
self.TimeSeriesSlowNextMan.OperateTrigger()
......
......@@ -21,6 +21,7 @@ If not, see <https://www.gnu.org/licenses/>.
class RamanBase(object):
def __init__(self):
self.name = None
self.connected = False
self.timeseries = False
......
......@@ -32,6 +32,7 @@ class SimulatedRaman(RamanBase):
ramanParameters = {}
def __init__(self):
super().__init__()
self.name = 'SimulatedRaman'
self.currentpos = None, 0., 0.
self.currentZ = 0.
# some plausible data to simulate consecutively changing positions
......
......@@ -232,19 +232,9 @@ class RamanScanUI(QtWidgets.QWidget):
if reply == QtWidgets.QMessageBox.Yes:
self.dataset.mode = "ramanscan"
measurements2particles = [[int(np.where(cmin == i)[0])] for i in range(len(cmin))] #i.e., list of scanIndicesPerParticle
for particleIndex, listOfScanIndices in enumerate(measurements2particles):
# curParticle = self.particleContainer.getParticleOfIndex(particleIndex)
for scanIndex in listOfScanIndices:
self.particleContainer.setMeasurementScanIndex(indexOfNewMeas, scanIndex)
for measIndex, ramanScanIndex in enumerate(cmin):
self.particleContainer.setMeasurementScaneIndex(measIndex, ramanScanIndex)
# self.dataset.ramanscansortindex = cmin
self.dataset.saveParticleData()
self.view.saveDataSet()
self.view.prepareAnalysis()
self.view.scaleImage(2.0)
......@@ -280,8 +270,9 @@ class RamanScanUI(QtWidgets.QWidget):
if i>=0:
self.progressbar.setValue(i+1)
self.view.highLightRamanIndex(i+1)
Npoints = len(self.dataset.ramanpoints)
self.view.highLightRamanIndex(i+1) #go to next scanmarker
Npoints = len(self.dataset.particleContainer.getMeasurementPixelCoords())
if i>3:
timerunning = time()-self.starttime
ttot = timerunning*Npoints/(i+1)
......@@ -294,7 +285,6 @@ class RamanScanUI(QtWidgets.QWidget):
self.dataset.ramanscandone = True
self.view.saveDataSet()
self.view.unblockUI()
# self.view.switchMode("ParticleAnalysis") #directly going to analysis is not feasible... We first have to export spectra etc...
self.progressbar.setValue(0)
self.progressbar.setEnabled(False)
self.progresstime.setEnabled(False)
......
......@@ -34,9 +34,8 @@ from zeissimporter import ZeissImporter
from viewitems import FitPosIndicator, Node, Edge, ScanIndicator, RamanScanIndicator, SegmentationContour
from analysis.colorlegend import getColorFromNameWithSeed
from helperfunctions import polygoncovering, cv2imread_fix
from ramancom.configRaman import RamanConfigWin
from analysis.particleeditor import ParticleEditor
from analysis.particleEditor import ParticleEditor
class SampleView(QtWidgets.QGraphicsView):
......@@ -101,7 +100,6 @@ class SampleView(QtWidgets.QGraphicsView):
self.update()
def takeScreenshot(self):
#TODO:
#LIMIT SCREENSHOT TO ACTUAL VIEWSIZE OF LOADED IMAGE...
......@@ -180,9 +178,6 @@ class SampleView(QtWidgets.QGraphicsView):
return
assert mode in ["OpticalScan", "ParticleDetection", "RamanScan", "ParticleAnalysis"]
self.oscanwidget.setVisible(False)
if self.detectionwidget is not None:
self.detectionwidget.close()
self.detectionwidget.destroy()
self.ramanwidget.setVisible(False)
self.mode = mode
self.loadPixmap(self.microscopeMode)
......@@ -193,9 +188,9 @@ class SampleView(QtWidgets.QGraphicsView):
elif mode == "ParticleDetection":
if self.detectionwidget is None:
self.detectionwidget = ParticleDetectionView(self.imgdata, self.dataset, self)
self.detectionwidget.show()
self.detectionwidget.imageUpdate.connect(self.detectionUpdate)
self.detectionwidget.detectionFinished.connect(self.activateMaxMode)
self.detectionwidget.show()
elif mode == "RamanScan":
self.ramanwidget.resetDataset(self.dataset)
......@@ -269,14 +264,9 @@ class SampleView(QtWidgets.QGraphicsView):
if self.particleEditor is None:
self.particleEditor = ParticleEditor(self, self.dataset.particleContainer)
#try disconnecting the signals. If they are connected multiple times, the functions will run accordingly...
# tryDisconnectingSignal(self.particleEditor.particleContoursChanged)
tryDisconnectingSignal(self.particleEditor.particleAssignmentChanged)
# self.particleEditor.particleContoursChanged.connect(self.resetParticleContours)
if self.analysiswidget is not None:
# self.particleEditor.particleContoursChanged.connect(self.analysiswidget.updateHistogramsAndContours)
self.particleEditor.particleAssignmentChanged.connect(self.analysiswidget.updateHistogramsAndContours)
def setMicroscopeMode(self):
......@@ -310,7 +300,7 @@ class SampleView(QtWidgets.QGraphicsView):
maxmode = "OpticalScan"
if os.path.exists(self.dataset.getImageName()):
maxmode = "ParticleDetection"
if len(self.dataset.ramanpoints)>0:
if self.dataset.particleDetectionDone:
maxmode = "RamanScan"
if self.dataset.ramanscandone:
maxmode = "ParticleAnalysis"
......@@ -331,11 +321,11 @@ class SampleView(QtWidgets.QGraphicsView):
elif self.mode=="ParticleDetection":
p0 = self.mapToScene(event.pos())
self.detectionwidget.setImageCenter([p0.x(), p0.y()])
else:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mousePressEvent(event)
else:
p0 = self.mapToScene(event.pos())
super(SampleView, self).mousePressEvent(event)
else:
self.particlePainter.mousePressEvent(event)
......@@ -382,9 +372,7 @@ class SampleView(QtWidgets.QGraphicsView):
self.dataset.readin = False
else:
return
# x, y, z = self.dataset.mapToLengthRaman([p0.x(), p0.y()],
# microscopeMode=self.microscopeMode,
# noz=(False if self.mode=="RamanScan" else True))
noz = (self.mode in ['OpticalScan', 'RamanScan'])
x, y, z = self.dataset.mapToLengthRaman([pos.x(), pos.y()], microscopeMode=self.microscopeMode, noz=noz)
if z is not None:
......@@ -401,7 +389,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
......@@ -412,6 +401,7 @@ class SampleView(QtWidgets.QGraphicsView):
p = QtCore.QPointF(p.x(), p.y())
for index, cnt in enumerate(self.contourItems):
if cnt.polygon.containsPoint(p, QtCore.Qt.OddEvenFill): #clicked on particle
if not event.modifiers()==QtCore.Qt.ShiftModifier:
acceptSelection(cnt)
......
This diff is collapsed.
......@@ -20,7 +20,7 @@ If not, see <https://www.gnu.org/licenses/>.
"""
#import numpy as np
from PyQt5 import QtCore, QtWidgets, QtGui
from analysis.particleeditor import ParticleContextMenu
from analysis.particleEditor import ParticleContextMenu
class SegmentationContour(QtWidgets.QGraphicsItem):
def __init__(self, viewparent, contourData, pos=(0,0)):
......@@ -29,7 +29,6 @@ class SegmentationContour(QtWidgets.QGraphicsItem):
self.setZValue(1)
self.setPos(pos[0], pos[1])
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
# self.setAcceptedMouseButtons(QtCore.Qt.AllButtons)
self.brect = QtCore.QRectF(0,0,1,1)
self.contourData = contourData
......@@ -55,10 +54,7 @@ class SegmentationContour(QtWidgets.QGraphicsItem):
def boundingRect(self):
return self.brect
# def createRamanScanIndices(self):
def setIndex(self, index):
self.particleIndex = index
......@@ -83,13 +79,6 @@ class SegmentationContour(QtWidgets.QGraphicsItem):
painter.drawPolygon(self.polygon)
# def mousePressEvent(self, event):
# print('press in contour')
#
# def mouseMoveEvent(self, event):
# print('move in contour')
#
def contextMenuEvent(self, event):
if self.isSelected:
self.contextMenu = ParticleContextMenu(self.viewparent)
......@@ -128,15 +117,15 @@ class FitPosIndicator(QtWidgets.QGraphicsItem):
class RamanScanIndicator(QtWidgets.QGraphicsItem):
def __init__(self, view, number, radius, pos=(0,0)):
super().__init__()
# self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.setZValue(100) #higher numbers will be in foreground. Shall always be in foreground!
self.setZValue(100) #higher zValues will be in foreground. Shall always be in foreground!
self.view = view
self.number = number
self.radius = radius
self.highlight = False
self.hidden = False
self.setPos(pos[0], pos[1])
self.hasNoParticleAssigned = False
def setHighLight(self, highlight):
if highlight!=self.highlight:
......@@ -157,6 +146,9 @@ class RamanScanIndicator(QtWidgets.QGraphicsItem):
if self.highlight:
painter.setPen(QtCore.Qt.red)
painter.setBrush(QtGui.QColor(100,250,100,150))
elif self.hasNoParticleAssigned:
painter.setPen(QtCore.Qt.black)
painter.setBrush(QtCore.Qt.red)
else:
painter.setPen(QtCore.Qt.green)
painter.setBrush(QtGui.QColor(50,50,250,150))
......@@ -166,14 +158,6 @@ class RamanScanIndicator(QtWidgets.QGraphicsItem):
font.setPointSize(10)
painter.setFont(font)
painter.drawText(rect, QtCore.Qt.AlignCenter, str(self.number))
# def mousePressEvent(self, event):
# p = event.pos()
# x, y = p.x(), p.y()
# r = np.sqrt(x**2+y**2)
# if r<self.radius:
# self.view.selectRamanScanPoint(self.number, r)
# super().mouseReleaseEvent(event)
class ScanIndicator(QtWidgets.QGraphicsItem):
......@@ -199,6 +183,7 @@ class ScanIndicator(QtWidgets.QGraphicsItem):
painter.drawText(rect, QtCore.Qt.AlignCenter, str(self.number))
painter.drawRect(rect)
class Edge(QtWidgets.QGraphicsItem):
def __init__(self, n1, n2):
......@@ -216,16 +201,16 @@ class Edge(QtWidgets.QGraphicsItem):
def paint(self, painter, option, widget):
painter.setPen(QtCore.Qt.green)
painter.drawLine(self.n1.pos(), self.n2.pos())
class Node(QtWidgets.QGraphicsItem):
def __init__(self, point, view):
self.view = view
self.point = point
self.edges = []
self.rectSize = 60
self.rectSize = 120
super().__init__()
self.setPos(self.point[0], self.point[1])
self.rectSize = 2*self.rectSize #<--- why that? Why not set it to 120 right in the first place??
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges)
self.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)
......@@ -242,9 +227,9 @@ class Node(QtWidgets.QGraphicsItem):
def paint(self, painter, option, widget):
painter.setBrush(QtGui.QColor(255,0,0,80))
painter.setPen(QtCore.Qt.red)
painter.drawLine(0,-self.rectSize/2.,0,self.rectSize/2)
painter.drawLine(-self.rectSize/2.,0,self.rectSize/2,0)
rect = QtCore.QRectF(-self.rectSize,-self.rectSize,2*self.rectSize,2*self.rectSize)
painter.drawLine(0, -self.rectSize/2., 0, self.rectSize/2)
painter.drawLine(-self.rectSize/2., 0, self.rectSize/2, 0)
rect = QtCore.QRectF(-self.rectSize, -self.rectSize, 2*self.rectSize, 2*self.rectSize)
painter.drawEllipse(rect)
def itemChange(self, change, value):
......