class DirectCVCamSource(BasePlugin): configParameter = [ ImageType('outputImageName', output=True), IntType('camId'), IntType('frameWidth'), IntType('frameHeight'), ] def __init__(self, **kwargs): super(DirectCVCamSource, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def preCyclicCall(self): self.initCam() def initCam(self): self.cam = cv2.VideoCapture(self.camId.value) if self.frameWidth > 0: self.cam.set(cv2.CAP_PROP_FRAME_WIDTH, self.frameWidth.value) if self.frameHeight > 0: self.cam.set(cv2.CAP_PROP_FRAME_HEIGHT, self.frameHeight.value) def timeBypassActions(self): self.cam.grab() def externalCall(self): self.cam.grab() i, image = self.cam.read() self.outputImageName.data = image.copy()
class CVDrawContours(BasePlugin): """ if inputContourIndexListName is empty, then draw all contours """ configParameter = [ NameType('inputImageName', input=True), NameType('outputImageName', output=True), NameType('inputContourName', input=True), IntType('thickness'), NameType('inputContourIndexListName', input=True), IntListType('contourColor'), ] def __init__(self, **kwargs): super(CVDrawContours, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def externalCall(self): if self.inputContourIndexListName.data: contidx = self.inputContourIndexListName.data else: contidx = range(len(self.inputContourName.data)) imagecpy = self.inputImageName.data.copy() for cidx in contidx: cv2.drawContours(imagecpy, self.inputContourName.data, cidx, color=self.contourColor, thickness=self.thickness.value) self.outputImageName.data = imagecpy
class Threshold(BasePlugin): configParameter = [ ImageType('inputImage', input=True), ImageType('outputImage', output=True), IntType('threshold'), IntType('max'), IntType('type'), ] def __init__(self, **kwargs): super(Threshold, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def externalCall(self): image = self.inputImage.data ret, image = cv2.threshold(image, self.threshold.value, self.max.value, self.type.value) self.outputImage.data = image
class Canny(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), NameType('outputImageName', output=True), IntType('threshold1', input=True), IntType('threshold2', input=True), ] def __init__(self, **kwargs): super(Canny, self).__init__(**kwargs) def externalCall(self): image = self.inputImageName.data image = cv2.GaussianBlur(image, (3, 3), 1) #image = cv2.Laplacian(image,cv2.CV_64F, delta=self.threshold1.value, scale=2) image = cv2.Canny(image, self.threshold1.value, self.threshold2.value, L2gradient=False) #, apertureSize=3) self.outputImageName.data = image
class DeltaTimePerFrame(BasePlugin): configParameter = [ BoolType('displayTime'), IntType('startFrame'), IntType('stopFrame'), ] def __init__(self, **kwargs): super(DeltaTimePerFrame, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def preCyclicCall(self): self.lastCallTime = time.time() self.timeList = list() self.frameCount = 1 def externalCall(self): curtime = time.time() difftime = curtime - self.lastCallTime self.lastCallTime = curtime if self.startFrame.value <= self.frameCount <= self.stopFrame.value: self.timeList.append(difftime) if self.displayTime.value: print 'Frame: <%d>' % self.frameCount, self.printTime(difftime) self.frameCount += 1 if self.frameCount == self.stopFrame: self.postCyclicCall() def postCyclicCall(self): midtime = float(sum(self.timeList)) / len(self.timeList) self.printTime(midtime) def printTime(self, time): print '%.2f' % (time * 1.e3), 'ms', 1 / time, 'Hz'
class CVGaussBlur(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), NameType('outputImageName', output=True), FloatType('sigmaX'), FloatType('sigmaY'), IntType('kSize', constraint=range(1,99,2)), ] def __init__(self, **kwargs): super(CVGaussBlur, self).__init__(**kwargs) def externalCall(self): image = self.inputImageName.data image = cv2.GaussianBlur(image, (self.kSize.value, self.kSize.value), sigmaX=self.sigmaX.value, sigmaY=self.sigmaY.value) self.outputImageName.data = image
class PyrDown(BasePlugin): configParameter = [ ImageType('inputImage', input=True), ImageType('outputImage', output=True), IntType('times'), ] def __init__(self, **kwargs): super(PyrDown, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def externalCall(self): image = self.inputImage.data for i in range(self.times.value): image = cv2.pyrDown(image) self.outputImage.data = image
class DirectKinectSource(BasePlugin): configParameter = [ IntType('camId'), ImageType('outputImageName', output=True), ImageType('outputDepthImageName', output=True), NameType('outputDepthRawName', output=True), BoolType('reverseDepthVisualisation'), ] def __init__(self, **kwargs): super(DirectKinectSource, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def externalCall(self): #try: self.log.debug('try to get image from cam') imageData, _ = freenect.sync_get_video(index=self.camId.value) depthDataRaw, _ = freenect.sync_get_depth() #except TypeError: # self.log.error('asd') imageData = np.array(imageData) imageData = cv2.cvtColor(imageData, cv2.COLOR_RGB2BGR) self.outputImageName.data = imageData.copy() depthDataImage = np.float32(depthDataRaw) #depthDataImage = (depthDataImage)/2047*256 #depthDataImage = np.uint8(depthDataImage) #depthDataImage = np.float32(depthDataImage) * 255 / 130 depthDataImage = np.uint8(depthDataImage) #depthDataImage = depthDataImage * 255 / 130 #depthDataImage = np.uint8(cv2.normalize(depthDataImage, depthDataImage, 0, 255, cv2.NORM_MINMAX)) if self.reverseDepthVisualisation.value: depthDataImage = 255 - depthDataImage self.outputDepthImageName.data = depthDataImage.copy() self.outputDepthRawName.data = depthDataRaw.copy()
class WaitKey(BasePlugin): configParameter = [ IntType('waitTime'), StringListType('keyList'), StringListType('functionList'), ] def __init__(self, **kwargs): super(WaitKey, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') self.cm = ContextManager() def preCyclicCall(self): self.pm = self.cm.processManager def timeBypassActions(self): self.checkKey() def externalCall(self): self.checkKey() def checkKey(self): key = (cv2.waitKey(self.waitTime.value) & 255) chkey = chr(key) if chkey in self.keyList: for k, v in enumerate(self.keyList.value): if chkey is v: fnc = getattr(self, self.functionList[k]) fnc() def stateHold(self): self.pm.changeState(self.pm.STATE_HOLD) print 'HOLD' def stateQuit(self): self.pm.changeState(self.pm.STATE_QUIT) print 'QUIT' def stateRun(self): self.pm.changeState(self.pm.STATE_RUN) print 'RUN'
class WeightChanels(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), ImageType('outputImageName', output=True), IntType('ofs'), ] def __init__(self, **kwargs): super(WeightChanels, self).__init__(**kwargs) def preCyclicCall(self): pass def externalCall(self): hlut = np.sin(np.linspace(0, np.pi, 31)) hblk = np.zeros(180 - hlut.size, np.float32) hlut = np.concatenate((hlut, hblk)) self.hlut = np.roll(hlut, self.ofs.value) flut = np.sin(np.linspace(0, np.pi * 0.5, 256)) * 255 fblk = np.zeros(256 - flut.size, np.float32) self.flut = np.concatenate((flut, fblk)) tflut = np.sin(np.linspace(0, np.pi * 0.8, 256)) * 255 tfblk = np.zeros(256 - tflut.size, np.float32) self.tflut = np.concatenate((tflut, tfblk)) image = self.inputImageName.data image = np.array(self.hlut[image[:, :, 0]] * \ (0.2 * self.tflut[image[:, :, 1]] + 0.8 * self.flut[image[:, :, 2]]), np.uint8) self.outputImageName.data = image
class CVDrawCicles(BasePlugin): """ if inputContourIndexListName is empty, then draw all contours """ configParameter = [ ImageType('inputImageName', input=True), StringType('circleData', input=True), ImageType('outputImageName', output=True), BoolType('binarizedOutput'), IntListType('color'), IntType('thickness'), ] def __init__(self, **kwargs): super(CVDrawCicles, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') def externalCall(self): if self.binarizedOutput.value: if len(self.inputImageName.data.shape) > 1: image = np.zeros(tuple(self.inputImageName.data.shape[:2]), np.uint8) else: image = np.zeros_like(self.inputImageName.data) else: image = self.inputImageName.data.copy() if self.circleData.data is not None: for circ in self.circleData.data[0]: cv2.circle(image, (circ[0], circ[1]), circ[2], self.color.value, self.thickness.value) self.outputImageName.data = image
class FilePickleSegmentOutput(BasePlugin): configParameter = [ NameType('inputImageName', input=True), NameType('inputContourName', input=True), NameType('inputContourIndexListName', input=True), StringType('outputFile'), BoolType('overwriteExistingFile'), BoolType('createFilePath'), IntType('cacheCycles'), BoolType('skipDump'), ] def __init__(self, **kwargs): super(FilePickleSegmentOutput, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') self.timelist = list() def preCyclicCall(self): self.log.debug('preCyclicCall called') self.pickleCycleCntr = 0 self.pickleCache = list() self.log.debug('open dataFile at <%s> in mode "write binary"', self.outputFile.value) self.dataFile = open(self.outputFile.value, 'wb') def externalCall(self): self.log.debug('externalCall called') self.appendOutputDataToCache() if self.cacheCycles.value is not -1 and self.pickleCycleCntr >= self.cacheCycles.value: self.writeCacheToFile() self.pickleCycleCntr = -1 self.pickleCycleCntr += 1 if len(self.timelist) > 0: print sum(self.timelist) / float(len(self.timelist)) def postCyclicCall(self): self.log.debug('postCyclicCall called') self.writeCacheToFile() self.dataFile.close() def appendOutputDataToCache(self): image = self.inputImageName.data cont = self.inputContourName.data if len(self.inputContourIndexListName.data) > 0: contidx = self.inputContourIndexListName.data else: contidx = range(len(cont)) #create #ToDo: Now there is a new Plugin called 'CreateContourBinaryImage'. Use it! shape = list(image.shape[0:2]) #shape = list(image.shape) shape.insert(0, len(contidx)) shape = tuple(shape) ccimage = np.zeros(shape, np.uint8) for k, v in enumerate(contidx): cv2.drawContours(ccimage[k], cont, v, (255, 255, 255), -1) singleImageDump = list() #each found segment in image for segmentid, segmentcnt in enumerate(ccimage): pixlist = np.nonzero(segmentcnt) singleImageDump.append([cont[contidx[segmentid]], pixlist]) print[cont[contidx[segmentid]], pixlist] #if len(singleImageDump) > 0: self.pickleCache.append(image) self.pickleCache.append(singleImageDump) def writeCacheToFile(self): self.log.debug('check if skipDump <%s>', self.skipDump.value) if self.skipDump.value: self.log.debug('writeCacheToFile method is skipped') return #ToDo: create directory if not exist and allowed cnt = 2 cntmax = len(self.pickleCache) objectDumpNames = ['raw-image', 'segments'] self.log.debug('dump %d frames to file <%s>', cntmax, self.outputFile.value) for data in self.pickleCache: stime = time.time() self.log.debug('Frame %d of %d (%s)', cnt / 2, cntmax / 2, objectDumpNames[cnt % 2]) pickle.dump(data, self.dataFile, -1) self.log.debug('Time to save file: %f3', (time.time() - stime) * 1000) cnt += 1 print self.pickleCache = list()
class MSER(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), ImageType('inputOrginalImageName', input=True), ImageType('outputImageName', output=True), ImageType('outputImageMask', output=True), ImageType('outputOrginalImageFilt', output=True), FloatType('maskScale'), IntType('minRadius'), IntType('maxRadius'), ] def __init__(self, **kwargs): super(MSER, self).__init__(**kwargs) def preCyclicCall(self): pass def externalCall(self): d_red = cv2.cv.RGB(200, 100, 100) l_red = cv2.cv.RGB(250, 200, 200) d_green = cv2.cv.RGB(100, 200, 100) l_green = cv2.cv.RGB(200, 250, 200) orig = self.inputOrginalImageName.data img = orig.copy() #img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img2 = self.inputImageName.data detector = cv2.FeatureDetector_create('MSER') fs = detector.detect(img2) #print dir(detector) fs.sort(key=lambda x: -x.size) def supress(x): for f in fs: distx = f.pt[0] - x.pt[0] disty = f.pt[1] - x.pt[1] dist = math.sqrt(distx*distx + disty*disty) #print f.size/1.5 if (f.size > x.size) and (dist < f.size/2) \ :#or (f.size > self.maxRadius.value) or (f.size < self.minRadius.value): #print dist, self.minRadius.value, self.maxRadius.value return True sfs = [x for x in fs if not supress(x)] mask = np.zeros_like(img2) for f in sfs: cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(2), d_red, 1) cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_green, 1) cv2.circle(mask, (int(f.pt[0]), int(f.pt[1])), int(f.size/1.5*self.maskScale.value), 255, -1) h, w = orig.shape[:2] #vis = np.zeros((h, w*2+5), np.uint8) #vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR) #vis[:h, :w] = orig #vis[:h, w+5:w*2+5] = img filt = np.zeros_like(orig) cv2.merge((mask, mask, mask), filt) filt = cv2.bitwise_and(orig, filt) self.outputImageMask.data = mask self.outputImageName.data = img self.outputOrginalImageFilt.data = filt
class SideCamCircleDetector(BasePlugin): configParameter = [ NameType('inputImageName', input=True), NameType('outputImageName', output=True), NameType('inputContourName', input=True), IntType('thickness'), NameType('inputContourIndexListName', input=True), BoolType('detected', output=True), ] def __init__(self, **kwargs): super(SideCamCircleDetector, self).__init__(**kwargs) def preCyclicCall(self): pass def externalCall(self): self.detected.data = False if self.inputContourIndexListName.data: contidx = self.inputContourIndexListName.data else: contidx = range(len(self.inputContourName.data)) image = self.inputImageName.data.copy() for cidx in contidx: cnt = self.inputContourName.data[cidx] mask = np.zeros(tuple(self.inputImageName.data.shape[:2]), np.uint8) cv2.drawContours(mask, self.inputContourName.data, -1, color=(250,250,50), thickness=-1) moments = cv2.moments(cnt) humoments = cv2.HuMoments(moments) try: centroid_x = moments['m10']/moments['m00'] centroid_y = moments['m01']/moments['m00'] except ZeroDivisionError: continue area = moments['m00'] equi_diameter = np.sqrt(4*area/np.pi) * 1.05 equi_radian = equi_diameter / 2.0 minhu = 1.59e-1 maxhu = 1.65e-1 # normal 1.64e-1 overhu = 1.70e-1 minarea = 2500 maxarea = 6000 quality = (humoments[0] - minhu) / (maxhu - minhu) color = (50, 250, 50) state = 'green' if humoments[0] > (maxhu) or humoments[0] < (minhu) or area < minarea or area > maxarea: color = (50, 50, 250) #continue state = 'red' self.detected.data = True if state == 'red': #continue pass #cv2.drawContours(image, self.inputContourName.data, -1, color=(250,250,50), thickness=1) #print '+++', state, gcorr, xm, 'sqrt ' + str(gcorr**2 - xm**2), '->', ym #self.scatter[int(ym*100)][int(xm*100)+100] += 0.14 #cv2.imshow('scatter', cv2.pyrUp(self.scatter)) #cv2.imwrite('data/scatterx.jpg', self.scatter) #self.drawText(image, '%.2f'%xm, int(xopt), int(centroid_y), scale=1, color=(225, 225, 225)) #self.drawText(image, '%.2f'%ym, int(centroid_x), image.shape[0]-10, scale=1, color=(225, 225, 225)) #cv2.line(image, (int(centroid_x), int(centroid_y)), (int(xopt), int(centroid_y)), (200,50,50), 1) #cv2.line(image, (int(centroid_x), int(centroid_y)), (int(centroid_x), image.shape[0]), (50,150,250), 1) #cv2.circle(image, (int(centroid_x), int(centroid_y)), int(equi_radian), (250, 250, 100), 1) #cv2.circle(image, (int(centroid_x), int(centroid_y)), 3, color=(255,50,50), thickness=-1) if True: #image[int(centroid_y-70-equi_radian):int(centroid_y-equi_radian-10), centroid_x-40:centroid_x+80] *= 0.45 #self.drawTextMarker(image, 'X: ' + str(round(centroid_x, 2)), centroid_x, centroid_y, equi_radian, 0, color) #self.drawTextMarker(image, 'Y: ' + str(round(centroid_y, 2)), centroid_x, centroid_y, equi_radian, 1, color) #self.drawTextMarker(image, 'Radian: ' + str(round(equi_radian, 2)), centroid_x, centroid_y, equi_radian, 1, color) self.drawTextMarker(image, 'HM0' + ': %.2e' % humoments[0], centroid_x, centroid_y, equi_radian, 2, color) self.drawTextMarker(image, 'Area' + ': %.2f' % area + 'm', centroid_x, centroid_y, equi_radian, 3, color) self.drawTextMarker(image, '' + ': %.2f' % (quality * 100) + '%', centroid_x, centroid_y, equi_radian, 4, color) cv2.imshow('xxx', image) crop = cv2.pyrUp(image) #crop = image[100:650, 550:1100] #crop = cv2.pyrUp(crop) cv2.imshow('crop', crop) def drawTextMarker(self, image, text, xpos, ypos, radian, line, color=(225, 225, 225)): xofs = -35 ystep = 15 yofs = int(radian) + ystep * 5 yofs *= -1 self.drawText(image, text, int(xpos) + xofs, int(ypos) + yofs + ystep * line, 0.8, color) def drawText(self, image, text, xpos, ypos, scale=1, color=(225, 225, 225)): for i in range(3, 0, -1): if i < 2: cv2.putText(image, text, (xpos+i, ypos+i), cv2.FONT_HERSHEY_PLAIN, scale, color) else: cv2.putText(image, text, (xpos+i, ypos+i), cv2.FONT_HERSHEY_PLAIN, scale, (50, 50, 50))
class Calibrate(BasePlugin): configParameter = [ ImageType('inputImage', input=True), ImageType('outputImage', output=True), IntType('visualTresholdLow'), IntType('gridX'), IntType('gridY'), IntType('dataPerGridCell'), IntType('successHue'), IntType('boardw'), IntType('boardh'), FloatType('delay'), StringType('outputFileName'), BoolType('syncCalculation'), ] def __init__(self, **kwargs): super(Calibrate, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') self.data = np.zeros((self.gridY.value, self.gridX.value), np.uint8) self.board_w = self.boardw.value self.board_h = self.boardh.value self.board_n = self.board_w * self.board_h self.board_sz = (self.board_w, self.board_h) # size of board pattern_size = (self.board_w, self.board_h) self.pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32) self.pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2) #pattern_points *= cbsq self.obj_points = list() self.img_points = list() self.last_time = time.time() self.syncObj = None self.calculationDone = False self.calculationVisualisation = False def externalCall(self): waitForSync = False if self.syncCalculation.value: waitForSync = True if not self.syncObj: self.syncObj = StringType('syncSection') self.syncObj.value = self.sectionConfig['syncSection'] self.syncObj.data = False self.sectionConfig['syncSection'] = self.syncObj syncObjOther = self.fullConfig[self.syncObj.value][ self.syncObj.name] if isinstance(syncObjOther, StringType): waitForSync = not syncObjOther.data #print self.logicSectionName, #print self.logicSectionName, self.fullConfig[secObj.value]['foo'] image = self.inputImage.data # PREPARE VISUALIZATION if self.data is None: self.data = np.zeros((self.gridY.value, self.gridX.value), np.uint8) hsv = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2HSV) hsv[..., 0] = 0 hsv[..., 1] = 255 dark = hsv[..., 2] < self.visualTresholdLow.value hsv[dark] = self.visualTresholdLow.value # DRAW VISUALIZATION totalx = image.shape[1] totaly = image.shape[0] xsize = totalx // self.gridX.value ysize = totaly // self.gridY.value for y, yline in enumerate(self.data): for x, value in enumerate(yline): hsv[ysize * y:ysize * (y + 1), xsize * x:xsize * (x + 1), 0] = value * int( self.successHue.value / self.dataPerGridCell.value) doCalculate = self.data.sum() >= (self.dataPerGridCell.value * self.data.size) # AQUIRE BOARD DATA isBoard = False waitForDelay = time.time() - self.last_time <= self.delay.value if not doCalculate and not waitForDelay: isBoard, boardData = cv2.findChessboardCorners( image, self.board_sz, self.board_n, cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FILTER_QUADS) attachToList = False if isBoard: cv2.drawChessboardCorners(hsv, self.board_sz, boardData, 0) for point in boardData: x, y = point[0] if self.data[y // ysize][x // xsize] < self.dataPerGridCell.value: self.data[y // ysize][x // xsize] += 1 attachToList = True self.last_time = time.time() if attachToList: self.img_points.append(boardData.reshape(-1, 2)) self.obj_points.append(self.pattern_points) # CALCULATE self.syncObj.data = doCalculate if doCalculate and not waitForSync and not self.calculationDone and self.calculationVisualisation: self.calculationDone = True rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera( self.obj_points, self.img_points, (totalx, totaly)) print '*' * 100 print self.logicSectionName print '*' * 100 print "RMS:", rms print "camera matrix:\n", camera_matrix print "distortion coefficients: ", dist_coefs.ravel() print '*' * 100 with open(self.outputFileName.value, 'wb') as f: pickle.dump(camera_matrix, f, -1) pickle.dump(dist_coefs, f, -1) pickle.dump(rms, f, -1) pickle.dump(rvecs, f, -1) pickle.dump(tvecs, f, -1) self.outputImage.data = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) if doCalculate: if waitForSync: textStr = 'wait for sync' else: if not self.calculationDone: textStr = 'calculating' self.calculationVisualisation = True else: textStr = 'done' else: if isBoard or waitForDelay: textStr = 'board found' else: textStr = 'searching board' drawText(self.outputImage.data, textStr, 50, 50, scale=2, thickness=3, bgthickness=3)
class Histogram(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), ImageType('outputImageName', output=True), IntType('scale'), ] def __init__(self, **kwargs): super(Histogram, self).__init__(**kwargs) self.log = logging.getLogger(__name__) self.log.debug('logging started') self.hsv_map = np.zeros((180, 256, 3), np.uint8) h, s = np.indices(self.hsv_map.shape[:2]) self.hsv_map[:, :, 0] = h self.hsv_map[:, :, 1] = s self.hsv_map[:, :, 2] = 255 self.hsv_map = cv2.cvtColor(self.hsv_map, cv2.COLOR_HSV2BGR) def externalCall(self): image = self.inputImageName.data image = cv2.pyrDown(image) hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) h = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256]) h = np.clip(h * 0.005 * self.scale.value, 0, 1) vis = self.hsv_map * h[:, :, np.newaxis] / 255.0 vis = cv2.pyrUp(vis) colsub = (0.2, 0.6, 0.2) colmain = (0.3, 0.9, 0.3) blacksize = 5 for i in range(10, 360, 10): cv2.line(vis, (0, i), (5, i), 0, blacksize) cv2.line(vis, (0, i), (5, i), colsub, 1) for i in range(30, 360, 30): cv2.line(vis, (0, i), (15, i), 0, blacksize) cv2.line(vis, (0, i), (15, i), colmain, 1) for i in range(20, 510, 20): cv2.line(vis, (i, 0), (i, 5), 0, blacksize) cv2.line(vis, (i, 0), (i, 5), colsub, 1) for i in range(100, 510, 100): cv2.line(vis, (i, 0), (i, 15), 0, blacksize) cv2.line(vis, (i, 0), (i, 15), colmain, 1) nvis = np.zeros((vis.shape[0] + 15, vis.shape[1] + 30, vis.shape[2])) nvis[15:, 30:, ...] = vis nvis[15:, 30, ...] = colsub self.drawText(nvis, 'SATURATION', 450, 10, 0.6, colsub) # 32 self.drawText(nvis, 'HUE', 4, 367, 0.6, colsub) for i in range(50, 300, 50): self.drawText(nvis, str(i), i * 2 + 17, 10, 0.75, colmain) for i in range(15, 180, 15): self.drawText(nvis, str(i), 0, i * 2 + 18, 0.75, colmain) #nvis = cv2.pyrUp(nvis) self.outputImageName.data = nvis def drawText(self, image, text, xpos, ypos, scale=1, color=(225, 225, 225)): xpos = int(xpos) ypos = int(ypos) for i in range(1, 0, -1): if i < 2: cv2.putText(image, text, (xpos + i, ypos + i), cv2.FONT_HERSHEY_PLAIN, scale, color) else: cv2.putText(image, text, (xpos + i, ypos + i), cv2.FONT_HERSHEY_PLAIN, scale, (50, 50, 50))
class HoughCircles(BasePlugin): configParameter = [ ImageType('inputImageName', input=True), StringType('circleData', output=True), IntType('dp', constraint=range(1, 1000)), IntType('minDist', constraint=range(1, 1000)), IntType('minRad', constraint=range(1, 1000)), IntType('maxRad', constraint=range(1, 1000)), IntType('threshold1', constraint=range(1, 1000)), IntType('threshold2', constraint=range(1, 1000)), ImageType('inputOrgImageName', input=True), BoolType('doDrawCircles'), ImageType('outputOrgCircleImageName', output=True), BoolType('doCannyOutput'), ImageType('outputCannyImageName', output=True), ] def __init__(self, **kwargs): super(HoughCircles, self).__init__(**kwargs) def externalCall(self): reslist = cv2.HoughCircles(self.inputImageName.data, cv2.cv.CV_HOUGH_GRADIENT, dp=self.dp.value, minDist=self.minDist.value, minRadius=self.minRad.value, maxRadius=self.maxRad.value, param1=self.threshold1.value, param2=self.threshold2.value) self.circleData.data = reslist if self.doCannyOutput.value: image = self.inputImageName.data canny = cv2.Canny(image, self.threshold1.value, self.threshold1.value // 2) self.outputCannyImageName.data = canny if self.doDrawCircles.value: resvisimage = self.inputOrgImageName.data.copy() if reslist is not None and len(reslist): for x in reslist[0]: corr = 5 mask = np.zeros(tuple(self.inputImageName.data.shape[:2]), np.uint8) cv2.circle(mask, (x[0], x[1]), int(x[2] - corr), 255, -1) mean_val = cv2.mean(self.inputOrgImageName.data, mask=mask) mv = np.zeros((1, 1, 3), np.uint8) mv[..., 0] = mean_val[0] mv[..., 1] = mean_val[1] mv[..., 2] = mean_val[2] mv2 = cv2.cvtColor(mv, cv2.COLOR_BGR2HSV) #cv2.circle(resvisimage, (x[0], x[1]), int(x[2]-corr), (mean_val[0],mean_val[1],mean_val[2]), -1) self.drawText(resvisimage, str(mv2[0, 0]), x[0] - 40, x[1] - self.maxRad.value - 4, 1) if 28 > mv2[0, 0, 0] or mv2[0, 0, 0] > 32 or mv2[ 0, 0, 1] < 70 or mv2[0, 0, 2] < 150: #continue pass cv2.circle(resvisimage, (x[0], x[1]), self.minRad.value, (100, 255, 100), 1) cv2.circle(resvisimage, (x[0], x[1]), self.maxRad.value, (100, 100, 255), 1) cv2.circle(resvisimage, (x[0], x[1]), self.minDist.value, (100, 100, 100), 1) cv2.circle(resvisimage, (x[0], x[1]), x[2], (255, 100, 100), 2) cv2.circle(resvisimage, (x[0], x[1]), 4, (50, 50, 50), -1) self.outputOrgCircleImageName.data = resvisimage def drawText(self, image, text, xpos, ypos, scale=1, color=(225, 225, 225)): xpos = int(xpos) ypos = int(ypos) for i in range(3, 0, -1): if i < 2: cv2.putText(image, text, (xpos + i, ypos + i), cv2.FONT_HERSHEY_PLAIN, scale, color) else: cv2.putText(image, text, (xpos + i, ypos + i), cv2.FONT_HERSHEY_PLAIN, scale, (50, 50, 50))
class CircleDetector(BasePlugin): configParameter = [ NameType('inputImageName', input=True), NameType('outputImageName', output=True), NameType('inputContourName', input=True), IntType('thickness'), NameType('inputContourIndexListName', input=True), NameType('inputCalibrationData', input=True), ] def __init__(self, **kwargs): super(CircleDetector, self).__init__(**kwargs) def preCyclicCall(self): pass def externalCall(self): if self.inputContourIndexListName.data: contidx = self.inputContourIndexListName.data else: contidx = range(len(self.inputContourName.data)) image = self.inputImageName.data.copy() for cidx in contidx: cnt = self.inputContourName.data[cidx] mask = np.zeros(tuple(self.inputImageName.data.shape[:2]), np.uint8) cv2.drawContours(mask, self.inputContourName.data, -1, color=(250,250,50), thickness=-1) moments = cv2.moments(cnt) humoments = cv2.HuMoments(moments) try: centroid_x = moments['m10']/moments['m00'] centroid_y = moments['m01']/moments['m00'] except ZeroDivisionError: continue area = moments['m00'] equi_diameter = np.sqrt(4*area/np.pi) * 1.05 equi_radian = equi_diameter / 2.0 #print self.inputCalibrationData.data xopt = self.inputCalibrationData.data[0, 2] yopt = self.inputCalibrationData.data[1, 2] # OPTICAL CENTER CROSSHAIR ########################## if showCalib: cv2.circle(image, (int(xopt), int(yopt)), 2, (100, 250, 100), -1) cv2.circle(image, (int(xopt), int(yopt)), 1, (250, 100, 100), -1) image[int(yopt), ..., 0:2] *= 0.5 image[int(yopt), ...] *= 255.0 / image[int(yopt), ...].max() image[...,int(xopt), 0:2] *= 0.5 image[...,int(xopt), 2] *= 255.0 / image[..., int(xopt), ...].max() mpp = 3.0677e-6 B = equi_diameter * mpp G = 0.0429 b = 4.02e-3 g = b/B*G gcorr = g + G/2 color = (50, 250, 50) minhu = 1.59e-1 maxhu = 1.65e-1 # normal 1.64e-1 overhu = 1.70e-1 quality = (humoments[0] - minhu) / (maxhu - minhu) state = 'green' if humoments[0] > (maxhu) or humoments[0] < (minhu) or equi_radian < 13 or equi_radian > 45: color = (50, 50, 250) #equi_diameter *= quality #equi_radian = equi_diameter / 2.0 if showCalib: continue #continue state = 'red' if humoments[0] < (overhu) and humoments[0] > (maxhu): color = (50, 150, 250) state = 'orange' if equi_radian < 13 or equi_radian > 45: color = (250, 150, 150) if state == 'red': #continue pass #cv2.drawContours(image, self.inputContourName.data, -1, color=(250,250,50), thickness=1) xpx = centroid_x - xopt xm = 0.0429 / equi_diameter * xpx ym = np.sqrt(gcorr**2 - np.abs(xm**2)) #print '+++', state, gcorr, xm, 'sqrt ' + str(gcorr**2 - xm**2), '->', ym #self.scatter[int(ym*100)][int(xm*100)+100] += 0.14 #cv2.imshow('scatter', cv2.pyrUp(self.scatter)) #cv2.imwrite('data/scatterx.jpg', self.scatter) if showCalib: self.drawText(image, '%.2f'%xm, int(xopt), int(centroid_y), scale=1, color=(225, 225, 225)) self.drawText(image, '%.2f'%ym, int(centroid_x), image.shape[0]-10, scale=1, color=(225, 225, 225)) cv2.line(image, (int(centroid_x), int(centroid_y)), (int(xopt), int(centroid_y)), (200,50,50), 1) cv2.line(image, (int(centroid_x), int(centroid_y)), (int(centroid_x), image.shape[0]), (50,150,250), 1) cv2.circle(image, (int(centroid_x), int(centroid_y)), int(equi_radian), (250, 250, 100), 1) cv2.circle(image, (int(centroid_x), int(centroid_y)), 3, color=(255,50,50), thickness=-1) if True: image[int(centroid_y-70-equi_radian):int(centroid_y-equi_radian-10), centroid_x-40:centroid_x+80] *= 0.45 #self.drawTextMarker(image, 'X: ' + str(round(centroid_x, 2)), centroid_x, centroid_y, equi_radian, 0, color) #self.drawTextMarker(image, 'Y: ' + str(round(centroid_y, 2)), centroid_x, centroid_y, equi_radian, 1, color) self.drawTextMarker(image, 'Radian: ' + str(round(equi_radian, 2)), centroid_x, centroid_y, equi_radian, 1, color) self.drawTextMarker(image, 'HM0' + ': %.2e' % humoments[0], centroid_x, centroid_y, equi_radian, 2, color) self.drawTextMarker(image, 'Distance' + ': %.2f' % gcorr + 'm', centroid_x, centroid_y, equi_radian, 3, color) self.drawTextMarker(image, 'Diff' + ': %.2f' % (quality * 100) + '%', centroid_x, centroid_y, equi_radian, 4, color) cv2.imshow('xxx', image) cv2.imwrite('data/bdvdoku/20_imagecd_false_positive.jpg', image) crop = image[50:375, 325:850] crop = cv2.pyrUp(crop) cv2.imshow('crop', crop) def drawTextMarker(self, image, text, xpos, ypos, radian, line, color=(225, 225, 225)): xofs = -35 ystep = 15 yofs = int(radian) + ystep * 5 yofs *= -1 self.drawText(image, text, int(xpos) + xofs, int(ypos) + yofs + ystep * line, 0.8, color) def drawText(self, image, text, xpos, ypos, scale=1, color=(225, 225, 225)): for i in range(3, 0, -1): if i < 2: cv2.putText(image, text, (xpos+i, ypos+i), cv2.FONT_HERSHEY_PLAIN, scale, color) else: cv2.putText(image, text, (xpos+i, ypos+i), cv2.FONT_HERSHEY_PLAIN, scale, (50, 50, 50))
class ProcessManager(object): """Manages the Process and is responsibly for the runtime behavior""" logicSectionName = 'GENERAL' configParameter = [ StringListType('pluginSequence'), StringType('exitKey'), IntType('leadTime'), BoolType('waitLeadTime'), BoolType('runOnce'), ] def __init__(self, pluginController, configController): """Gets the 'GENERAL' section from the ConfigController and acquires and instantiate the Plugins specified by the 'pluginSequence' Option in the Configuration :param pluginController: Instance of the ``PluginController`` :param configController: Instance of the ``ConfigController`` :param dataLinkController: Instance of the ``DataLinkController`` """ # Logging ########## self.log = logging.getLogger(__name__) self.log.debug('logging started') # ProcessStuff ############### assert isinstance(pluginController, PluginController) self.pluginController = pluginController assert isinstance(configController, ConfigController) self.configController = configController # Init-Specific (Config / Plugins) ################################### fullConfig = self.configController.getConfig() self.sectionConfig = self.configController.getSection(self.logicSectionName) bp = BasePlugin(sectionConfig=self.sectionConfig, logicSectionName=self.logicSectionName, fullConfig=fullConfig) bp.loadOptions(self) self.pluginDtoList = self.acquirePlugins() self.instantiatePlugins() # Cycle-Specific (execute Plugins / handle runtime characteristics) #################################################################### curTime = time.time() self.lastExecTime = curTime self.lastBypassTime = curTime self.lastCycleTime = curTime self.deltaExecTime = 0 self.deltaBypassTime = 0 def acquirePlugins(self): """Acquire the Plugins specified by the 'pluginSequence' Option in the Configuration given by the dict generalConfigSection or internal config if generalConfigSection is None. Furthermore returns a list of PluginDto for each loaded Plugin whose Name in the pluginSequence Option don't start with an exclamation mark :param generalConfigSection: Config for 'GENERAL' section (default ``None``) """ self.log.debug('enter acquirePlugins') pluginDtoList = list() for section in self.pluginSequence: if not section.startswith('!'): pdto = PluginDTO() pdto.sectionName = section self.log.debug('try loading for sectionName <%s>', pdto.sectionName) #FIXME: Figure out when it fails! try: pdto.modulePath = self.configController.getOption(section, 'pluginPath') except AssertionError as e: self.log.critical('asd %s', e.message) pdto.classObject = self.pluginController.loadPluginClass( pdto.modulePath) if pdto.classObject is None: continue pluginDtoList.append(pdto) return pluginDtoList def instantiatePlugins(self, pluginDtoList=None): """Instantiate the Plugins in the list of PluginDto's :param pluginDtoList: List of PluginDto's (default None) """ self.log.debug('enter instantiatePlugins') self.log.debug('check pluginDtoList') if pluginDtoList is None: self.log.debug('load private data') pluginDtoList = self.pluginDtoList if pluginDtoList is None: return None self.log.debug('instantiate Plugins') for pdto in pluginDtoList: assert isinstance(pdto, PluginDTO) self.log.debug('instantiate Plugin <%s> for Section <%s>', pdto.modulePath, pdto.sectionName) fullConfig = self.configController.getConfig() sectionConfig = self.configController.getSection(pdto.sectionName) pdto.instanceObject = pdto.classObject(sectionConfig=sectionConfig, logicSectionName=pdto.sectionName, fullConfig=fullConfig) def executePlugins(self, pluginDtoList=None): if pluginDtoList is None: pluginDtoList = self.pluginDtoList assert isinstance(pluginDtoList, list) self.log.debug('') self.log.debug('=' * 30 + ' REGISTER DEPENDENCY ' + '=' * 30) self.registerDependency() self.log.debug('') self.log.debug('=' * 30 + ' RUN ACTIVE MODULES ' + '=' * 30) self.triggerPluginMethods('preCyclicCall') isFirstRun = True while True: leadTime = self.leadTime.value / 1000.0 curTime = time.time() deltaExec = curTime - self.lastExecTime if isFirstRun or (deltaExec + self.deltaBypassTime) > leadTime: waitTime = leadTime - deltaExec if self.waitLeadTime.value and not isFirstRun and waitTime > 0: time.sleep(waitTime) self.lastExecTime = time.time() self.triggerPluginMethods('externalCall') self.deltaExecTime = time.time() - self.lastExecTime else: self.lastBypassTime = time.time() self.triggerPluginMethods('timeBypassActions') self.deltaBypassTime = time.time() - self.lastBypassTime isFirstRun = False if self.runOnce.value: break if (cv2.waitKey(10) & 255) == ord(self.exitKey.value): break self.triggerPluginMethods('postCyclicCall') def triggerPluginMethods(self, methodName, pluginDtoList=None): """Triggers the corresponding methods of the active Plugins in the pluginDtoList :param methodName: Name of the Plugin-Method to trigger :param pluginDtoList: List of PluginDto's (default None) """ if pluginDtoList is None: pluginDtoList = self.pluginDtoList assert isinstance(pluginDtoList, list) for pdto in pluginDtoList: assert isinstance(pdto, PluginDTO) pdtoObj = pdto.instanceObject if not pdtoObj.activeModule: self.log.debug('Skipping inactive Module <%s> for logical Section <%s>', pdtoObj.__class__.__name__, pdtoObj.logicSectionName) continue self.log.debug('Calling Module <%s> for logical Section <%s>', pdtoObj.__class__.__name__, pdtoObj.logicSectionName) moduleFunction = getattr(pdtoObj, methodName) moduleFunction() def registerDependency(self, pluginDtoList=None): if pluginDtoList is None: pluginDtoList = self.pluginDtoList assert isinstance(pluginDtoList, list) inputParameter = dict() outputParameter = dict() self.log.debug('') self.log.debug('-' * 30 + ' PreLoad I/O-Parameter ' + '-' * 30) for pdto in pluginDtoList: self.log.debug('.' * 20 + ' <%s> ' + '.' * 20, pdto.instanceObject.logicSectionName) assert isinstance(pdto, PluginDTO) baseTypeParameter = [x for x in pdto.instanceObject.sectionConfig.values() if issubclass(type(x), BaseType) and (x.output or x.input)] for x in baseTypeParameter: if x.input: self.log.debug('input found:') self.attachToDependencyIOList(x, inputParameter) if x.output: self.log.debug('output found:') self.attachToDependencyIOList(x, outputParameter) self.log.debug('') self.log.debug('-' * 30 + ' Wire I/O-Callbacks for Parameter-Types ' + '-' * 30) for oname, opara in outputParameter.items(): if oname in inputParameter: for output in opara: for ipara in inputParameter[oname]: self.log.debug('parameter <%s> for value <%s> to <%s> on value <%s> ', output.name, output.value, ipara.value, ipara.name) output.registerDataUpdate(ipara.dataUpdateCallback) def attachToDependencyIOList(self, para, dstList): valueList = para.value if not isinstance(valueList, list): valueList = [valueList] for value in valueList: if value not in dstList: dstList[value] = list() self.log.debug('parameter <%s> for value <%s>', para.name, value) dstList[value].append(para)