Spaces:
Running
on
Zero
Running
on
Zero
# MIT License | |
# Copyright (c) 2022 Intelligent Systems Lab Org | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# The above copyright notice and this permission notice shall be included in all | |
# copies or substantial portions of the Software. | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
# File author: Shariq Farooq Bhat | |
import numpy as np | |
from dataclasses import dataclass | |
from typing import Tuple, List | |
# dataclass to store the crop parameters | |
class CropParams: | |
top: int | |
bottom: int | |
left: int | |
right: int | |
def get_border_params(rgb_image, tolerance=0.1, cut_off=20, value=0, level_diff_threshold=5, channel_axis=-1, min_border=5) -> CropParams: | |
gray_image = np.mean(rgb_image, axis=channel_axis) | |
h, w = gray_image.shape | |
def num_value_pixels(arr): | |
return np.sum(np.abs(arr - value) < level_diff_threshold) | |
def is_above_tolerance(arr, total_pixels): | |
return (num_value_pixels(arr) / total_pixels) > tolerance | |
# Crop top border until number of value pixels become below tolerance | |
top = min_border | |
while is_above_tolerance(gray_image[top, :], w) and top < h-1: | |
top += 1 | |
if top > cut_off: | |
break | |
# Crop bottom border until number of value pixels become below tolerance | |
bottom = h - min_border | |
while is_above_tolerance(gray_image[bottom, :], w) and bottom > 0: | |
bottom -= 1 | |
if h - bottom > cut_off: | |
break | |
# Crop left border until number of value pixels become below tolerance | |
left = min_border | |
while is_above_tolerance(gray_image[:, left], h) and left < w-1: | |
left += 1 | |
if left > cut_off: | |
break | |
# Crop right border until number of value pixels become below tolerance | |
right = w - min_border | |
while is_above_tolerance(gray_image[:, right], h) and right > 0: | |
right -= 1 | |
if w - right > cut_off: | |
break | |
return CropParams(top, bottom, left, right) | |
def get_white_border(rgb_image, value=255, **kwargs) -> CropParams: | |
"""Crops the white border of the RGB. | |
Args: | |
rgb: RGB image, shape (H, W, 3). | |
Returns: | |
Crop parameters. | |
""" | |
if value == 255: | |
# assert range of values in rgb image is [0, 255] | |
assert np.max(rgb_image) <= 255 and np.min(rgb_image) >= 0, "RGB image values are not in range [0, 255]." | |
assert rgb_image.max() > 1, "RGB image values are not in range [0, 255]." | |
elif value == 1: | |
# assert range of values in rgb image is [0, 1] | |
assert np.max(rgb_image) <= 1 and np.min(rgb_image) >= 0, "RGB image values are not in range [0, 1]." | |
return get_border_params(rgb_image, value=value, **kwargs) | |
def get_black_border(rgb_image, **kwargs) -> CropParams: | |
"""Crops the black border of the RGB. | |
Args: | |
rgb: RGB image, shape (H, W, 3). | |
Returns: | |
Crop parameters. | |
""" | |
return get_border_params(rgb_image, value=0, **kwargs) | |
def crop_image(image: np.ndarray, crop_params: CropParams) -> np.ndarray: | |
"""Crops the image according to the crop parameters. | |
Args: | |
image: RGB or depth image, shape (H, W, 3) or (H, W). | |
crop_params: Crop parameters. | |
Returns: | |
Cropped image. | |
""" | |
return image[crop_params.top:crop_params.bottom, crop_params.left:crop_params.right] | |
def crop_images(*images: np.ndarray, crop_params: CropParams) -> Tuple[np.ndarray]: | |
"""Crops the images according to the crop parameters. | |
Args: | |
images: RGB or depth images, shape (H, W, 3) or (H, W). | |
crop_params: Crop parameters. | |
Returns: | |
Cropped images. | |
""" | |
return tuple(crop_image(image, crop_params) for image in images) | |
def crop_black_or_white_border(rgb_image, *other_images: np.ndarray, tolerance=0.1, cut_off=20, level_diff_threshold=5) -> Tuple[np.ndarray]: | |
"""Crops the white and black border of the RGB and depth images. | |
Args: | |
rgb: RGB image, shape (H, W, 3). This image is used to determine the border. | |
other_images: The other images to crop according to the border of the RGB image. | |
Returns: | |
Cropped RGB and other images. | |
""" | |
# crop black border | |
crop_params = get_black_border(rgb_image, tolerance=tolerance, cut_off=cut_off, level_diff_threshold=level_diff_threshold) | |
cropped_images = crop_images(rgb_image, *other_images, crop_params=crop_params) | |
# crop white border | |
crop_params = get_white_border(cropped_images[0], tolerance=tolerance, cut_off=cut_off, level_diff_threshold=level_diff_threshold) | |
cropped_images = crop_images(*cropped_images, crop_params=crop_params) | |
return cropped_images | |