Beispiel #1
0
class VideoProcessor:
    """
    Class to help with processing a video
    """
    def __init__(self, input_file, output_file, image_size, debug=False):
        """
        Creates the processor
        :param input_file: the input video file name
        :param output_file: the output video file name
        :param image_size: the image size of the video
        :param debug: set to True to get debug output

        Use VideoProcessor:process to start processing
        """
        self.input_file = input_file
        self.output_file = output_file
        self.lane = Lane()
        self.image_size = image_size
        self.calibration = self.create_camera_calibration()
        self.transform = self.create_transform(self.image_size)
        self.debug = debug

    @staticmethod
    def create_camera_calibration():
        return CameraCalibration.default()

    @staticmethod
    def create_transform(image_size):
        height = image_size[0]
        width = image_size[1]
        return PerspectiveTransform.default(height, width)

    def process(self, sub_clip=None):
        """
        Process the video clip
        :param sub_clip: optionally specify a sub clip (start, end)
        :return: None
        """
        clip = VideoFileClip(self.input_file)
        if sub_clip:
            clip = clip.subclip(sub_clip[0], sub_clip[1])
        out_clip = clip.fl(lambda gf, t: self._process_image(gf(t), t))
        out_clip.write_videofile(self.output_file, audio=False)

    def scale_image(self, image, scale_factor=3):
        return cv2.resize(image,
                          dsize=(self.image_size[1] // scale_factor,
                                 self.image_size[0] // scale_factor),
                          interpolation=cv2.INTER_CUBIC)

    def create_birds_eye_view(self, warped_image):
        """
        Create a image of the birds-eye view projection
        :param warped_image: warped binary image
        :return: RGB scaled image
        """

        # Stack the binary image and expand the color range
        warped_image = np.dstack(
            (warped_image, warped_image, warped_image)) * 255
        overlay_large = self.lane.overlay(warped_image,
                                          draw_lines=True,
                                          fill_lane=False)

        # Resize
        return self.scale_image(overlay_large)

    @staticmethod
    def add_image_overlay(image, overlay, offset=(0, 0)):
        y_offset = offset[0]
        x_offset = offset[1]
        image[y_offset:y_offset + overlay.shape[0],
              x_offset:x_offset + overlay.shape[1]] = overlay
        return image

    def _process_image(self, org_image, t):
        # Create the warped binary image (birds-eye view with lane lines highlighted)
        undistorted_image = self.calibration.undistort(np.copy(org_image))
        warped_image = self.transform.transform(undistorted_image)
        warped_image, _ = threshold(warped_image, stack=False)

        # Update our lane tracker
        updated = self.lane.update(warped_image=warped_image)
        if self.debug and updated:
            # output the image for analysis
            bgr_image = cv2.cvtColor(org_image, cv2.COLOR_RGB2BGR)
            cv2.imwrite(
                'output_videos/invalid_frame_{:.3f}_original.png'.format(t),
                bgr_image)
            polygonned = cv2.polylines(np.copy(bgr_image),
                                       [np.int32(self.transform.src)],
                                       False,
                                       color=255,
                                       thickness=1)
            cv2.imwrite(
                'output_videos/invalid_frame_{:.3f}_framed.png'.format(t),
                polygonned)
            cv2.imwrite(
                'output_videos/invalid_frame_{:.3f}_warped.png'.format(t),
                np.dstack((warped_image, warped_image, warped_image)) * 255)

        # Add the lane overlay to our original image
        org_image = self.lane.overlay(org_image,
                                      transform=self.transform.invert())
        self.lane.overlay_text(org_image)

        # Create picture-in-picture overlays
        birds_eye_overlay = self.create_birds_eye_view(warped_image)
        binary_overlay = self.scale_image(
            np.dstack((warped_image, warped_image, warped_image)) * 255)

        # Overlay picture-in-picture style on original
        self.add_image_overlay(org_image, binary_overlay)
        self.add_image_overlay(org_image,
                               birds_eye_overlay,
                               offset=(0, org_image.shape[1] -
                                       birds_eye_overlay.shape[1]))

        return org_image