def __init__(self, **kwargs): """Read arguments (and change settings) and initialize modules.""" # Default Data Inputs self.image = None self.plant_db = DB() # Default Parameter Inputs self.params = Parameters() self.params.add_missing_params('detect') # Load keyword argument inputs self._data_inputs(kwargs) self._parameter_inputs(kwargs) self.args = kwargs # Set remaining arguments to defaults self._set_defaults() # Changes based on inputs if self.args['calibration_img'] is not None: # self.coordinates = True self.args['coordinates'] = True if self.args['GUI']: self.args['save'] = False self.args['text_output'] = False if self.args['app']: self.args['verbose'] = False self.args['from_env_var'] = True self.plant_db.app = True # Remaining initialization self.p2c = None self.capture = Capture().capture self.final_marked_image = None self.plant_db.tmp_dir = None
def setUp(self): self.outfile = open('db_text_output_test.txt', 'w') sys.stdout = self.outfile self.db = DB() self.db.plants['known'] = [{'x': 1000, 'y': 1000, 'radius': 100}] self.db.coordinate_locations = [[1000, 1000, 75], [1000, 825, 50], [800, 1000, 50], [1090, 1000, 75], [900, 900, 50], [1000, 1150, 50], [700, 700, 0], [600, 600, 1000], [-100, -100, 10], ] self.remove = [{'radius': 50.0, 'x': 1000.0, 'y': 825.0}, {'radius': 50.0, 'x': 800.0, 'y': 1000.0}] self.safe_remove = [{'radius': 50.0, 'x': 900.0, 'y': 900.0}, {'radius': 50.0, 'x': 1000.0, 'y': 1150.0}] self.save = [{'radius': 75.0, 'x': 1000.0, 'y': 1000.0}, {'radius': 75.0, 'x': 1090.0, 'y': 1000.0}, ] self.db.identify({ 'use_bounds': True, 'min_radius': 1, 'max_radius': 100, }) self.add_point = [{'body': [{'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by'}}], 'kind': 'add_point', 'args': {'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': {'y': 825.0, 'x': 1000.0, 'z': 0}}}}, {'body': [{'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by'}}], 'kind': 'add_point', 'args': {'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': {'y': 1000.0, 'x': 800.0, 'z': 0}}}}] self.point_data = { 'pointer_type': 'Weed', 'name': 'Weed', 'x': '1000.0', 'y': '825.0', 'z': 0, 'radius': '50.0', 'plant_stage': 'pending', 'meta': { 'created_by': 'plant-detection', 'color': 'red', 'type': 'weed', 'removal_method': 'automatic', } }
def test_origin_location(self): p2c = Pixel2coord(DB()) p2c.calibration_params['image_bot_origin_location'] = [0, 0] p2c.calibration_params['center_pixel_location'] = [100, 200] p2c._block_rotations(90) self.assertEqual( p2c.calibration_params['image_bot_origin_location'], [1, 0])
def test_location_rotation(self): """Detect using different calibration object locations and rotations.""" i = 0 for flip in range(3): for angle in [-10, 10]: img = 'test_objects_{}.jpg'.format(i) i += 1 calibration_img = cv2.imread( 'plant_detection/p2c_test_calibration.jpg', 1) if flip > 1: cv2.circle(calibration_img, (465, 290), int(1000), (255, 255, 255), -1) cv2.circle(calibration_img, (172, 290), int(25), (0, 0, 255), -1) cv2.circle(calibration_img, (755, 290), int(25), (0, 0, 255), -1) elif flip: calibration_img = cv2.flip(calibration_img, 0) calibration_img = rotate(calibration_img, angle) cv2.imwrite(img, calibration_img) p2c = Pixel2coord(DB(), calibration_image=img, calibration_data=self.calibration_data) p2c.calibration() self.assertAlmostEqual( p2c.calibration_params['total_rotation_angle'], -angle, delta=1) self.assertAlmostEqual( p2c.calibration_params['coord_scale'], 1.7, delta=0.1)
def test_one_object(self): """Detect one object during calibration""" db = DB() p2c = Pixel2coord( db, calibration_image=image_file('one.jpg', self.one_object)) exit_flag = p2c.calibration() self.assertEqual(db.object_count, 1) self.assertTrue(exit_flag)
def test_zero_objects(self): """Detect zero objects during calibration""" db = DB() p2c = Pixel2coord( db, calibration_image=image_file('zero.jpg', self.zero_objects)) exit_flag = p2c.calibration() self.assertEqual(db.object_count, 0) self.assertTrue(exit_flag)
def test_three_objects(self): """Detect three objects during calibration""" db = DB() p2c = Pixel2coord( db, calibration_image=image_file('three.jpg', self.three_objects)) exit_flag = p2c.calibration() self.assertEqual(db.object_count, 3) self.assertFalse(exit_flag)
def test_orientation(self): """Detect calibration objects based on image origin. | top (0) | bottom (1) | --------- ---------- left (0) | 00 | 01 | --------- ---------- right (1) | 10 | 11 | --------- ---------- """ orientations = [[0, 0], [0, 1], [1, 0], [1, 1]] expectations = [{ "x": 1300, "y": 800 }, { "x": 1300, "y": 200 }, { "x": 300, "y": 800 }, { "x": 300, "y": 200 }] for orientation, expectation in zip(orientations, expectations): image_origin = '{} {}'.format(['top', 'bottom'][orientation[1]], ['left', 'right'][orientation[0]]) convert_to_env_var = { '[0, 0]': 'TOP_LEFT', '[1, 0]': 'TOP_RIGHT', '[0, 1]': 'BOTTOM_LEFT', '[1, 1]': 'BOTTOM_RIGHT' } os.environ[ 'CAMERA_CALIBRATION_image_bot_origin_location'] = json.dumps( convert_to_env_var[str(orientation)]) os.environ[ 'CAMERA_CALIBRATION_calibration_object_separation'] = '1000' os.environ['CAMERA_CALIBRATION_camera_offset_x'] = '200' os.environ['CAMERA_CALIBRATION_camera_offset_y'] = '100' os.environ['CAMERA_CALIBRATION_calibration_along_axis'] = 'X' p2c = Pixel2coord( DB(), calibration_image='plant_detection/p2c_test_calibration.jpg', load_data_from='env_var') p2c.calibration() p2c.image.load('single_object.jpg') coordinates = p2c.determine_coordinates() for axis in ['x', 'y']: self.assertAlmostEqual( coordinates[0][axis], expectation[axis], delta=5, msg="object {} coordinate {} != {} within 5 delta for {}" " image origin".format(axis, coordinates[0][axis], expectation[axis], image_origin))
def setUp(self): self.outfile = open('p2c_text_output_test.txt', 'w') sys.stdout = self.outfile self.db = DB() self.two_objects = cv2.imread( 'plant_detection/p2c_test_calibration.jpg', 1) self.three_objects = self.two_objects.copy() self.one_object = self.two_objects.copy() self.zero_objects = self.two_objects.copy() cv2.circle(self.zero_objects, (600, 300), int(1000), (255, 255, 255), -1) cv2.circle(self.one_object, (175, 475), int(50), (255, 255, 255), -1) cv2.circle(self.three_objects, (600, 300), int(25), (0, 0, 255), -1)
def __init__(self, farmwarename): self.farmwarename = farmwarename prefix = self.farmwarename.lower().replace('-', '_') self.input_default_speed = int(os.environ.get(prefix + "_default_speed", 800)) self.x_photo_pos = 400 self.y_photo_pos = 235 self.z_photo_pos = 0 self.image = None self.plant_db = DB() self.params = Parameters() self.plant_detection = None self.dir = os.path.dirname(os.path.realpath(__file__)) + os.sep """"self.api = API(self)
class LocationTest(unittest.TestCase): """Get the bot's location""" def setUp(self): self.coordinates = [300, 500, -100] self.test_coordinates = [600, 400, 0] self.r = fakeredis.FakeStrictRedis() self.db = DB() def test_get_coordinates(self): """Get location from redis""" self.r.set('BOT_STATUS.location_data.position.x', self.coordinates[0]) self.r.set('BOT_STATUS.location_data.position.y', self.coordinates[1]) self.r.set('BOT_STATUS.location_data.position.z', self.coordinates[2]) self.db.getcoordinates(redis=self.r) self.assertEqual(self.db.coordinates, self.coordinates) def test_partial_coordinates(self): """Coordinates aren't complete""" self.r.set('BOT_STATUS.location_data.position.x', self.coordinates[0]) self.r.set('BOT_STATUS.location_data.position.y', self.coordinates[1]) self.db.getcoordinates(redis=self.r) self.assertEqual(self.db.coordinates, self.test_coordinates) def test_no_coordinates(self): """Coordinates don't exist""" self.db.getcoordinates(redis=self.r) self.assertEqual(self.db.coordinates, self.test_coordinates) def test_not_coordinates(self): """Coordinates aren't numbers""" self.r.set('BOT_STATUS.location_data.position.x', 'text') self.r.set('BOT_STATUS.location_data.position.y', 'text') self.r.set('BOT_STATUS.location_data.position.z', 'text') self.db.getcoordinates(redis=self.r) self.assertEqual(self.db.coordinates, self.test_coordinates) def tearDown(self): self.r.flushall()
def setUp(self): self.parameters = Parameters() self.db = DB() self.image = Image(self.parameters, self.db)
self.image.initial_processing() self.image.find(calibration=True) self.plant_db.print_count(calibration=True) # print detected obj count self.p2c(self.plant_db) self.plant_db.print_coordinates() if self.viewoutputimage: self.image.grid(self) self.image.images['current'] = self.image.images['marked'] self.image.show() return self.plant_db.get_json_coordinates() if __name__ == "__main__": DIR = os.path.dirname(os.path.realpath(__file__)) + os.sep print("Calibration image load...") P2C = Pixel2coord(DB(), calibration_image=DIR + "p2c_test_calibration.jpg") P2C.viewoutputimage = True # Calibration P2C.image.rotate_main_images(P2C.test_rotation) EXIT = P2C.calibration() if EXIT: sys.exit(0) P2C.plant_db.print_count(calibration=True) # print detected object count if P2C.calibration_params['total_rotation_angle'] != 0: print(" Note: required rotation executed = {:.2f} degrees".format( P2C.calibration_params['total_rotation_angle'])) # Tests # Object detection print("Calibration object test...") P2C.image.load(DIR + "p2c_test_objects.jpg")
class PlantDetection(object): """Detect plants in image and output an image with plants marked. Kwargs: image (str): filename of image to process (default = None) None -> take photo instead coordinates (boolean): use coordinate conversion (default = False) calibration_img (filename): calibration image filename used to output coordinates instead of pixel locations (default = None) calibration_data (dict): calibration data inputs, overwrites other calibration data inputs (default = None) known_plants (list): {'x': x, 'y': y, 'radius': radius} of known (intentional) plants (default = None) debug (boolean): output debug images (default = False) blur (int): blur kernel size (must be odd, default = 5) morph (int): amount of filtering (default = 5) iterations (int): number of morphological iterations (default = 1) array (list): list of morphs to run [morph kernel size, morph kernel type, morph type, iterations] example: [{"size": 5, "kernel": 'ellipse', "type": 'erode', "iters": 2}, {"size": 3, "kernel": 'ellipse', "type": 'dilate', "iters": 8}] (default = None) save (boolean): save images (default = True) clump_buster (boolean): attempt to break plant clusters (default = False) HSV_min (list): green lower bound Hue(0-179), Saturation(0-255), and Value(0-255) (default = [30, 20, 20]) HSV_max (list): green upper bound Hue(0-179), Saturation(0-255), and Value(0-255) (default = [90, 255, 255]) from_file (boolean): load data from file plant-detection_inputs.json plant-detection_p2c_calibration_parameters.json plant-detection_plants.json (default = False) from_env_var (boolean): load data from environment variable, overriding other parameter inputs (default = False) text_output (boolean): print text to STDOUT (default = True) verbose (boolean): print verbose text to STDOUT. otherwise, print condensed text output (default = True) print_all_json (boolean): print all JSON data used to STDOUT (default = False) grey_out (boolean): grey out regions in image that have not been selected (default = False) draw_contours (boolean): draw an outline around the boundary of detected plants (default = True) circle_plants (boolean): draw an enclosing circle around detected plants (default = True) GUI (boolean): settings for the local GUI (default = False) app (boolean): connect to the FarmBot web app (default = False) app_image_id (string): use image from the FarmBot API (default = None) Examples: PD = PlantDetection() PD.detect_plants() PD = PlantDetection( image='plant_detection/soil_image.jpg', morph=3, iterations=10, debug=True) PD.detect_plants() PD = PlantDetection( image='plant_detection/soil_image.jpg', blur=9, morph=7, iterations=4, calibration_img="plant_detection/p2c_test_calibration.jpg") PD.calibrate() PD.detect_plants() PD = PlantDetection( image='plant_detection/soil_image.jpg', blur=15, grey_out=True, array=[ {"size": 5, "kernel": 'ellipse', "type": 'erode', "iters": 2}, {"size": 3, "kernel": 'ellipse', "type": 'dilate', "iters": 8}], debug=True, clump_buster=False, HSV_min=[30, 15, 15], HSV_max=[85, 245, 245]) PD.detect_plants() """ def __init__(self, **kwargs): """Read arguments (and change settings) and initialize modules.""" # Default Data Inputs self.image = None self.plant_db = DB() # Default Parameter Inputs self.params = Parameters() self.params.add_missing_params('detect') # Load keyword argument inputs self._data_inputs(kwargs) self._parameter_inputs(kwargs) self.args = kwargs # Set remaining arguments to defaults self._set_defaults() # Changes based on inputs if self.args['calibration_img'] is not None: # self.coordinates = True self.args['coordinates'] = True if self.args['GUI']: self.args['save'] = False self.args['text_output'] = False if self.args['app']: self.args['verbose'] = False self.args['from_env_var'] = True self.plant_db.app = True # Remaining initialization self.p2c = None self.capture = Capture().capture self.final_marked_image = None self.plant_db.tmp_dir = None def _set_defaults(self): default_args = { # Default Data Inputs 'image': None, 'calibration_img': None, 'known_plants': None, 'app_image_id': None, 'calibration_data': None, # Default Program Options 'coordinates': False, 'from_file': False, 'from_env_var': False, 'clump_buster': False, 'GUI': False, 'app': False, # Default Output Options 'debug': False, 'save': True, 'text_output': True, 'verbose': True, 'print_all_json': False, 'output_celeryscript_points': False, # Default Graphic Options 'grey_out': False, 'draw_contours': True, 'circle_plants': True, # Default processing options 'array': None, 'blur': self.params.parameters['blur'], 'morph': self.params.parameters['morph'], 'iterations': self.params.parameters['iterations'], 'HSV_min': [ self.params.parameters['H'][0], self.params.parameters['S'][0], self.params.parameters['V'][0] ], 'HSV_max': [ self.params.parameters['H'][1], self.params.parameters['S'][1], self.params.parameters['V'][1] ], } for key, value in default_args.items(): if key not in self.args: self.args[key] = value def _data_inputs(self, kwargs): """Load data inputs from keyword arguments.""" for key in kwargs: if key == 'known_plants': self.plant_db.plants['known'] = kwargs[key] def _parameter_inputs(self, kwargs): """Load parameter inputs from keyword arguments.""" for key in kwargs: if key == 'blur': self.params.parameters['blur'] = kwargs[key] if key == 'morph': self.params.parameters['morph'] = kwargs[key] if key == 'iterations': self.params.parameters['iterations'] = kwargs[key] if key == 'array': self.params.array = kwargs[key] if key == 'HSV_min': hsv_min = kwargs[key] self.params.parameters['H'][0] = hsv_min[0] self.params.parameters['S'][0] = hsv_min[1] self.params.parameters['V'][0] = hsv_min[2] if key == 'HSV_max': hsv_max = kwargs[key] self.params.parameters['H'][1] = hsv_max[0] self.params.parameters['S'][1] = hsv_max[1] self.params.parameters['V'][1] = hsv_max[2] def _calibration_input(self): # provide inputs to calibration if self.args['app_image_id'] is not None: self.args['calibration_img'] = int(self.args['app_image_id']) if self.args['calibration_img'] is None and self.args['coordinates']: # Calibration requested, but no image provided. # Take a calibration image. self.args['calibration_img'] = self.capture() # Set calibration input parameters if self.args['from_env_var']: calibration_input = 'env_var' elif self.args['from_file']: # try to load from file calibration_input = 'file' else: # Use default calibration inputs calibration_input = None # Call coordinate conversion module self.p2c = Pixel2coord(self.plant_db, calibration_image=self.args['calibration_img'], calibration_data=self.args['calibration_data'], load_data_from=calibration_input) self.p2c.debug = self.args['debug'] def calibrate(self): """Calibrate the camera for plant detection. Initialize the coordinate conversion module using a calibration image, perform calibration, and save calibration data. """ self._calibration_input() # initialize coordinate conversion module exit_flag = self.p2c.calibration() # perform calibration if exit_flag: sys.exit(0) self._calibration_output() # save calibration data def _calibration_output(self): # save calibration data if self.args['save'] or self.args['debug']: self.p2c.image.images['current'] = self.p2c.image.images['marked'] self.p2c.image.save('calibration_result') # Print verbose results if self.args['verbose'] and self.args['text_output']: if self.p2c.calibration_params['total_rotation_angle'] != 0: print(" Note: required rotation of " "{:.2f} degrees executed.".format( self.p2c.calibration_params['total_rotation_angle'])) if self.args['debug']: # print number of objects detected self.plant_db.print_count(calibration=True) # print coordinate locations of calibration objects self.p2c.p2c(self.plant_db) self.plant_db.print_coordinates() print('') # Print condensed output if verbose output is not chosen if self.args['text_output'] and not self.args['verbose']: print("Calibration complete. (rotation:{}, scale:{})".format( self.p2c.calibration_params['total_rotation_angle'], self.p2c.calibration_params['coord_scale'])) # Send calibration result log toast if self.args['app']: log( 'Camera calibration complete; setting pixel coordinate scale' ' to {} and camera rotation to {} degrees.'.format( self.p2c.calibration_params['coord_scale'], self.p2c.calibration_params['total_rotation_angle']), 'success', 'Success', ['toast'], True) # Save calibration data if self.args['from_env_var']: # to environment variable self.p2c.save_calibration_data_to_env() elif self.args['from_file']: # to file self.p2c.save_calibration_parameters() else: # to Parameters() instance self.params.calibration_data = self.p2c.calibration_params def _detection_input(self): # provide input to detect_plants # Load input parameters if self.args['from_file']: # Requested to load detection parameters from file try: self.params.load('detect') except IOError: print("Warning: Input parameter file load failed. " "Using defaults.") self.plant_db.load_plants_from_file() if self.args['app']: self.plant_db.load_plants_from_web_app() if self.args['from_env_var']: # Requested to load detection parameters from json ENV variable self.params.load_env_var('detect') # Print input parameters and filename of image to process if self.args['verbose'] and self.args['text_output']: self.params.print_input() print("\nProcessing image: {}".format(self.args['image'])) def _detection_image(self): # get image to process self.image = Image(self.params, self.plant_db) # Get image to process try: # check for API image ID image_id = self.args['app_image_id'] except KeyError: image_id = None if image_id is not None: # download image try: self.image.download(image_id) except IOError: print("Image download failed for image ID {}.".format( str(image_id))) sys.exit(0) elif self.args['image'] is None: # No image provided. Capture one. self.image.capture() if self.args['debug']: self.image.save('photo') else: # Image provided. Load it. filename = self.args['image'] self.image.load(filename) self.image.debug = self.args['debug'] def _coordinate_conversion(self): # determine detected object coordinates # Load calibration data load_data_from = None calibration_data = None if self.args['from_env_var']: load_data_from = 'env_var' elif self.args['from_file']: load_data_from = 'file' else: # use data saved in self.params calibration_data = self.params.calibration_data # Initialize coordinate conversion module self.p2c = Pixel2coord(self.plant_db, load_data_from=load_data_from, calibration_data=calibration_data) self.p2c.debug = self.args['debug'] # Check for coordinate conversion calibration results present = { 'coord_scale': False, 'camera_z': False, 'center_pixel_location': False, 'total_rotation_angle': False } try: for key in present: present[key] = self.p2c.calibration_params[key] except KeyError: log( "ERROR: Coordinate conversion calibration values " "not found. Run calibration first.", message_type='error', title='plant-detection') sys.exit(0) # Validate coordinate conversion calibration data for image calibration_data_valid = self.p2c.validate_calibration_data( self.image.images['current']) if not calibration_data_valid: log( "ERROR: Coordinate conversion calibration values " "invalid for provided image.", message_type='error', title='plant-detection') sys.exit(0) # Determine object coordinates self.image.coordinates(self.p2c, draw_contours=self.args['draw_contours']) # Organize objects into plants and weeds self.plant_db.identify(self.params.parameters) if self.plant_db.plants['safe_remove']: self.image.safe_remove(self.p2c) def _coordinate_conversion_output(self): # output detected object data # Print and output results if self.args['text_output']: self.plant_db.print_count() # print number of objects detected if self.args['verbose'] and self.args['text_output']: self.plant_db.print_identified() # print organized plant data if self.args['output_celeryscript_points']: self.plant_db.output_celery_script() # print points JSON to stdout if self.args['app']: save_detected_plants = self.params.parameters[ 'save_detected_plants'] # add detected weeds and points to FarmBot Web App self.plant_db.upload_plants(save_detected_plants) if self.args['debug']: self.image.save_annotated('contours') self.image.images['current'] = self.image.images['marked'] self.image.save_annotated('coordinates_found') if self.args['circle_plants']: self.image.label(self.p2c) # mark objects with colored circles self.image.grid(self.p2c) # add coordinate grid and features def detect_plants(self): """Detect the green objects in the image.""" # Gather inputs self._detection_input() self._detection_image() # Process image in preparation for detecting plants (blur, mask, morph) self.image.initial_processing() # Optionally break up masses by splitting them into quarters if self.args['clump_buster']: self.image.clump_buster() # Optionally grey out regions not detected as objects if self.args['grey_out']: self.image.grey() # Return coordinates if requested if self.args['coordinates']: # Convert pixel locations to coordinates self._coordinate_conversion() self._coordinate_conversion_output() else: # No coordinate conversion # get pixel locations of objects self.image.find(draw_contours=self.args['draw_contours']) if self.args['circle_plants']: self.image.label() # Mark plants with red circle if self.args['debug']: self.image.save_annotated('contours') if self.args['text_output']: self.plant_db.print_count() # print number of objects detected if self.args['verbose'] and self.args['text_output']: self.plant_db.print_pixel() # print object pixel location text self.image.images['current'] = self.image.images['marked'] self._show_detection_output() # show output data self._save_detection_output() # save output data def _show_detection_output(self): # show detect_plants output # Print raw JSON to STDOUT if self.args['print_all_json']: print("\nJSON:") print(self.params.parameters) print(self.plant_db.plants) if self.p2c is not None: print(self.p2c.calibration_params) # Print condensed inputs if verbose output is not chosen if self.args['text_output'] and not self.args['verbose']: print('{}: {}'.format('known plants input', self.plant_db.plants['known'])) print('{}: {}'.format('parameters input', self.params.parameters)) print('{}: {}'.format('coordinates input', self.plant_db.coordinates)) def _save_detection_output(self): # save detect_plants output # Final marked image if self.args['save'] or self.args['debug']: self.image.save('marked') elif self.args['GUI']: self.final_marked_image = self.image.images['marked'] # Save input parameters if self.args['from_env_var']: # to environment variable self.params.save_to_env_var('detect') elif self.args['save']: # to file self.params.save() elif self.args['GUI']: # to file for GUI self.params.save() # Save plants if self.args['save']: self.plant_db.save_plants()
class DBTest(unittest.TestCase): """Check plant identification""" def setUp(self): self.outfile = open('db_text_output_test.txt', 'w') sys.stdout = self.outfile self.db = DB() self.db.plants['known'] = [{'x': 1000, 'y': 1000, 'radius': 100}] self.db.coordinate_locations = [[1000, 1000, 75], [1000, 825, 50], [800, 1000, 50], [1090, 1000, 75], [900, 900, 50], [1000, 1150, 50]] self.remove = [{ 'radius': 50.0, 'x': 1000.0, 'y': 825.0 }, { 'radius': 50.0, 'x': 800.0, 'y': 1000.0 }] self.safe_remove = [{ 'radius': 50.0, 'x': 900.0, 'y': 900.0 }, { 'radius': 50.0, 'x': 1000.0, 'y': 1150.0 }] self.save = [ { 'radius': 75.0, 'x': 1000.0, 'y': 1000.0 }, { 'radius': 75.0, 'x': 1090.0, 'y': 1000.0 }, ] self.db.identify() self.add_point = [{ 'body': [{ 'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by' } }], 'kind': 'add_point', 'args': { 'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': { 'y': 825.0, 'x': 1000.0, 'z': 0 } } } }, { 'body': [{ 'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by' } }], 'kind': 'add_point', 'args': { 'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': { 'y': 1000.0, 'x': 800.0, 'z': 0 } } } }] self.point_data = { 'pointer_type': 'Weed', 'name': 'Weed', 'x': '1000.0', 'y': '825.0', 'z': 0, 'radius': '50.0', 'plant_stage': 'pending', 'meta': { 'created_by': 'plant-detection', 'color': 'red', 'type': 'weed', 'removal_method': 'automatic', } } def test_plant_id_remove(self): """Check plants to be removed""" self.assertEqual(self.remove, self.db.plants['remove']) def test_plant_id_save(self): """Check plants to be saved""" self.assertEqual(self.save, self.db.plants['save']) def test_plant_id_safe_remove(self): """Check plants to be safely removed""" self.assertEqual(self.safe_remove, self.db.plants['safe_remove']) def test_point_data_preparation(self): """Verify point data content and format.""" self.assertEqual(self.point_data, self.db.prepare_point_data(self.remove[0], 'Weed')) def test_api_download(self): """Run (failing) plant download assuming no API_TOKEN ENV""" self.db.load_plants_from_web_app() self.assertEqual(self.db.errors, {} if USING_FT else {'401': 1}) def test_api_upload(self): """Run (failing) plant upload assuming no API_TOKEN ENV""" self.db.upload_plants() self.assertEqual(self.db.errors, {} if USING_FT else {'401': 1}) def test_print_coordinates(self): """Print unidentified plant coordinate data""" self.db.print_coordinates() self.outfile.close() self.outfile = open('db_text_output_test.txt', 'r') self.assertEqual(sum(1 for line in self.outfile), 7) def test_cs_add_point(self): """Output Celery Script add_point""" add_point = self.db.output_celery_script() self.assertEqual(add_point, self.add_point) def test_save_to_tmp(self): """Save plants to file in tmp directory""" self.db.tmp_dir = "/tmp/" self.db.save_plants() def tearDown(self): self.outfile.close() sys.stdout = sys.__stdout__ os.remove('db_text_output_test.txt')
def setUp(self): self.coordinates = [300, 500, -100] self.test_coordinates = [600, 400, 0] self.r = fakeredis.FakeStrictRedis() self.db = DB()
self.image.initial_processing() self.image.find(calibration=True) self.plant_db.print_count(calibration=True) # print detected obj count self.p2c(self.plant_db) self.plant_db.print_coordinates() if self.viewoutputimage: self.image.grid(self) self.image.images['current'] = self.image.images['marked'] self.image.show() return self.plant_db.get_json_coordinates() if __name__ == "__main__": DIR = os.path.dirname(os.path.realpath(__file__)) + os.sep print("Calibration image load...") P2C = Pixel2coord(DB(), calibration_image=DIR + "p2c_test_calibration.jpg") P2C.viewoutputimage = True # Calibration P2C.image.rotate_main_images(P2C.test_rotation) EXIT = P2C.calibration() if EXIT: sys.exit(0) P2C.plant_db.print_count(calibration=True) # print detected object count if P2C.calibration_params['total_rotation_angle'] != 0: print(" Note: required rotation executed = {:.2f} degrees".format( P2C.calibration_params['total_rotation_angle'])) # Tests # Object detection print("Calibration object test...") P2C.image.load(DIR + "p2c_test_objects.jpg") P2C.image.rotate_main_images(P2C.test_rotation)
def setUp(self): self.outfile = open('db_text_output_test.txt', 'w') sys.stdout = self.outfile self.db = DB() self.db.plants['known'] = [{'x': 1000, 'y': 1000, 'radius': 100}] self.db.coordinate_locations = [[1000, 1000, 75], [1000, 825, 50], [800, 1000, 50], [1090, 1000, 75], [900, 900, 50], [1000, 1150, 50]] self.remove = [{ 'radius': 50.0, 'x': 1000.0, 'y': 825.0 }, { 'radius': 50.0, 'x': 800.0, 'y': 1000.0 }] self.safe_remove = [{ 'radius': 50.0, 'x': 900.0, 'y': 900.0 }, { 'radius': 50.0, 'x': 1000.0, 'y': 1150.0 }] self.save = [ { 'radius': 75.0, 'x': 1000.0, 'y': 1000.0 }, { 'radius': 75.0, 'x': 1090.0, 'y': 1000.0 }, ] self.db.identify() self.add_point = [{ 'body': [{ 'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by' } }], 'kind': 'add_point', 'args': { 'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': { 'y': 825.0, 'x': 1000.0, 'z': 0 } } } }, { 'body': [{ 'kind': 'pair', 'args': { 'value': 'plant-detection', 'label': 'created_by' } }], 'kind': 'add_point', 'args': { 'radius': 50.0, 'location': { 'kind': 'coordinate', 'args': { 'y': 1000.0, 'x': 800.0, 'z': 0 } } } }] self.point_data = { "pointer_type": "GenericPointer", "name": "Weed", "x": "1000.0", "y": "825.0", "z": 0, "radius": "50.0", "meta": { "created_by": "plant-detection", "color": "red" } }