Esempio n. 1
0
def run():
    global img_file, res_prefix, s_factors, n_splits, ovlap

    # print(img_file)
    # print(res_prefix)
    # print(s_factors)
    # print(n_splits)
    # print(ovlap)

    r = ET.Element('meta')
    t = ET.SubElement(r, 'file')
    t.text = img_file

    t = ET.SubElement(r, 'parameters')
    t1 = ET.SubElement(t, 'prefix')
    t1.text = res_prefix

    t1 = ET.SubElement(t, 'shrink')
    for s in s_factors:
        t2 = ET.SubElement(t1, 'factor')
        t2.text = str(s)

    t1 = ET.SubElement(t, 'split')
    for s in n_splits:
        t2 = ET.SubElement(t1, 'tile')
        t2.text = str(s)

    t1 = ET.SubElement(t, 'overlap')
    t1.text = str(ovlap)

    img = VImage.VImage(img_file)

    t1 = ET.SubElement(r, 'original')
    t2 = ET.SubElement(t1, 'width')
    t2.text = str(img.Xsize())
    t2 = ET.SubElement(t1, 'height')
    t2.text = str(img.Ysize())
    t2 = ET.SubElement(t1, 'channels')
    t2.text = str(img.Bands())
    t2 = ET.SubElement(t1, 'xres')
    t2.text = str(img.Xres())
    t2 = ET.SubElement(t1, 'yres')
    t2.text = str(img.Yres())
    t2 = ET.SubElement(t1, 'scale')
    t2.text = '1.0'
    t2 = ET.SubElement(t1, 'tile')
    t2.text = '(1, 1)'

    path = res_prefix + '/' + os.path.basename(img_file)
    if os.path.exists(path):
        print('Warning: Overwriting old files!')
    else:
        os.mkdir(path)

    print("ROI detection: ")
    # Find the ROI:
    # img_scaled = img.shrink(100, 100)
    os.spawnv(os.P_WAIT, 'div100', ['./div100', img_file, path + '/small.ppm'])
    # save downscaled image - not the best way for going to Scikit Image,
    # but for large images we go through disk I/O anyway:
    # print("    -saving small version of the image")
    # img_scaled.write(path+'/small.ppm')

    print("    -read into scikit-learn")
    img_scaled = imread(path + '/small.ppm')

    # compute a minimal area based on the resolution of the image
    # -the image is 100x smaller than the original -> resolution is
    print("    -computing mask")
    xres, yres = img.Xres() / 100, img.Yres() / 100
    min_area = 4 * min(xres, yres)  # ~4 mm**2
    mask, _ = tissue_region_from_rgb(img_scaled, min_area)

    # save the mask:
    print("    -saving mask")
    imsave(path + '/' + 'mask_div100.pbm', mask)
    t2 = ET.SubElement(t1, 'mask')
    t2.text = 'mask_div100.pbm'

    # coordinates of the ROI encompassing the objects, at 0.01 of original image
    print("    -detect ROI")
    rmin, cmin, rmax, cmax = bounding_box(mask)
    mask = mask[rmin:rmax + 1, cmin:cmax + 1]

    # get back to original coordinates, with an approximation of 100 pixels...
    rmin *= 100
    cmin *= 100
    rmax = min((rmax + 1) * 100, img.Ysize())
    cmax = min((cmax + 1) * 100, img.Xsize())

    t2 = ET.SubElement(t1, 'roi', {
        'xmin': str(cmin),
        'ymin': str(rmin),
        'xmax': str(cmax),
        'ymax': str(rmax)
    })

    print("...end ROI detection.")

    # Save initial level 0:
    print("Crop ROI and save...")
    img_cropped = img.extract_area(cmin, rmin, cmax - cmin + 1,
                                   rmax - rmin + 1)
    img_cropped.write(path + '/pyramid-level_0.ppm')
    new_width, new_height = img_cropped.Xsize(), img_cropped.Ysize()
    img_cropped = None
    print("...OK")

    mask = None
    img = None  # done with it
    gc.collect()

    # Generate the pyramid
    t1 = ET.SubElement(r, 'pyramid')
    t2 = ET.SubElement(t1, 'level', {
        'value': '0',
        'file': 'pyramid-level_0.ppm'
    })
    t2 = ET.SubElement(t1, 'level', {
        'value': '1',
        'file': 'pyramid-level_1.ppm'
    })
    t2 = ET.SubElement(t1, 'level', {
        'value': '2',
        'file': 'pyramid-level_2.ppm'
    })
    t2 = ET.SubElement(t1, 'level', {
        'value': '3',
        'file': 'pyramid-level_3.ppm'
    })
    t2 = ET.SubElement(t1, 'level', {
        'value': '4',
        'file': 'pyramid-level_4.ppm'
    })
    t2 = ET.SubElement(t1, 'level', {
        'value': '5',
        'file': 'pyramid-level_5.ppm'
    })

    # call external tool:
    print("Computing pyramid...")
    os.spawnv(os.P_WAIT, 'pyr', [
        './pyr', path + '/pyramid-level_0.ppm', path + '/pyramid',
        str(n_levels)
    ])
    print("...done")

    k = 0
    for l in np.arange(n_levels + 1):
        f = s_factors[l]
        pt = path + '/' + str(s_factors[l])
        if not os.path.exists(pt):
            os.mkdir(pt)

        t1 = ET.SubElement(r, 'version')
        t2 = ET.SubElement(t1, 'scale')
        t2.text = str(f)

        n_horiz, n_vert = n_splits[k]
        t2 = ET.SubElement(t1, 'split')
        t2.text = str((n_horiz, n_vert))

        # img_scaled = img_cropped.shrink(f, f)
        # load the corresponding level in the pyramid:
        img_scaled = VImage.VImage(path + '/pyramid-level_' + str(l) + '.ppm')
        width = img_scaled.Xsize()
        height = img_scaled.Ysize()

        w = width / n_horiz
        h = height / n_vert
        ov = ovlap / 100.0 / 2.0  # ovlap is in % and we need half of it
        sv = int(n_vert != 1)
        sh = int(n_horiz != 1)

        print('Processing scale %d and tile %d,%d' % (f, n_horiz, n_vert))

        y0 = 0
        for i in np.arange(n_vert):
            x0 = 0

            if i < n_vert - 1:
                y1 = int(y0 + h * (1.0 + sv * ov)) - 1
            else:
                y1 = height - 1

            for j in np.arange(n_horiz):
                if j < n_horiz - 1:
                    x1 = int(x0 + w * (1.0 + sh * ov)) - 1
                else:
                    x1 = width - 1

                tile_name = 'tile_' + str(i) + '_' + str(j) + '.' + res_format
                res_file = pt + '/' + tile_name
                print('Save to' + res_file)
                t2 = ET.SubElement(
                    t1, 'tile', {
                        'name': tile_name,
                        'x0': str(x0),
                        'y0': str(y0),
                        'x1': str(x1),
                        'y1': str(y1)
                    })

                #print('x0 = %d, y0 = %d, x1 = %d, y1 = %d, sh = %d, ov = %f; image: %d x %d' % (x0, y0, x1, y1, sh, ov, width, height))

                # do the actual work...
                img_sub = img_scaled.extract_area(x0, y0, x1 - x0 + 1,
                                                  y1 - y0 + 1)
                img_sub.write(res_file)

                x0 = int(x1 + 1 - 2.0 * w * ov)

            y0 = int(y1 + 1 - 2.0 * w * ov)

        k += 1

    raw_txt = ET.tostring(r, 'utf-8')
    reparsed = minidom.parseString(raw_txt)
    pp_txt = reparsed.toprettyxml(indent='  ')

    #print(pp_txt)
    meta_file = open(path + '/meta.xml', 'w')
    meta_file.write(pp_txt)

    return
Esempio n. 2
0
def main():
    p = opt.ArgumentParser(description="""
            Constructs a dictionary for image representation based on a set of specified local
            descriptors. The dictionary is built from a set of images given as a list in an
            input file.
            """)
    p.add_argument('config', action='store', help='a configuration file')
    args = p.parse_args()
    cfg_file = args.config
    
    parser = SafeConfigParser()
    parser.read(cfg_file)
    
    #---------
    # sampler:
    if not parser.has_section('sampler'):
        raise ValueError('"sampler" section is mandatory')
    if not parser.has_option('sampler', 'type'):
        raise ValueError('"sampler.type" is mandatory')
    tmp = parser.get('sampler', 'type').lower()
    if tmp not in ['random', 'sliding']:
        raise ValueError('Unkown sampling type')
    sampler_type = tmp
    if not parser.has_option('sampler', 'window_size'):
        raise ValueError('"sampler.window_size" is mandatory')
    wnd_size = ast.literal_eval(parser.get('sampler', 'window_size'))
    if type(wnd_size) != tuple:
        raise ValueError('"sampler.window_size" specification error')
    it_start = (0,0)
    it_step = (1,1)
    if sampler_type == 'sliding':
        if parser.has_option('sampler', 'start'):
            it_start = ast.literal_eval(parser.get('sampler','start'))
        if parser.has_option('sampler', 'step'):
            it_step  = ast.literal_eval(parser.get('sampler','step'))
    nwindows = parser.getint('sampler', 'nwindows')
                                    

    local_descriptors = []
    #---------
    # haar:
    if parser.has_section('haar'):
        tmp = True
        if parser.has_option('haar', 'norm'):
            tmp = parser.getboolean('haar', 'norm')
        if len(parser.items('haar')) == 0:
            # empty section, use defaults
            h = HaarLikeDescriptor(HaarLikeDescriptor.haars1())
        else:
            h = HaarLikeDescriptor([ast.literal_eval(v) for n, v in parser.items('haar')
                                    if n.lower() != 'norm'],
                _norm=tmp)
        local_descriptors.append(h)
        
        
    #---------
    # identity:
    if parser.has_section('identity'):
        local_descriptors.append(IdentityDescriptor())
        
    #---------
    # stats:
    if parser.has_section('stats'):
        tmp = []
        if parser.has_option('stats', 'mean') and parser.getboolean('stats', 'mean'):
            tmp.append('mean')
        if parser.has_option('stats', 'std') and parser.getboolean('stats', 'std'):
            tmp.append('std')
        if parser.has_option('stats', 'kurtosis') and parser.getboolean('stats', 'kurtosis'):
            tmp.append('kurtosis')
        if parser.has_option('stats', 'skewness') and parser.getboolean('stats', 'skewness'):
            tmp.append('skewness')
        if len(tmp) == 0:
            tmp = None
        local_descriptors.append(StatsDescriptor(tmp))
    
    #---------
    # hist:
    if parser.has_section('hist'):
        tmp = (0.0, 1.0)
        tmp2 = 10
        if parser.has_option('hist', 'min_max'):
            tmp = ast.literal_eval(parser.get('hist', 'min_max'))
            if type(tmp) != tuple:
                raise ValueError('"hist.min_max" specification error')
        if parser.has_option('hist', 'nbins'):
            tmp2 = parser.getint('hist', 'nbins')
        local_descriptors.append(HistDescriptor(_interval=tmp, _nbins=tmp2))
    
    
    #---------
    # HoG
    if parser.has_section('hog'):
        tmp = 9
        tmp2 = (128, 128)
        tmp3 = (4, 4)
        
        if parser.has_option('hog', 'norient'):
            tmp = parser.getint('hog', 'norient')
        if parser.has_option('hog', 'ppc'):
            tmp2 = ast.literal_eval(parser.get('hog', 'ppc'))
            if type(tmp2) != tuple:
                raise ValueError('"hog.ppc" specification error')
        if parser.has_option('hog', 'cpb'):
            tmp3 = ast.literal_eval(parser.get('hog', 'cpb'))
            if type(tmp3) != tuple:
                raise ValueError('"hog.cpb" specification error')
        local_descriptors.append(HOGDescriptor(_norient=tmp, _ppc=tmp2, _cpb=tmp3))
        
        
    #---------
    # LBP
    if parser.has_section('lbp'):
        tmp = 3
        tmp2 = 8*tmp
        tmp3 = 'uniform'
        
        if parser.has_option('lbp', 'radius'):
            tmp = parser.getint('lbp', 'radius')
        if parser.has_option('lbp', 'npoints'):
            tmp2 = parser.getint('lbp', 'npoints')
            if tmp2 == 0:
                tmp2 = 8* tmp
        if parser.has_option('lbp', 'method'):
            tmp3 = parser.get('lbp', 'method')
        local_descriptors.append(LBPDescriptor(radius=tmp, npoints=tmp2, method=tmp3))

    #---------
    # Gabor
    if parser.has_section('gabor'):
        tmp  = np.array([0.0, np.pi / 4.0, np.pi / 2.0, 3.0 * np.pi / 4.0], dtype=np.double)
        tmp2 = np.array([3.0 / 4.0, 3.0 / 8.0, 3.0 / 16.0], dtype=np.double)
        tmp3 = np.array([1.0, 2 * np.sqrt(2.0)], dtype=np.double)

        if parser.has_option('gabor', 'theta'):
            tmp = ast.literal_eval(parser.get('gabor', 'theta'))
        if parser.has_option('gabor', 'freq'):
            tmp2 = ast.literal_eval(parser.get('gabor', 'freq'))
        if parser.has_option('gabor', 'sigma'):
            tmp3 = ast.literal_eval(parser.get('gabor', 'sigma'))
        local_descriptors.append(GaborDescriptor(theta=tmp, freq=tmp2, sigma=tmp3))
            
    print('No. of descriptors: ', len(local_descriptors))
    
    #---------
    # data
    if not parser.has_section('data'):
        raise ValueError('Section "data" is mandatory.')
    data_path = parser.get('data', 'input_path')
    img_ext = parser.get('data', 'image_type')
    res_path = parser.get('data', 'output_path')
    
    img_files = glob.glob(data_path + '/*.' + img_ext)
    if len(img_files) == 0:
        return
    
    ## Process:

    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)    # unbuferred output
    for img_name in img_files:
        print("Image: ", img_name, " ...reading... ", end='')
        im = imread(img_name)
        print("preprocessing... ", end='')
        # -preprocessing
        if im.ndim == 3:
            im_h, _, _ = rgb2he2(im)
        else:
            raise ValueError('Input image must be RGB.')
        
        # detect object region:
        # -try to load a precomputed mask:
        mask_file_name = data_path+'/mask/'+ \
            os.path.splitext(os.path.split(img_name)[1])[0]+ \
            '_tissue_mask.pbm'
        if os.path.exists(mask_file_name):
            print('(loading mask)...', end='')
            mask = imread(mask_file_name)
            mask = img_as_bool(mask)
            mask = remove_small_objects(mask, min_size=500, connectivity=1, in_place=True)
        else:
            print('(computing mask)...', end='')
            mask, _ = tissue_region_from_rgb(im, _min_area=500)
        
        row_min, col_min, row_max, col_max = bounding_box(mask)
        im_h[np.logical_not(mask)] = 0                       # make sure background is 0
        mask = None
        im = None
        im_h = im_h[row_min:row_max+1, col_min:col_max+1]

        print("growing the bag...", end='')
        # -image bag growing
        bag = None                               # bag for current image
        for d in local_descriptors:
            if bag is None:
                bag = grow_bag_from_new_image(im_h, d, wnd_size, nwindows, discard_empty=True)
            else:
                bag[d.name] = grow_bag_with_new_features(im_h, bag['regs'], d)[d.name]

        # save the results for each image, one file per descriptor
        desc_names = bag.keys()
        desc_names.remove('regs')                  # keep all keys but the regions
        # -save the ROI from the original image:
        res_file = res_path + '/' + 'roi-' + \
                   os.path.splitext(os.path.split(img_name)[1])[0] + '.dat'
        with open(res_file, 'w') as f:
            f.write('\t'.join([str(x_) for x_ in [row_min, row_max, col_min, col_max]]))
                    
        for dn in desc_names:
            res_file = res_path + '/' + dn + '_bag-' + \
                       os.path.splitext(os.path.split(img_name)[1])[0] + '.dat'
            with open(res_file, 'w') as f:
                n = len(bag[dn])                       # total number of descriptors of this type
                for i in range(n):
                    s = '\t'.join([str(x_) for x_ in bag['regs'][i]]) + '\t' + \
                        '\t'.join([str(x_) for x_ in bag[dn][i]]) + '\n'
                    f.write(s)
            
        print('OK')
        
        bag = None
        gc.collect()
        gc.collect()
Esempio n. 3
0
def run():
    global img_file, res_prefix, s_factors, n_splits, ovlap

    # print(img_file)
    # print(res_prefix)
    # print(s_factors)
    # print(n_splits)
    # print(ovlap)

    r = ET.Element('meta')
    t = ET.SubElement(r, 'file')
    t.text = img_file

    t = ET.SubElement(r, 'parameters')
    t1 = ET.SubElement(t, 'prefix')
    t1.text = res_prefix

    t1 = ET.SubElement(t, 'shrink')
    for s in s_factors:
        t2 = ET.SubElement(t1, 'factor')
        t2.text = str(s)

    t1 = ET.SubElement(t, 'split')
    for s in n_splits:
        t2 = ET.SubElement(t1, 'tile')
        t2.text = str(s)

    t1 = ET.SubElement(t, 'overlap')
    t1.text = str(ovlap)

    img = VImage.VImage(img_file)

    t1 = ET.SubElement(r, 'original')
    t2 = ET.SubElement(t1, 'width')
    t2.text = str(img.Xsize())
    t2 = ET.SubElement(t1, 'height')
    t2.text = str(img.Ysize())
    t2 = ET.SubElement(t1, 'channels')
    t2.text = str(img.Bands())
    t2 = ET.SubElement(t1, 'xres')
    t2.text = str(img.Xres())
    t2 = ET.SubElement(t1, 'yres')
    t2.text = str(img.Yres())
    t2 = ET.SubElement(t1, 'scale')
    t2.text = '1.0'
    t2 = ET.SubElement(t1, 'tile')
    t2.text = '(1, 1)'

    path = res_prefix + '/' + os.path.basename(img_file)
    if os.path.exists(path):
        print('Warning: Overwriting old files!')
    else:
        os.mkdir(path)

    print("ROI detection: ")
    # Find the ROI:
    # img_scaled = img.shrink(100, 100)
    os.spawnv(os.P_WAIT, 'div100', ['./div100', img_file, path+'/small.ppm'])
    # save downscaled image - not the best way for going to Scikit Image,
    # but for large images we go through disk I/O anyway:
    # print("    -saving small version of the image")
    # img_scaled.write(path+'/small.ppm')

    print("    -read into scikit-learn")
    img_scaled = imread(path+'/small.ppm')

    # compute a minimal area based on the resolution of the image
    # -the image is 100x smaller than the original -> resolution is
    print("    -computing mask")
    xres, yres = img.Xres() / 100, img.Yres() / 100
    min_area   = 4 * min(xres, yres)   # ~4 mm**2
    mask, _ = tissue_region_from_rgb(img_scaled, min_area)

    # save the mask:
    print("    -saving mask")
    imsave(path + '/' + 'mask_div100.pbm', mask)
    t2 = ET.SubElement(t1, 'mask')
    t2.text = 'mask_div100.pbm'

    # coordinates of the ROI encompassing the objects, at 0.01 of original image
    print("    -detect ROI")
    rmin, cmin, rmax, cmax = bounding_box(mask)
    mask = mask[rmin:rmax+1, cmin:cmax+1]

    # get back to original coordinates, with an approximation of 100 pixels...
    rmin *= 100
    cmin *= 100
    rmax = min((rmax + 1) * 100, img.Ysize())
    cmax = min((cmax + 1) * 100, img.Xsize())

    t2 = ET.SubElement(t1, 'roi',
        {'xmin': str(cmin), 'ymin': str(rmin), 'xmax': str(cmax), 'ymax': str(rmax)})

    print("...end ROI detection.")

    # Save initial level 0:
    print("Crop ROI and save...")
    img_cropped = img.extract_area(cmin, rmin, cmax-cmin+1, rmax-rmin+1)
    img_cropped.write(path + '/pyramid-level_0.ppm')
    new_width, new_height = img_cropped.Xsize(), img_cropped.Ysize()
    img_cropped = None
    print("...OK")

    mask = None
    img = None                                            # done with it
    gc.collect()

    # Generate the pyramid
    t1 = ET.SubElement(r, 'pyramid')
    t2 = ET.SubElement(t1, 'level', {'value': '0', 'file': 'pyramid-level_0.ppm'})
    t2 = ET.SubElement(t1, 'level', {'value': '1', 'file': 'pyramid-level_1.ppm'})
    t2 = ET.SubElement(t1, 'level', {'value': '2', 'file': 'pyramid-level_2.ppm'})
    t2 = ET.SubElement(t1, 'level', {'value': '3', 'file': 'pyramid-level_3.ppm'})
    t2 = ET.SubElement(t1, 'level', {'value': '4', 'file': 'pyramid-level_4.ppm'})
    t2 = ET.SubElement(t1, 'level', {'value': '5', 'file': 'pyramid-level_5.ppm'})

    # call external tool:
    print("Computing pyramid...")
    os.spawnv(os.P_WAIT, 'pyr', ['./pyr', path+'/pyramid-level_0.ppm', path+'/pyramid', str(n_levels)])
    print("...done")

    k = 0
    for l in np.arange(n_levels+1):
        f = s_factors[l]
        pt = path + '/' + str(s_factors[l])
        if not os.path.exists(pt):
            os.mkdir(pt)

        t1 = ET.SubElement(r, 'version')
        t2 = ET.SubElement(t1, 'scale')
        t2.text = str(f)

        n_horiz, n_vert = n_splits[k]
        t2 = ET.SubElement(t1, 'split')
        t2.text = str((n_horiz, n_vert))

        # img_scaled = img_cropped.shrink(f, f)
        # load the corresponding level in the pyramid:
        img_scaled = VImage.VImage(path + '/pyramid-level_' + str(l) + '.ppm')
        width = img_scaled.Xsize()
        height = img_scaled.Ysize()

        w = width / n_horiz
        h = height / n_vert
        ov = ovlap/100.0/2.0  # ovlap is in % and we need half of it
        sv = int(n_vert != 1)
        sh = int(n_horiz != 1)

        print('Processing scale %d and tile %d,%d' % (f, n_horiz, n_vert))

        y0 = 0
        for i in np.arange(n_vert):
            x0 = 0

            if i < n_vert - 1:
                y1 = int(y0 + h * (1.0 + sv*ov)) - 1
            else:
                y1 = height - 1

            for j in np.arange(n_horiz):
                if j < n_horiz - 1:
                    x1 = int(x0 + w * (1.0 + sh*ov)) - 1
                else:
                    x1 = width - 1

                tile_name = 'tile_' + str(i) + '_' + str(j) + '.' + res_format
                res_file = pt + '/' + tile_name
                print('Save to' + res_file)
                t2 = ET.SubElement(t1, 'tile',
                    {'name': tile_name, 'x0':str(x0), 'y0':str(y0), 'x1':str(x1), 'y1':str(y1)})

                #print('x0 = %d, y0 = %d, x1 = %d, y1 = %d, sh = %d, ov = %f; image: %d x %d' % (x0, y0, x1, y1, sh, ov, width, height))

                # do the actual work...
                img_sub = img_scaled.extract_area(x0, y0, x1-x0+1, y1-y0+1)
                img_sub.write(res_file)

                x0 = int(x1 + 1 - 2.0 * w * ov)

            y0 = int(y1 + 1 - 2.0 * w * ov)

        k += 1


    raw_txt = ET.tostring(r, 'utf-8')
    reparsed = minidom.parseString(raw_txt)
    pp_txt = reparsed.toprettyxml(indent='  ')

    #print(pp_txt)
    meta_file = open(path+'/meta.xml', 'w')
    meta_file.write(pp_txt)

    return
Esempio n. 4
0
def main():
    p = opt.ArgumentParser(description="""
            Constructs a dictionary for image representation based on a set of specified local
            descriptors. The dictionary is built from a set of images given as a list in an
            input file.
            """)
    p.add_argument('config', action='store', help='a configuration file')
    args = p.parse_args()
    cfg_file = args.config

    parser = SafeConfigParser()
    parser.read(cfg_file)

    #---------
    # sampler:
    if not parser.has_section('sampler'):
        raise ValueError('"sampler" section is mandatory')
    if not parser.has_option('sampler', 'type'):
        raise ValueError('"sampler.type" is mandatory')
    tmp = parser.get('sampler', 'type').lower()
    if tmp not in ['random', 'sliding']:
        raise ValueError('Unkown sampling type')
    sampler_type = tmp
    if not parser.has_option('sampler', 'window_size'):
        raise ValueError('"sampler.window_size" is mandatory')
    wnd_size = ast.literal_eval(parser.get('sampler', 'window_size'))
    if type(wnd_size) != tuple:
        raise ValueError('"sampler.window_size" specification error')
    it_start = (0, 0)
    it_step = (1, 1)
    if sampler_type == 'sliding':
        if parser.has_option('sampler', 'start'):
            it_start = ast.literal_eval(parser.get('sampler', 'start'))
        if parser.has_option('sampler', 'step'):
            it_step = ast.literal_eval(parser.get('sampler', 'step'))
    nwindows = parser.getint('sampler', 'nwindows')

    local_descriptors = []
    #---------
    # haar:
    if parser.has_section('haar'):
        tmp = True
        if parser.has_option('haar', 'norm'):
            tmp = parser.getboolean('haar', 'norm')
        if len(parser.items('haar')) == 0:
            # empty section, use defaults
            h = HaarLikeDescriptor(HaarLikeDescriptor.haars1())
        else:
            h = HaarLikeDescriptor([
                ast.literal_eval(v)
                for n, v in parser.items('haar') if n.lower() != 'norm'
            ],
                                   _norm=tmp)
        local_descriptors.append(h)

    #---------
    # identity:
    if parser.has_section('identity'):
        local_descriptors.append(IdentityDescriptor())

    #---------
    # stats:
    if parser.has_section('stats'):
        tmp = []
        if parser.has_option('stats', 'mean') and parser.getboolean(
                'stats', 'mean'):
            tmp.append('mean')
        if parser.has_option('stats', 'std') and parser.getboolean(
                'stats', 'std'):
            tmp.append('std')
        if parser.has_option('stats', 'kurtosis') and parser.getboolean(
                'stats', 'kurtosis'):
            tmp.append('kurtosis')
        if parser.has_option('stats', 'skewness') and parser.getboolean(
                'stats', 'skewness'):
            tmp.append('skewness')
        if len(tmp) == 0:
            tmp = None
        local_descriptors.append(StatsDescriptor(tmp))

    #---------
    # hist:
    if parser.has_section('hist'):
        tmp = (0.0, 1.0)
        tmp2 = 10
        if parser.has_option('hist', 'min_max'):
            tmp = ast.literal_eval(parser.get('hist', 'min_max'))
            if type(tmp) != tuple:
                raise ValueError('"hist.min_max" specification error')
        if parser.has_option('hist', 'nbins'):
            tmp2 = parser.getint('hist', 'nbins')
        local_descriptors.append(HistDescriptor(_interval=tmp, _nbins=tmp2))

    #---------
    # HoG
    if parser.has_section('hog'):
        tmp = 9
        tmp2 = (128, 128)
        tmp3 = (4, 4)

        if parser.has_option('hog', 'norient'):
            tmp = parser.getint('hog', 'norient')
        if parser.has_option('hog', 'ppc'):
            tmp2 = ast.literal_eval(parser.get('hog', 'ppc'))
            if type(tmp2) != tuple:
                raise ValueError('"hog.ppc" specification error')
        if parser.has_option('hog', 'cpb'):
            tmp3 = ast.literal_eval(parser.get('hog', 'cpb'))
            if type(tmp3) != tuple:
                raise ValueError('"hog.cpb" specification error')
        local_descriptors.append(
            HOGDescriptor(_norient=tmp, _ppc=tmp2, _cpb=tmp3))

    #---------
    # LBP
    if parser.has_section('lbp'):
        tmp = 3
        tmp2 = 8 * tmp
        tmp3 = 'uniform'

        if parser.has_option('lbp', 'radius'):
            tmp = parser.getint('lbp', 'radius')
        if parser.has_option('lbp', 'npoints'):
            tmp2 = parser.getint('lbp', 'npoints')
            if tmp2 == 0:
                tmp2 = 8 * tmp
        if parser.has_option('lbp', 'method'):
            tmp3 = parser.get('lbp', 'method')
        local_descriptors.append(
            LBPDescriptor(radius=tmp, npoints=tmp2, method=tmp3))

    #---------
    # Gabor
    if parser.has_section('gabor'):
        tmp = np.array([0.0, np.pi / 4.0, np.pi / 2.0, 3.0 * np.pi / 4.0],
                       dtype=np.double)
        tmp2 = np.array([3.0 / 4.0, 3.0 / 8.0, 3.0 / 16.0], dtype=np.double)
        tmp3 = np.array([1.0, 2 * np.sqrt(2.0)], dtype=np.double)

        if parser.has_option('gabor', 'theta'):
            tmp = ast.literal_eval(parser.get('gabor', 'theta'))
        if parser.has_option('gabor', 'freq'):
            tmp2 = ast.literal_eval(parser.get('gabor', 'freq'))
        if parser.has_option('gabor', 'sigma'):
            tmp3 = ast.literal_eval(parser.get('gabor', 'sigma'))
        local_descriptors.append(
            GaborDescriptor(theta=tmp, freq=tmp2, sigma=tmp3))

    print('No. of descriptors: ', len(local_descriptors))

    #---------
    # data
    if not parser.has_section('data'):
        raise ValueError('Section "data" is mandatory.')
    data_path = parser.get('data', 'input_path')
    img_ext = parser.get('data', 'image_type')
    res_path = parser.get('data', 'output_path')

    img_files = glob.glob(data_path + '/*.' + img_ext)
    if len(img_files) == 0:
        return

    ## Process:

    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)  # unbuferred output
    for img_name in img_files:
        print("Image: ", img_name, " ...reading... ", end='')
        im = imread(img_name)
        print("preprocessing... ", end='')
        # -preprocessing
        if im.ndim == 3:
            im_h, _, _ = rgb2he2(im)
        else:
            raise ValueError('Input image must be RGB.')

        # detect object region:
        # -try to load a precomputed mask:
        mask_file_name = data_path+'/mask/'+ \
            os.path.splitext(os.path.split(img_name)[1])[0]+ \
            '_tissue_mask.pbm'
        if os.path.exists(mask_file_name):
            print('(loading mask)...', end='')
            mask = imread(mask_file_name)
            mask = img_as_bool(mask)
            mask = remove_small_objects(mask,
                                        min_size=500,
                                        connectivity=1,
                                        in_place=True)
        else:
            print('(computing mask)...', end='')
            mask, _ = tissue_region_from_rgb(im, _min_area=500)

        row_min, col_min, row_max, col_max = bounding_box(mask)
        im_h[np.logical_not(mask)] = 0  # make sure background is 0
        mask = None
        im = None
        im_h = im_h[row_min:row_max + 1, col_min:col_max + 1]

        print("growing the bag...", end='')
        # -image bag growing
        bag = None  # bag for current image
        for d in local_descriptors:
            if bag is None:
                bag = grow_bag_from_new_image(im_h,
                                              d,
                                              wnd_size,
                                              nwindows,
                                              discard_empty=True)
            else:
                bag[d.name] = grow_bag_with_new_features(im_h, bag['regs'],
                                                         d)[d.name]

        # save the results for each image, one file per descriptor
        desc_names = bag.keys()
        desc_names.remove('regs')  # keep all keys but the regions
        # -save the ROI from the original image:
        res_file = res_path + '/' + 'roi-' + \
                   os.path.splitext(os.path.split(img_name)[1])[0] + '.dat'
        with open(res_file, 'w') as f:
            f.write('\t'.join(
                [str(x_) for x_ in [row_min, row_max, col_min, col_max]]))

        for dn in desc_names:
            res_file = res_path + '/' + dn + '_bag-' + \
                       os.path.splitext(os.path.split(img_name)[1])[0] + '.dat'
            with open(res_file, 'w') as f:
                n = len(bag[dn])  # total number of descriptors of this type
                for i in range(n):
                    s = '\t'.join([str(x_) for x_ in bag['regs'][i]]) + '\t' + \
                        '\t'.join([str(x_) for x_ in bag[dn][i]]) + '\n'
                    f.write(s)

        print('OK')

        bag = None
        gc.collect()
        gc.collect()