def __Update(self): while self.__Running: # If we lose our device, stop this thread. if self.__CheckTimeout() is False: break # if we suddenly lose our instance, set an error flag and attempt to get it again if self.__cap is None: self.__SetError() self.__FPSSync() continue retVal, image = self.__cap.read() if not retVal: self.__SetStatus("Encountered frame capture error") self.__SetError() self.__FPSSync() continue else: DogCamLogger.Log("Webstream: Capturing image", DCLogLevel.Verbose) self.__img = cv2.resize(image, (self.resWidth, self.resHeight)) if self.__LastErrorTime > 0.0: DogCamLogger.Log("Webstream: Recovered from net disruption") self.__SetStatus("Recovered from net disruption") self.__LastErrorTime = 0.0 self.__FPSSync()
def CreateAI(aiType, aiModel, boundsXSize=10, boundsYSize=10, minimumConfidence=0.3, displayOut=False, detectionID=0, logMatches=False, throttleTilt=False, tiltCooldown=0.75): NewAIClass = None DogCamLogger.Log(f"AI: Using model file {aiModel}", DCLogLevel.Verbose) if not path.exists(aiModel): DogCamLogger.Log(f"AI: Given model file {aiModel} does not exist!", DCLogLevel.Error) return None className = aiType if className == "tf": NewAIClass = DogCamAITFLite(aiModel) elif className == "dnn": NewAIClass = DogCamAIDNN(aiModel) if NewAIClass is not None: NewAIClass.Initialize(boundsXSize, boundsYSize, minimumConfidence, displayOut, detectionID, logMatches, throttleTilt, tiltCooldown) else: DogCamLogger.Log( f"AI: Could not create class of type {className}! Fatal error!", DCLogLevel.Error) return NewAIClass
def Open(self): DogCamLogger.Log("Webstream: Loading video feed", DCLogLevel.Notice) if self.__cap is not None: DogCamLogger.Log("Webstream: Another capture instance already exists", DCLogLevel.Warn) self.__LastConnectionAttempt = time.time() self.__cap = cv2.VideoCapture(self.vidURL) # Keep only a few frames in the buffer, dropping dead frames self.__cap.set(cv2.CAP_PROP_BUFFERSIZE, self.fbSize) if not self.__cap.isOpened(): DogCamLogger.Log("Webstream: Could not capture the video!", DCLogLevel.Warn) self.__SetStatus("Failed to load video capture") self.__cap = None return False else: self.__SetStatus("Video feed loaded") if self.resWidth == 0: self.resWidth = self.__cap.get(cv2.CAP_PROP_FRAME_WIDTH) if self.resHeight == 0: self.resHeight = self.__cap.get(cv2.CAP_PROP_FRAME_HEIGHT) self.__LastErrorTime = 0.0 return True
def Start(self): # if we already have a running instance, don't start it again if self.__cap is not None: return True if self.Open(): DogCamLogger.Log("Webstream: Starting thread") self.__Running = True self.__thread = threading.Thread(target=self.__Update, daemon=True) self.__thread.start() return True else: DogCamLogger.Log("Webstream: Failed to start!", DCLogLevel.Warn) self.Stop() return False
def __SetError(self): # If we already have a pending error time, then we're already handling this issue somewhere else if self.__LastErrorTime <= 1.0: DogCamLogger.Log("Webstream: Detected error, waiting...", DCLogLevel.Error) self.__LastErrorTime = time.time() self.__BlankImage() self.__ReleaseCapture()
def __MessageThread(self): while self.__processing: # Attempt to handle reconnection if self.IsConnectionReady() is False: # Handle timeouts if self.__reconnectTimeout == 0.0: DogCamLogger.Log("Websocket: Detected disconnection", DCLogLevel.Warn) self.__reconnectTimeout = time.time() self.__reconnect = True elif (time.time() - self.__reconnectTimeout) >= self.__maxTimeout: DogCamLogger.Log( "Websocket: Exhausted retries to reconnect", DCLogLevel.Error) self.__processing = False break if self.__reconnect is True: self.Connect() time.sleep(2) continue try: Message = self.__socket.recv() if not Message: time.sleep(1) continue DogCamLogger.Log(f"Websocket: Got message: {Message}", DCLogLevel.Debug) except (websocket.WebSocketConnectionClosedException, BrokenPipeError): DogCamLogger.Log("Websocket: was disconnected!", DCLogLevel.Warn) self.__socket = None continue except KeyboardInterrupt: break time.sleep(0.5)
def SendMessage(self, message): if message is None or self.IsConnectionReady() is False: return try: self.__socket.send(message) except Exception as ex: DogCamLogger.Log( f"Websocket: Failed to send message {message}!\nException: {ex}", DCLogLevel.Warn)
def Connect(self): self.__reconnect = False try: self.__socket.close() self.__socket = None except: DogCamLogger.Log("Websocket: Socket constructing") try: self.__socket = websocket.WebSocket() self.__socket.connect(self.URL) DogCamLogger.Log("Websocket: Socket connected!", DCLogLevel.Notice) self.__OnConnected() except KeyboardInterrupt: DogCamLogger.Log("Websocket: Interrupted!", DCLogLevel.Debug) raise except Exception as ex: DogCamLogger.Log(f"Websocket: Failed to connect!\nException: {ex}", DCLogLevel.Warn) self.__socket = None self.__reconnect = True
def __CheckTimeout(self): lastConnectionAttempt = (time.time() - self.__LastConnectionAttempt) isTotalDisconnection = (time.time() - self.__LastErrorTime) >= self.netTimeout and self.__LastErrorTime > 0.0 isConnectionRetry = (self.__cap is None or self.__cap.isOpened() is False) and lastConnectionAttempt >= 5.0 # See if we should check to restart the capture software again if isTotalDisconnection: # At this point we are starved of updates entirely and we fail out. DogCamLogger.Log("Webstream: Timeout has occurred!", DCLogLevel.Notice) self.__SetStatus("Total timeout has occurred! Stopping video capture service") self.__Running = False self.__ReleaseCapture() self.__BlankImage() return False elif isConnectionRetry: DogCamLogger.Log("Webstream: Attempting to restart capture", DCLogLevel.Log) self.__SetStatus(f"Attempting to restart capture at {lastConnectionAttempt} of max time {self.netTimeout}") self.__BlankImage() self.__ReleaseCapture() self.Open() time.sleep(1) return True
def __ProcessImage(self): # Unlikely, but we'll be safe anyways if self._image is None: DogCamLogger.Log("AI: Skipping blank image", DCLogLevel.Debug) return ProcessingTime = time.time() # Handle tilt throttling if (ProcessingTime - self._LastTiltMoveTime) > self._TiltMoveCooldown: self._blockTiltMove = False DogCamLogger.Log(f"AI: Processing image at {ProcessingTime}!", DCLogLevel.Verbose) self._ProcessImageInternal() ProcessingTime = time.time() - ProcessingTime if self.debugDisplay: DogCamLogger.Log("AI: Displaying image", DCLogLevel.Debug) cv2.imshow("Output", self._image) DogCamLogger.Log(f"AI: Image processed in {ProcessingTime} seconds", DCLogLevel.Verbose)
def Initialize(self, boundsXSize=10, boundsYSize=10, minimumConfidence=0.3, displayOut=False, detectionID=0, logMatches=False, throttleTilt=False, tiltCooldown=0.75): self.debugDisplay = displayOut self._boundsX = int(boundsXSize) self._boundsY = int(boundsYSize) self._minConfidence = float(minimumConfidence) self._image = None self._logMatches = logMatches self.__pendingImage = None self._targetID = detectionID self._ThrottleTiltMovement = throttleTilt self._TiltMoveCooldown = tiltCooldown self._thread = threading.Thread(target=self.__Update) DogCamLogger.Log("AI: Initialized", DCLogLevel.Debug)
def _LogObjectFound(self, objectID, confidence): if confidence >= self._minConfidence and self._logMatches is True: DogCamLogger.Log( f"AI: Found object {objectID} with confidence {confidence}")
def __init__(self): with open("./config.json","r") as cfg_file: ConfigData = json.load(cfg_file) self.__dict__ = ConfigData DogCamLogger.SetLogLevel(self.LoggingLevel) DogCamLogger.Log("Config data has been loaded!", DCLogLevel.Notice)
def __BlankImage(self): DogCamLogger.Log("Webstream: Blanking image", DCLogLevel.Debug) self.__img = None
def PushImage(self, image): if image is None: DogCamLogger.Log("AI: Image pushed was empty", DCLogLevel.Debug) return self.__pendingImage = image
def SetDimensions(self, W, H): self._width = int(W) self._height = int(H) DogCamLogger.Log(f"AI: Resolution is {self._width}x{self._height}")
def __init__(self): DogCamLogger.Log("AI: Allocated", DCLogLevel.Verbose)
from dogcamstreamer import DogCamStreamer from dogcamaifactory import DogCamAIFactory from dogcamsocket import DogCamSocket from dogcamconfig import DogCamConfig from dogcamlogger import DogCamLogger, DCLogLevel from pathlib import Path import time import os # Remove any handles before we start if os.path.exists('exit_handle'): os.remove('exit_handle') # Start AI stuff DogCamLogger.Start() DogCamLogger.Log("Starting classes", DCLogLevel.Notice) exit_handle = Path('exit_handle') dcc = DogCamConfig() aiUsed = dcc.AIMethod.lower() dcai = DogCamAIFactory.CreateAI(aiType=aiUsed, aiModel=dcc.AIModels[aiUsed], boundsXSize=dcc.AIBoundsXSize, boundsYSize=dcc.AIBoundsYSize, minimumConfidence=dcc.AIMinimumConfidence, displayOut=dcc.AIDisplayVision, detectionID=dcc.AIDetectID, logMatches=dcc.AILogMatches,
def Stop(self): if self._runningThread: DogCamLogger.Log("AI: AI Processing Halted", DCLogLevel.Warn) self._runningThread = False self._thread.join()
def Start(self): DogCamLogger.Log("AI: AI Processing Started", DCLogLevel.Notice) self._runningThread = True self._thread.start()
def __SetStatus(self, message): DogCamLogger.Log(f"Webstream: set debug string to {message}", DCLogLevel.Debug) self.__CurrentStatus = f"AI Stream: {message}"