class Gui(QtWidgets.QMainWindow): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) logger.warning('starting up') self.startRecTime = None ## Instantiate classes self.ui = Ui_TrackerUI() self.ui.setupUi(self) self._cap = None #What to display on screeeeeeen source = [0, 1, 2, 3 ] try: dirList = os.listdir(os.getcwd()) for fileName in dirList: if 'avi' in fileName: source.append(fileName) except Exception as e: logger.exception(str(e)) for s in source: self.ui.srcCombo.addItem(str(s)) self.ui.srcCombo.setCurrentText('0') self.showImage = False ## If True, video gets displayed (need _cap) ## Stuff you can change in the UI self.idealRes = [1280, 960] ## Video stuff self._timer = QtCore.QTimer( self ) self._timer.timeout.connect( self.play ) self._timer.start(27) self.update() ## Tracking parameters self._lastCheck = time.time() self._sampleFreq = 0.1 self.motorsOn = False self.runTracking = False self.ebb = None self._wormFinder = None cv2.namedWindow('gaussian') ## Register button actions self.ui.buttonRight.clicked.connect( partial( self.motors, 'right' ) ) self.ui.buttonLeft.clicked.connect( partial( self.motors, 'left' ) ) self.ui.buttonUp.clicked.connect( partial( self.motors, 'up' ) ) self.ui.buttonDown.clicked.connect( partial( self.motors, 'down' ) ) self.ui.buttonRefresh.clicked.connect( self.getNewRef ) self.ui.buttonRun.clicked.connect( self.run ) self.ui.buttonConnect.clicked.connect( self.connectMotors ) self.ui.buttonReset.clicked.connect (self.resetAll ) self.ui.buttonMotorized.clicked.connect( self.motorized ) self.ui.buttonRec.clicked.connect( self.record ) self.ui.srcCombo.activated['QString'].connect( self.setSource ) self.ui.scalingSlider.valueChanged[int].connect( self.setMultFactor ) self.ui.scalingSlider.setValue(10) #default to 10 steps self.ui.scaling.setText( 'Step scaling is %d' % self.ui.scalingSlider.value() ) self.multFactor = self.ui.scalingSlider.value() self.ui.studyName.returnPressed.connect( self.setFileName ) ## Change button colors for pretty self.ui.buttonMotorized.setText("Turn On") self.ui.buttonRec.setText("Start") self.ui.fps.setText("") self.ui.lcdNumber.display("") ## Read in file from calibration GUI self.readInCalibration() ## Disable buttons self.setAble( 'motors', False ) self.setAble( 'motorized', False ) self.setAble( 'source', False ) self.setAble( 'buttons', False ) self.setAble( 'recording', False ) def setAble( self, group, ability ): groups = { 'connectMotors' : [ self.ui.buttonConnect ], 'motors' : [ self.ui.scaling, self.ui.buttonUp, self.ui.buttonDown, self.ui.buttonLeft, self.ui.buttonRight ], 'motorized' : [ self.ui.buttonMotorized, self.ui.motorsDesc ], 'study' : [ self.ui.studyDesc, self.ui.studyName ], 'source': [ self.ui.srcDesc, self.ui.srcCombo ], 'buttons': [ self.ui.buttonRun, self.ui.buttonConnect, self.ui.buttonRefresh ], 'recording' : [ self.ui.recordingDesc, self.ui.buttonRec ], 'reset' : [ self.ui.scaling, self.ui.buttonUp, self.ui.buttonDown, self.ui.buttonLeft, self.ui.buttonRight, self.ui.buttonMotorized, self.ui.motorsDesc, self.ui.studyDesc, self.ui.studyName, self.ui.buttonRun, self.ui.buttonConnect, self.ui.buttonRefresh, self.ui.recordingDesc, self.ui.buttonRec ] } for c in groups[group]: c.setEnabled(ability) def setFileName ( self ) : self.shareFileName = '%s/%s-%s' % ('output', self.ui.studyName.text(), time.strftime( "%a_%d_%b_%Y-%H%M%S" ) ) self.setLogging('debug') self.setAble( 'study', False ) self.setAble( 'buttons', True) self.ui.buttonRefresh.setEnabled(False) def getNewRef( self ): if self._wormFinder: self._wormFinder.resetRef() def record( self ): if self._cap.isWritingVideo: self._cap.stopWritingVideo() self.ui.buttonRec.setStyleSheet('QPushButton {color:green}') self.ui.buttonRec.setText("Start") self.startRecTime = None else: self.startRecTime = time.time() self.shareFileName = '%s/%s-%s' % ('output', self.ui.studyName.text(), time.strftime( "%a_%d_%b_%Y-%H%M%S" ) ) logger.debug('New sharefilename') platform = sys.platform.lower() if platform in ['win32', 'win64']: fourcc = cv2.VideoWriter_fourcc(*'IYUV') logger.warning( 'fourcc is IYUV') else: fourcc = cv2.cv.CV_FOURCC(*'MJPG')#cv2.VideoWriter_fourcc(*'MJPG') logger.warning( 'fourcc is MJPG') if not self._cap.isWritingVideo: self._cap.startWritingVideo('%s.avi' % self.shareFileName, fourcc) self.ui.buttonRec.setStyleSheet('QPushButton {color:red}') self.ui.buttonRec.setText("Stop") def motorized( self ): if self.motorsOn: self.motorsOn = False logger.info('motors off') self.ui.buttonMotorized.setStyleSheet('QPushButton {color:green}') self.ui.buttonMotorized.setText("Turn On") self.setAble('motors', True) else: self.motorsOn = True self._wormFinder.launch = 0 logger.info('motors on') self.ui.buttonMotorized.setStyleSheet('QPushButton {color:red}') self.ui.buttonMotorized.setText("Turn Off") self.setAble('motors', False) def run ( self ): logger.info("Start worm finder") if self._wormFinder: self._wormFinder = None if not self._cap: self.setSource(self.ui.sourceCombo.currentText()) self.centerPt = utils.Point(self.actualRes[0] / 2, self.actualRes[1] / 2) self.cropSize = 150 self.finderArgs = { 'gsize' : 45, 'gsig' : 9, 'window' : 3, 'method' : 'lazyc', 'MAXONEFRAME': 500, 'REFPING' : 1000, 'MAXREF': 1000, 'cropSize': self.cropSize, 'centerPt': self.centerPt, 'servos': self.ebb, 'actualRes': self.actualRes, 'motorsOn': self.motorsOn } self._wormFinder = WormFinder( **self.finderArgs ) self.runTracking = True self.startTrackTime = time.time() self.showImage = True self.ui.buttonRun.setEnabled(False) self.ui.buttonRefresh.setEnabled(True) if self.ebb: self.setAble('motorized', True ) self.setAble('recording', True ) def connectMotors( self ): logger.info("Connect Motors") if self._cap: try: logger.debug('width mm %d' % self.widthMM) self.ebb = EasyEBB(resolution = self.actualRes, sizeMM = self.widthMM) self.setAble('motors', True) self.setAble('connectMotors', False) self._cap.resetFPSestimate() if self._wormFinder: self._wormFinder.servos = self.ebb self.setAble('motorized', True) except serial.SerialException as e: logger.exception(str(e)) QtWidgets.QMessageBox.information( self, "Motors Issue", "Unable to connect to motors. Please connect or reboot motors. If problem persists, reboot computer") def setSource ( self, value ): self.existingVid = False if type(value) != int: nums = re.compile(r'\d*') mat = re.match(nums,value).group(0) if re.match(nums, value).group(0) is not u'': src = int(value) else: src = str(value) self.existingVid = True else: #read in from calibration src = value self.ui.sourceCombo.setCurrentText(str(src)) if self._cap: if self._cap._capture.isOpened(): #ugly access to VideoCapture object from managers self._cap._capture.release() self._cap = CaptureManager( cv2.VideoCapture(src) ) self.showImage = True self.actualRes = self._cap.getResolution() if self.actualRes != self.calibrationRes and not self.existingVid: self._cap.setProp( 'height', self.calibrationRes[1] ) self._cap.setProp( 'width', self.calibrationRes[0] ) self.showImage = True self.actualRes = self._cap.getResolution() logger.warning("Actual resolution from cam is %s" % str( self.actualRes ) ) self.setAble('source', False) self.setAble('buttons', True) self.ui.buttonRefresh.setEnabled(False) def setLogging( self, value ): addFile = True formatter = logging.Formatter( '%(asctime)s\t%(levelname)s\t%(name)s\t\t%(message)s' ) file = logging.FileHandler( '%s.log' % self.shareFileName ) logger.warning('New file') file.setLevel( LOGGING_LEVELS['debug'] ) file.setFormatter( formatter ) console = logging.StreamHandler() console.setLevel( LOGGING_LEVELS['debug'] ) console.setFormatter( formatter ) for h in logger.handlers: if type(h) == logging.StreamHandler: logger.removeHandler( h ) elif type(h) == logging.FileHandler: #if file has started, leave it be!!! addFile = False if addFile: logger.addHandler( file ) logger.addHandler( console ) self.newFileFLAG = False def setMultFactor ( self, value ): self.multFactor = value self.ui.scaling.setText( 'Step scaling is %d' % value) def readInCalibration( self ): c = os.path.dirname(os.getcwd()) cc = os.path.dirname(c) f = open( ("%s/config.txt" % cc) , "r") line = f.readline() f.close() logger.warning('line: %s' % str(line) ) w, h, widthMM, source = line.split('|') self.widthMM = float(widthMM) self.calibrationRes = [int(w), int(h)] if source is not None: self.setSource( source ) def motors( self, direction): if self.ebb: xdir = 1 ydir = 1 #up is down t = 100 dir ={ 'left': (t, xdir * self.multFactor * (-1), 0 ) , 'right': ( t, xdir * self.multFactor * (1), 0 ), 'up': (t, 0, ydir * self.multFactor * (1) ), 'down': (t, 0, ydir * self.multFactor * (-1) ) } #print dir[direction] th = threading.Thread(target = self.ebb.move , args = dir[direction] ) try: th.start() except Exception as e: logger.exception( str(e) ) def resetAll ( self ): if self.ebb: self.ebb.closeSerial() if self._wormFinder: self._wormFinder = None self.runTracking = False cv2.destroyWindow('gaussian') if self._cap.isWritingVideo: self.record() self.ui.buttonRec.setStyleSheet('QPushButton {}') # self._cap.stopWritingVideo() if self._cap._capture.isOpened(): self._cap._capture.release() self.showImage = False self.runTracking = False if self.motorsOn: self.motorized() self.motorsOn = False self.ui.buttonMotorized.setStyleSheet('QPushButton {}') self.ui.videoFrame.setText("Select source if video not displayed here on boot up") self.ui.fps.setText("") logger.info("Reset button pressed") self.setAble('source', True) self.setAble('reset', False) def closeEvent ( self, event): logger.debug("closing") if self.ebb: self.ebb.closeSerial() if self._cap.isWritingVideo: self._cap.stopWritingVideo() for h in logger.handlers: if type(h) == logging.FileHandler: h.close() try: cv2.destroyWindow('gaussian') except Exception as e: pass def isColor( self, imgIn ): s = np.shape(imgIn) if s == 3: try: ncolor = np.shape(imgIn)[2] boolt = int(ncolor) > 2 return boolt except IndexError: if self.existingVid: logger.warning('Video has ended') self.existingVid = False self.resetAll() else: logger.warning('Issue with video input') self.resetAll() else: return False def play( self ): if self.showImage: ## Get image from camera self._cap.enterFrame() self.currentFrame = self._cap.getFrame() self.color = self.isColor(self.currentFrame) t1 = time.time() if self.color: try: self.currentFrame = cv2.cvtColor(self.currentFrame, cv2.COLOR_BGR2GRAY) except TypeError: logger.exception("No Frame") finally: self._cap.exitFrame() else: self._cap.exitFrame() if not self.runTracking: #no finder if self.showImage: #yes capture self.ui.videoFrame.setPixmap(self._cap.convertFrame(self.currentFrame)) self.ui.videoFrame.setScaledContents(True) else: # yes finder ## Stop if too dark!!! if time.time() - self.startTrackTime < 5: self.firstAvgPixIntensity = np.mean(self.currentFrame) logger.warning('first avg int: %d' % self.firstAvgPixIntensity) ## Tracking procedure if time.time() - self._lastCheck >= self._sampleFreq: gaussian = self._wormFinder.processFrame( self.currentFrame ) if gaussian is not None: cv2.imshow( 'gaussian', gaussian ) if self.motorsOn: #yes motorized ## Stop motors if too dark self.currentAvgPixIntensity = np.mean(self.currentFrame) logger.warning('current avg int: %d' % self.currentAvgPixIntensity) if self.currentAvgPixIntensity < self.firstAvgPixIntensity - 50: logger.warning('Darkening of picture: motors turned off') if self.motorsOn: self.motorized() if self._cap.isWritingVideo: self.record() else: self._wormFinder.decideMove() self._lastCheck = time.time() self._wormFinder.drawDebugCropped( self.currentFrame) self.ui.videoFrame.setPixmap(self._cap.convertFrame(self.currentFrame)) self.ui.videoFrame.setScaledContents(True) if self._cap._fpsEstimate: self.ui.fps.setText( 'FPS: %0.2f' % ( self._cap._fpsEstimate )) if self.startRecTime: elapsedSec = time.time() - self.startRecTime elapsed = time.strftime("%H.%M.%S", time.gmtime(elapsedSec) ) self.ui.lcdNumber.setNumDigits(8) self.ui.lcdNumber.display( elapsed ) else: self.ui.lcdNumber.display("") return '''
class Gui(QtWidgets.QMainWindow): ## Signals #closeGui = QtCore.pyqtSignal() def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) ## Instantiate classes self.ui = Ui_CalibrationUI() self.ui.setupUi(self) self._cap = None self.ebb = None ## Stuff you can change in the UI self.width = None self.idealRes = [1280, 960] self.colSteps = 0 self.rowSteps = 0 self.multFactor = 1 self.motorsAble = False self.showImage = False ## Stuff that doesn't change #self._cap = CaptureManager( cv2.VideoCapture(0) ) ## Video stuff self._timer = QtCore.QTimer( self ) self._timer.timeout.connect( self.play ) self._timer.start(27) self.update() source = [0, 1, 2,3, 'led_move1.avi', 'screencast.avi', 'screencast 1.avi', 'shortNoBox.avi', 'longNoBox.avi', 'H299.avi', 'testRec.avi', 'longDemo.avi'] for s in source: self.ui.sourceCombo.addItem(str(s)) ## Register button actions self.ui.buttonSet.clicked.connect( self.set ) self.ui.buttonCenter.clicked.connect( self.center ) self.ui.buttonReset.clicked.connect( self.reset ) self.ui.buttonSave.clicked.connect( self.save ) self.ui.buttonRight.clicked.connect( partial( self.motors, 'right' ) ) self.ui.buttonLeft.clicked.connect( partial( self.motors, 'left' ) ) self.ui.buttonUp.clicked.connect( partial( self.motors, 'up' ) ) self.ui.buttonDown.clicked.connect( partial( self.motors, 'down' ) ) self.ui.scalingSlider.valueChanged[int].connect( self.setMultFactor ) self.ui.scalingSlider.setValue(10) self.ui.scaling.setText( 'Motor scaling is %d' % self.ui.scalingSlider.value() ) self.ui.sourceCombo.activated[int].connect( self.setSource ) self.ui.comboBox.activated.connect ( self.resolutionSelect ) self.setAble('settings', False) self.setAble('motors', False) self.setAble('center', False) self.setAble('reset', False) self.setAble('save', False) def setSource ( self, value ): if self._cap: if self._cap._capture.isOpened(): #ugly access to VideoCapture object from managers self._cap._capture.release() self._cap = CaptureManager( cv2.VideoCapture(int(value)) ) #self.indWindow = cv2.namedWindow("Camera Display") self.showImage = True self.actualRes = self._cap.getResolution() # Set to default resolution from camera (640x480) #res = "%d x %d" % (int(self.actualRes[0]), int(self.actualRes[1]) ) #index = self.ui.comboBox.findText(res) #Sets picker to default resolution #self.ui.comboBox.setCurrentIndex(index) # Set to Hoky desired default res (1280x960) res = "%d x %d" % (int(self.idealRes[0]), int(self.idealRes[1]) ) index = self.ui.comboBox.findText(res) #Sets picker to default resolution self.ui.comboBox.setCurrentIndex(index) self.resolutionSelect() self.p = Point(200,300) self.c = Point(self.actualRes[0] // 2, self.actualRes[1] // 2) self.setAble('settings', True) def resolutionSelect ( self ): # Get desired resolution from the user: self.idealRes = self.ui.comboBox.currentText().split('x') self.idealRes = map(lambda x: int(x), self.idealRes) logger.debug("User input res: %d %d" % (self.idealRes[0], self.idealRes[1]) ) # Attempt to change the resolution: self._cap.setProp('width', self.idealRes[0]) self._cap.setProp('height', self.idealRes[1]) self.actualRes = self._cap.getResolution() # Something went wrong with resolution assignment -- possible need for shut down if resolution can't even be queried self.c = Point(self.actualRes[0] // 2, self.actualRes[1] // 2) if not ( self.actualRes == self.idealRes ): QtWidgets.QMessageBox.information( self, "Resolution", "That resolution isn't supported by the camera. Instead, your actual resolution is: %d x %d" % (self.actualRes[0], self.actualRes[1] ) ) res = "%d x %d" % (int(self.actualRes[0]), int(self.actualRes[1]) ) index = self.ui.comboBox.findText(res) self.ui.comboBox.setCurrentIndex(index) def save( self ): c = os.path.dirname(os.getcwd()) cc = os.path.dirname(c) f = open( ("%s/config.txt" % cc) , "w") f.write('%d|%d|%s|%s\n' % ( self.actualRes[0], self.actualRes[1], self.ui.widthLine.text(), self.ui.sourceCombo.currentText() )) f.close() def setMultFactor ( self, value ): self.multFactor = value self.ui.scaling.setText( 'Step scaling is %d' % value) def setAble( self, group, ability ): groups = { 'motors' : [self.ui.buttonLeft, self.ui.buttonRight, self.ui.buttonUp, self.ui.buttonDown, self.ui.scalingSlider, self.ui.scaling], 'center' : [self.ui.buttonCenter], 'reset' : [self.ui.buttonReset], 'settings': [self.ui.resDesc, self.ui.framewDesc, self.ui.buttonSet, self.ui.widthLine, self.ui.comboBox], 'save': [self.ui.buttonSave] } for g in groups[group]: g.setEnabled(ability) def motors( self, direction): xdir = 1 ydir = 1 #comp up is down t = 300 dir ={ 'left': (t, xdir * self.multFactor * (-1), 0 ) , 'right': ( t, xdir * self.multFactor * (1), 0 ), 'up': (t, 0, ydir * self.multFactor * (1) ), 'down': (t, 0, ydir * self.multFactor * (-1) ) } #print dir[direction] th = threading.Thread(target = self.ebb.move , args = dir[direction] ) try: #partial(self.ebb.move, dir[direction]) th.start() #th.join() except Exception as e: logger.exception( str(e) ) def reset ( self ): self.ebb.move(300, -self.colSteps, -self.rowSteps) if self.ebb.connected: self.ebb.closeSerial() self.setAble('motors', False) self.setAble('settings', True) def center ( self ): #th = threading.Thread(target = self.ebb.move , args = (100,200,300) ) try: #partial(self.ebb.move, dir[direction]) self.colSteps, self.rowSteps = self.ebb.centerWorm(300,200,300) #th.join() except Exception as e: logger.exception( str(e) ) self.setAble('reset', True) self.setAble('save', True) def set( self ): if self.ui.widthLine.text(): try: float( self.ui.widthLine.text() ) except ValueError as e: QtWidgets.QMessageBox.information( self, "Invalid Width", "Cannot convert that width to a float! Make sure you enter a number (decimals accepted)") return if self.ui.widthLine.text() and self.ui.comboBox.currentText(): self.resolutionSelect() # Instantiate motors try: self.ebb = EasyEBB( resolution = self.actualRes, sizeMM = float(self.ui.widthLine.text() ) ) self.setAble('settings', False) self.setAble('motors', True) self.setAble('center', True) except serial.SerialException as e: logger.exception(e) QtWidgets.QMessageBox.information( self, "Motors Issue", "Please connect motors or restart them, having issues connecting now") else: QtWidgets.QMessageBox.information( self, "Validation", "Please enter a measurement for the width and double-check your resolution choice") def closeEvent ( self, event): logger.debug("closing") if self._cap._capture.isOpened(): self._cap._capture.release() #if self._cap: # cv2.destroyWindow("Camera Display") # cv2.destroyAllWindows() if self.ebb: self.ebb.closeSerial() def isColor( self, imgIn ): s = np.shape(imgIn) if np.size(s) == 3: try: ncolor = np.shape(imgIn)[2] boolt = int(ncolor) > 2 return boolt except IndexError: QtWidgets.QMessageBox.information( self, "Camera Issue", "Please Check Camera Source") logger.error("Something wrong with camera input") self.showImage = False else: return False def play( self ): if self.showImage: self._cap.enterFrame() self.currentFrame = self._cap.frame self.color = self.isColor(self.currentFrame) t1 = time.time() if self.color: try: self.currentFrame = cv2.cvtColor(self.currentFrame, cv2.COLOR_BGR2GRAY) if self.currentFrame is not None: self.currentFrame = self.p.draw(self.currentFrame, 'black-1') self.currentFrame = self.c.draw(self.currentFrame, 'black-1') self.ui.videoFrame.setPixmap(self._cap.convertFrame(self.currentFrame)) self.ui.videoFrame.setScaledContents(True) else: QtWidgets.QMessageBox.information( self, "Camera Issue", "Please Check Camera Source") logger.error("Something wrong with camera input") #cv2.imshow( "Camera Display",self.currentFrame) except TypeError: logger.exception("No Frame") QtWidgets.QMessageBox.information( self, "Camera Issue", "Please Check Camera Source") finally: self._cap.exitFrame() else: try: if self.currentFrame is not None: self.currentFrame = self.p.draw(self.currentFrame, 'black-1') self.currentFrame = self.c.draw(self.currentFrame, 'black-1') self.ui.videoFrame.setPixmap(self._cap.convertFrame(self.currentFrame)) self.ui.videoFrame.setScaledContents(True) else: QtWidgets.QMessageBox.information( self, "Camera Issue", "Please Check Camera Source") logger.error("Something wrong with camera input") logger.exception("No Frame") self.showImage = False #cv2.imshow( "Camera Display",self.currentFrame) except TypeError: logger.exception("No Frame") finally: self._cap.exitFrame() self._cap.exitFrame()