# Path: kraken/binarization.py
# def nlbin(im: Image.Image,
#           threshold: float = 0.5,
#           zoom: float = 0.5,
#           escale: float = 1.0,
#           border: float = 0.1,
#           perc: int = 80,
#           range: int = 20,
#           low: int = 5,
#           high: int = 90) -> Image.Image:
#     """
#     Performs binarization using non-linear processing.
# 
#     Args:
#         im: Input image
#         threshold:
#         zoom: Zoom for background page estimation
#         escale: Scale for estimating a mask over the text region
#         border: Ignore this much of the border
#         perc: Percentage for filters
#         range: Range for filters
#         low: Percentile for black estimation
#         high: Percentile for white estimation
# 
#     Returns:
#         PIL.Image.Image containing the binarized image
# 
#     Raises:
#         KrakenInputException: When trying to binarize an empty image.
#     """
#     im_str = get_im_str(im)
#     logger.info(f'Binarizing {im_str}')
#     if is_bitonal(im):
#         logger.info(f'Skipping binarization because {im_str} is bitonal.')
#         return im
#     # convert to grayscale first
#     logger.debug(f'Converting {im_str} to grayscale')
#     im = im.convert('L')
#     raw = pil2array(im)
#     logger.debug('Scaling and normalizing')
#     # rescale image to between -1 or 0 and 1
#     raw = raw/float(np.iinfo(raw.dtype).max)
#     # perform image normalization
#     if np.amax(raw) == np.amin(raw):
#         logger.warning(f'Trying to binarize empty image {im_str}')
#         raise KrakenInputException('Image is empty')
#     image = raw-np.amin(raw)
#     image /= np.amax(image)
# 
#     logger.debug('Interpolation and percentile filtering')
#     with warnings.catch_warnings():
#         warnings.simplefilter('ignore', UserWarning)
#         m = interpolation.zoom(image, zoom)
#         m = filters.percentile_filter(m, perc, size=(range, 2))
#         m = filters.percentile_filter(m, perc, size=(2, range))
#         mh, mw = m.shape
#         oh, ow = image.shape
#         scale = np.diag([mh * 1.0/oh, mw * 1.0/ow])
#         m = affine_transform(m, scale, output_shape=image.shape)
#     w, h = np.minimum(np.array(image.shape), np.array(m.shape))
#     flat = np.clip(image[:w, :h]-m[:w, :h]+1, 0, 1)
# 
#     # estimate low and high thresholds
#     d0, d1 = flat.shape
#     o0, o1 = int(border*d0), int(border*d1)
#     est = flat[o0:d0-o0, o1:d1-o1]
#     logger.debug('Threshold estimates {}'.format(est))
#     # by default, we use only regions that contain
#     # significant variance; this makes the percentile
#     # based low and high estimates more reliable
#     logger.debug('Refine estimates')
#     v = est-filters.gaussian_filter(est, escale*20.0)
#     v = filters.gaussian_filter(v**2, escale*20.0)**0.5
#     v = (v > 0.3*np.amax(v))
#     v = morphology.binary_dilation(v, structure=np.ones((int(escale * 50), 1)))
#     v = morphology.binary_dilation(v, structure=np.ones((1, int(escale * 50))))
#     est = est[v]
#     lo = np.percentile(est.ravel(), low)
#     hi = np.percentile(est.ravel(), high)
#     flat -= lo
#     flat /= (hi-lo)
#     flat = np.clip(flat, 0, 1)
#     logger.debug(f'Thresholding at {threshold}')
#     bin = np.array(255*(flat > threshold), 'B')
#     return array2pil(bin)
# 
# Path: kraken/lib/exceptions.py
# class KrakenInputException(Exception):
# 
#     def __init__(self, message=None):
#         Exception.__init__(self, message)


import unittest
from pytest import raises
from PIL import Image
from pathlib import Path
from kraken.binarization import nlbin
from kraken.lib.exceptions import KrakenInputException


thisfile = Path(__file__).resolve().parent
resources = thisfile / 'resources'

class TestBinarization(unittest.TestCase):

    """
    Tests of the nlbin function for binarization of images
    """
    def test_not_binarize_empty(self):
        """
        Test that mode '1' images aren't binarized again.
        """
        with raises(KrakenInputException):
            with Image.new('1', (1000,1000)) as im:
                nlbin(im)

    def test_not_binarize_bw(self):
        """
        Test that mode '1' images aren't binarized again.
        """
        with Image.open(resources / 'bw.png') as im:
            self.assertEqual(im, nlbin(im))

    def test_binarize_no_bw(self):
        """
        Tests binarization of image formats without a 1bpp mode (JPG).
        """
        with Image.open(resources / 'input.jpg') as im:

# Path: kraken/binarization.py
# def nlbin(im: Image.Image,
#           threshold: float = 0.5,
#           zoom: float = 0.5,
#           escale: float = 1.0,
#           border: float = 0.1,
#           perc: int = 80,
#           range: int = 20,
#           low: int = 5,
#           high: int = 90) -> Image.Image:
#     """
#     Performs binarization using non-linear processing.
# 
#     Args:
#         im: Input image
#         threshold:
#         zoom: Zoom for background page estimation
#         escale: Scale for estimating a mask over the text region
#         border: Ignore this much of the border
#         perc: Percentage for filters
#         range: Range for filters
#         low: Percentile for black estimation
#         high: Percentile for white estimation
# 
#     Returns:
#         PIL.Image.Image containing the binarized image
# 
#     Raises:
#         KrakenInputException: When trying to binarize an empty image.
#     """
#     im_str = get_im_str(im)
#     logger.info(f'Binarizing {im_str}')
#     if is_bitonal(im):
#         logger.info(f'Skipping binarization because {im_str} is bitonal.')
#         return im
#     # convert to grayscale first
#     logger.debug(f'Converting {im_str} to grayscale')
#     im = im.convert('L')
#     raw = pil2array(im)
#     logger.debug('Scaling and normalizing')
#     # rescale image to between -1 or 0 and 1
#     raw = raw/float(np.iinfo(raw.dtype).max)
#     # perform image normalization
#     if np.amax(raw) == np.amin(raw):
#         logger.warning(f'Trying to binarize empty image {im_str}')
#         raise KrakenInputException('Image is empty')
#     image = raw-np.amin(raw)
#     image /= np.amax(image)
# 
#     logger.debug('Interpolation and percentile filtering')
#     with warnings.catch_warnings():
#         warnings.simplefilter('ignore', UserWarning)
#         m = interpolation.zoom(image, zoom)
#         m = filters.percentile_filter(m, perc, size=(range, 2))
#         m = filters.percentile_filter(m, perc, size=(2, range))
#         mh, mw = m.shape
#         oh, ow = image.shape
#         scale = np.diag([mh * 1.0/oh, mw * 1.0/ow])
#         m = affine_transform(m, scale, output_shape=image.shape)
#     w, h = np.minimum(np.array(image.shape), np.array(m.shape))
#     flat = np.clip(image[:w, :h]-m[:w, :h]+1, 0, 1)
# 
#     # estimate low and high thresholds
#     d0, d1 = flat.shape
#     o0, o1 = int(border*d0), int(border*d1)
#     est = flat[o0:d0-o0, o1:d1-o1]
#     logger.debug('Threshold estimates {}'.format(est))
#     # by default, we use only regions that contain
#     # significant variance; this makes the percentile
#     # based low and high estimates more reliable
#     logger.debug('Refine estimates')
#     v = est-filters.gaussian_filter(est, escale*20.0)
#     v = filters.gaussian_filter(v**2, escale*20.0)**0.5
#     v = (v > 0.3*np.amax(v))
#     v = morphology.binary_dilation(v, structure=np.ones((int(escale * 50), 1)))
#     v = morphology.binary_dilation(v, structure=np.ones((1, int(escale * 50))))
#     est = est[v]
#     lo = np.percentile(est.ravel(), low)
#     hi = np.percentile(est.ravel(), high)
#     flat -= lo
#     flat /= (hi-lo)
#     flat = np.clip(flat, 0, 1)
#     logger.debug(f'Thresholding at {threshold}')
#     bin = np.array(255*(flat > threshold), 'B')
#     return array2pil(bin)
# 
# Path: kraken/lib/exceptions.py
# class KrakenInputException(Exception):
# 
#     def __init__(self, message=None):
#         Exception.__init__(self, message)


# Path: tests/test_binarization.py
import unittest
from pytest import raises
from PIL import Image
from pathlib import Path
from kraken.binarization import nlbin
from kraken.lib.exceptions import KrakenInputException



thisfile = Path(__file__).resolve().parent
resources = thisfile / 'resources'

class TestBinarization(unittest.TestCase):

    """
    Tests of the nlbin function for binarization of images
    """
    def test_not_binarize_empty(self):
        """
        Test that mode '1' images aren't binarized again.
        """
        with raises(KrakenInputException):
            with Image.new('1', (1000,1000)) as im:
                nlbin(im)

    def test_not_binarize_bw(self):
        """
        Test that mode '1' images aren't binarized again.
        """
        with Image.open(resources / 'bw.png') as im:
            self.assertEqual(im, nlbin(im))

    def test_binarize_no_bw(self):
        """
        Tests binarization of image formats without a 1bpp mode (JPG).
        """
        with Image.open(resources / 'input.jpg') as im:

            res = nlbin(im)