def home(self, *args) : print 'Home is clicked' fig = self.canvas.figure fig.myXmin = None fig.myXmax = None fig.myYmin = None fig.myYmax = None NavigationToolbar.home(self)
def home(self, *args): print 'Home is clicked' fig = self.canvas.figure fig.myXmin = None fig.myXmax = None fig.myYmin = None fig.myYmax = None NavigationToolbar.home(self)
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) # self.toolbar.hide() # Just some button self.button = QtGui.QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QtGui.QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QtGui.QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QtGui.QPushButton('Home') self.button3.clicked.connect(self.home) # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(211) ax.hold(False) ax.plot(data, '*-') bx = self.figure.add_subplot(212) bx.hold(False) bx.plot(data, '*-') self.canvas.draw()
class MPlotWidget(QtGui.QWidget): def __init__(self, parent=None): super(MPlotWidget, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() self.plotbutton = QtGui.QPushButton('Plot') self.zoombutton = QtGui.QPushButton('Zoom') self.zoombutton.clicked.connect(self.zoom) self.panbutton = QtGui.QPushButton('Pan') self.panbutton.clicked.connect(self.pan) self.homebutton = QtGui.QPushButton('Home') self.homebutton.clicked.connect(self.home) self.savebutton = QtGui.QPushButton('Save') self.savebutton.clicked.connect(self.save) layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) buttonbox = QtGui.QHBoxLayout() buttonbox.addWidget(self.plotbutton) buttonbox.addWidget(self.zoombutton) buttonbox.addWidget(self.panbutton) buttonbox.addWidget(self.homebutton) buttonbox.addWidget(self.savebutton) layout.addLayout(buttonbox) self.setLayout(layout) self.ax = self.figure.add_subplot(111) self.ax.hold(False) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def save(self): self.figure.savefig('1.png') """
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button = QtGui.QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QtGui.QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QtGui.QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QtGui.QPushButton('Home') self.button3.clicked.connect(self.home) # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(111) ax.hold(False) ax.plot(data, '*-') self.canvas.draw()
def home(self): """ Reset everything to default, including colormap when home pressed. """ NavigationToolbar2QTAgg.home(self) self.parent.canvas.reset_figure()
def home(self): """ Reset everything to default, including colormap when home pressed. """ NavigationToolbar2QTAgg.home(self) self.parent.canvas.reset_figure()
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Timestream info self.timestreamLabel = QtGui.QLabel('Time-stream root path:') self.timestreamText = QtGui.QLineEdit('') self.timestreamText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.timestreamDateLabel = QtGui.QLabel('Start date (yyyy_mm_dd_hh_mm_ss):') self.timestreamDateText = QtGui.QLineEdit('') self.timestreamDateText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.timestreamTimeLabel = QtGui.QLabel('Time interval (seconds):') self.timestreamTimeText = QtGui.QLineEdit('') self.timestreamTimeText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.initStreamTimeButton = QtGui.QPushButton('&Initialise timestream by time') self.initStreamTimeButton.clicked.connect(self.initialiseTimestreamByTime) self.initStreamFileButton = QtGui.QPushButton('&Initialise timestream by files') self.initStreamFileButton.clicked.connect(self.initialiseTimestreamByFiles) # Image loading and processing self.loadImageButton = QtGui.QPushButton('&Load (next) image') self.loadImageButton.clicked.connect(self.loadImage) self.rotateImageButton = QtGui.QPushButton('&Rotate 90-deg') self.rotateImageButton.clicked.connect(self.rotateImage90Degrees) self.slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.slider.setFocusPolicy(QtCore.Qt.StrongFocus) self.slider.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.slider.setTickPosition(QtGui.QSlider.TicksBothSides) self.slider.setMinimum(-16) self.slider.setMaximum(16) self.slider.setValue(0) self.slider.setTickInterval(4) self.slider.setSingleStep(1) self.slider.valueChanged.connect(self.rotateSmallAngle) self.applySmallRotationButton = QtGui.QPushButton('&Apply') self.applySmallRotationButton.clicked.connect(self.applySmallRotation) self.loadCamCalibButton = QtGui.QPushButton('Load &cam. param.') self.loadCamCalibButton.clicked.connect(self.loadCamCalib) self.colorcardRadioButton = QtGui.QRadioButton('Select color car&d') self.colorcardRadioButton.setChecked(False) self.colorcardRadioButton.clicked.connect(self.selectWhat) self.trayRadioButton = QtGui.QRadioButton('Select &tray') self.trayRadioButton.setChecked(False) self.trayRadioButton.clicked.connect(self.selectWhat) self.trayRoundCheckBox = QtGui.QCheckBox('Round') self.trayRoundCheckBox.setChecked(True) self.potRadioButton = QtGui.QRadioButton('Select &pot') self.potRadioButton.setChecked(False) self.potRadioButton.clicked.connect(self.selectWhat) self.zoomButton = QtGui.QPushButton('&Zoom') self.zoomButton.setCheckable(True) self.zoomButton.clicked.connect(self.zoom) self.panButton = QtGui.QPushButton('&Pan') self.panButton.setCheckable(True) self.panButton.clicked.connect(self.pan) self.homeButton = QtGui.QPushButton('&Home') self.homeButton.clicked.connect(self.home) self.correctColorButton = QtGui.QPushButton('Correct colo&r') self.correctColorButton.clicked.connect(self.correctColor) self.save2PipelineButton = QtGui.QPushButton('&Save as pipeline settings') self.save2PipelineButton.clicked.connect(self.savePipelineSettings) self.testPipelineButton = QtGui.QPushButton('Test &pipeline processing') self.testPipelineButton.clicked.connect(self.testPipeline) self.status = QtGui.QTextEdit('') self.status.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.mousePosition = QtGui.QLabel('') # set the layout layout = QtGui.QHBoxLayout() rightWidget = QtGui.QWidget() buttonlayout = QtGui.QVBoxLayout(rightWidget) buttonlayout.addWidget(self.timestreamLabel) buttonlayout.addWidget(self.timestreamText) buttonlayout.addWidget(self.timestreamDateLabel) buttonlayout.addWidget(self.timestreamDateText) buttonlayout.addWidget(self.timestreamTimeLabel) buttonlayout.addWidget(self.timestreamTimeText) buttonlayout.addWidget(self.initStreamTimeButton) buttonlayout.addWidget(self.initStreamFileButton) buttonlayout.addWidget(self.loadImageButton) buttonlayout.addWidget(self.loadCamCalibButton) buttonlayout.addWidget(self.rotateImageButton) layoutSmallRotation = QtGui.QHBoxLayout() layoutSmallRotation.addWidget(self.slider) layoutSmallRotation.addWidget(self.applySmallRotationButton) buttonlayout.addLayout(layoutSmallRotation) buttonlayout.addWidget(self.colorcardRadioButton) layoutTrayShape = QtGui.QHBoxLayout() layoutTrayShape.addWidget(self.trayRadioButton) layoutTrayShape.addWidget(self.trayRoundCheckBox) buttonlayout.addLayout(layoutTrayShape) buttonlayout.addWidget(self.potRadioButton) buttonlayout.addWidget(self.zoomButton) buttonlayout.addWidget(self.panButton) buttonlayout.addWidget(self.homeButton) buttonlayout.addWidget(self.correctColorButton) buttonlayout.addWidget(self.save2PipelineButton) buttonlayout.addWidget(self.testPipelineButton) buttonlayout.addWidget(self.status) buttonlayout.addWidget(self.mousePosition) rightWidget.setMaximumWidth(250) leftLayout = QtGui.QVBoxLayout() leftLayout.addWidget(self.toolbar) leftLayout.addWidget(self.canvas) layout.addWidget(rightWidget) layout.addLayout(leftLayout) self.setLayout(layout) self.group = QtGui.QButtonGroup() self.group.addButton(self.colorcardRadioButton) self.group.addButton(self.trayRadioButton) self.group.addButton(self.potRadioButton) self.loadPreviousInputs() self.panMode = False self.zoomMode = False self.ts = None self.tsImages = None self.ax = None self.plotRect = None self.plotImg = None self.image = None self.potTemplate = None self.UndistMapX = None self.UndistMapY = None self.trayAspectRatio = 0.835 self.colorcardAspectRatio = 1.5 self.potAspectRatio = 1.0 self.leftClicks = [] self.colorcardParams = None self.scriptPath = os.path.dirname(os.path.realpath(__file__)) self.timestreamRootPath = None self.pl = None # Ouput parameters self.ImageSize = None self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0.0 self.smaleRotationAngle = 0.0 self.CameraMatrix = None self.DistCoefs = None self.isDistortionCorrected = False self.settingFileName = None def selectWhat(self): if self.trayRadioButton.isChecked(): self.status.append('Start selecting tray.') elif self.colorcardRadioButton.isChecked(): self.status.append('Start selecting color bar.') else: self.status.append('Start selecting pot.') def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() if not self.zoomMode: self.zoomMode = True self.panMode = False self.panButton.setChecked(False) else: self.zoomMode = False def pan(self): self.toolbar.pan() if not self.panMode: self.panMode = True self.zoomMode = False self.zoomButton.setChecked(False) else: self.panMode = False def initialiseTimestreamByTime(self): self.timestreamRootPath = str(self.timestreamText.text()) if len(self.timestreamRootPath) > 0: self.status.append('Initialise a timestream at ' + str(self.timestreamRootPath)) self.ts = timestream.TimeStream() self.ts.load(self.timestreamRootPath) self.status.append('Done') startDate = None timeInterval = None date = str(self.timestreamDateText.text()) if len(date) > 0: startDate = timestream.parse.ts_parse_date(date) time = str(self.timestreamTimeText.text()) if len(time) > 0: timeInterval = int(eval(time)) self.tsImages = self.ts.iter_by_timepoints(start = startDate, interval = timeInterval, remove_gaps=False) self.loadImage() else: self.status.append('Please provide timestream root path.') def initialiseTimestreamByFiles(self): self.timestreamRootPath = str(self.timestreamText.text()) if len(self.timestreamRootPath) > 0: self.status.append('Initialise a timestream at ' + str(self.timestreamRootPath)) self.ts = timestream.TimeStream() self.ts.load(self.timestreamRootPath) self.status.append('Done') self.tsImages = self.ts.iter_by_files() self.loadImage() else: self.status.append('Please provide timestream root path.') def loadImage(self): ''' load and show an image''' if self.tsImages != None: try: tsImage = self.tsImages.next() if tsImage.pixels == np.array([]): self.status.append('Missing image.') except: tsImage.pixels == np.array([]) self.status.append('There is no more images.') if tsImage.pixels == np.array([]): self.image = None self.updateFigure() return self.image = tsImage.pixels fname = tsImage.path else: fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/mnt/phenocam/a_data/TimeStreams/Borevitz/BVZ0036/BVZ0036-GC02L-C01~fullres-orig/2014/2014_06/2014_06_24/2014_06_24_08/') app.processEvents() if len(fname) == 0: return self.image = cv2.imread(str(fname))[:,:,::-1] self.status.append('Loaded image from ' + str(fname)) # reset all outputs # self.colorcardList = [] # self.trayList = [] # self.potList = [] self.isDistortionCorrected = False if self.rotationAngle != None: self.image = cd.rotateImage(self.image, self.rotationAngle + self.smaleRotationAngle) # Undistort image if mapping available if not self.isDistortionCorrected and self.UndistMapX != None and self.UndistMapY != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.updateFigure() def changeCursor(self, event): # cursor = Cursor(self.ax, useblit=True, color='red', linewidth=1) self.canvas.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) def updateFigure(self, image = None, resetFigure = False): if self.image != None: if image == None: image = self.image if self.ax == None: self.ax = self.figure.add_subplot(111) self.ax.figure.canvas.mpl_connect('button_press_event', self.onMouseClicked) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onMouseMoves) self.ax.figure.canvas.mpl_connect('figure_enter_event', self.changeCursor) self.ax.hold(False) if self.plotImg == None or resetFigure: self.plotImg = self.ax.imshow(image) else: self.plotImg.set_data(image) self.figure.tight_layout() xs, ys = [], [] for Rect in self.colorcardList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.trayList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.potList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for x,y in self.leftClicks: xs = xs + [x] ys = ys + [y] # if self.crosshair != None: # xs = xs + [np.nan, 0, self.image.shape[1], np.nan, self.crosshair[0], self.crosshair[0], np.nan] # ys = ys + [np.nan, self.crosshair[1], self.crosshair[1], np.nan, 0, self.image.shape[0], np.nan] if len(xs) > 0 and len(ys) > 0: if self.plotRect == None: self.ax.hold(True) self.plotRect, = self.ax.plot(xs, ys, 'b') self.ax.hold(False) self.ax.set_xlim([0,self.image.shape[1]]) self.ax.set_ylim([0,self.image.shape[0]]) self.ax.invert_yaxis() else: self.plotRect.set_data(xs, ys) self.canvas.draw() app.processEvents() def loadCamCalib(self): ''' load camera calibration image and show an image''' calibPath = os.path.join(self.scriptPath, './data') CalibFile = QtGui.QFileDialog.getOpenFileName(self, 'Open image', calibPath) self.ImageSize, SquareSize, self.CameraMatrix, self.DistCoefs, RVecs, TVecs = cd.readCalibration(CalibFile) self.status.append('Loaded camera parameters from ' + CalibFile) print('CameraMatrix =', self.CameraMatrix) print('DistCoefs =', self.DistCoefs) self.UndistMapX, self.UndistMapY = cv2.initUndistortRectifyMap(self.CameraMatrix, self.DistCoefs, \ None, self.CameraMatrix, self.ImageSize, cv2.CV_32FC1) if self.image != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.status.append('Corrected image distortion.') self.updateFigure() # def loadPotTemplate(self): # ''' load pot template image''' # fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') # self.status.append('Loading image...') # app.processEvents() # self.potTemplate = cv2.imread(str(fname))[:,:,::-1] # if len(self.potList) > 0: def correctColor(self): if self.colorcardParams == None: if len(self.colorcardList) > 0: medianSize = cd.getMedianRectSize(self.colorcardList) capturedColorcards = cd.rectifyRectImages(self.image, self.colorcardList, medianSize) self.colorcardColors, _ = cd.getColorcardColors(capturedColorcards[0], GridSize = [6, 4]) self.colorcardParams = cd.estimateColorParameters(cd.CameraTrax_24ColorCard, self.colorcardColors) else: self.status.append('Need to select a color card first.') return colorMatrix, colorConstant, colorGamma = self.colorcardParams self.imageCorrected = cd.correctColorVectorised(self.image.astype(np.float), colorMatrix, colorConstant, colorGamma) self.imageCorrected[np.where(self.imageCorrected < 0)] = 0 self.imageCorrected[np.where(self.imageCorrected > 255)] = 255 self.imageCorrected = self.imageCorrected.astype(np.uint8) self.updateFigure(self.imageCorrected) def savePipelineSettings(self): ''' save to pipeline setting file''' self.settingFileName = str(QtGui.QFileDialog.getSaveFileName(self, \ 'Save selection (default in ./_data)', self.timestreamRootPath)) if len(self.settingFileName) == 0: return self.settingPath = os.path.relpath(os.path.dirname(self.settingFileName), self.timestreamRootPath) self.settings = {} if self.ImageSize != None and self.CameraMatrix != None and self.DistCoefs != None: undistortDic = {'cameraMatrix': self.CameraMatrix.tolist(), \ 'distortCoefs': self.DistCoefs.tolist(), \ 'imageSize': list(self.ImageSize), 'rotationAngle': self.rotationAngle + self.smaleRotationAngle } else: undistortDic = {} self.settings['undistort'] = undistortDic if len(self.colorcardList) > 0: medianSize = cd.getMedianRectSize(self.colorcardList) capturedColorcards = cd.rectifyRectImages(self.image, self.colorcardList, medianSize) colorCardFile = 'CapturedColorcard.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, colorCardFile), capturedColorcards[0][:,:,::-1].astype(np.uint8)) colorcardColors, colorStd = cd.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) colorcardPosition, Width, Height, Angle = cd.getRectangleParamters(self.colorcardList[0]) colorcardDic = {'colorcardFile': colorCardFile,\ 'colorcardPosition': colorcardPosition.tolist(),\ 'colorcardTrueColors': cd.CameraTrax_24ColorCard,\ 'settingPath': '_data' } else: colorcardDic = {} self.settings['colorcarddetect'] = colorcardDic self.settings['colorcorrect'] = {'minIntensity': 15} if len(self.trayList) > 0: trayMedianSize = cd.getMedianRectSize(self.trayList) trayImages = cd.rectifyRectImages(self.image, self.trayList, trayMedianSize) trayDict = {} trayDict['settingPath'] = '_data' trayDict['trayNumber'] = len(self.trayList) trayDict['trayFiles'] = 'Tray_%02d.png' trayPositions = [] for i,tray in enumerate(trayImages): cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, trayDict['trayFiles'] %i), tray[:,:,::-1].astype(np.uint8)) trayPosition, Width, Height, Angle = cd.getRectangleParamters(self.trayList[i]) trayPositions.append(trayPosition.tolist()) trayDict['trayPositions'] = trayPositions else: trayDict = {} self.settings['traydetect'] = trayDict if len(self.potList) > 0: trayMedianSize = cd.getMedianRectSize(self.trayList) potPosition, Width, Height, Angle = cd.getRectangleParamters(self.potList[0]) Width, Height = int(Width), int(Height) topLeft = [int(self.potList[0][0][0]), int(self.potList[0][0][1])] self.potImage = self.image[topLeft[1]:topLeft[1]+Height, topLeft[0]:topLeft[0]+Width, :] potFile = 'Pot.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, potFile), self.potImage[:,:,::-1].astype(np.uint8)) potDict = {} potDict['potPositions'] = potPosition.tolist() potDict['potSize'] = [int(Width), int(Height)] potDict['traySize'] = [int(trayMedianSize[0]), int(trayMedianSize[1])] potDict['potFile'] = potFile potDict['potTemplateFile'] = 'PotTemplate.png' potDict['settingPath'] = '_data' potTemplatePathIn = os.path.join(self.scriptPath, './data/PotTemplate.png') potTemplatePathOut = os.path.join(self.timestreamRootPath, self.settingPath, potDict['potTemplateFile']) shutil.copyfile(potTemplatePathIn, potTemplatePathOut) if self.potTemplate != None: potTemplateFile = 'potTemplate.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, potTemplateFile), self.potTemplate[:,:,::-1]) potDict['potTemplateFile'] = potTemplateFile else: potDict = {} self.settings['potdetect'] = potDict self.settings['plantextract'] = {'meth': 'method1', 'methargs': {'threshold' : 0.6, 'kSize' : 5, 'blobMinSize' : 50} } with open(self.settingFileName, 'w') as outfile: outfile.write( yaml.dump(self.settings, default_flow_style=None) ) self.status.append('Saved initial data to ' + self.settingFileName) def testPipeline(self): ''' try running processing pipeline based on user inputs''' if self.tsImages != None: # load setting file if missing if self.settingFileName == None: settingFileName = str(QtGui.QFileDialog.getOpenFileName(self, 'Open pipeline setting file', self.ts.path)) if len(settingFileName) > 0: self.settingFileName = settingFileName else: return # initialise pipeline if self.pl == None: f = file(self.settingFileName) self.settings = yaml.load(f) self.ts.data["settings"] = self.settings self.pl = pipeline.ImagePipeline(self.settings) # process only from undistortion to pot detection self.pl.pipeline = self.pl.pipeline[:5] # read next image instant of pipeline try: tsImage = self.tsImages.next() if tsImage == None: self.status.append('Missing image.') return except: tsImage = None self.status.append('There is no more images.') return self.status.append('Processing ' + tsImage.path) context = {"rts":self.ts, "wts":None, "img":tsImage} result = self.pl.process(context, [tsImage]) self.image, potPosList2 = result potSize = self.settings[4][1]["potSize"] self.potList = [] for potPosList in potPosList2: if potPosList == None: continue for potPos in potPosList: tl = [potPos[0] - potSize[0]//2, potPos[1] - potSize[1]//2] bl = [potPos[0] - potSize[0]//2, potPos[1] + potSize[1]//2] br = [potPos[0] + potSize[0]//2, potPos[1] + potSize[1]//2] tr = [potPos[0] + potSize[0]//2, potPos[1] - potSize[1]//2] self.potList.append([tl, bl, br, tr]) self.updateFigure() self.status.append('Done') else: self.status.append('Pipeline or setting file is missing.') def rotateImage90Degrees(self): if self.image == None: self.status.append('No image to rotate.') return self.rotationAngle = self.rotationAngle + 90 if self.rotationAngle >= 360: self.rotationAngle = self.rotationAngle - 360 self.image = np.rot90(self.image) #.astype(uint8) self.status.append('Rot. angle = %d deg' %self.rotationAngle) self.updateFigure(resetFigure = True) def rotateSmallAngle(self, value): self.smaleRotationAngle = float(value)/4.0 if self.image != None: self.rotatedImage = cd.rotateImage(self.image, self.smaleRotationAngle) self.updateFigure(self.rotatedImage) self.status.append('Rot. angle = %f deg' %(self.rotationAngle + self.smaleRotationAngle)) def applySmallRotation(self): if self.image != None: self.image = cd.rotateImage(self.image, self.smaleRotationAngle) self.updateFigure() self.status.append('Apply small angle rotation') def onMouseClicked(self, event): if self.panMode or self.zoomMode: return print('click', event.button, event.xdata, event.ydata) if event.button == 1 and event.xdata != None and event.ydata != None: self.leftClicks.append([event.xdata, event.ydata]) print('self.leftClicks =', self.leftClicks) Rect = [] AspectRatio = None if self.trayRadioButton.isChecked(): AspectRatio = self.trayAspectRatio elif self.colorcardRadioButton.isChecked(): AspectRatio = self.colorcardAspectRatio elif self.potRadioButton.isChecked(): AspectRatio = self.potAspectRatio if len(self.leftClicks) == 2 and AspectRatio != None: if self.colorcardRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio) if self.trayRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = self.trayRoundCheckBox.isChecked()) elif self.potRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = True) self.leftClicks = [] elif len(self.leftClicks) == 4: Rect = [[x,y] for x,y in self.leftClicks] Rect = cd.correctPointOrder(Rect) self.leftClicks = [] if len(Rect) > 0: if self.trayRadioButton.isChecked(): self.trayList.append(Rect) self.status.append('Added tray selection.') elif self.colorcardRadioButton.isChecked(): self.colorcardList.append(Rect) self.status.append('Added color card selection.') else: self.potList.append(Rect) self.status.append('Added pot selection.') self.updateFigure() elif event.button == 3: # remove the last selection if len(self.leftClicks) > 0: self.leftClicks = self.leftClicks[:-1] self.status.append('Removed a previous click') else: if self.trayRadioButton.isChecked() and len(self.trayList) > 0: self.trayList = self.trayList[:-1] self.status.append('Removed a previous tray selection') elif self.colorcardRadioButton.isChecked() and len(self.colorcardList) > 0: self.colorcardList = self.colorcardList[:-1] self.status.append('Removed a previous color card selection.') elif self.potRadioButton.isChecked() and len(self.potList) > 0: self.potList = self.potList[:-1] self.status.append('Removed a previous pot selection') self.updateFigure() else: print('Ignored click') def onMouseMoves(self, event): if event.inaxes == self.ax: self.mousePosition.setText('x=%d, y=%d' %(event.xdata, event.ydata)) # self.crosshair = [event.xdata, event.ydata] else: self.mousePosition.setText('') # self.crosshair = None # self.updateFigure() def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): quit_msg = "Are you sure you want to exit the program?" reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: self.saveInputs() event.accept() else: event.ignore() def saveInputs(self): with open('./.inputs.yml', 'w') as myfile: dicInputs = {'rootPath': str(self.timestreamText.text()), 'startDate': str(self.timestreamDateText.text()), 'timeInterval': str(self.timestreamTimeText.text()), } myfile.write( yaml.dump(dicInputs, default_flow_style=None) ) def loadPreviousInputs(self): try: with open('./.inputs.yml', 'r') as myfile: dicInputs = yaml.load(myfile) self.timestreamText.setText(dicInputs['rootPath']) self.timestreamDateText.setText(dicInputs['startDate']) self.timestreamTimeText.setText(dicInputs['timeInterval']) except: pass
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.colorcardRadioButton = QtGui.QRadioButton('Select color car&d') self.colorcardRadioButton.setChecked(False) self.colorcardRadioButton.clicked.connect(self.selectWhat) self.trayRadioButton = QtGui.QRadioButton('Select &tray') self.trayRadioButton.setChecked(False) self.trayRadioButton.clicked.connect(self.selectWhat) self.potRadioButton = QtGui.QRadioButton('Select &pot') self.potRadioButton.setChecked(False) self.potRadioButton.clicked.connect(self.selectWhat) self.loadImageButton = QtGui.QPushButton('&Load image') self.loadImageButton.clicked.connect(self.loadImage) self.rotateImageButton = QtGui.QPushButton('&Rotate 90-deg') self.rotateImageButton.clicked.connect(self.rotateImage90Degrees) self.loadCamCalibButton = QtGui.QPushButton('Load &cam. param.') self.loadCamCalibButton.clicked.connect(self.loadCamCalib) self.saveGeometriesButton = QtGui.QPushButton('&Save selected geometries') self.saveGeometriesButton.clicked.connect(self.saveSelectedGeometries) self.saveTraysButton = QtGui.QPushButton('&Save selected tray images') self.saveTraysButton.clicked.connect(self.saveSelectedTrayImages) self.saveColorcadButton = QtGui.QPushButton('&Save sel. col. card images') self.saveColorcadButton.clicked.connect(self.saveSelectedColorcardImages) self.save2PipelineButton = QtGui.QPushButton('&Save as pipeline settings') self.save2PipelineButton.clicked.connect(self.savePipelineSettings) self.zoomButton = QtGui.QPushButton('&Zoom') self.zoomButton.setCheckable(True) self.zoomButton.clicked.connect(self.zoom) self.panButton = QtGui.QPushButton('&Pan') self.panButton.setCheckable(True) self.panButton.clicked.connect(self.pan) self.homeButton = QtGui.QPushButton('&Home') self.homeButton.clicked.connect(self.home) self.status = QtGui.QTextEdit('') self.status.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.mousePosition = QtGui.QLabel('') # set the layout layout = QtGui.QHBoxLayout() rightWidget = QtGui.QWidget() buttonlayout = QtGui.QVBoxLayout(rightWidget) buttonlayout.addWidget(self.loadImageButton) buttonlayout.addWidget(self.rotateImageButton) buttonlayout.addWidget(self.loadCamCalibButton) buttonlayout.addWidget(self.colorcardRadioButton) buttonlayout.addWidget(self.trayRadioButton) buttonlayout.addWidget(self.potRadioButton) buttonlayout.addWidget(self.zoomButton) buttonlayout.addWidget(self.panButton) buttonlayout.addWidget(self.homeButton) buttonlayout.addWidget(self.saveGeometriesButton) buttonlayout.addWidget(self.saveColorcadButton) buttonlayout.addWidget(self.saveTraysButton) buttonlayout.addWidget(self.save2PipelineButton) buttonlayout.addWidget(self.status) buttonlayout.addWidget(self.mousePosition) rightWidget.setMaximumWidth(200) leftLayout = QtGui.QVBoxLayout() leftLayout.addWidget(self.toolbar) leftLayout.addWidget(self.canvas) layout.addWidget(rightWidget) layout.addLayout(leftLayout) self.setLayout(layout) self.group = QtGui.QButtonGroup() self.group.addButton(self.colorcardRadioButton) self.group.addButton(self.trayRadioButton) self.group.addButton(self.potRadioButton) self.panMode = False self.zoomMode = False self.ax = None self.plotRect = None self.plotImg = None self.image = None self.potTemplate = None self.UndistMapX = None self.UndistMapY = None self.trayAspectRatio = 0.835 self.colorcardAspectRatio = 1.5 self.potAspectRatio = 1.0 self.leftClicks = [] self.ImageSize = None self.CameraMatrix = None self.DistCoefs = None # # change cursor shape # self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) # Ouput parameters self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0 self.isDistortionCorrected = False def selectWhat(self): if self.trayRadioButton.isChecked(): self.status.append('Start selecting tray.') elif self.colorcardRadioButton.isChecked(): self.status.append('Start selecting color bar.') else: self.status.append('Start selecting pot.') def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() if not self.zoomMode: self.zoomMode = True self.panMode = False self.panButton.setChecked(False) else: self.zoomMode = False def pan(self): self.toolbar.pan() if not self.panMode: self.panMode = True self.zoomMode = False self.zoomButton.setChecked(False) else: self.panMode = False def loadImage(self): ''' load and show an image''' fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/mnt/phenocam/a_data/TimeStreams/BorevitzTest/BVZ0036/BVZ0036-GC02L~fullres-orig/2014/2014_06/2014_06_20/2014_06_20_12') self.status.append('Loading image...') app.processEvents() self.image = cv2.imread(str(fname))[:,:,::-1] self.status.append('Loaded image from ' + str(fname)) # reset all outputs self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0 self.isDistortionCorrected = False # Undistort image if mapping available if not self.isDistortionCorrected and self.UndistMapX != None and self.UndistMapY != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True if self.image != None: if self.ax == None: self.ax = self.figure.add_subplot(111) self.ax.figure.canvas.mpl_connect('button_press_event', self.onMouseClicked) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onMouseMoves) self.ax.figure.canvas.mpl_connect('figure_enter_event', self.changeCursor) self.ax.hold(False) if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.figure.tight_layout() self.canvas.draw() def changeCursor(self, event): # cursor = Cursor(self.ax, useblit=True, color='red', linewidth=1) self.canvas.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) def updateFigure(self): xs, ys = [], [] for Rect in self.colorcardList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.trayList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.potList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for x,y in self.leftClicks: xs = xs + [x] ys = ys + [y] # if self.crosshair != None: # xs = xs + [np.nan, 0, self.image.shape[1], np.nan, self.crosshair[0], self.crosshair[0], np.nan] # ys = ys + [np.nan, self.crosshair[1], self.crosshair[1], np.nan, 0, self.image.shape[0], np.nan] if len(xs) > 0 and len(ys) > 0: if self.plotRect == None: self.ax.hold(True) self.plotRect, = self.ax.plot(xs, ys, 'b') self.ax.hold(False) self.ax.set_xlim([0,self.image.shape[1]]) self.ax.set_ylim([0,self.image.shape[0]]) self.ax.invert_yaxis() else: self.plotRect.set_data(xs, ys) self.canvas.draw() app.processEvents() def loadCamCalib(self): ''' load camera calibration image and show an image''' CalibFile = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') self.ImageSize, SquareSize, self.CameraMatrix, self.DistCoefs, RVecs, TVecs = utils.readCalibration(CalibFile) self.status.append('Loaded camera parameters from ' + CalibFile) print('CameraMatrix =', self.CameraMatrix) print('DistCoefs =', self.DistCoefs) self.UndistMapX, self.UndistMapY = cv2.initUndistortRectifyMap(self.CameraMatrix, self.DistCoefs, \ None, self.CameraMatrix, self.ImageSize, cv2.CV_32FC1) if self.image != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.status.append('Corrected image distortion.') if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.canvas.draw() # def loadPotTemplate(self): # ''' load pot template image''' # fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') # self.status.append('Loading image...') # app.processEvents() # self.potTemplate = cv2.imread(str(fname))[:,:,::-1] # if len(self.potList) > 0: def saveSelectedGeometries(self): ''' save selected geometries''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected geometries', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') colorcardList2 = [] for colorcard in self.colorcardList: colorcardList2 = colorcardList2 + colorcard trayList2 = [] for tray in self.trayList: trayList2 = trayList2 + tray potList2 = [] for pot in self.potList: potList2 = potList2 + pot dicdata = {'colorcardself.crosshair = NoneList':np.asarray(colorcardList2), \ 'trayList':np.asarray(trayList2), \ 'potList':np.asarray(potList2), \ 'rotationAngle':self.rotationAngle, \ 'distortionCorrected':int(self.isDistortionCorrected)} cv2yml.dic2yml(fname, dicdata) self.status.append('Saved selected geometries to ' + fname) def saveSelectedTrayImages(self): ''' save selected trays''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected tray images', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') medianWidth, medianHeight = utils.getMedianRectSize(self.trayList) rectifiedTrayImages = utils.rectifyRectImages(self.image, self.trayList, MedianSize = [medianWidth, medianHeight]) for i,rectifiedImage in enumerate(rectifiedTrayImages): cv2.imwrite(str(fname) %i, rectifiedImage) def saveSelectedColorcardImages(self): ''' save selected trays''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected color card images', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') medianWidth, medianHeight = utils.getMedianRectSize(self.colorcardList) rectifiedColorcardImages = utils.rectifyRectImages(self.image, self.colorcardList, MedianSize = [medianWidth, medianHeight]) for i,rectifiedImage in enumerate(rectifiedColorcardImages): cv2.imwrite(str(fname) %i, rectifiedImage) def savePipelineSettings(self): ''' save to pipeline setting file''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selection to pipeline settings', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') settingPath = os.path.dirname(str(fname)) settings = [] if self.ImageSize != None and self.CameraMatrix != None and self.DistCoefs != None: undistort = ['undistort', \ {'mess': 'perform optical undistortion', \ 'cameraMatrix': self.CameraMatrix.tolist(), \ 'distortCoefs': self.DistCoefs.tolist(), \ 'imageSize': list(self.ImageSize), 'rotationAngle': self.rotationAngle } \ ] else: undistort = ['undistort', {'mess': '---skip optical undistortion---'}] settings.append(undistort) if len(self.colorcardList) > 0: medianSize = utils.getMedianRectSize(self.colorcardList) capturedColorcards = utils.rectifyRectImages(self.image, self.colorcardList, medianSize) colorCardFile = 'CapturedColorcard.png' cv2.imwrite(os.path.join(settingPath, colorCardFile), capturedColorcards[0][:,:,::-1].astype(np.uint8)) colorcardColors, colorStd = utils.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) colorcardPosition, Width, Height, Angle = utils.getRectangleParamters(self.colorcardList[0]) colorcarddetect = ['colorcarddetect', \ {'mess': '---perform color card detection---', \ 'colorcardFile': colorCardFile,\ 'colorcardPosition': colorcardPosition.tolist(),\ 'colorcardTrueColors': utils.CameraTrax_24ColorCard } ] else: colorcarddetect = ['colorcarddetect', {'mess': '---skip color card detection---'}] settings.append(colorcarddetect) colorcorrect = ['colorcorrect', {'mess': '---perform color correction---'}] settings.append(colorcorrect) if len(self.trayList) > 0: trayMedianSize = utils.getMedianRectSize(self.trayList) trayImages = utils.rectifyRectImages(self.image, self.trayList, trayMedianSize) colorcardColors, colorStd = utils.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) trayDict = {'mess': '---perform tray detection---'} trayDict['trayNumber'] = len(self.trayList) trayDict['trayFiles'] = 'Tray_%02d.png' trayPositions = [] for i,tray in enumerate(trayImages): cv2.imwrite(os.path.join(settingPath, trayDict['trayFiles'] %i), tray[:,:,::-1].astype(np.uint8)) trayPosition, Width, Height, Angle = utils.getRectangleParamters(self.trayList[i]) trayPositions.append(trayPosition.tolist()) trayDict['trayPositions'] = trayPositions traydetect = ['traydetect', trayDict] else: traydetect = ['traydetect', {'mess': '---skip tray detection---'}] settings.append(traydetect) if len(self.potList) > 0: trayMedianSize = utils.getMedianRectSize(self.trayList) potPosition, Width, Height, Angle = utils.getRectangleParamters(self.potList[0]) Width, Height = int(Width), int(Height) topLeft = [int(self.potList[0][0][0]), int(self.potList[0][0][1])] self.potImage = self.image[topLeft[1]:topLeft[1]+Height, topLeft[0]:topLeft[0]+Width, :] potFile = 'Pot.png' cv2.imwrite(os.path.join(settingPath, potFile), self.potImage[:,:,::-1].astype(np.uint8)) potDict = {'mess': '---perform pot detection---'} potDict['potPosition'] = potPosition.tolist() potDict['potSize'] = [int(Width), int(Height)] potDict['traySize'] = [int(trayMedianSize[0]), int(trayMedianSize[1])] potDict['potFile'] = potFile if self.potTemplate != None: potTemplateFile = 'potTemplate.png' cv2.imwrite(os.path.join(settingPath, potTemplateFile), self.potTemplate[:,:,::-1]) potDict['potTemplateFile'] = potTemplateFile potdetect = ['potdetect', potDict] else: potdetect = ['potdetect', {'mess': '---skip pot detection---'}] settings.append(potdetect) plantextract = ['plantextract', {'mess': '---perfrom plant biometrics extraction---'}] settings.append(plantextract) with open(fname, 'w') as outfile: outfile.write( yaml.dump(settings, default_flow_style=None) ) def rotateImage90Degrees(self): if self.image == None: self.status.append('No image to rotate.') return self.rotationAngle = self.rotationAngle + 90 if self.rotationAngle >= 360: self.rotationAngle = self.rotationAngle - 360 self.image = np.rot90(self.image) #.astype(uint8) self.status.append('Rot. angle = %d deg' %self.rotationAngle) if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.canvas.draw() def onMouseClicked(self, event): if self.panMode or self.zoomMode: return print('click', event.button, event.xdata, event.ydata) if event.button == 1 and event.xdata != None and event.ydata != None: self.leftClicks.append([event.xdata, event.ydata]) print('self.leftClicks =', self.leftClicks) Rect = [] AspectRatio = None if self.trayRadioButton.isChecked(): AspectRatio = self.trayAspectRatio elif self.colorcardRadioButton.isChecked(): AspectRatio = self.colorcardAspectRatio elif self.potRadioButton.isChecked(): AspectRatio = self.potAspectRatio if len(self.leftClicks) == 2 and AspectRatio != None: if self.potRadioButton.isChecked(): Rect = utils.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = True) else: Rect = utils.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio) self.leftClicks = [] elif len(self.leftClicks) == 4: Rect = [[x,y] for x,y in self.leftClicks] Rect = utils.correctPointOrder(Rect) self.leftClicks = [] if len(Rect) > 0: if self.trayRadioButton.isChecked(): self.trayList.append(Rect) self.status.append('Added tray selection.') elif self.colorcardRadioButton.isChecked(): self.colorcardList.append(Rect) self.status.append('Added color card selection.') else: self.potList.append(Rect) self.status.append('Added pot selection.') self.updateFigure() elif event.button == 3: # remove the last selection if len(self.leftClicks) > 0: self.leftClicks = self.leftClicks[:-1] self.status.append('Removed a previous click') else: if self.trayRadioButton.isChecked() and len(self.trayList) > 0: self.trayList = self.trayList[:-1] self.status.append('Removed a previous tray selection') elif self.colorcardRadioButton.isChecked() and len(self.colorcardList) > 0: self.colorcardList = self.colorcardList[:-1] self.status.append('Removed a previous color card selection.') elif self.potRadioButton.isChecked() and len(self.potList) > 0: self.potList = self.potList[:-1] self.status.append('Removed a previous pot selection') self.updateFigure() else: print('Ignored click') def onMouseMoves(self, event): if event.inaxes == self.ax: self.mousePosition.setText('x=%d, y=%d' %(event.xdata, event.ydata)) # self.crosshair = [event.xdata, event.ydata] else: self.mousePosition.setText('') # self.crosshair = None # self.updateFigure() def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): quit_msg = "Are you sure you want to exit the program?" reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: event.accept() else: event.ignore()