Exemple #1
0
class Moment(object):
    def __init__(self):
        self.stop = False
        logging.basicConfig()
        self.logger = logging.getLogger("MMNT")
        if DEBUG:
            self.logger.setLevel(logging.DEBUG)
        else:
            self.logger.setLevel(logging.INFO)
        self.logger.info("Initializing")

        self.masterSampleTime = time.time()
        self.slaveSampleTime = time.time()

        self.humanSampleTime = time.time()
        self.micSampleTime = time.time()

        self.logger.debug("Initializing motor control")
        self.mc = MotorControl()
        self.mc.resetMotors()

        self.logger.debug("Initializing microphone")
        dev = usb.core.find(idVendor=0x2886, idProduct=0x0018)
        if not dev:
            sys.exit("Could not find ReSpeaker Mic Array through USB")
        self.mic = Tuning(dev)
        self.mic.write("NONSTATNOISEONOFF", 1)
        self.mic.write("STATNOISEONOFF", 1)
        self.mic.write("ECHOONOFF", 1)

        self.logger.debug("Initializing video streams")
        self.topCamStream = VideoStream(1)
        self.botCamStream = VideoStream(2)

        self.logger.debug("Initializing models")
        self.ht_model = ht.get_model()
        self.tfPose = TfPoseEstimator(get_graph_path(TF_MODEL),
                                      target_size=(VideoStream.DEFAULT_WIDTH,
                                                   VideoStream.DEFAULT_HEIGHT))
        self.logger.info("Initialization complete")

        self.topCamState = State.IDLE
        self.botCamState = State.IDLE

        self.topCamAngle = 0
        self.topAngleUpdated = False
        self.botCamAngle = 180
        self.botAngleUpdated = False
        self.master = Cams.TOP
        self.lastMaster = Cams.TOP

        self.botCamProc = None
        self.topCamProc = None

        self.audioMap = Map(15)
        self.checkMic()

    def stop(self):
        self.stop = True

    def updateTopAngle(self, angle):
        if abs(angle - self.topCamAngle) > ANGLE_THRESHOLD and abs(
                angle - self.botCamAngle) > OVERLAP_THRESHOLD:
            self.topCamAngle = angle
            self.topAngleUpdated = True

    def updateBotAngle(self, angle):
        if abs(angle - self.botCamAngle) > ANGLE_THRESHOLD and abs(
                angle - self.topCamAngle) > OVERLAP_THRESHOLD:
            self.botCamAngle = angle
            self.botAngleUpdated = True

    def updatePositions(self):
        # Send Serial Commands
        if self.topAngleUpdated and self.botAngleUpdated:
            self.logger.debug("Top Angle: {}".format(self.topCamAngle))
            self.logger.debug("Bot Angle: {}".format(self.botCamAngle))
            self.topAngleUpdated = False
            self.botAngleUpdated = False
            self.mc.runMotors(self.topCamAngle, self.botCamAngle)
        elif self.topAngleUpdated:
            self.logger.debug("Top Angle: {}".format(self.topCamAngle))
            self.topAngleUpdated = False
            self.mc.runTopMotor(self.topCamAngle)
        elif self.botAngleUpdated:
            self.logger.debug("Bot Angle: {}".format(self.botCamAngle))
            self.botAngleUpdated = False
            self.mc.runBotMotor(self.botCamAngle)

    def isWithinNoiseFov(self, angle):
        topDiff = abs(angle - self.topCamAngle)
        botDiff = abs(angle - self.botCamAngle)

        if topDiff < NOISE_ANGLE_THRESHOLD:
            self.topCamState |= State.NOISE
            if self.topCamState == State.BOTH:
                self.master = Cams.TOP
            return True
        else:
            self.topCamState &= ~State.NOISE
        if botDiff < NOISE_ANGLE_THRESHOLD:
            self.botCamState |= State.NOISE
            if self.botCamState == State.BOTH:
                self.master = Cams.BOT
            return True
        else:
            self.botCamState &= ~State.NOISE

        return False

    def checkMic(self):
        speechDetected, micDOA = self.mic.speech_detected(), self.mic.direction
        if not speechDetected:
            # self.audioMap.update_map_with_no_noise()
            self.topCamState &= ~State.NOISE
            self.botCamState &= ~State.NOISE
            return
        self.logger.debug("speech detected from {}".format(micDOA))
        self.audioMap.update_map_with_noise(micDOA)

        primaryMicDOA, secondaryMicDOA = self.audioMap.get_POI_location()
        if DEBUG:
            self.audioMap.print_map()
        if primaryMicDOA == -1:
            self.logger.debug("no good audio source")
            return

        self.logger.debug("mapped audio from {}".format(primaryMicDOA))

        # Check if camera is already looking at the primary noise source
        if self.isWithinNoiseFov(primaryMicDOA):
            # If camera is already looking, check the secondary noise source
            if secondaryMicDOA == -1:
                self.logger.debug("no good secondary audio source")
                return
            elif self.isWithinNoiseFov(secondaryMicDOA):
                return
            else:
                micDOA = secondaryMicDOA
        else:
            micDOA = primaryMicDOA

        topDiff = abs(micDOA - self.topCamAngle)
        botDiff = abs(micDOA - self.botCamAngle)

        # Camera is NOT looking at the noise source at this point
        # If both Cameras are not tracking a human,
        # move the closest camera
        if self.topCamState < State.HUMAN and self.botCamState < State.HUMAN:
            if botDiff < topDiff:
                self.botCamState |= State.NOISE
                self.updateBotAngle(micDOA)
                if self.botCamState == State.IDLE:
                    self.master = Cams.TOP
            else:
                self.topCamState |= State.NOISE
                self.updateTopAngle(micDOA)
                if self.topCamState == State.IDLE:
                    self.master = Cams.BOT
        # One of the cameras are on a human, if the other camera is not on a human, move it
        elif self.topCamState < State.HUMAN:
            self.topCamState |= State.NOISE
            self.updateTopAngle(micDOA)
            self.master = Cams.BOT
        elif self.botCamState < State.HUMAN:
            self.botCamState |= State.NOISE
            self.updateBotAngle(micDOA)
            self.master = Cams.TOP
        # The cameras are on a human
        else:
            # If both are on a human, move the one that's not master
            if self.topCamState == State.HUMAN and self.botCamState == State.HUMAN:
                if self.master != Cams.BOT:
                    self.botCamState |= State.NOISE
                    self.updateBotAngle(micDOA)
                else:
                    self.topCamState |= State.NOISE
                    self.updateTopAngle(micDOA)
            # One of the cameras are on a HUMAN+NOISE, move the one that's not only on a HUMAN
            elif self.topCamState == State.HUMAN:
                self.topCamState |= State.NOISE
                self.updateTopAngle(micDOA)
                self.master = Cams.BOT
            elif self.botCamState == State.HUMAN:
                self.botCamState |= State.NOISE
                self.updateBotAngle(micDOA)
                self.master = Cams.TOP

    def getBestFace(self, humans):
        midX = -1
        bestHuman = humans[0]
        maxScore = 0
        for human in humans:
            gotMidX = False
            score = 0
            currMidX = -1
            for part in headParts:
                if part in human.body_parts:
                    score += human.body_parts[part].score
                    if not gotMidX:
                        currMidX = human.body_parts[
                            part].x * VideoStream.DEFAULT_WIDTH
                        gotMidX = True
            if score > maxScore:
                maxScore = score
                midX = currMidX
                bestHuman = human

        return bestHuman, midX

    def checkHumans(self, frame, camera):
        humans = self.tfPose.inference(frame,
                                       resize_to_default=True,
                                       upsample_size=RESIZE_RATIO)
        if len(humans):
            if camera == Cams.TOP:
                self.topCamState |= State.HUMAN
                if self.topCamState == State.BOTH:
                    self.master = Cams.TOP
            else:
                self.botCamState |= State.HUMAN
                if self.botCamState == State.BOTH:
                    self.master = Cams.BOT

            if DISPLAY_VIDEO and DRAW_ON_FRAME:
                TfPoseEstimator.draw_humans(frame, humans, imgcopy=False)
            human, midX = self.getBestFace(humans)

            if (ht.is_hands_above_head(human)):
                self.logger.debug("HANDS ABOVE HEAD!!!")

            if midX != -1:
                centerDiff = abs(midX - VideoStream.DEFAULT_WIDTH / 2)
                if centerDiff > FACE_THRESHOLD:
                    if midX < VideoStream.DEFAULT_WIDTH / 2:
                        # rotate CCW
                        if camera == Cams.TOP:
                            self.updateTopAngle(
                                (self.topCamAngle +
                                 centerDiff * degreePerPixel) % 360)
                        else:
                            self.updateBotAngle(
                                (self.botCamAngle +
                                 centerDiff * degreePerPixel) % 360)
                    elif midX > VideoStream.DEFAULT_WIDTH / 2:
                        # rotate CW
                        if camera == Cams.TOP:
                            self.updateTopAngle(
                                (self.topCamAngle -
                                 centerDiff * degreePerPixel) % 360)
                        else:
                            self.updateBotAngle(
                                (self.botCamAngle -
                                 centerDiff * degreePerPixel) % 360)
        else:
            if camera == Cams.TOP:
                self.topCamState &= ~State.HUMAN
            else:
                self.botCamState &= ~State.HUMAN
        return frame

    def playVideo(self, cam):
        if cam == Cams.TOP:
            if self.botCamProc is not None and self.botCamProc.poll(
            ) is not None:
                self.botCamProc.kill()
            self.topCamProc = subprocess.Popen(
                "ffmpeg -f v4l2 -i /dev/video3 -f v4l2 /dev/video5",
                shell=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL)
        elif cam == Cams.BOT:
            if self.topCamProc is not None and self.topCamProc.poll(
            ) is not None:
                self.topCamProc.kill()
            self.botCamProc = subprocess.Popen(
                "ffmpeg -f v4l2 -i /dev/video4 -f v4l2 /dev/video5",
                shell=True,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL)

    def start(self):
        Thread(target=self.run, args=()).start()

    def run(self):
        self.stop = False
        while not self.stop:
            try:
                topFrame = self.topCamStream.read()
                botFrame = self.botCamStream.read()
                if time.time() - self.humanSampleTime > HUMAN_SAMPLE_FREQ:
                    if topFrame is not None:
                        topFrame = self.checkHumans(topFrame, Cams.TOP)
                    if botFrame is not None:
                        botFrame = self.checkHumans(botFrame, Cams.BOT)
                    self.humanSampleTime = time.time()

                if time.time() - self.micSampleTime > MIC_SAMPLE_FREQ:
                    self.checkMic()
                    self.micSampleTime = time.time()

                self.updatePositions()

                # if DISPLAY_VIDEO and topFrame is not None and botFrame is not None:
                #     if self.master == Cams.TOP:
                #         if topFrame is not None:
                #             cv.imshow('Master', topFrame)
                #         if botFrame is not None:
                #             cv.imshow('Slave', botFrame)
                #     else:
                #         if botFrame is not None:
                #             cv.imshow('Master', botFrame)
                #         if topFrame is not None:
                #             cv.imshow('Slave', topFrame)
                #     if cv.waitKey(1) == 27:
                #         pass
                if DISPLAY_VIDEO and topFrame is not None and botFrame is not None:
                    if self.master == Cams.TOP:
                        top_master = np.concatenate((topFrame, botFrame),
                                                    axis=1)
                        cv.imshow('Master + Slave', top_master)
                    else:
                        bot_master = np.concatenate((botFrame, topFrame),
                                                    axis=1)
                        cv.imshow('Master + Slave', bot_master)
                    if cv.waitKey(1) == 27:
                        pass

            except KeyboardInterrupt:
                self.logger.debug("Keyboard interrupt! Terminating.")
                break

        self.mc.resetMotors()
Exemple #2
0
def main():
    logging.basicConfig()
    logger = logging.getLogger("MMNT")
    logger.setLevel(logging.INFO)
    logger.info("Initializing")

    masterSampleTime = time.time()
    slaveSampleTime = time.time()

    logger.debug("Initializing motor control")
    mc = MotorControl()
    mc.resetMotors()
    logger.debug("Initializing microphone")
    dev = usb.core.find(idVendor=0x2886, idProduct=0x0018)
    if not dev:
        sys.exit("Could not find ReSpeaker Mic Array through USB")
    mic = Tuning(dev)
    mic.write("NONSTATNOISEONOFF", 1)
    mic.write("STATNOISEONOFF", 1)

    logger.debug("Initializing models")
    ht_model = ht.get_model()
    tfPose = TfPoseEstimator(get_graph_path(TF_MODEL), target_size=(VideoStream.DEFAULT_WIDTH, VideoStream.DEFAULT_HEIGHT))

    logger.debug("Initializing video streams")
    topCamStream = VideoStream(1)
    botCamStream = VideoStream(2)

    topCamStream.start()
    botCamStream.start()


    masterCamID = TOP_CAM_ID
    masterStream = topCamStream
    slaveCamID = BOT_CAM_ID
    slaveStream = botCamStream

    masterTargetAngle = 0
    slaveTargetAngle = 180

    updateMasterAngle = False
    updateSlaveAngle = False

    masterTracking = False

    logger.info("Initialization complete")
    while True:
        try:
            # MASTER
            masterFrame = masterStream.read()
            if time.time() - masterSampleTime > MASTER_SAMPLE_FREQ:
                humans = tfPose.inference(masterFrame, resize_to_default=True, upsample_size=RESIZE_RATIO)
                if len(humans):
                    logger.debug("Master tracking")
                    masterTracking = True
                    if DISPLAY_VIDEO:
                        TfPoseEstimator.draw_humans(masterFrame, humans, imgcopy=False)
                    human = humans[0]
                    if (ht.is_hands_above_head(human)):
                        logger.debug("HANDS ABOVE HEAD!!!")
                    midX = -1
                    for part in headParts:
                        if part in human.body_parts:
                            midX = human.body_parts[part].x * VideoStream.DEFAULT_WIDTH
                            break
                    if midX != -1:
                        centerDiff = abs(midX - VideoStream.DEFAULT_WIDTH/2)
                        if centerDiff > FACE_THRESHOLD:
                            if midX < VideoStream.DEFAULT_WIDTH/2:
                                # rotate CCW
                                masterTargetAngle += centerDiff * degreePerPixel
                            elif midX > VideoStream.DEFAULT_WIDTH/2:
                                # rotate CW
                                masterTargetAngle -= centerDiff * degreePerPixel

                            masterTargetAngle = masterTargetAngle % 360
                            updateMasterAngle = True
                            masterSampleTime = time.time()
                else:
                    logger.debug("Master stopped tracking")
                    masterTracking = False

                # If master is not tracking a human, move towards speech
                if not masterTracking:
                    speechDetected, micDOA = mic.speech_detected(), mic.direction
                    logger.debug("master speech detected:", speechDetected, "diff:", abs(micDOA - masterTargetAngle))
                    if speechDetected and abs(micDOA - masterTargetAngle) > ANGLE_THRESHOLD:
                        masterTargetAngle = micDOA
                        logger.debug("Update master angle:", masterTargetAngle)
                        masterSampleTime = time.time()
                        updateMasterAngle = True

            # SLAVE
            slaveFrame = slaveStream.read()
            if time.time() - slaveSampleTime > SLAVE_SAMPLE_FREQ:
                # If master is not tracking a human and a slave sees a human, move master to the visible human and move slave away
                if not masterTracking and time.time() - masterSampleTime > MASTER_SAMPLE_FREQ:
                    humans = tfPose.inference(slaveFrame, resize_to_default=True, upsample_size=RESIZE_RATIO)
                    if len(humans):
                        logger.debug("slave found mans")
                        if DISPLAY_VIDEO:
                            TfPoseEstimator.draw_humans(slaveFrame, humans, imgcopy=False)
                        human = humans[0]
                        if (ht.is_hands_above_head(human)):
                            logger.debug("HANDS ABOVE HEAD!!!")
                        midX = -1
                        for part in headParts:
                            if part in human.body_parts:
                                midX = human.body_parts[part].x * VideoStream.DEFAULT_WIDTH
                                break
                        if midX != -1:
                            centerDiff = abs(midX - VideoStream.DEFAULT_WIDTH/2)
                            # if centerDiff > FACE_THRESHOLD:
                            if midX < VideoStream.DEFAULT_WIDTH/2:
                                # rotate CCW
                                masterTargetAngle = slaveTargetAngle + centerDiff * degreePerPixel
                            elif midX > VideoStream.DEFAULT_WIDTH/2:
                                # rotate CW
                                masterTargetAngle = slaveTargetAngle - centerDiff * degreePerPixel

                            masterTargetAngle = masterTargetAngle % 360
                            updateMasterAngle = True
                            masterSampleTime = time.time()
                            slaveTargetAngle = (masterTargetAngle + 180) % 360
                            updateSlaveAngle = True
                            logger.debug("Moving master to slave:", masterTargetAngle)

                speechDetected, micDOA = mic.speech_detected(), mic.direction
                speechMasterDiff = abs(micDOA - masterTargetAngle)
                if speechDetected and speechMasterDiff > SLAVE_MASTER_THRESHOLD and abs(micDOA - slaveTargetAngle) > ANGLE_THRESHOLD:
                    slaveTargetAngle = micDOA
                    logger.debug("Update slave angle:", slaveTargetAngle)
                    slaveSampleTime = time.time()
                    updateSlaveAngle = True


            # Send Serial Commands
            if updateSlaveAngle and updateMasterAngle:
                logger.debug("Slave Angle:", slaveTargetAngle)
                logger.debug("Master Angle:", masterTargetAngle)
                updateSlaveAngle = False
                updateMasterAngle = False
                if slaveCamID == BOT_CAM_ID:
                    mc.runMotors(masterTargetAngle, slaveTargetAngle)
                else:
                    mc.runMotors(slaveTargetAngle, masterTargetAngle)
            elif updateSlaveAngle:
                mc.runMotor(slaveCamID, slaveTargetAngle)
                logger.debug("Slave Angle:", slaveTargetAngle)
                updateSlaveAngle = False
            elif updateMasterAngle:
                mc.runMotor(masterCamID, masterTargetAngle)
                logger.debug("Master Angle:", masterTargetAngle)
                updateMasterAngle = False

            if DISPLAY_VIDEO:
                cv.imshow('Master Camera', masterFrame)
                cv.imshow('Slave Camera', slaveFrame)
                if cv.waitKey(1) == 27:
                    pass

        except KeyboardInterrupt:
            logger.debug("Keyboard interrupt! Terminating.")
            mc.stopMotors()
            slaveStream.stop()
            masterStream.stop()
            mic.close()
            time.sleep(2)
            break

    cv.destroyAllWindows()