# Path: kraken/lib/default_specs.py
# SEGMENTATION_SPEC = '[1,1200,0,3 Cr7,7,64,2,2 Gn32 Cr3,3,128,2,2 Gn32 Cr3,3,128 Gn32 Cr3,3,256 Gn32 Cr3,3,256 Gn32 Lbx32 Lby32 Cr1,1,32 Gn32 Lby32 Lbx32]' # NOQA
# RECOGNITION_SPEC = '[1,48,0,1 Cr4,2,32,4,2 Gn32 Cr4,2,64,1,1 Gn32 Mp4,2,4,2 Cr3,3,128,1,1 Gn32 Mp1,2,1,2 S1(1x0)1,3 Lbx256 Do0.5 Lbx256 Do0.5 Lbx256 Do0.5]' # NOQA
# RECOGNITION_HYPER_PARAMS = {'pad': 16,
#                             'freq': 1.0,
#                             'batch_size': 1,
#                             'quit': 'early',
#                             'epochs': -1,
#                             'min_epochs': 5,
#                             'lag': 5,
#                             'min_delta': None,
#                             'optimizer': 'Adam',
#                             'lrate': 1e-3,
#                             'momentum': 0.9,
#                             'weight_decay': 0.0,
#                             'schedule': 'constant',
#                             'normalization': None,
#                             'normalize_whitespace': True,
#                             'completed_epochs': 0,
#                             'augment': False,
#                             # lr scheduler params
#                             # step/exp decay
#                             'step_size': 10,
#                             'gamma': 0.1,
#                             # reduce on plateau
#                             'rop_factor': 0.1,
#                             'rop_patience': 5,
#                             # cosine
#                             'cos_t_max': 50,
#                             }
# SEGMENTATION_HYPER_PARAMS = {'line_width': 8,
#                              'freq': 1.0,
#                              'quit': 'dumb',
#                              'epochs': 50,
#                              'min_epochs': 5,
#                              'lag': 10,
#                              'min_delta': None,
#                              'optimizer': 'Adam',
#                              'lrate': 2e-4,
#                              'momentum': 0.9,
#                              'weight_decay': 1e-5,
#                              'schedule': 'constant',
#                              'completed_epochs': 0,
#                              'augment': False,
#                              # lr scheduler params
#                              # step/exp decay
#                              'step_size': 10,
#                              'gamma': 0.1,
#                              # reduce on plateau
#                              'rop_factor': 0.1,
#                              'rop_patience': 5,
#                              # cosine
#                              'cos_t_max': 50,
#                              }
# 
# Path: kraken/lib/exceptions.py
# class KrakenInputException(Exception):
# 
#     def __init__(self, message=None):
#         Exception.__init__(self, message)


import PIL
import logging
import numpy as np
import shapely.geometry as geom
from collections import defaultdict
from PIL import Image
from scipy.ndimage import maximum_filter, binary_erosion
from scipy.ndimage.morphology import distance_transform_cdt
from scipy.spatial.distance import pdist, squareform
from shapely.ops import nearest_points, unary_union
from skimage import draw, filters
from skimage.graph import MCP_Connect
from skimage.filters import apply_hysteresis_threshold, sobel
from skimage.measure import approximate_polygon, subdivide_polygon, regionprops, label
from skimage.morphology import skeletonize
from skimage.transform import PiecewiseAffineTransform, SimilarityTransform, AffineTransform, warp
from typing import List, Tuple, Union, Dict, Any, Sequence, Optional
from kraken.lib import default_specs
from kraken.lib.exceptions import KrakenInputException
from scipy.signal import convolve2d
from scipy.ndimage.filters import gaussian_filter
                       ....]
            }
            ```
            or bounding box format:
            ```
            {'boxes': [[x_0, y_0, x_1, y_1], ...],
             'text_direction': 'horizontal-lr'}
            ```

    Yields:
        The extracted subimage
    """
    if 'type' in bounds and bounds['type'] == 'baselines':
        # select proper interpolation scheme depending on shape
        if im.mode == '1':
            order = 0
            im = im.convert('L')
        else:
            order = 1
        im = np.array(im)

        for line in bounds['lines']:
            if line['boundary'] is None:
                raise KrakenInputException('No boundary given for line')
            pl = np.array(line['boundary'])
            baseline = np.array(line['baseline'])
            c_min, c_max = int(pl[:, 0].min()), int(pl[:, 0].max())
            r_min, r_max = int(pl[:, 1].min()), int(pl[:, 1].max())

            if (pl < 0).any() or (pl.max(axis=0)[::-1] >= im.shape[:2]).any():

# Path: kraken/lib/default_specs.py
# SEGMENTATION_SPEC = '[1,1200,0,3 Cr7,7,64,2,2 Gn32 Cr3,3,128,2,2 Gn32 Cr3,3,128 Gn32 Cr3,3,256 Gn32 Cr3,3,256 Gn32 Lbx32 Lby32 Cr1,1,32 Gn32 Lby32 Lbx32]' # NOQA
# RECOGNITION_SPEC = '[1,48,0,1 Cr4,2,32,4,2 Gn32 Cr4,2,64,1,1 Gn32 Mp4,2,4,2 Cr3,3,128,1,1 Gn32 Mp1,2,1,2 S1(1x0)1,3 Lbx256 Do0.5 Lbx256 Do0.5 Lbx256 Do0.5]' # NOQA
# RECOGNITION_HYPER_PARAMS = {'pad': 16,
#                             'freq': 1.0,
#                             'batch_size': 1,
#                             'quit': 'early',
#                             'epochs': -1,
#                             'min_epochs': 5,
#                             'lag': 5,
#                             'min_delta': None,
#                             'optimizer': 'Adam',
#                             'lrate': 1e-3,
#                             'momentum': 0.9,
#                             'weight_decay': 0.0,
#                             'schedule': 'constant',
#                             'normalization': None,
#                             'normalize_whitespace': True,
#                             'completed_epochs': 0,
#                             'augment': False,
#                             # lr scheduler params
#                             # step/exp decay
#                             'step_size': 10,
#                             'gamma': 0.1,
#                             # reduce on plateau
#                             'rop_factor': 0.1,
#                             'rop_patience': 5,
#                             # cosine
#                             'cos_t_max': 50,
#                             }
# SEGMENTATION_HYPER_PARAMS = {'line_width': 8,
#                              'freq': 1.0,
#                              'quit': 'dumb',
#                              'epochs': 50,
#                              'min_epochs': 5,
#                              'lag': 10,
#                              'min_delta': None,
#                              'optimizer': 'Adam',
#                              'lrate': 2e-4,
#                              'momentum': 0.9,
#                              'weight_decay': 1e-5,
#                              'schedule': 'constant',
#                              'completed_epochs': 0,
#                              'augment': False,
#                              # lr scheduler params
#                              # step/exp decay
#                              'step_size': 10,
#                              'gamma': 0.1,
#                              # reduce on plateau
#                              'rop_factor': 0.1,
#                              'rop_patience': 5,
#                              # cosine
#                              'cos_t_max': 50,
#                              }
# 
# Path: kraken/lib/exceptions.py
# class KrakenInputException(Exception):
# 
#     def __init__(self, message=None):
#         Exception.__init__(self, message)


# Path: kraken/lib/segmentation.py
import PIL
import logging
import numpy as np
import shapely.geometry as geom
from collections import defaultdict
from PIL import Image
from scipy.ndimage import maximum_filter, binary_erosion
from scipy.ndimage.morphology import distance_transform_cdt
from scipy.spatial.distance import pdist, squareform
from shapely.ops import nearest_points, unary_union
from skimage import draw, filters
from skimage.graph import MCP_Connect
from skimage.filters import apply_hysteresis_threshold, sobel
from skimage.measure import approximate_polygon, subdivide_polygon, regionprops, label
from skimage.morphology import skeletonize
from skimage.transform import PiecewiseAffineTransform, SimilarityTransform, AffineTransform, warp
from typing import List, Tuple, Union, Dict, Any, Sequence, Optional
from kraken.lib import default_specs
from kraken.lib.exceptions import KrakenInputException
from scipy.signal import convolve2d
from scipy.ndimage.filters import gaussian_filter

                       ....]
            }
            ```
            or bounding box format:
            ```
            {'boxes': [[x_0, y_0, x_1, y_1], ...],
             'text_direction': 'horizontal-lr'}
            ```

    Yields:
        The extracted subimage
    """
    if 'type' in bounds and bounds['type'] == 'baselines':
        # select proper interpolation scheme depending on shape
        if im.mode == '1':
            order = 0
            im = im.convert('L')
        else:
            order = 1
        im = np.array(im)

        for line in bounds['lines']:
            if line['boundary'] is None:
                raise KrakenInputException('No boundary given for line')
            pl = np.array(line['boundary'])
            baseline = np.array(line['baseline'])
            c_min, c_max = int(pl[:, 0].min()), int(pl[:, 0].max())
            r_min, r_max = int(pl[:, 1].min()), int(pl[:, 1].max())

            if (pl < 0).any() or (pl.max(axis=0)[::-1] >= im.shape[:2]).any():

                raise KrakenInputException('Line polygon outside of image bounds')