class Processor: def __init__(self, name, camera, pipeline): print("Creating Processor: camera=" + camera.name + " pipeline=" + pipeline.name) self.name = name self.camera = camera # Lock to protect access to pipeline member var self.lock = Lock() self.pipeline = pipeline self.cubby = Cubbyhole() self.fps = FrameRate() self.running = False def start(self): print("Processor " + self.name + " STARTING") t = Thread(target=self.run, args=()) t.daemon = True t.start() return self def run(self): print("Processor " + self.name + " RUNNING") self.running = True while True: frame = self.camera.read(self) self.fps.start() self.lock.acquire() pipeline = self.pipeline self.lock.release() pipeline.process(frame) self.cubby.put(frame) self.fps.stop() def setPipeline(self, pipeline): if pipeline == self.pipeline: return self.lock.acquire() self.pipeline = pipeline self.lock.release() print( "Processor " + self.name + " pipeline now=" + pipeline.name) def read(self): return self.cubby.get() def isRunning(self): return self.running
class ImgSink: def __init__(self): self.fps = FrameRate() self.bitrate = BitRate() self.cubby = Cubbyhole() # Gets frames from selected processor, # displays vid in local window, # compresses frame to jpg buffer & hands buffer to web server. # Called from main thread - note, imshow can only be called from main thread or big crash! def show(self): theProcessor = processors[currentCam.value] img = theProcessor.read() self.fps.start() # Write some useful info on the frame camFps, camUtil = theProcessor.camera.fps.get() procFps, procUtil = theProcessor.fps.get() srvFps, srvUtil = self.fps.get() srvBitrate = self.bitrate.get() cv2.putText(img, "{:.1f} : {:.0f}%".format(camFps, 100*camUtil), (0, 20), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.putText(img, "{:.1f} : {:.0f}%".format(procFps, 100*procUtil), (0, 40), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.putText(img, "{:.1f} : {:.0f}% : {:.2f}".format(srvFps, 100*srvUtil, srvBitrate), (0, 60), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.putText(img, currentCam.value, (0, 80), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.putText(img, theProcessor.pipeline.name, (0, 100), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) # Compress image to jpeg and stash in cubbyhole for webserver to grab _, jpg = cv2.imencode(".jpg", img, (cv2.IMWRITE_JPEG_QUALITY, 80)) buf = bytearray(jpg) self.cubby.put(buf) self.bitrate.update(len(buf)) self.fps.stop() # Show the final image in local window and watch for keypresses. cv2.imshow( "Image", img) key = cv2.waitKey(1) return key # Web Server calls this to get jpeg to send def get(self): return self.cubby.get()
class Camera: def __init__(self, name, src, width, height, exposure): print("Creating Camera " + name) self.name = name self.src = src self.stream = cv2.VideoCapture(src) self.stream.set(cv2.CAP_PROP_FRAME_WIDTH,width) self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT,height) self.exposure = None self.setExposure(exposure) self.fps = FrameRate() self.running = False # Dict maps user (client) to the Cubbyhole instance used to pass it frames self.userDict = {} self.userDictLock = Lock() # Protects shared access to userDict self.rate = self.stream.get(cv2.CAP_PROP_FPS) print("RATE = " + str(self.rate)) self.brightness = self.stream.get(cv2.CAP_PROP_BRIGHTNESS) print("BRIGHT = " + str(self.brightness)) self.contrast = self.stream.get(cv2.CAP_PROP_CONTRAST) print("CONTRAST = " + str(self.contrast)) self.saturation = self.stream.get(cv2.CAP_PROP_SATURATION) print("SATURATION = " + str(self.saturation)) print("EXPOSURE = " + str(self.exposure)) def start(self): print("Camera " + self.name + " STARTING") t = Thread(target=self.run, args=()) t.daemon = True t.start() return self def run(self): print("Camera " + self.name + " RUNNING") self.running = True while True: (grabbed, frame) = self.stream.read() self.fps.start() # grabbed will be false if camera has been disconnected. # How to deal with that?? # Should probably try to reconnect somehow? Don't know how... if grabbed: # Pass a copy of the frame to each user in userDict self.userDictLock.acquire() values = self.userDict.values() self.userDictLock.release() for mb in values: mb.put(frame.copy()) self.fps.stop() def read(self, user): # See if this user already registered in userDict. # If not, create a new Cubbyhole instance to pass frames to user. # If so, just get the user's Cubbyhole instance. # Then get the frame from the Cubbyhole & return it. self.userDictLock.acquire() if not user in self.userDict: self.userDict[user] = Cubbyhole() mb = self.userDict[user] self.userDictLock.release() return mb.get() def processUserCommand(self, key): if key == ord('w'): self.brightness+=1 self.stream.set(cv2.CAP_PROP_BRIGHTNESS,self.brightness) print("BRIGHT = " + str(self.brightness)) elif key == ord('s'): self.brightness-=1 self.stream.set(cv2.CAP_PROP_BRIGHTNESS,self.brightness) print("BRIGHT = " + str(self.brightness)) elif key == ord('d'): self.contrast+=1 self.stream.set(cv2.CAP_PROP_CONTRAST,self.contrast) print("CONTRAST = " + str(self.contrast)) elif key == ord('a'): self.contrast-=1 self.stream.set(cv2.CAP_PROP_CONTRAST,self.contrast) print("CONTRAST = " + str(self.contrast)) elif key == ord('e'): self.saturation+=1 self.stream.set(cv2.CAP_PROP_SATURATION,self.saturation) print("SATURATION = " + str(self.saturation)) elif key == ord('q'): self.saturation-=1 self.stream.set(cv2.CAP_PROP_SATURATION,self.saturation) print("SATURATION = " + str(self.saturation)) elif key == ord('z'): self.setExposure(self.exposure+1) print("EXPOSURE = " + str(self.exposure)) elif key == ord('c'): self.setExposure(self.exposure-1) print("EXPOSURE = " + str(self.exposure)) ## elif key == ord('p'): ## self.iso +=1 ## self.stream.set(cv2.CAP_PROP_ISO_SPEED, self.iso) ## elif key == ord('i'): ## self.iso -=1 ## self.stream.set(cv2.CAP_PROP_ISO_SPEED, self.iso) def setExposure(self, exposure): if self.exposure == exposure : return self.exposure = exposure # cv2 exposure control DOES NOT WORK ON PI if (platform.system() == 'Windows' or platform.system() == 'Darwin'): self.stream.set(cv2.CAP_PROP_EXPOSURE, self.exposure) else: cmd = ['v4l2-ctl --device=' + str(self.src) + ' -c exposure_auto=1 -c exposure_absolute=' + str(self.exposure)] call(cmd,shell=True) return def isRunning(self): return self.running