예제 #1
0
    def test(self):
        resetAutonomousDb()
        
        rest = ImagingInterface(isManual=False)
        # table should be empty
        self.assertIsNone(rest.getNextCroppedImage())

        # push image into the table so that we can get it
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        cropId = int(resp.headers['X-Crop-Id'])

        # post a second image so we can confirm it gets the first posted one first
        resp = rest.postCroppedImage(ret[1], ret[0], [33, 33], [789, 789])
        cropId2 = int(resp.headers['X-Crop-Id'])

        self.assertNotEqual(cropId, cropId2)

        result = rest.getNextCroppedImage()
        self.assertIsNotNone(result)
        self.assertIsNotNone(result[0])
        self.assertEqual(result[1], cropId)

        result = rest.getNextCroppedImage()
        self.assertIsNotNone(result)
        self.assertIsNotNone(result[0])
        self.assertEqual(result[1], cropId2)
예제 #2
0
    def test(self):
        resetDb()
        rest = ImagingInterface(isManual=False)

        # empty table
        self.assertIsNone(rest.getAllSubmittedTargets())

        # create one target
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId = int(resp.headers['X-Crop-Id'])
        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = int(resp.headers['X-Class-Id'])
        modelResult = rest.getClassById(classId)
        self.assertIsNotNone(modelResult)
        targetId = modelResult.target

        # post a second crop and classification which goes to a different target:
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId2 = int(resp.headers['X-Crop-Id'])
        # since it's shape is different, this should be a different target
        classToPost = Classification(cropId2, 'standard', 'NE', 'square',
                                     'orange', 'T', 'black')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId2 = int(resp.headers['X-Class-Id'])
        modelResult = rest.getClassById(classId2)
        self.assertIsNotNone(modelResult)
        targetId2 = modelResult.target

        self.assertNotEqual(targetId, targetId2)

        self.assertIsNotNone(rest.postSubmitAllTargets())

        resp = rest.getAllSubmittedTargets()
        self.assertIsNotNone(resp)
        self.assertEqual(len(resp), 2)

        if resp[0].target == targetId:
            self.assertEqual(resp[0].crop_id, cropId)
            self.assertEqual(resp[1].crop_id, cropId2)
        elif resp[0].target == targetId2:
            self.assertEqual(resp[0].crop_id, cropId2)
        else:
            self.fail(
                msg=
                "errrmmm. One of the returned target ids does not match what we submitted"
            )
예제 #3
0
    def test(self):
        resetManualDb()

        rest = ImagingInterface()
        ret = rest.getNextRawImage()

        self.assertIsNotNone(ret)
        self.assertEqual(len(ret), 2)
        self.assertIsNotNone(ret[0])
        self.assertIsNotNone(ret[1])
        self.assertIsNotNone(ret[0].size)  # (width, height) of image

        self.assertNotEqual(id, -1)
예제 #4
0
    def test(self):
        resetManualDb()

        rest = ImagingInterface()
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)

        resp = rest.postCroppedImage(ret[1], ret[0], [0, 0], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code, 200)  # assert successful post

        cropId = int(resp.headers['X-Crop-Id'])
        self.assertIsNotNone(cropId)
        self.assertNotEqual(cropId, -1)
예제 #5
0
    def test(self):
        resetManualDb()

        rest = ImagingInterface()
        # table should be empty
        self.assertIsNone(rest.getCroppedImage(100))

        # push image into the table so that we can get it
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        cropId = int(resp.headers['X-Crop-Id'])

        resp = rest.getCroppedImage(cropId)
        self.assertIsNotNone(resp)
        self.assertIsNotNone(resp[0])
        self.assertEqual(resp[1], cropId)
    def test(self):
        resetDb()

        rest = ImagingInterface()
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)

        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped

        _, cropId, _ = rest.getNextCroppedImage(
        )  # get the cropId as they would in the gui

        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')

        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = resp.headers['X-Class-Id']
        self.assertIsNotNone(classId)
        self.assertNotEqual(int(classId), -1)

        # should fail to update stuff that doesn't exist
        stuffToUpdate = Classification(None, None, "SE", "square", None, "Y",
                                       "purple")
        self.assertIsNone(rest.updateClass(int(classId) + 20, stuffToUpdate))

        resp = rest.updateClass(classId, stuffToUpdate)

        # confirm update claims success
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code, 200)

        # confirm update was acutlaly successful
        updated = rest.getClassById(classId)
        self.assertIsNotNone(updated)
        self.assertEqual(updated.crop_id, cropId)
        self.assertEqual(updated.type, 'standard')
        self.assertEqual(updated.orientation, 'SE')
        self.assertEqual(updated.shape, 'square')
        self.assertEqual(updated.background_color, 'white')
        self.assertEqual(updated.alphanumeric, "Y")
        self.assertEqual(updated.alphanumeric_color, "purple")
예제 #7
0
    def test(self):
        resetDb()

        rest = ImagingInterface()

        # empty table
        self.assertIsNone(rest.getSubmittedTargetById(100))

        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId = int(resp.headers['X-Crop-Id'])
        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = int(resp.headers['X-Class-Id'])
        modelResult = rest.getClassById(classId)
        self.assertIsNotNone(modelResult)
        targetId = modelResult.target

        # should still be none since the target is unsubmitted
        self.assertIsNone(rest.getSubmittedTargetById(targetId))

        # submit the target
        resp = rest.postSubmitTargetById(targetId)
        self.assertIsNotNone(resp)

        # now lets see if the getter works:
        resp = rest.getSubmittedTargetById(targetId)
        self.assertIsNotNone(resp)
        self.assertIsInstance(resp, Classification)
        self.assertEqual(resp.target, targetId)
        self.assertEqual(resp.crop_id, cropId)
        self.assertEqual(resp.type, 'standard')
        self.assertEqual(resp.shape, 'circle')
        self.assertEqual(resp.orientation, 'NE')
        self.assertEqual(resp.background_color, 'white')
        self.assertEqual(resp.alphanumeric, 'T')
        self.assertEqual(resp.alphanumeric_color, 'yellow')
        self.assertEqual(resp.submitted, 'pending')
예제 #8
0
    def test(self):
        resetDb()

        rest = ImagingInterface()

        # should get none when we try and post on empty table
        self.assertIsNone(rest.postSubmitTargetById(100))

        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId = int(resp.headers['X-Crop-Id'])
        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = int(resp.headers['X-Class-Id'])
        modelResult = rest.getClassById(classId)
        self.assertIsNotNone(modelResult)
        targetId = modelResult.target

        # trying to submit an id that doesn't exist should also fail
        self.assertIsNone(rest.postSubmitTargetById(targetId + 20))

        resp = rest.postSubmitTargetById(targetId)
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code, 200)

        # confirm that the classification's status has changed to submitted
        modelResult = rest.getClassById(classId)
        self.assertIsNotNone(modelResult)
        self.assertIsNotNone(modelResult.target)
        self.assertEqual(modelResult.submitted, 'submitted')

        # trying to submit the same target again should fail:
        self.assertIsNone(rest.postSubmitTargetById(targetId))
    def test(self):
        resetDb()

        rest = ImagingInterface()
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)

        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped

        _, cropId, _ = rest.getNextCroppedImage(
        )  # get the cropId as they would in the gui

        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')

        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = resp.headers['X-Class-Id']
        self.assertIsNotNone(classId)
        self.assertNotEqual(int(classId), -1)
예제 #10
0
    def test(self):
        resetManualDb()

        rest = ImagingInterface()
        # table should be empty
        self.assertIsNone(rest.getCroppedImageInfo(100))

        # push image into the table so that we can get it
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        cropId = int(resp.headers['X-Crop-Id'])
        # post a second image just for funnsies
        resp = rest.postCroppedImage(ret[1], ret[0], [33, 33], [789, 789])
        cropId2 = int(resp.headers['X-Crop-Id'])

        resp = rest.getAllCroppedInfo()
        self.assertIsNotNone(resp)
        # verify the returned data is what we put in
        self.assertEqual(len(resp), 2)

        modelA = resp[0]
        modelB = resp[1]
        if modelA.cropId == cropId:
            self.assertEqual(modelA.imgId, ret[1])  #image_id
            self.assertTrue(hasattr(modelA, 'path'))
            self.assertTrue(hasattr(modelA, 'time_stamp'))
            self.assertEqual(modelA.tl[0], 22)
            self.assertEqual(modelA.tl[1], 22)
            self.assertEqual(modelA.br[0], 236)
            self.assertEqual(modelA.br[1], 236)
            self.assertFalse(modelA.isTapped)

            # check model B
            self.assertEqual(modelB.imgId, ret[1])  #image_id
            self.assertTrue(hasattr(modelB, 'path'))
            self.assertTrue(hasattr(modelB, 'time_stamp'))
            self.assertEqual(modelB.tl[0], 33)
            self.assertEqual(modelB.tl[1], 33)
            self.assertEqual(modelB.br[0], 789)
            self.assertEqual(modelB.br[1], 789)
            self.assertFalse(modelB.isTapped)
        elif modelA.cropId == cropId2:
            self.assertEqual(modelA.imgId, ret[1])  #image_id
            self.assertTrue(hasattr(modelA, 'path'))
            self.assertTrue(hasattr(modelA, 'time_stamp'))
            self.assertEqual(modelA.tl[0], 33)
            self.assertEqual(modelA.tl[1], 33)
            self.assertEqual(modelA.br[0], 789)
            self.assertEqual(modelA.br[1], 789)
            self.assertFalse(modelA.isTapped)

            #check model b
            self.assertEqual(modelB.imgId, ret[1])  #image_id
            self.assertTrue(hasattr(modelB, 'path'))
            self.assertTrue(hasattr(modelB, 'time_stamp'))
            self.assertEqual(modelB.tl[0], 22)
            self.assertEqual(modelB.tl[1], 22)
            self.assertEqual(modelB.br[0], 236)
            self.assertEqual(modelB.br[1], 236)
            self.assertFalse(modelB.isTapped)
        else:
            self.fail()
예제 #11
0
    def test(self):
        resetDb()

        rest = ImagingInterface()

        # should get none if classification/pend list is empty:
        self.assertIsNone(rest.getPendingSubmissions())

        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)

        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped

        cropId = int(resp.headers['X-Crop-Id'])
        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = resp.headers['X-Class-Id']

        resp = rest.getPendingSubmissions()
        self.assertIsNotNone(resp)
        self.assertEqual(len(resp), 1)
        self.assertEqual(len(resp[0]), 1)
        self.assertEqual(resp[0][0].class_id, int(classId))
        self.assertEqual(resp[0][0].crop_id, int(cropId))

        # post a second crop and classification which goes to a different target:
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId2 = int(resp.headers['X-Crop-Id'])
        # since it's shape is different, this should be a different target
        classToPost = Classification(cropId2, 'standard', 'NE', 'square',
                                     'orange', 'T', 'black')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId2 = int(resp.headers['X-Class-Id'])
        resp = rest.getPendingSubmissions()
        self.assertIsNotNone(resp)
        self.assertEqual(len(resp), 2)
        self.assertEqual(len(resp[0]), 1)
        self.assertEqual(len(resp[1]), 1)

        # post a third crop and classification which goes to one of our already existing targets
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        cropId3 = int(resp.headers['X-Crop-Id'])
        # this should be a match with target2
        classToPost = Classification(cropId3, 'standard', 'SE', 'square',
                                     'purple', 'T', 'black')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId3 = int(resp.headers['X-Class-Id'])
        self.assertNotEqual(classId2, classId3)

        resp = rest.getPendingSubmissions()
        self.assertIsNotNone(resp)
        self.assertEqual(len(resp), 2)

        if len(resp[0]) == 2:
            self.assertEqual(resp[0][1].type, 'standard')
            self.assertEqual(resp[0][1].shape, 'square')
            self.assertEqual(resp[0][0].alphanumeric, 'T')
            self.assertEqual(resp[1][0].class_id, int(classId))
            self.assertEqual(resp[1][0].crop_id, int(cropId))
        elif len(resp[1]) == 2:
            self.assertEqual(resp[0][0].class_id, int(classId))
            self.assertEqual(resp[0][0].crop_id, int(cropId))
            self.assertEqual(resp[1][1].type, 'standard')
            self.assertEqual(resp[1][1].shape, 'square')
            self.assertEqual(resp[1][0].alphanumeric, 'T')
        else:
            self.fail(msg="one of the targets should have two classifications")
    def test(self):
        resetDb()

        rest = ImagingInterface()
        ret = rest.getNextRawImage()
        self.assertIsNotNone(ret)

        # get stuff into the cropped and classification table
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        _, cropId, _ = rest.getNextCroppedImage(
        )  # get the cropId as they would in the gui
        classToPost = Classification(cropId, 'standard', 'NE', 'circle',
                                     'white', 'T', 'yellow')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId = int(resp.headers['X-Class-Id'])

        # post a second crop and classification:
        resp = rest.postCroppedImage(ret[1], ret[0], [22, 22], [236, 236])
        self.assertIsNotNone(resp)
        self.assertEqual(resp.status_code,
                         200)  # assert successful post to cropped
        _, cropId2, _ = rest.getNextCroppedImage(
        )  # get the cropId as they would in the gui
        classToPost = Classification(cropId2, 'off_axis', 'NE', 'square',
                                     'orange', 'T', 'black')
        resp = rest.postClass(classToPost)
        self.assertIsNotNone(resp)
        classId2 = int(resp.headers['X-Class-Id'])

        # get all:
        resp = rest.getAllClass()
        self.assertIsNotNone(resp)
        self.assertEqual(len(resp), 2)

        modelA = resp[0]
        modelB = resp[1]

        if modelA.class_id == classId:
            #check model A
            self.assertEqual(modelA.crop_id, cropId)
            self.assertEqual(modelA.class_id, classId)
            self.assertEqual(modelA.type, 'standard')
            self.assertEqual(modelA.orientation, 'NE')
            self.assertEqual(modelA.shape, 'circle')
            self.assertEqual(modelA.background_color, 'white')
            self.assertEqual(modelA.alphanumeric, 'T')
            self.assertEqual(modelA.alphanumeric_color, 'yellow')
            self.assertEqual(modelA.submitted, 'unsubmitted')
            self.assertEqual(modelA.description, '')
            self.assertIsNotNone(modelA.target)

            # check model B
            self.assertEqual(modelB.crop_id, cropId2)
            self.assertEqual(modelB.class_id, classId2)
            self.assertEqual(modelB.type, 'off_axis')
            self.assertEqual(modelB.orientation, 'NE')
            self.assertEqual(modelB.shape, 'square')
            self.assertEqual(modelB.background_color, 'orange')
            self.assertEqual(modelB.alphanumeric, 'T')
            self.assertEqual(modelB.alphanumeric_color, 'black')
            self.assertEqual(modelB.submitted, 'unsubmitted')
            self.assertEqual(modelB.description, '')
            self.assertIsNotNone(modelB.target)
        elif modelA.class_id == classId2:
            #check model B
            self.assertEqual(modelB.crop_id, cropId)
            self.assertEqual(modelB.class_id, classId)
            self.assertEqual(modelB.type, 'standard')
            self.assertEqual(modelB.orientation, 'NE')
            self.assertEqual(modelB.shape, 'circle')
            self.assertEqual(modelB.background_color, 'white')
            self.assertEqual(modelB.alphanumeric, 'T')
            self.assertEqual(modelB.alphanumeric_color, 'yellow')
            self.assertEqual(modelB.submitted, 'unsubmitted')
            self.assertEqual(modelB.description, '')
            self.assertIsNotNone(modelB.target)

            # check model A
            self.assertEqual(modelA.crop_id, cropId2)
            self.assertEqual(modelA.class_id, classId2)
            self.assertEqual(modelA.type, 'off_axis')
            self.assertEqual(modelA.orientation, 'NE')
            self.assertEqual(modelA.shape, 'square')
            self.assertEqual(modelA.background_color, 'orange')
            self.assertEqual(modelA.alphanumeric, 'T')
            self.assertEqual(modelA.alphanumeric_color, 'black')
            self.assertEqual(modelA.submitted, 'unsubmitted')
            self.assertEqual(modelA.description, '')
            self.assertIsNotNone(modelA.target)
        else:
            self.fail()
예제 #13
0
class AutonomousManager():
    def __init__(self,
                 serverHost,
                 serverPort,
                 detection=True,
                 classification=True,
                 img_start=None,
                 submit_interval=120,
                 show=False):
        """
            Initialize a top-level autonomous manager

            @param serverHost: Local ip address of the machine the imaging server is running on

            @param serverPort: Port the server is running on. Default 5000

            @param detection: Whether the detector should be run by this manager. Default: True

            @param classification: Whether the classifiers should be run by this manager. Default: False
        """
        print("Autonomous Startup")
        self._should_shutdown = False
        self.client = ImagingInterface(serverHost,
                                       serverPort,
                                       isDebug=False,
                                       isManual=False)

        self.submit_interval = submit_interval
        self.show = show

        # for manually specifying which image in the server to start detection on
        self.img_start = img_start
        self.img_num = img_start

        # we give the option of having a machine thats running this Manager run
        #   ONLY the detection algorithm, or ONLY the classification algorithm,
        #   or both
        self.doDetection = detection
        self.doClassification = classification
        if detection and classification:
            self.detector = AutonomousDetection()
            self.classifier = AutonomousClassification()
        elif not detection:
            print("Turning off classification for this autonomous process")
            self.detector = AutonomousDetection()
            self.doClassification = False
            self.doDetection = True
        elif not classification:
            print("Turning off detection for this autonomous process")
            self.classifier = AutonomousClassification()
            self.doDetection = False
            self.doClassification = True

        if not classification and not detection:
            print("ERROR:: Cant disable both detection and classification!")
            exit(1)

    def submitTargets(self):
        """
            submit all pending autonomous targets
        """
        print("Submitting all pending targets...")
        self.client.postSubmitAllTargets()

    def runClassification(self):
        """
            If this autonomous manager is set todo so, run classification on an available
            cropped image, if any.
        """
        toClassify = self.client.getNextCroppedImage()

        if toClassify is not None:
            imgToClassify = np.array(toClassify[0])[:, :, ::-1]
            cropId = toClassify[1]

            cropInfo = self.client.getCroppedImageInfo(cropId)
            if cropInfo is None:
                print("Failed to get cropped image info!")
                return  # couldnt get info on the cropped image? weird..

            rawInfo = self.client.getImageInfo(cropInfo.imgId)
            stateMeas = None

            if rawInfo is None:
                print(
                    "Failed to get raw image info while attempting to classify!"
                )
            else:
                # get the state measurement closest to the raw image timestamp
                stateMeas = self.client.getStateByTs(rawInfo.time_stamp)

            classified = None
            if stateMeas is not None:
                # if we were able to get a state measurement close to our raw img timestamp use it to try and decide orientation
                classified = self.classifier.classify(imgToClassify,
                                                      show=False,
                                                      yaw=stateMeas.yaw)
            else:
                # attempt to classify without orientation data
                classified = self.classifier.classify(imgToClassify,
                                                      show=False)

            # print("Crop #: %i" % (cropId))
            if self.show:
                to_display = self.classifier.blur_crop.copy()
                cv2.putText(to_display, str(cropId), (5, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1,
                            cv2.LINE_AA)
                cv2.imshow('Crop', to_display)
                key = cv2.waitKey(1) & 0xFF

            if classified is not None:
                print("Successfully classified crop {}!".format(cropId))
                print(
                    "\tshape={},letter={},shapeClr={}letterClr={},orientation={}"
                    .format(classified['shape'], classified['letter'],
                            classified['shapeColor'],
                            classified['letterColor'],
                            classified['orientation']))
                # TODO: Always assuming standard target for now..
                toPost = Classification(cropId,
                                        "standard",
                                        orientation=classified['orientation'],
                                        shape=classified['shape'],
                                        bgColor=classified['shapeColor'],
                                        alpha=classified['letter'],
                                        alphaColor=classified['letterColor'])
                self.client.postClass(toPost)

            else:
                print("Crop # %i rejected as false positive" % (cropId))

    def runDetection(self):
        """
            If this autonomous manager is set todo so, run detection on an available
            raw image, if any.

            One issue here is client_rest expects/returns a PIL image and the
            detector expects/returns an opencv image (aka numpy array). So
            this method has to deal with converting between the two
        """
        if self.img_start is not None:
            toDetect = self.client.getRawImage(
                self.img_num)  #returns None if the image id doesn't exist
            if toDetect is not None:
                self.img_num += 1
        else:
            toDetect = self.client.getNextRawImage(
            )  # returns tuple of (image, image_id)

        # if there are new raw images to process
        if toDetect is not None:
            imgToDetect = np.array(toDetect[0])[:, :, ::-1]
            imgId = toDetect[1]

            results = self.detector.detect(imgToDetect, 0)
            print('Img #: %i' % (imgId), ' Results: %i' % (len(results)))
            print(hasattr(self.detector, 'keypoints_image'))
            if self.show:  # and hasattr(self.detector, 'keypoints_image'):
                to_display = self.detector.keypoints_image.copy()
                cv2.putText(to_display, str(imgId), (10, 50),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 1,
                            cv2.LINE_AA)
                cv2.imshow('Detected', to_display)
                key = cv2.waitKey(1) & 0xFF

            # if the detector actually returned something that's not an empty list
            if results is not None and results:
                # then lets post each of its cropped images to the server
                for detectedTarget in results:
                    pilCrop = cv2.cvtColor(detectedTarget.crop,
                                           cv2.COLOR_BGR2RGB)
                    pilCrop = Image.fromarray(pilCrop)
                    self.client.postCroppedImage(imgId, pilCrop,
                                                 detectedTarget.topLeft,
                                                 detectedTarget.bottomRight)

    def run(self):
        """
        Sit and spin, checking for new images and processing them as necessary
        """

        last_submit = time.time()
        while 1:

            if not self.client.ping(
            ):  # confirm we can still connect to the server
                print("WARN:: Cannot connect to server")
                time.sleep(5)

            if self.doDetection:
                self.runDetection()

            if self.doClassification:
                self.runClassification()

                if (time.time() - last_submit) > self.submit_interval:
                    self.submitTargets()
                    last_submit = time.time()

            time.sleep(0.1)

    def shutdown(self):
        self._should_shutdown = True