Skip to content

Image manipulation functionality


Here are implemented functions for performing various image manipulations

get_common_value(v, axis=0)

Calculate initial most common value of the given array with given axis

Parameters:

Name Type Description Default
v ndarray

input vector

required
axis int

axis to calculate value

0

Returns:

Name Type Description
common_value Union[float, ndarray]
Source code in src/tools/processing.py
def get_common_value(v: np.ndarray, axis: int = 0) -> Union[float, np.ndarray]:
    """
    Calculate initial most common value of the given array with given axis

    Parameters
    ----------
    v : np.ndarray
        input vector
    axis : int
        axis to calculate value

    Returns
    -------
    common_value : Union[float,np.ndarray]
    """
    values, counts = np.unique(v, return_counts=True, axis=axis)
    common_value = values[np.argmax(counts)]
    return common_value

calculate_normalize_difference(x, y)

Calculate norm of the difference x/n-y/n, where n is the length of the vectors.

Parameters:

Name Type Description Default
x ndarray

first array

required
y ndarray

second array

required

Returns:

Name Type Description
normalized_difference float

resulting distance

Source code in src/tools/processing.py
def calculate_normalize_difference(x: np.ndarray, y: np.ndarray) -> float:
    """
    Calculate norm of the difference x/n-y/n, where n is the length of the vectors.

    Parameters
    ----------
    x : np.ndarray
        first array
    y : np.ndarray
        second array

    Returns
    -------
    normalized_difference : float
        resulting distance
    """
    if len(x) != len(y):
        raise ValueError('Cannot compare vectors with unequal length')

    n = len(x)

    normalized_difference = np.linalg.norm(x - y) / n
    return normalized_difference

need_to_trim(img, direction, initial_thresh=10)

Check, whatever the given direction(t,b,l,r) is need to be trimmed (cropped). Function compares the norm of dummy vector and actual vector of pixels.

Parameters:

Name Type Description Default
img ndarray

input image

required
direction str

given direction (t,b,l,r)

required
initial_thresh float

identification thresh

10

Returns:

Type Description
flag, initial_vector, blank_vector, to_iter : bool, np.ndarray, np.ndarray, range
Source code in src/tools/processing.py
def need_to_trim(img: np.ndarray, direction: str, initial_thresh: float = 10) -> Tuple[
    bool, np.ndarray, np.ndarray, range]:
    """
    Check, whatever the given direction(t,b,l,r) is need to be trimmed (cropped).
    Function compares the norm of dummy vector and actual vector of pixels.

    Parameters
    ----------
    img : np.ndarray
        input image
    direction : str
        given direction (t,b,l,r)
    initial_thresh : float
        identification thresh

    Returns
    -------
    flag, initial_vector, blank_vector, to_iter : bool, np.ndarray, np.ndarray, range

    """
    h, w = img.shape[0], img.shape[1],
    if img.ndim == 3:
        dim = img.shape[2]
    elif img.ndim == 2:
        dim = 1
    else:
        raise ValueError(f'Unknown image shape {img.shape}')

    if direction == 't':
        initial_vector = img[0, :, :]
        initial_pixel_value = get_common_value(v=initial_vector)
        blank_vector = np.ones((w, dim)) * initial_pixel_value
        to_iter = range(h)

    elif direction == 'b':

        initial_vector = img[-1, :, :]
        initial_pixel_value = get_common_value(v=initial_vector)
        blank_vector = np.ones((w, dim)) * initial_pixel_value
        to_iter = range(h)[::-1]

    elif direction == 'l':
        initial_vector = img[:, 0, :]
        initial_pixel_value = get_common_value(v=initial_vector)
        blank_vector = np.ones((h, dim)) * initial_pixel_value
        to_iter = range(w)

    elif direction == 'r':
        initial_vector = img[:, -1, :]
        initial_pixel_value = get_common_value(v=initial_vector)
        blank_vector = np.ones((h, dim)) * initial_pixel_value
        to_iter = range(w)[::-1]

    else:
        raise ValueError

    normalized_difference = calculate_normalize_difference(x=initial_vector, y=blank_vector)
    flag = normalized_difference <= initial_thresh

    return flag, initial_vector, blank_vector, to_iter

trim_image_with_thresh(img, norm_thresh=5000, initial_thresh=10, c_contiguous=True)

Perform image trimming operation for all the directions. For each direction (t,b,l,r) function checks if trimming is necessary and performs image cropping. Function is robust regarding different background colors and small watermarks in the background.

Parameters:

Name Type Description Default
img ndarray

input image

required
norm_thresh float

norm threshold to consider vectors the same

5000
initial_thresh float

identification thresh

10
c_contiguous bool

true for converting out array to c_contiguous

True

Returns:

Name Type Description
result ndarray

out image

Source code in src/tools/processing.py
def trim_image_with_thresh(img: np.ndarray, norm_thresh: float = 5000, initial_thresh: float = 10,
                           c_contiguous: bool = True):
    """
    Perform image trimming operation for all the directions.
    For each direction (t,b,l,r) function checks if trimming is necessary and performs image cropping.
    Function is robust regarding different background colors and small watermarks in the background.

    Parameters
    ----------
    img : np.ndarray
        input image
    norm_thresh : float
        norm threshold to consider vectors the same
    initial_thresh : float
        identification thresh
    c_contiguous : bool
        true for converting out array to c_contiguous

    Returns
    -------
    result : np.ndarray
        out image
    """
    # check dims
    if not (1 < img.ndim <= 4):
        raise ValueError('Not a valid image')

    # define directions, default limits and axes
    limits = {'t': 0, 'b': -1, 'l': 0, 'r': -1}
    axes = [0, 0, 1, 1]

    # iterate over directions
    for ax, (direction, dir_limit_ind) in zip(axes, limits.items()):
        # check if the given direction need to be trimmed
        flag, initial_vector, blank_vector, to_iter = need_to_trim(img=img, direction=direction,
                                                                   initial_thresh=initial_thresh)
        if flag:
            # iterate over direction and get limit
            for i in to_iter:
                current_vector = img.take(indices=i, axis=ax)
                normalized_difference = calculate_normalize_difference(x=current_vector, y=blank_vector,
                                                                       )

                if normalized_difference > norm_thresh:
                    limits[direction] = i
                    break

    # slice image
    result = img[limits['t']:limits['b'], limits['l']:limits['r'], :]

    if c_contiguous:
        result = np.ascontiguousarray(result)

    return result