示例#1
0
 def return_to_start(self):
     """Move back to starting position."""
     if self.relative_starting_position is not None:
         log('Returning to starting location...',
             message_type='info',
             title='camera-calibration')
         self._move(self.relative_starting_position)
 def find_pattern(self, img, move_back=False, save_output=None):
     """Find calibration pattern circles in single image."""
     if img is None:
         log('ERROR: Calibration failed. Image missing.',
             message_type='error', title='camera-calibration')
         self.success_flag = False
     original = img.copy()
     # first pass with basic pre-processing
     img = self.preprocess(original, basic=True)
     ret, centers = self.detect_circles(img)
     if not ret:
         # second pass with heavier pre-processing
         img = self.preprocess(original)
         ret, centers = self.detect_circles(img, downsample=True)
     if save_output is not None:
         cv2.drawChessboardCorners(img, self.pattern['size'], centers, ret)
         save_output(ret, img, original)
     if not ret and save_output is None:
         if move_back:
             self.return_to_start()
         log('ERROR: Calibration failed, calibration object not ' +
             'detected in image. Check recent photos.',
             message_type='error', title='camera-calibration')
         self.success_flag = False
     return ret, centers
示例#3
0
 def move_and_capture(self):
     """Move the bot along x and y axes, take photos, and detect circles."""
     for i, movement in enumerate(RELATIVE_MOVEMENTS):
         if i > 0:
             if self.relative_starting_position is None:
                 self.relative_starting_position = {'x': 0, 'y': 0, 'z': 0}
             log('Moving to next camera calibration photo location.',
                 message_type='info',
                 title='camera-calibration')
             self._move(movement)
             for axis in movement:
                 self.relative_starting_position[axis] -= movement[axis]
         log('Taking camera calibration photo. ({}/3)'.format(i + 1),
             message_type='info',
             title='camera-calibration')
         img_filename = self.capture()
         if USE_FARMWARE_TOOLS:
             coordinates = device.get_current_position()
             for axis, coordinate in coordinates.items():
                 coordinates[axis] = float(coordinate)
         else:
             coordinates = {'z': 0}
         img = cv2.imread(img_filename, 1)
         os.remove(img_filename)
         ret, centers = self.find_pattern(img, True)
         if not self.success_flag:
             self.save_image(img, str(i + 1))
             return self.success_flag
         self.dot_images[i]['circles'] = centers
         self.dot_images[i]['found'] = ret
         self.dot_images[i]['image'] = img
         self.dot_images[i]['coordinates'] = coordinates
     self.return_to_start()
     return self.success_flag
示例#4
0
 def move_and_capture(self):
     """Move the bot along x and y axes, take photos, and detect circles."""
     for i, move in enumerate(RELATIVE_MOVEMENTS):
         if i > 0:
             log('Moving to next camera calibration photo location.',
                 message_type='info',
                 title='camera-calibration')
             if USE_FARMWARE_TOOLS:
                 device.move_relative(move['x'], move['y'], move['z'], 100)
             else:
                 CeleryPy.move_relative((move['x'], move['y'], move['z']),
                                        speed=100)
         log('Taking camera calibration photo. ({}/3)'.format(i + 1),
             message_type='info',
             title='camera-calibration')
         img_filename = self.capture()
         if USE_FARMWARE_TOOLS:
             coordinates = device.get_current_position()
             for axis, coordinate in coordinates.items():
                 coordinates[axis] = float(coordinate)
         else:
             coordinates = {'z': 0}
         img = cv2.imread(img_filename, 1)
         os.remove(img_filename)
         ret, centers = self.find_pattern(img)
         if not self.success_flag:
             self.save_image(img, str(i + 1))
             return self.success_flag
         self.dot_images[i]['circles'] = centers
         self.dot_images[i]['found'] = ret
         self.dot_images[i]['image'] = img
         self.dot_images[i]['coordinates'] = coordinates
     return self.success_flag
示例#5
0
 def load(self, filename):
     """Load image from file."""
     self.images['original'] = cv2.imread(filename, 1)
     if self.plant_db.coordinates is None:
         self.plant_db.getcoordinates(test_coordinates=False)
     if self.plant_db.coordinates is None and self.plant_db.app:
         log("ERROR: Could not get image coordinates.",
             message_type='error', title='take-photo')
         sys.exit(0)
     if self.images['original'] is None:
         print("ERROR: Incorrect image path ({}).".format(filename))
         sys.exit(0)
     self.image_name = os.path.splitext(os.path.basename(filename))[0]
     self._prepare()
示例#6
0
 def calibration(self):
     """Determine pixel to coordinate scale and image rotation angle."""
     total_rotation_angle = 0
     warning_issued = False
     if self.debug:
         self.cparams.print_input()
     if self.calibration_params['easy_calibration']:
         from plant_detection.PatternCalibration import PatternCalibration
         pattern_calibration = PatternCalibration(self.calibration_params)
         result_flag = pattern_calibration.move_and_capture()
         if not result_flag:
             fail_flag = True
             return fail_flag
         result_flag = pattern_calibration.calibrate()
         if not result_flag:
             fail_flag = True
             return fail_flag
         self.image.images['marked'] = pattern_calibration.output_img
         self.image.grid(self)
         fail_flag = False
         return fail_flag
     for i in range(0, self.calibration_params['calibration_iters']):
         self.image.initial_processing()
         self.image.find(calibration=True)  # find objects
         # If not the last iteration, determine camera rotation angle
         if i != (self.calibration_params['calibration_iters'] - 1):
             # Check number of objects detected and notify user if needed.
             if len(self.plant_db.calibration_pixel_locations) == 0:
                 log("ERROR: Calibration failed. No objects detected.",
                     message_type='error', title='camera-calibration')
                 return True
             if self.plant_db.object_count > 2:
                 if not warning_issued:
                     log(" Warning: {} objects detected. "
                         "Exactly 2 recommended. "
                         "Incorrect results possible. Check output.".format(
                             self.plant_db.object_count),
                         message_type='warn', title='camera-calibration')
                     warning_issued = True
             if self.plant_db.object_count < 2:
                 log(" ERROR: {} objects detected. "
                     "At least 2 required. Exactly 2 recommended.".format(
                         self.plant_db.object_count),
                     message_type='error', title='camera-calibration')
                 return True
             # Use detected objects to determine required rotation angle
             self.rotationdetermination()
             if abs(self.rotationangle) > 120:
                 log(" ERROR: Excessive rotation required. "
                     "Check that the calibration objects are "
                     "parallel with the desired axis and that "
                     "they are the only two objects detected.",
                     message_type='error', title='camera-calibration')
                 return True
             self.image.rotate_main_images(self.rotationangle)
             total_rotation_angle += self.rotationangle
     self.determine_scale()
     fail_flag = self._calibration_output(total_rotation_angle)
     return fail_flag
 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)
示例#8
0
 def camera_check(self):
     """Check for camera at ports 0 and 1."""
     if not os.path.exists('/dev/video' + str(self.camera_port)):
         if not self.silent:
             print('No camera detected at video{}.'.format(
                 self.camera_port))
         self.camera_port = 1
         if not self.silent:
             print('Trying video{}...'.format(self.camera_port))
         if not os.path.exists('/dev/video' + str(self.camera_port)):
             if not self.silent:
                 print('No camera detected at video{}.'.format(
                     self.camera_port))
                 log('USB Camera not detected.',
                     message_type='error', title='take-photo')
示例#9
0
 def capture(self):
     """Take a photo."""
     WIDTH = os.getenv('take_photo_width', '640')
     HEIGHT = os.getenv('take_photo_height', '480')
     if 'NONE' in CAMERA:
         log('No camera selected. Choose a camera on the device page.',
             message_type='error',
             title='take-photo')
         self.exit()
     elif 'RPI' in CAMERA:
         # With Raspberry Pi Camera:
         image_filename = self.save(filename_only=True)
         width = min(int(WIDTH), 4056)
         height = min(int(HEIGHT), 3040)
         size = ['-w', str(width), '-h', str(height)]
         if height > 1500:
             size = ['-md', '3']
         try:
             retcode = call(['raspistill'] + size + ['-o', image_filename])
         except OSError:
             log('Raspberry Pi Camera not detected.',
                 message_type='error',
                 title='take-photo')
             self.exit()
         else:
             if retcode == 0:
                 print('Image saved: {}'.format(image_filename))
                 return image_filename
             else:
                 log('Problem getting image.',
                     message_type='error',
                     title='take-photo')
                 self.exit()
     else:  # With USB camera:
         self.camera_port = 0
         image_width = int(WIDTH)
         image_height = int(HEIGHT)
         discard_frames = 20
         self.camera_check()  # check for camera
         camera = cv2.VideoCapture(self.camera_port)
         sleep(0.1)
         try:
             camera.set(cv2.CAP_PROP_FRAME_WIDTH, image_width)
             camera.set(cv2.CAP_PROP_FRAME_HEIGHT, image_height)
         except AttributeError:
             camera.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, image_width)
             camera.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, image_height)
         for _ in range(discard_frames):
             camera.grab()
         self.ret, self.image = camera.read()
         camera.release()
         if not self.ret:
             log('Problem getting image.',
                 message_type='error',
                 title='take-photo')
             self.exit()
         self.image_captured = True
         return self.save()
示例#10
0
 def find_pattern(self, img):
     """Find calibration pattern circles in single image."""
     if img is None:
         log("ERROR: Calibration failed. Image missing.",
             message_type='error',
             title='camera-calibration')
         self.success_flag = False
     img = cv2.bitwise_not(img.copy())
     ret, centers = cv2.findCirclesGrid(img,
                                        self.pattern['size'],
                                        flags=self.pattern['type'])
     if not ret:
         log("ERROR: Calibration failed, calibration object not " +
             "detected in image. Check recent photos.",
             message_type='error',
             title='camera-calibration')
         self.success_flag = False
     return ret, centers
示例#11
0
 def capture(self):
     """Take a photo."""
     if 'NONE' in CAMERA:
         log('No camera selected. Choose a camera on the device page.',
             message_type='error',
             title='take-photo')
         sys.exit(0)
     elif 'RPI' in CAMERA:
         # With Raspberry Pi Camera:
         image_filename = self.save(filename_only=True)
         try:
             retcode = call([
                 'raspistill', '-w', '640', '-h', '480', '-o',
                 image_filename
             ])
         except OSError:
             log('Raspberry Pi Camera not detected.',
                 message_type='error',
                 title='take-photo')
             sys.exit(0)
         else:
             if retcode == 0:
                 print('Image saved: {}'.format(image_filename))
                 return image_filename
             else:
                 log('Problem getting image.',
                     message_type='error',
                     title='take-photo')
                 sys.exit(0)
     else:  # With USB camera:
         self.camera_port = 0
         # image_width = 1600
         # image_height = 1200
         discard_frames = 20
         self.camera_check()  # check for camera
         camera = cv2.VideoCapture(self.camera_port)
         sleep(0.1)
         # try:
         #     camera.set(cv2.CAP_PROP_FRAME_WIDTH, image_width)
         #     camera.set(cv2.CAP_PROP_FRAME_HEIGHT, image_height)
         # except AttributeError:
         #     camera.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, image_width)
         #     camera.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, image_height)
         for _ in range(discard_frames):
             camera.grab()
         self.ret, self.image = camera.read()
         camera.release()
         if not self.ret:
             log('Problem getting image.',
                 message_type='error',
                 title='take-photo')
             sys.exit(0)
         self.image_captured = True
         return self.save()
    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
示例#13
0
 def _calibration_output(self, total_rotation_angle):
     if self.viewoutputimage:
         self.image.images['current'] = self.image.images['marked']
         self.image.show()
     while abs(total_rotation_angle) > 360:
         if total_rotation_angle < 0:
             total_rotation_angle += 360
         else:
             total_rotation_angle -= 360
     self.calibration_params['total_rotation_angle'] = round(
         total_rotation_angle, 2)
     self.calibration_params['camera_z'] = self.plant_db.coordinates[2]
     try:
         self.calibration_params['coord_scale']  # pylint:disable=W0104
         failure_flag = False
     except KeyError:
         log("ERROR: Calibration failed.",
             message_type='error', title='camera-calibration')
         failure_flag = True
     return failure_flag
示例#14
0
 def find_pattern(self, img, move_back=False):
     """Find calibration pattern circles in single image."""
     if img is None:
         log('ERROR: Calibration failed. Image missing.',
             message_type='error',
             title='camera-calibration')
         self.success_flag = False
     img = cv2.bitwise_not(img.copy())
     img = cv2.medianBlur(img, 5)
     ret, centers = cv2.findCirclesGrid(img,
                                        self.pattern['size'],
                                        flags=self.pattern['type'])
     if not ret:
         if move_back:
             self.return_to_start()
         log('ERROR: Calibration failed, calibration object not ' +
             'detected in image. Check recent photos.',
             message_type='error',
             title='camera-calibration')
         self.success_flag = False
     return ret, centers
示例#15
0
 def capture(self):
     """Take a photo."""
     if CAMERA == 'RPI':
         # With Raspberry Pi Camera:
         image_filename = self.save(filename_only=True)
         try:
             retcode = call([
                 "raspistill", "-w", "640", "-h", "480", "-o",
                 image_filename
             ])
         except OSError:
             log("Raspberry Pi Camera not detected.",
                 message_type='error',
                 title='take-photo')
             sys.exit(0)
         else:
             if retcode == 0:
                 print("Image saved: {}".format(image_filename))
                 return image_filename
             else:
                 log("Problem getting image.",
                     message_type='error',
                     title='take-photo')
                 sys.exit(0)
     else:  # With USB camera:
         self.camera_port = 0
         # image_width = 1600
         # image_height = 1200
         discard_frames = 20
         self.camera_check()  # check for camera
         camera = cv2.VideoCapture(self.camera_port)
         sleep(0.1)
         # try:
         #     camera.set(cv2.CAP_PROP_FRAME_WIDTH, image_width)
         #     camera.set(cv2.CAP_PROP_FRAME_HEIGHT, image_height)
         # except AttributeError:
         #     camera.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, image_width)
         #     camera.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, image_height)
         for _ in range(discard_frames):
             camera.grab()
         self.ret, self.image = camera.read()
         camera.release()
         if not self.ret:
             log("Problem getting image.",
                 message_type='error',
                 title='take-photo')
             sys.exit(0)
         self.image_captured = True
         return self.save()
"""Download an image from the Web App and use it to calibrate the camera.

download the image corresponding to the ID provided and run calibration
"""

import os
import sys

sys.path.insert(1, os.path.join(sys.path[0], '..'))

from plant_detection.PlantDetection import PlantDetection
from plant_detection import ENV
from plant_detection.Log import log

if __name__ == "__main__":
    IMAGE_ID = ENV.load('CAMERA_CALIBRATION_selected_image', get_json=False)
    if IMAGE_ID is None:
        log('No image selected.',
            message_type='error',
            title='historical-camera-calibration')
        sys.exit(0)
    PD = PlantDetection(coordinates=True, app=True, app_image_id=IMAGE_ID)
    PD.calibrate()