Beispiel #1
0
def estimate_angle(raw, maxskew=2, skewsteps=8, perc=80, range=20, zoom=0.5, bignore=0.1):
    comment = ""
    rawF = read_image_gray(raw)
    # perform image normalization
    image = rawF - amin(rawF)
    if amax(image) == amin(image):
        print "# image is empty", fname
        return
    image /= amax(image)

    extreme = (sum(image < 0.05) + sum(image > 0.95)) * 1.0 / prod(image.shape)
    if extreme > 0.95:
        comment += " no-normalization"
        flat = image
    else:
        # check whether the image is already effectively binarized
        # if not, we need to flatten it by estimating the local whitelevel
        m = interpolation.zoom(image, zoom)
        m = filters.percentile_filter(m, perc, size=(range, 2))
        m = filters.percentile_filter(m, perc, size=(2, range))
        m = interpolation.zoom(m, 1.0 / zoom)
        w, h = minimum(array(image.shape), array(m.shape))
        flat = clip(image[:w, :h] - m[:w, :h] + 1, 0, 1)

    # estimate skew angle and rotate
    d0, d1 = flat.shape
    o0, o1 = int(bignore * d0), int(bignore * d1)
    flat = amax(flat) - flat
    flat -= amin(flat)
    est = flat[o0 : d0 - o0, o1 : d1 - o1]
    ma = maxskew
    ms = int(2 * maxskew * skewsteps)
    angle = estimate_skew_angle(est, linspace(-ma, ma, ms + 1))
    return angle
Beispiel #2
0
def nlbin(im, threshold=0.5, zoom=0.5, escale=1.0, border=0.1, perc=80,
          range=20, low=5, high=90):
    """
    Performs binarization using non-linear processing.

    Args:
        im (PIL.Image):
        threshold (float):
        zoom (float): Zoom for background page estimation
        escale (float): Scale for estimating a mask over the text region
        border (float): Ignore this much of the border
        perc (int): Percentage for filters
        range (int): Range for filters
        low (int): Percentile for black estimation
        high (int): Percentile for white estimation

    Returns:
        PIL.Image containing the binarized image
    """
    if im.mode == '1':
        return im
    raw = pil2array(im)
    # rescale image to between -1 or 0 and 1
    raw = raw/np.float(np.iinfo(raw.dtype).max)
    if raw.ndim == 3:
        raw = np.mean(raw, 2)
    # perform image normalization
    if np.amax(raw) == np.amin(raw):
        raise KrakenInputException('Image is empty')
    image = raw-np.amin(raw)
    image /= np.amax(image)

    m = interpolation.zoom(image, zoom)
    m = filters.percentile_filter(m, perc, size=(range, 2))
    m = filters.percentile_filter(m, perc, size=(2, range))
    m = interpolation.zoom(m, 1.0/zoom)
    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]
    # by default, we use only regions that contain
    # significant variance; this makes the percentile
    # based low and high estimates more reliable
    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((escale*50, 1)))
    v = morphology.binary_dilation(v, structure=np.ones((1, 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)
    bin = np.array(255*(flat > threshold), 'B')
    return array2pil(bin)
Beispiel #3
0
def cleanMe(spec, window=75, p=10):
    # returns a cleaned spectrum, removing extreme outlier peaks and troughs
    a = np.array(spec)
    topcut = percentile_filter( a, 100-p, size=window )
    a[ a>topcut ] = topcut[ a>topcut ]
    botcut = percentile_filter( a, p, size=window )
    a[ a<botcut ] = botcut[ a<botcut ]
    return a
Beispiel #4
0
def order_statistics_filter(grid,window_size=(3,3,3),statistics_type='median',rank=1):
    filtered = grid.copy()
    if statistics_type=='minimum':
        scifilt.minimum_filter(grid,window_size,None,filtered, mode='nearest')
    elif statistics_type=='maximum':
        scifilt.maximum_filter(grid,window_size,None,filtered, mode='nearest')
    elif statistics_type=='median':
        scifilt.median_filter(grid,window_size,None,filtered, mode='nearest')
    elif statistics_type[:-2]=='percentile' or statistics_type[:-2]=='per':
        per = np.int(statistics_type[-2:])
        scifilt.percentile_filter(grid,per,window_size,None,filtered, mode='nearest')
    elif statistics_type=='rank':
        scifilt.rank_filter(grid,rank,window_size,None,filtered, mode='nearest')
    return filtered
        
    return filtered
Beispiel #5
0
    def normalize(self, method='percentile', window=None, perc=20, offset=0.1):
        """
        Normalize by subtracting and dividing by a baseline.

        Baseline can be derived from a global mean or percentile,
        or a smoothed percentile estimated within a rolling window.
        Windowed baselines may only be well-defined for
        temporal series data.

        Parameters
        ----------
        baseline : str, optional, default = 'percentile'
            Quantity to use as the baseline, options are 'mean', 'percentile',
            'window', or 'window-exact'.

        window : int, optional, default = 6
            Size of window for baseline estimation,
            for 'window' and 'window-exact' baseline only.

        perc : int, optional, default = 20
            Percentile value to use, for 'percentile',
            'window', or 'window-exact' baseline only.

        offset : float, optional, default = 0.1
             Scalar added to baseline during division to avoid division by 0.
        """

        check_options(method, ['mean', 'percentile', 'window', 'window-exact'])

        from warnings import warn
        if not (method == 'window' or method == 'window-exact') and window is not None:
            warn('Setting window without using method "window" has no effect')

        if method == 'mean':
            baseFunc = mean

        if method == 'percentile':
            baseFunc = lambda x: percentile(x, perc)

        if method == 'window':
            from scipy.ndimage.filters import percentile_filter
            baseFunc = lambda x: percentile_filter(x.astype(float64), perc, window, mode='nearest')

        if method == 'window-exact':
            if window & 0x1:
                left, right = (ceil(window/2), ceil(window/2) + 1)
            else:
                left, right = (window/2, window/2)

            n = len(self.index)
            baseFunc = lambda x: asarray([percentile(x[max(ix-left, 0):min(ix+right+1, n)], perc)
                                          for ix in arange(0, n)])

        def get(y):
            b = baseFunc(y)
            return (y - b) / (b + offset)

        return self.map(get)
Beispiel #6
0
    def normalize(self, baseline='percentile', window=None, perc=20):
        """
        Normalize each time series by subtracting and dividing by a baseline.

        Baseline can be derived from a global mean or percentile,
        or a smoothed percentile estimated within a rolling window.

        Parameters
        ----------
        baseline : str, optional, default = 'percentile'
            Quantity to use as the baseline, options are 'mean', 'percentile', 'window', or 'window-fast'

        window : int, optional, default = 6
            Size of window for baseline estimation, for 'window' and 'window-fast' baseline only

        perc : int, optional, default = 20
            Percentile value to use, for 'percentile', 'window', or 'window-fast' baseline only
        """
        checkParams(baseline, ['mean', 'percentile', 'window', 'window-fast'])
        method = baseline.lower()
    
        from warnings import warn
        if not (method == 'window' or method == 'window-fast') and window is not None:
            warn('Setting window without using method "window" has no effect')

        if method == 'mean':
            baseFunc = mean

        if method == 'percentile':
            baseFunc = lambda x: percentile(x, perc)

        if method == 'window':
            if window & 0x1:
                left, right = (ceil(window/2), ceil(window/2) + 1)
            else:
                left, right = (window/2, window/2)

            n = len(self.index)
            baseFunc = lambda x: asarray([percentile(x[max(ix-left, 0):min(ix+right+1, n)], perc)
                                          for ix in arange(0, n)])

        if method == 'window-fast':
            from scipy.ndimage.filters import percentile_filter
            baseFunc = lambda x: percentile_filter(x.astype(float64), perc, window, mode='nearest')

        def get(y):
            b = baseFunc(y)
            return (y - b) / (b + 0.1)

        return self.applyValues(get, keepIndex=True)
Beispiel #7
0
 def deadPixelMask(self, pic):
     '''
     pixels with much lower intensity compare to adjacent pixels will be masked
     
     :param pic: 2d array, image array to be processed
     
     :return: 2d array of boolean, 1 stands for masked pixel
     '''
     avgpic = np.average(pic)
     ks = np.ones((5, 5))
     ks1 = np.ones((7, 7))
     picb = snf.percentile_filter(pic, 5, 3) < avgpic / 10
     picb = snm.binary_dilation(picb, structure=ks)
     picb = snm.binary_erosion(picb, structure=ks1)
     return picb
Beispiel #8
0
 def darkPixelMask(self, pic, r=None):
     '''
     pixels with much lower intensity compare to adjacent pixels will be masked
     
     :param pic: 2d array, image array to be processed
     :param r: float, a threshold for masked pixels
     
     :return: 2d array of boolean, 1 stands for masked pixel
     '''
     r = self.config.darkpixelr if r == None else r  # 0.1
     
     avgpic = np.average(pic)
     ks = np.ones((5, 5))
     ks1 = np.ones((7, 7))
     picb = snf.percentile_filter(pic, 5, 3) < avgpic * r
     picb = snm.binary_dilation(picb, structure=ks)
     picb = snm.binary_erosion(picb, structure=ks1)
     return picb
def ndi_med(image, n):
    return percentile_filter(image, 50, size=n * 2 - 1)
plt.xticks(range(0, 1500, 300), [0, '', '', 30, ''])
plt.xlim(0, 1200)
plt.ylim(0, 1.)
plt.xlabel('Time [s]', labelpad=-10)
plt.ylabel('Activity')

# real data

try:
    data = loadmat(filename)
    fmean_roi = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][
        0]['valueMatrix'].item().ravel()
    fmean_neuropil = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][
        1]['valueMatrix'].item().ravel()
    fmean_comp = np.ravel(fmean_roi - 0.7 * fmean_neuropil)
    b = percentile_filter(fmean_comp, 20, 3000, mode='nearest')
    mu = .075
    # shift such that baseline is not negative, but ~0
    y = ((fmean_comp - b) / (b + 10)).astype(float) + mu

    t_frame = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][
        0]['time'].item().ravel()

    filt = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][3][
        'valueMatrix'].item().ravel()
    t_ephys = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][
        3]['time'].item().ravel()

    detected_spikes = data['obj']['timeSeriesArrayHash'].item()[0]['value'].item()[0][4][
        'valueMatrix'].item().ravel()
    spike_time = t_ephys[detected_spikes.astype(bool)]
Beispiel #11
0
def nlbin(im: 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:
    """
    Performs binarization using non-linear processing.

    Args:
        im (PIL.Image):
        threshold (float):
        zoom (float): Zoom for background page estimation
        escale (float): Scale for estimating a mask over the text region
        border (float): Ignore this much of the border
        perc (int): Percentage for filters
        range (int): Range for filters
        low (int): Percentile for black estimation
        high (int): Percentile for white estimation

    Returns:
        PIL.Image containing the binarized image

    Raises:
        KrakenInputException when trying to binarize an empty image.
    """
    im_str = get_im_str(im)
    logger.info('Binarizing {}'.format(im_str))
    if is_bitonal(im):
        logger.info(
            'Skipping binarization because {} is bitonal.'.format(im_str))
        return im
    # convert to grayscale first
    logger.debug('Converting {} to grayscale'.format(im_str))
    im = im.convert('L')
    raw = pil2array(im)
    logger.debug('Scaling and normalizing')
    # rescale image to between -1 or 0 and 1
    raw = raw / np.float(np.iinfo(raw.dtype).max)
    # perform image normalization
    if np.amax(raw) == np.amin(raw):
        logger.warning('Trying to binarize empty image {}'.format(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('Thresholding at {}'.format(threshold))
    bin = np.array(255 * (flat > threshold), 'B')
    return array2pil(bin)
def ndi_med(image, n):
    return percentile_filter(image, 50, size=n * 2 - 1)
Beispiel #13
0
def moving_window_atribute(data,atribute='mean',window=(3,3,3),percentile=50,rank=1,clip_limits=(0,1),fisher=True,border_mode='nearest'):
    #reflect’, ‘constant’, ‘nearest’, ‘mirror’, ‘wrap’
    # minimum,maximum,median,percentile,rank,mean,variance,std,clip,sum,product,peak2peak,signal2noise,skewness
    # kurtosis
    if atribute == 'minimum':
        atrib = data.copy()
        scifilt.minimum_filter(data,window,None,atrib, mode=border_mode)
        return atrib
    elif atribute == 'maximum':
        atrib = data.copy()
        scifilt.maximum_filter(data,window,None,atrib, mode=border_mode)
        return atrib
    elif atribute == 'median':
        atrib = data.copy()
        scifilt.median_filter(data,window,None,atrib, mode=border_mode)
        return atrib
    elif atribute == 'percentile':
        atrib = data.copy()
        scifilt.percentile_filter(data,percentile,window,None,atrib, mode=border_mode)
        return atrib
    elif atribute == 'rank':
        atrib = data.copy()
        scifilt.rank_filter(data,rank,window,None,atrib, mode=border_mode)
        return atrib
    elif atribute == 'mean':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].mean()
        return atrib
    elif atribute == 'variance':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].var()
        return atrib
    elif atribute == 'std':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].std()
        return atrib
    elif atribute == 'clip':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    m = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].flatten()
                    l0 = np.percentile(m,clip_limits[0])
                    l1 = np.percentile(m,clip_limits[1])
                    m.clip(l0,l1)
                    atrib[i,j,k] = np.percentile(m,50)
        return atrib
    elif atribute == 'sum':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].sum()
        return atrib
    elif atribute == 'product':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].prod()
        return atrib
    elif atribute == 'peak2peak':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    atrib[i,j,k] = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].ptp()
        return atrib
    elif atribute == 'signal2noise':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    m = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].mean()
                    v = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].std()
                    atrib[i,j,k] = m/v
        return atrib
    elif atribute == 'skewness':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    m = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].flatten()
                    v = st.skew(m)
                    atrib[i,j,k] = v
        return atrib
    elif atribute == 'kurtosis':
        atrib = data.copy()
        blocks = atrib.shape
        for i in xrange(blocks[0]):
            for j in xrange(blocks[1]):
                for k in xrange(blocks[2]):
                    m = data[np.clip(i-window[0],0,blocks[0]):i+window[0]+1,np.clip(j-window[1],0,blocks[1]):j+window[1]+1,np.clip(k-window[2],0,blocks[2]):k+window[2]+1].flatten()
                    v = st.kurtosis(m,fisher=fisher)
                    atrib[i,j,k] = v
        return atrib
    else:
        return False
Beispiel #14
0
 def low_high(d, winsize):
     high = percentile_filter(d, 95, winsize)
     low = percentile_filter(d, 5, winsize)
     high = filters.lowpass_fir(high, winsize)
     low = filters.lowpass_fir(low, winsize)
     return low, high
Beispiel #15
0
    def _process_segment(self, page_image, page, page_xywh, page_id,
                         input_file, n):
        LOG = getLogger('OcrdAnybaseocrBinarizer')
        raw = ocrolib.pil2array(page_image)
        if len(raw.shape) > 2:
            raw = np.mean(raw, 2)
        raw = raw.astype("float64")
        # perform image normalization
        image = raw - amin(raw)
        if amax(image) == amin(image):
            LOG.info("# image is empty: %s" % (page_id))
            return
        image /= amax(image)

        # check whether the image is already effectively binarized
        if self.parameter['gray']:
            extreme = 0
        else:
            extreme = (np.sum(image < 0.05) +
                       np.sum(image > 0.95)) * 1.0 / np.prod(image.shape)
        if extreme > 0.95:
            comment = "no-normalization"
            flat = image
        else:
            comment = ""
            # if not, we need to flatten it by estimating the local whitelevel
            LOG.info("Flattening")
            m = interpolation.zoom(image, self.parameter['zoom'])
            m = filters.percentile_filter(m,
                                          self.parameter['perc'],
                                          size=(self.parameter['range'], 2))
            m = filters.percentile_filter(m,
                                          self.parameter['perc'],
                                          size=(2, self.parameter['range']))
            m = interpolation.zoom(m, 1.0 / self.parameter['zoom'])
            if self.parameter['debug'] > 0:
                clf()
                imshow(m, vmin=0, vmax=1)
                ginput(1, self.parameter['debug'])
            w, h = minimum(array(image.shape), array(m.shape))
            flat = clip(image[:w, :h] - m[:w, :h] + 1, 0, 1)
            if self.parameter['debug'] > 0:
                clf()
                imshow(flat, vmin=0, vmax=1)
                ginput(1, self.parameter['debug'])

        # estimate low and high thresholds
        LOG.info("Estimating Thresholds")
        d0, d1 = flat.shape
        o0, o1 = int(self.parameter['bignore'] * d0), int(
            self.parameter['bignore'] * d1)
        est = flat[o0:d0 - o0, o1:d1 - o1]
        if self.parameter['escale'] > 0:
            # by default, we use only regions that contain
            # significant variance; this makes the percentile
            # based low and high estimates more reliable
            e = self.parameter['escale']
            v = est - filters.gaussian_filter(est, e * 20.0)
            v = filters.gaussian_filter(v**2, e * 20.0)**0.5
            v = (v > 0.3 * amax(v))
            v = morphology.binary_dilation(v, structure=ones((int(e * 50), 1)))
            v = morphology.binary_dilation(v, structure=ones((1, int(e * 50))))
            if self.parameter['debug'] > 0:
                imshow(v)
                ginput(1, self.parameter['debug'])
            est = est[v]
        lo = stats.scoreatpercentile(est.ravel(), self.parameter['lo'])
        hi = stats.scoreatpercentile(est.ravel(), self.parameter['hi'])
        # rescale the image to get the gray scale image
        LOG.info("Rescaling")
        flat -= lo
        flat /= (hi - lo)
        flat = clip(flat, 0, 1)
        if self.parameter['debug'] > 0:
            imshow(flat, vmin=0, vmax=1)
            ginput(1, self.parameter['debug'])
        binarized = 1 * (flat > self.parameter['threshold'])

        # output the normalized grayscale and the thresholded images
        # print_info("%s lo-hi (%.2f %.2f) angle %4.1f %s" % (fname, lo, hi, angle, comment))
        LOG.info("%s lo-hi (%.2f %.2f) %s" % (page_id, lo, hi, comment))
        LOG.info("writing")
        if self.parameter['debug'] > 0 or self.parameter['show']:
            clf()
            gray()
            imshow(binarized)
            ginput(1, max(0.1, self.parameter['debug']))

        page_xywh['features'] += ',binarized'

        bin_array = array(255 * (binarized > ocrolib.midrange(binarized)), 'B')
        bin_image = ocrolib.array2pil(bin_array)

        file_id = make_file_id(input_file, self.output_file_grp)
        file_path = self.workspace.save_image_file(
            bin_image,
            file_id + '-IMG',
            page_id=page_id,
            file_grp=self.output_file_grp)
        page.add_AlternativeImage(
            AlternativeImageType(filename=file_path,
                                 comments=page_xywh['features']))
def dbl_pct_filt(arr):
    # Define percentile filter for clipping off artefactual IAS protrusions due to dangling epidermis
    out = percentile_filter(percentile_filter(arr, size=30, percentile=10),
                            size=30,
                            percentile=90)
    return out
Beispiel #17
0
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:
    """
    Performs binarization using non-linear processing.

    Args:
        im (PIL.Image.Image):
        threshold (float):
        zoom (float): Zoom for background page estimation
        escale (float): Scale for estimating a mask over the text region
        border (float): Ignore this much of the border
        perc (int): Percentage for filters
        range (int): Range for filters
        low (int): Percentile for black estimation
        high (int): Percentile for white estimation

    Returns:
        PIL.Image containing the binarized image

    Raises:
        KrakenInputException when trying to binarize an empty image.
    """
    im_str = get_im_str(im)
    logger.info('Binarizing {}'.format(im_str))
    if is_bitonal(im):
        logger.info('Skipping binarization because {} is bitonal.'.format(im_str))
        return im
    # convert to grayscale first
    logger.debug('Converting {} to grayscale'.format(im_str))
    im = im.convert('L')
    raw = pil2array(im)
    logger.debug('Scaling and normalizing')
    # rescale image to between -1 or 0 and 1
    raw = raw/np.float(np.iinfo(raw.dtype).max)
    # perform image normalization
    if np.amax(raw) == np.amin(raw):
        logger.warning('Trying to binarize empty image {}'.format(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('Thresholding at {}'.format(threshold))
    bin = np.array(255*(flat > threshold), 'B')
    return array2pil(bin)