def finalize(self, **kwargs): import kwimage from ndsampler.utils import util_gdal final = self.cache.get('final', None) if final is None: if util_gdal.have_gdal(): final = util_gdal.LazyGDalFrameFile(self.fpath) else: # TODO: delay even further with gdal final = kwimage.imread(self.fpath) final = kwarray.atleast_nd(final, 3) dsize = self.meta.get('dsize', None) if dsize is not None: final = np.asarray(final) final = kwimage.imresize(final, dsize=dsize) self.cache['final'] = final as_xarray = kwargs.get('as_xarray', False) if as_xarray: # FIXME: might not work with import xarray as xr channels = self.channels coords = {} if channels is not None: coords['c'] = channels.code_list() final = xr.DataArray(final, dims=('y', 'x', 'c'), coords=coords) return final
def main(): image_fpath = 'path/to/image.jpg' detector_fpath = 'path/to/detector.zip' # Determine the database annotation ids. dset = kwcoco.CocoDataset.coerce('path/to/kwcoco-dataset/data.kwcoco.json') aids: list[int] = list(dset.annots()) detector = whodis.Detector.load(detector_fpath) imdata: np.ndarray = kwimage.imread(image_fpath) detections = detector.detect(imdata) database = whodis.ReidDataset.from_kwcoco(dset, aids) matches = database.query(detections) # Do filtering based on some criterion decisions = matches.filter(config={ 'method': 'name-score', 'threshold': 0.3 }) # not sure of the details here # will need to export edge information, and update the state of whatever # the managing datastore is. decisions.export()
def bench_imread(): import ubelt as ub # fpath = ub.grabdata('http://www.topcoder.com/contest/problem/UrbanMapper3D/JAX_Tile_043_DTM.tif') import kwimage fpath = kwimage.grab_test_image_fpath('airport') # A color-table geotiff # https://download.osgeo.org/geotiff/samples/ # fpath = ub.grabdata('https://download.osgeo.org/geotiff/samples/usgs/c41078a1.tif') ti = ub.Timerit(100, bestof=5, verbose=2) results = {} fpath = '/home/joncrall/data/sample_ptif.ptif' fpath = '/home/joncrall/data/sample_cog.cog.tif' for timer in ti.reset('gdal-v1'): with timer: image = _read_gdal_v1(fpath) results[ti.label] = image.sum() for timer in ti.reset('gdal-v2'): with timer: image = _read_gdal_v2(fpath) results[ti.label] = image.sum() for timer in ti.reset('rasterio'): with timer: image = _read_rasterio(fpath) results[ti.label] = image.sum() import skimage.io """ pip install tifffile pip install imagecodecs """ for timer in ti.reset('skimage'): with timer: image = skimage.io.imread(fpath) results[ti.label] = image.sum() import kwimage for timer in ti.reset('kwimage'): with timer: image = kwimage.imread(fpath) results[ti.label] = image.sum() import cv2 for timer in ti.reset('cv2'): with timer: image = cv2.imread(fpath) results[ti.label] = image.sum() for timer in ti.reset('pil'): with timer: image = _read_pil(fpath) results[ti.label] = image.sum()
def _rectify_image(self, path_or_image): if isinstance(path_or_image, six.string_types): self.info('Reading {!r}'.format(path_or_image)) full_rgb = kwimage.imread(path_or_image, space='rgb') else: full_rgb = path_or_image return full_rgb
def validate(self, orig_fpath=None, orig_data=None): """ Check for any corruption issues Args: orig_fpath (str): if specified and the data seems to be all zero, we check if the pixels are close to the pixels in this other image. If not the warning becomes an error. orig_data (ndarray): alternative to orig_fpath if the data is in memory. Returns: Dict: info about errors, warnings, and details """ info = { 'errors': [], 'warnings': [], 'details': {}, 'fpath': self.cog_fpath, 'orig_fpath': orig_fpath, } try: from ndsampler.utils.validate_cog import validate as _validate_cog warnings, errors, details = _validate_cog(self.cog_fpath) except Exception as ex: info['errors'].append(repr(ex)) else: info['errors'].extend(errors) info['warnings'].extend(warnings) info['details'] = details try: has_data = validate_nonzero_data(self) if not has_data: if orig_data is None and orig_fpath is not None: import kwimage orig_data = kwimage.imread(orig_fpath) if orig_data is None: # All we can do is warn here info['warnings'].append('image appears to be all black') else: orig_sum = orig_data.sum() if orig_sum > 0: info['errors'].append( 'image is all zeros, but orig_sum = {!r}'.format( orig_sum)) except Exception as ex: info['errors'].append(repr(ex)) if info['errors']: info['status'] = 'fail' else: info['status'] = 'pass' return info
def _npy_cache_write(gpath, cache_gpath, config=None): # Load all the image data and dump it to npy format import kwimage raw_data = kwimage.imread(gpath) # Even with the file-lock and atomic save there is still a race # condition somewhere. Not sure what it is. # _semi_atomic_numpy_save(cache_gpath, raw_data) # with atomicwrites.atomic_write(cache_gpath, mode='wb', overwrite=True) as file: with open(cache_gpath, mode='wb') as file: np.save(file, raw_data)
def camvid_load_truth(img): # TODO: better way to load per-pixel truth with sampler mask_fpath = join(coco_dset.img_root, img['segmentation']) rgb_mask = kwimage.imread(mask_fpath, space='rgb') r, g, b = rgb_mask.T.astype(np.int64) cid_mask = np.ascontiguousarray(rgb_to_cid(r, g, b).T) ignore_idx = 0 cidx_mask = np.full_like(cid_mask, fill_value=ignore_idx) for cx, cid in enumerate(cx_to_cid): locs = (cid_mask == cid) cidx_mask[locs] = cx return cidx_mask
def resize_all(): in_dpath = '/media/joncrall/raid/Pictures/Bezoar' out_dpath = '/media/joncrall/raid/Pictures/BezoarSmall' IMAGE_EXTENSIONS = ( '.bmp', '.pgm', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.ntf', '.nitf', '.ptif', '.cog.tiff', '.cog.tif', '.r0', '.r1', '.r2', '.r3', '.r4', '.r5', '.nsf', ) import os from os.path import join, relpath import kwimage recursive = False max_dim = 2000 tasks = [] for root, ds, fs in os.walk(in_dpath): if not recursive: ds[:] = [] valid_fs = [f for f in fs if f.lower().endswith(IMAGE_EXTENSIONS)] valid_fpaths = [join(root, fname) for fname in valid_fs] for in_fpath in valid_fpaths: out_fpath = join(out_dpath, relpath(in_fpath, in_dpath)) tasks.append((in_fpath, out_fpath)) import ubelt as ub for in_fpath, out_fpath in ub.ProgIter(tasks): in_imdata = kwimage.imread(in_fpath) out_imdata = kwimage.imresize(in_imdata, max_dim=max_dim) kwimage.imwrite(out_fpath, out_imdata)
def _load_native_channel(self, chan_name, cache=True): """ Load a specific auxiliary channel, optionally caching it """ chan = self.pathinfo['channels'][chan_name] if not cache: import kwimage gpath = chan['path'] data = kwimage.imread(gpath) else: cache_key = chan_name _channel_memcache = self._channel_memcache if _channel_memcache is not None and cache_key in _channel_memcache: return _channel_memcache[cache_key] gpath = chan['path'] cache_type = chan['cache_type'] if cache_type is None: import kwimage data = kwimage.imread(gpath) elif cache_type == 'cog': cache_gpath = chan['cache'] config = self.cache_backend['config'] hack_use_cli = self.cache_backend['_hack_use_cli'] data = _ensure_image_cog(gpath, cache_gpath, config, hack_use_cli) elif cache_type == 'npy': cache_gpath = chan['cache'] data = _ensure_image_npy(gpath, cache_gpath) else: raise KeyError(cache_type) if _channel_memcache is not None: _channel_memcache[cache_key] = data return data
def _doctest_check_cog(data, fpath): from ndsampler.utils.validate_cog import validate as _validate_cog import kwimage print('---- CHECK COG ---') print('fpath = {!r}'.format(fpath)) disk_shape = kwimage.imread(fpath).shape errors = _validate_cog(fpath) warnings, errors, details = _validate_cog(fpath) print('disk_shape = {!r}'.format(disk_shape)) print('details = ' + ub.repr2(details, nl=2)) print('warnings = ' + ub.repr2(warnings, nl=1)) print('errors = ' + ub.repr2(errors, nl=1)) passed = not errors assert data.shape == disk_shape return passed
def draw_true_and_pred_boxes(true_fpath, pred_fpath, gid, viz_fpath): """ How do you generally visualize gt and predicted bounding boxes together? Example: >>> import kwcoco >>> import ubelt as ub >>> from os.path import join >>> from kwcoco.demo.perterb import perterb_coco >>> # Create a working directory >>> dpath = ub.ensure_app_cache_dir('kwcoco/examples/draw_true_and_pred_boxes') >>> # Lets setup some dummy true data >>> true_dset = kwcoco.CocoDataset.demo('shapes2') >>> true_dset.fpath = join(dpath, 'true_dset.kwcoco.json') >>> true_dset.dump(true_dset.fpath, newlines=True) >>> # Lets setup some dummy predicted data >>> pred_dset = perterb_coco(true_dset, box_noise=100, rng=421) >>> pred_dset.fpath = join(dpath, 'pred_dset.kwcoco.json') >>> pred_dset.dump(pred_dset.fpath, newlines=True) >>> # >>> # We now have our true and predicted data, lets visualize >>> true_fpath = true_dset.fpath >>> pred_fpath = pred_dset.fpath >>> print('dpath = {!r}'.format(dpath)) >>> print('true_fpath = {!r}'.format(true_fpath)) >>> print('pred_fpath = {!r}'.format(pred_fpath)) >>> # Lets choose an image id to visualize and a path to write to >>> gid = 1 >>> viz_fpath = join(dpath, 'viz_{}.jpg'.format(gid)) >>> # The answer to the question is in the logic of this function >>> draw_true_and_pred_boxes(true_fpath, pred_fpath, gid, viz_fpath) """ import kwimage import kwcoco true_dset = kwcoco.CocoDataset(true_fpath) pred_dset = kwcoco.CocoDataset(pred_fpath) if __debug__: # I hope your image ids are aligned between datasets true_img = true_dset.imgs[gid] pred_img = pred_dset.imgs[gid] assert true_img['file_name'] == pred_img['file_name'] # Get the true/pred annotation dictionaries from the chosen image true_aids = true_dset.index.gid_to_aids[gid] pred_aids = pred_dset.index.gid_to_aids[gid] true_anns = [true_dset.index.anns[aid] for aid in true_aids] pred_anns = [pred_dset.index.anns[aid] for aid in pred_aids] # Create Detections from the coco annotation dictionaries true_dets = kwimage.Detections.from_coco_annots(true_anns, dset=true_dset) pred_dets = kwimage.Detections.from_coco_annots(pred_anns, dset=pred_dset) print('true_dets.boxes = {!r}'.format(true_dets.boxes)) print('pred_dets.boxes = {!r}'.format(pred_dets.boxes)) # Load the image fpath = true_dset.get_image_fpath(gid) canvas = kwimage.imread(fpath) # Use kwimage.Detections draw_on method to modify the image canvas = true_dets.draw_on(canvas, color='green') canvas = pred_dets.draw_on(canvas, color='blue') kwimage.imwrite(viz_fpath, canvas)
def predict(self, path_or_image): self._preload() if isinstance(path_or_image, six.string_types): print('Reading {!r}'.format(path_or_image)) full_rgb = kwimage.imread(path_or_image, space='rgb') else: full_rgb = path_or_image # Note, this doesn't handle the case where the image is smaller than # the window input_dims = full_rgb.shape[0:2] try: classes = self.model.module.classes except AttributeError: classes = self.model.classes stitchers = { 'class_energy': nh.util.Stitcher((len(classes),) + tuple(input_dims)) } slider = nh.util.SlidingWindow(input_dims, self.config['window_dims'], overlap=0, keepbound=True, allow_overshoot=True) slider_dset = PredSlidingWindowDataset(slider, full_rgb) slider_loader = torch.utils.data.DataLoader(slider_dset, batch_size=self.config['batch_size'], num_workers=self.config['workers'], shuffle=False, pin_memory=True) prog = ub.ProgIter(slider_loader, desc='sliding window') with torch.no_grad(): for raw_batch in prog: im = self.xpu.move(raw_batch['im']) outputs = self.model(im) class_energy = outputs['class_energy'].data.cpu().numpy() batch_sl_st_dims = raw_batch['sl_st_dims'].data.cpu().long().numpy().tolist() batch_sl_dims = [tuple(slice(s, t) for s, t in item) for item in batch_sl_st_dims] for sl_dims, energy in zip(batch_sl_dims, class_energy): slices = (slice(None),) + sl_dims stitchers['class_energy'].add(slices, energy) full_class_energy = stitchers['class_energy'].finalize() full_class_probs = torch.FloatTensor(full_class_energy).softmax(dim=0) full_class_probs = full_class_probs.numpy() full_class_idx = full_class_probs.argmax(axis=0) pred_heatmap = kwimage.Heatmap( class_probs=full_class_probs, class_idx=full_class_idx, classes=classes, datakeys=['class_idx'], ) return pred_heatmap
def imshow(img, fnum=None, pnum=None, xlabel=None, title=None, figtitle=None, ax=None, norm=None, cmap=None, data_colorbar=False, colorspace='rgb', interpolation='nearest', alpha=None, **kwargs): r""" Args: img (ndarray): image data. Height, Width, and Channel dimensions can either be in standard (H, W, C) format or in (C, H, W) format. If C in [3, 4], we assume data is in the rgb / rgba colorspace by default. colorspace (str): if the data is 3-4 channels, this indicates the colorspace 1 channel data is assumed grayscale. 4 channels assumes alpha. interpolation (str): either nearest (default), bicubic, bilinear norm (bool): if True, normalizes the image intensities to fit in a colormap. cmap (Colormap): color map used if data is not starndard image data data_colorbar (bool): if True, displays a color scale indicating how colors map to image intensities. fnum (int): figure number pnum (tuple): plot number xlabel (str): sets the label for the x axis title (str): set axes title (if ax is not given) figtitle (None): set figure title (if ax is not given) ax (Axes): axes to draw on (alternative to fnum and pnum) **kwargs: docla, doclf, projection Returns: tuple: (fig, ax) Ignore: >>> import kwplot >>> kwplot.autompl() >>> import kwimage >>> img = kwimage.grab_test_image('carl') >>> (fig, ax) = imshow(img) >>> result = ('(fig, ax) = %s' % (str((fig, ax)),)) >>> print(result) >>> kwplot.show_if_requested() """ import matplotlib as mpl import matplotlib.pyplot as plt if ax is not None: fig = ax.figure nospecial = True else: fig = figure(fnum=fnum, pnum=pnum, title=title, figtitle=figtitle, **kwargs) ax = fig.gca() nospecial = False if isinstance(img, six.string_types): # Allow for path to image to be specified img_fpath = img import kwimage img = kwimage.imread(img_fpath) valid_interpolation_choices = ['nearest', 'bicubic', 'bilinear'] if interpolation not in valid_interpolation_choices: raise KeyError( 'Invalid interpolation choice {}. Can be {}'.format( interpolation, valid_interpolation_choices)) plt_imshow_kwargs = { 'interpolation': interpolation, } if alpha is not None: plt_imshow_kwargs['alpha'] = alpha if norm is not None: if norm is True: norm = 'linear' if isinstance(norm, six.string_types): norm_choices = { 'linear': mpl.colors.Normalize, 'log': mpl.colors.LogNorm, } try: norm = norm_choices[norm]() except KeyError: raise KeyError('norm={} not in valid choices: {}'.format( norm, list(norm_choices) )) if not isinstance(norm, mpl.colors.Normalize): raise TypeError('norm={} must be an instance of {} or in {}'.format( norm, mpl.colors.Normalize, list(norm_choices))) plt_imshow_kwargs['norm'] = norm else: if cmap is None and not nospecial: plt_imshow_kwargs['vmin'] = 0 plt_imshow_kwargs['vmax'] = 255 # Handle tensor chw format in most cases try: if 'torch' in img.__module__: img = img.cpu().data.numpy() except Exception: pass if img.ndim == 3: if img.shape[0] == 3 or img.shape[0] == 1: if img.shape[2] > 4: # probably in chw format img = img.transpose(1, 2, 0) try: if len(img.shape) == 3 and (img.shape[2] == 3 or img.shape[2] == 4): # img is in a color format dst_space = 'rgb' import kwimage imgRGB = kwimage.convert_colorspace(img, src_space=colorspace, dst_space=dst_space, implicit=True) if not norm: if imgRGB.dtype.kind == 'f': maxval = imgRGB.max() if maxval > 1.01 and maxval < 256: imgRGB = np.array(imgRGB, dtype=np.uint8) cs = ax.imshow(imgRGB, **plt_imshow_kwargs) elif len(img.shape) == 2 or (len(img.shape) == 3 and img.shape[2] == 1): # img is in grayscale if len(img.shape) == 3: imgGRAY = img.reshape(img.shape[0:2]) else: imgGRAY = img if cmap is None: cmap = plt.get_cmap('gray') if isinstance(cmap, six.string_types): cmap = plt.get_cmap(cmap) # for some reason gray floats aren't working right if not norm: if imgGRAY.max() <= 1.01 and imgGRAY.min() >= -1E-9: imgGRAY = (imgGRAY * 255).astype(np.uint8) cs = ax.imshow(imgGRAY, cmap=cmap, **plt_imshow_kwargs) else: raise AssertionError( 'Unknown image format. ' 'img.dtype={!r}, img.shape={!r}'.format( img.dtype, img.shape) ) except TypeError as te: print('[imshow] imshow ERROR %r' % (te,)) raise except Exception as ex: print('!!! WARNING !!!') print('[imshow] type(img) = %r' % type(img)) if not isinstance(img, np.ndarray): print('!!! ERRROR !!!') pass print('[imshow] img.dtype = %r' % (img.dtype,)) print('[imshow] type(img) = %r' % (type(img),)) print('[imshow] img.shape = %r' % (img.shape,)) print('[imshow] imshow ERROR %r' % ex) raise ax.set_xticks([]) ax.set_yticks([]) if data_colorbar: # Use the axes to supply the colorbar info # Does this mean we can depricate `colorbar`? cbar = fig.colorbar(cs) if isinstance(norm, mpl.colors.LogNorm): # References: # https://github.com/matplotlib/matplotlib/issues/8307 cbar.ax.yaxis.set_major_locator(mpl.ticker.LogLocator()) # <- Why? See refs cbar.set_ticks(cbar.ax.yaxis.get_major_locator().tick_values( img.min(), img.max())) # scores = np.unique(img.flatten()) # if cmap is None: # cmap = 'hot' # colors = scores_to_color(scores, cmap) # colorbar(scores, colors) if xlabel is not None: ax.set_xlabel(xlabel) if figtitle is not None: set_figtitle(figtitle) return fig, ax
def multiple_items_from_a_dictionary(): """ Spotlight: ubelt.take Modivation: Working with Lists of Dictionaries Requires: kwimage """ ... """ When working with data, a common pattern is to iterate through it, and gather information about the work to be done, so a you can make a final structured pass through the data. In python we might do this by initializing an empty list and appending **dictionary of information**, to the list. (or you might yield dictionaries of information from a generator instead, either way you have a flat list). Some people might use lists of tuples instead of Lists of dictionaries, but using dictionaries makes it easy to add new information later (and it works very will with pandas). """ import ubelt as ub import kwimage kwimage_test_image_names = [ 'airport', 'amazon', 'astro', 'carl', 'lowcontrast' ] rows = [] for test_image in kwimage_test_image_names: fpath = ub.Path(kwimage.grab_test_image_fpath(test_image)) imdata = kwimage.imread(fpath) row = { 'mean': imdata.mean(), 'std': imdata.std(), 'sum': imdata.sum(), 'max': imdata.max(), 'min': imdata.min(), } rows.append(row) """ For each row, you might want to grab multiple specific items from it. But having a separate assignment on each row wastes a lot of vertical space. """ for row in rows: mean = row['mean'] std = row['std'] sum = row['sum'] min = row['min'] max = row['max'] """ You might put them one line explicitly, but that wastes a lot of horizontal space """ for row in rows: mean, std, sum, min, max = row['mean'], row['std'], row['sum'], row[ 'min'], row['max'] """ What if we try to be clever? We can use a list comprehension """ for row in rows: mean, std, sum, min, max = [ row[k] for k in ['mean', 'std', 'sum', 'min', 'max'] ] """ That's not too bad, but we can do better """ for row in rows: mean, std, sum, min, max = ub.take( row, ['mean', 'std', 'sum', 'min', 'max'])
def test_variable_backend(): """ CommandLine: xdoctest -m $HOME/code/ndsampler/tests/tests_frame_backends.py test_variable_backend --debug-validate-cog --debug-load-cog """ try: import gdal # NOQA except ImportError: import pytest pytest.skip('cog requires gdal') import ndsampler import kwcoco import ubelt as ub dpath = ub.ensure_app_cache_dir('ndsampler/tests/test_variable_backend') ub.delete(dpath) ub.ensuredir(dpath) fnames = [ 'test_rgb_255.jpg', 'test_gray_255.jpg', 'test_rgb_255.png', 'test_rgba_255.png', 'test_gray_255.png', 'test_rgb_01.tif', 'test_rgb_255.tif', 'test_rgba_01.tif', 'test_rgba_255.tif', 'test_gray_01.tif', 'test_gray_255.tif', ] import kwarray import kwimage fpaths = [] rng = kwarray.ensure_rng(0) h, w = 1200, 1055 for fname in ub.ProgIter(fnames, desc='create test data'): if 'rgb_' in fname: data = rng.rand(h, w, 3) elif 'rgba_' in fname: data = rng.rand(h, w, 4) elif 'gray_' in fname: data = rng.rand(h, w, 1) if '01' in fname: pass elif '255' in fname: data = (data * 255).astype(np.uint8) fpath = join(dpath, fname) fpaths.append(fpath) kwimage.imwrite(fpath, data) for fpath in fpaths: data = kwimage.imread(fpath) print( ub.repr2( { 'fname': basename(fpath), 'data.shape': data.shape, 'data.dtype': data.dtype, }, nl=0)) dset = kwcoco.CocoDataset.from_image_paths(fpaths) sampler = ndsampler.CocoSampler(dset, backend='cog', workdir=dpath) frames = sampler.frames # frames.prepare() if 1: for gid in frames.image_ids: print('======== < START IMAGE ID > ===============') gpath, cache_gpath = frames._gnames(gid) print('gpath = {!r}'.format(gpath)) print('cache_gpath = {!r}'.format(cache_gpath)) image = frames.load_image(gid) print('image = {!r}'.format(image)) print('image.shape = {!r}'.format(image.shape)) print('image.dtype = {!r}'.format(image.dtype)) subdata = image[0:8, 0:8] print('subdata.dtype = {!r}'.format(subdata.dtype)) print('subdata.shape = {!r}'.format(subdata.shape)) # info = ub.cmd('gdalinfo ' + cache_gpath, verbose=0) # print('GDAL INFO:') # print(ub.indent(info['out'])) # assert info['ret'] == 0 # dataset = gdal.OpenEx(cache_gpath) dataset = gdal.Open(cache_gpath, gdal.GA_ReadOnly) md = dataset.GetMetadata('IMAGE_STRUCTURE') print('md = {!r}'.format(md)) # Use dict.get method in case the metadata dict does not have a 'COMPRESSION' key compression = md.get('COMPRESSION', 'RAW') print('compression = {!r}'.format(compression)) print('======== < END IMAGE ID > ===============')
def detect_cli(config={}): """ CommandLine: python -m bioharn.detect_predict --help CommandLine: python -m bioharn.detect_predict \ --dataset=~/data/noaa/Habcam_2015_g027250_a00102917_c0001_v2_test.mscoco.json \ --deployed=/home/joncrall/work/bioharn/fit/runs/bioharn-det-v11-test-cascade/myovdqvi/deploy_MM_CascadeRCNN_myovdqvi_035_MVKVVR.zip \ --out_dpath=~/work/bioharn/habcam_test_out \ --draw=100 \ --input_dims=512,512 \ --xpu=0 --batch_size=1 Ignore: >>> config = {} >>> config['dataset'] = '~/data/noaa/Habcam_2015_g027250_a00102917_c0001_v2_vali.mscoco.json' >>> config['deployed'] = '/home/joncrall/work/bioharn/fit/runs/bioharn-det-v11-test-cascade/myovdqvi/deploy_MM_CascadeRCNN_myovdqvi_035_MVKVVR.zip' >>> config['out_dpath'] = 'out' """ import kwarray import ndsampler from os.path import basename, join, exists, isfile, isdir # NOQA config = DetectPredictCLIConfig(config, cmdline=True) print('config = {}'.format(ub.repr2(config.asdict()))) out_dpath = ub.expandpath(config.get('out_dpath')) import six if isinstance(config['dataset'], six.string_types): if config['dataset'].endswith('.json'): dataset_fpath = ub.expandpath(config['dataset']) coco_dset = ndsampler.CocoDataset(dataset_fpath) # Running prediction is much faster if you can build a sampler. sampler_backend = { 'type': 'cog', 'config': { 'compress': 'JPEG', }, '_hack_old_names': False, # flip to true to use legacy caches } sampler_backend = None print('coco hashid = {}'.format(coco_dset._build_hashid())) else: sampler_backend = None if exists(config['dataset']) and isfile(config['dataset']): # Single image case image_fpath = ub.expandpath(config['dataset']) coco_dset = ndsampler.CocoDataset() coco_dset.add_image(image_fpath) elif isinstance(config['dataset'], list): # Multiple image case gpaths = config['dataset'] gpaths = [ub.expandpath(g) for g in gpaths] coco_dset = ndsampler.CocoDataset() for gpath in gpaths: coco_dset.add_image(gpath) else: raise TypeError(config['dataset']) draw = config.get('draw') workdir = ub.expandpath(config.get('workdir')) det_outdir = ub.ensuredir((out_dpath, 'pred')) pred_config = ub.dict_subset(config, DetectPredictConfig.default) print('Create sampler') sampler = ndsampler.CocoSampler(coco_dset, workdir=workdir, backend=sampler_backend) print('prepare frames') sampler.frames.prepare(workers=config['workers']) print('Create predictor') predictor = DetectPredictor(pred_config) print('Ensure model') predictor._ensure_model() pred_dataset = coco_dset.dataset.copy() pred_dataset['annotations'] = [] pred_dset = ndsampler.CocoDataset(pred_dataset) # self = predictor predictor.config['verbose'] = 1 pred_gen = predictor.predict_sampler(sampler) buffered_gen = AsyncBufferedGenerator(pred_gen, size=coco_dset.n_images) gid_to_pred = {} prog = ub.ProgIter(buffered_gen, total=coco_dset.n_images, desc='buffered detect') for img_idx, (gid, dets) in enumerate(prog): gid_to_pred[gid] = dets for ann in dets.to_coco(): ann['image_id'] = gid try: catname = ann['category_name'] ann['category_id'] = pred_dset._resolve_to_cid(catname) except KeyError: if 'category_id' not in ann: cid = pred_dset.add_category(catname) ann['category_id'] = cid pred_dset.add_annotation(**ann) single_img_coco = pred_dset.subset([gid]) single_pred_dpath = ub.ensuredir((det_outdir, 'single_image')) single_pred_fpath = join(single_pred_dpath, 'detections_gid_{:08d}.mscoco.json'.format(gid)) single_img_coco.dump(single_pred_fpath, newlines=True) if draw is True or (draw and img_idx < draw): draw_outdir = ub.ensuredir((out_dpath, 'draw')) img_fpath = coco_dset.load_image_fpath(gid) gname = basename(img_fpath) viz_fname = ub.augpath(gname, prefix='detect_', ext='.jpg') viz_fpath = join(draw_outdir, viz_fname) image = kwimage.imread(img_fpath) flags = dets.scores > .2 flags[kwarray.argmaxima(dets.scores, num=10)] = True top_dets = dets.compress(flags) toshow = top_dets.draw_on(image, alpha=None) # kwplot.imshow(toshow) kwimage.imwrite(viz_fpath, toshow, space='rgb') pred_fpath = join(det_outdir, 'detections.mscoco.json') print('Dump detections to pred_fpath = {!r}'.format(pred_fpath)) pred_dset.dump(pred_fpath, newlines=True)
def main(cls, cmdline=True, **kw): """ CommandLine: xdoctest -m make_coco_from_masks.py MakeCocoFromMasksCLI.main Example: >>> import ubelt as ub >>> cls = MakeCocoFromMasksCLI >>> cmdline = False >>> dpath = _make_intmask_demodata() >>> kw = {'src': join(dpath, '*.png'), 'dst': 'masks.mscoco.json'} >>> fpath = cls.main(cmdline, **kw) >>> # Check validity >>> import kwcoco >>> dset = kwcoco.CocoDataset(fpath) >>> dset._check_integrity() >>> # Ensure we can convert to kwimage and access segmentations >>> dset.annots().detections.data['segmentations'][0].data """ import kwcoco config = cls.CLIConfig(kw, cmdline=cmdline) print('config = {}'.format(ub.repr2(dict(config), nl=2))) serialization_method = config['serialization'] # Initialize an empty COCO dataset coco_dset = kwcoco.CocoDataset() # Path to each mask object mask_fpaths = config['src'] for mask_fpath in mask_fpaths: # I assume each mask corresponds to a single image, but I dont know # what those images should be at the moment. TODO: if this is going # to be a real script, then we should find a nice way of specifying # the correspondences between masks and the images to which they # belong. For now, I'm going to use the mask itself as a dummy # value. img_fpath = mask_fpath image_id = coco_dset.add_image(file_name=img_fpath) # Parse the mask file, and add each object as a new annotation multi_mask = kwimage.imread(mask_fpath) # I recall there is a better opencv of splitting these sort of # masks up into binary masks, maybe it was a connected-component # function? I guess it depends if you want disconnected objects # represented as separte annotations or not. I'm just going to do # the naive thing for now. obj_idxs = np.setdiff1d(np.unique(multi_mask), [0]) for obj_idx in obj_idxs: bin_data = (multi_mask == obj_idx).astype(np.uint8) # Create a kwimage object which has nice `to_coco` methods bin_mask = kwimage.Mask(bin_data, format='c_mask') # We can either save in our coco file as a raster RLE style # mask, or we can use a vector polygon style mask. Either of # the resulting coco_sseg objects is a valid value for an # annotation's "segmentation" field. if serialization_method == 'raster': sseg = bin_mask coco_sseg = sseg.to_coco(style='new') elif serialization_method == 'vector': bin_poly = bin_mask.to_multi_polygon() sseg = bin_poly coco_sseg = sseg.to_coco(style='new') # Now we add this segmentation to the coco dataset as a new # annotation. The annotation needs to know which image it # belongs to, and ideally it has a category and a bounding box # as well. # We can make up a dummy category (note that ensure_category # will not fail if there is a duplicate entry but add_category # will) category_id = coco_dset.ensure_category( 'class_{}'.format(obj_idx)) # We can use the kwimage sseg object to get the bounding box # FIXME: apparently the MultiPolygon object doesnt implement # `to_boxes`, at the moment, so force an inefficient conversion # back to a mask as a hack and use its to_boxes method. # Technically, the bounding box should not be required, but its # a good idea to always include it. bbox = list( sseg.to_mask( dims=multi_mask.shape).to_boxes().to_coco())[0] METHOD1 = False if METHOD1: # We could just add it diretly like this # FIXME: it should be ok to add an annotation without a # category, but it seems like a recent change in kwcoco has # broken that. That will be fixed in the future. annot_id = coco_dset.add_annotation( image_id=image_id, category_id=category_id, bbox=bbox, segmentation=coco_sseg) else: # But lets do it as if we were adding a segmentation to an # existing dataset. In this case we access the # CocoDataset's annotation index structure. # # First add the basic annotation annot_id = coco_dset.add_annotation( image_id=image_id, category_id=category_id, bbox=bbox) # Then use the annotation id to look up its coco-dictionary # representation and simply add the segmentation field ann = coco_dset.anns[annot_id] ann['segmentation'] = coco_sseg # You dont have to set the fpath attr, but I tend to like it coco_dset.fpath = config['dst'] print('Writing to fpath = {}'.format(ub.repr2(coco_dset.fpath, nl=1))) coco_dset.dump(coco_dset.fpath, newlines=True) return coco_dset.fpath
def _cog_cache_write(gpath, cache_gpath, config=None): """ CommandLine: xdoctest -m ndsampler.abstract_frames _cog_cache_write Example: >>> # xdoctest: +REQUIRES(module:osgeo) >>> import ndsampler >>> from ndsampler.abstract_frames import * >>> import kwcoco >>> workdir = ub.ensure_app_cache_dir('ndsampler') >>> dset = kwcoco.CocoDataset.demo() >>> imgs = dset.images() >>> id_to_name = imgs.lookup('file_name', keepid=True) >>> id_to_path = {gid: join(dset.img_root, name) >>> for gid, name in id_to_name.items()} >>> self = SimpleFrames(id_to_path, workdir=workdir) >>> image_id = ub.peek(id_to_name) >>> #gpath = self._lookup_gpath(image_id) #### EXIT # >>> hashid = self._lookup_hashid(image_id) # >>> cog_gname = '{}_{}.cog.tiff'.format(image_id, hashid) # >>> cache_gpath = cog_gpath = join(self.cache_dpath, cog_gname) # >>> _cog_cache_write(gpath, cache_gpath, {}) """ assert config is not None # FIXME: if gdal_translate is not installed (because libgdal exists, but # gdal-bin doesn't) then this seems to fail without throwing an error when # hack_use_cli=1. hack_use_cli = config.pop('hack_use_cli', False) if DEBUG_COG_ATOMIC_WRITE: import multiprocessing from multiprocessing import current_process from threading import current_thread is_main = (current_thread().name == 'MainThread' and current_process().name == 'MainProcess') proc = multiprocessing.current_process() def _debug(msg): msg_ = '[{}, {}, {}] '.format(ub.timestamp(), proc, proc.pid) + msg + '\n' if is_main: print(msg_) with open(cache_gpath + '.atomic.debug', 'a') as f: f.write(msg_) _debug('attempts aquire'.format()) if not hack_use_cli: # Load all the image data and dump it to cog format import kwimage if DEBUG_COG_ATOMIC_WRITE: _debug('reading data') raw_data = kwimage.imread(gpath) # raw_data = kwimage.atleast_3channels(raw_data, copy=False) # TODO: THERE HAS TO BE A CORRECT WAY TO DO THIS. # However, I'm not sure what it is. I extend my appologies to whoever is # maintaining this code. Note: mode MUST be 'w' with atomicwrites.atomic_write(cache_gpath + '.atomic', mode='w', overwrite=True) as file: if DEBUG_COG_ATOMIC_WRITE: _debug('begin') _debug('gpath = {}'.format(gpath)) _debug('cache_gpath = {}'.format(cache_gpath)) try: file.write('begin: {}\n'.format(ub.timestamp())) file.write('gpath = {}\n'.format(gpath)) file.write('cache_gpath = {}\n'.format(cache_gpath)) if not exists(cache_gpath): if not hack_use_cli: util_gdal._imwrite_cloud_optimized_geotiff( cache_gpath, raw_data, **config) else: # The CLI is experimental and might make this pipeline # faster by avoiding the initial read. util_gdal._cli_convert_cloud_optimized_geotiff( gpath, cache_gpath, **config) if DEBUG_COG_ATOMIC_WRITE: _debug('finished write: {}\n'.format(ub.timestamp())) else: if DEBUG_COG_ATOMIC_WRITE: _debug('ALREADY EXISTS did not write: {}\n'.format(ub.timestamp())) file.write('end: {}\n'.format(ub.timestamp())) except Exception as ex: file.write('FAILED DUE TO EXCEPTION: {}: {}\n'.format(ex, ub.timestamp())) if DEBUG_COG_ATOMIC_WRITE: _debug('FAILED DUE TO EXCEPTION: {}'.format(ex)) raise finally: if DEBUG_COG_ATOMIC_WRITE: _debug('finally') if RUN_COG_CORRUPTION_CHECKS: # CHECK THAT THE DATA WAS WRITTEN CORRECTLY file = util_gdal.LazyGDalFrameFile(cache_gpath) is_valid = util_gdal.validate_nonzero_data(file) if not is_valid: if hack_use_cli: import kwimage raw_data = kwimage.imread(gpath) # The check may fail on zero images, so check that orig_sum = raw_data.sum() # cache_sum = file[:].sum() # if DEBUG: # _debug('is_valid = {}'.format(is_valid)) # _debug('cache_sum = {}'.format(cache_sum)) if orig_sum > 0: print('FAILED TO WRITE COG FILE') print('orig_sum = {!r}'.format(orig_sum)) # print(kwimage.imread(cache_gpath).sum()) if DEBUG_COG_ATOMIC_WRITE: _debug('FAILED TO WRITE COG FILE') ub.delete(cache_gpath) raise CorruptCOG('FAILED TO WRITE COG FILE CORRECTLY')
def check_nitfs(): nitfs = unsafe_grab_nitfs() import xdev import netharn as nh total = 0 for fpath in nitfs: nbytes = nh.util.get_file_info(fpath)['filesize'] print('nbytes = {!r}'.format(xdev.byte_str(nbytes))) total += nbytes print(xdev.byte_str(total)) failed_fpaths = [] passed_fpaths = [] for fpath in nitfs: import kwimage try: kwimage.imread(fpath) passed_fpaths.append(fpath) except Exception: failed_fpaths.append(fpath) print('passed = {}'.format(len(passed_fpaths))) print('failed = {}'.format(len(failed_fpaths))) print('CANT HANDLE') for fpath in failed_fpaths: name = splitext(basename(fpath))[0] desc = NITF_DESC[name] print(desc) for fpath in failed_fpaths: print('\n-----') print('fpath = {!r}'.format(fpath)) try: kwimage.imread(fpath) except Exception: pass print('\n-----') from ndsampler.abstract_frames import _cog_cache_write for gpath in passed_fpaths: cache_gpath = ub.augpath(gpath, ext='.test.api.cog') ub.delete(cache_gpath) # config = {'hack_use_cli': True} config = {'hack_use_cli': False, 'compress': 'LZW'} _cog_cache_write(gpath, cache_gpath, config=config) from ndsampler.abstract_frames import _cog_cache_write for gpath in passed_fpaths: cache_gpath = ub.augpath(gpath, ext='.test.cli.cog') ub.delete(cache_gpath) # config = {'hack_use_cli': True} config = {'hack_use_cli': True, 'compress': 'LZW'} _cog_cache_write(gpath, cache_gpath, config=config) from ndsampler.abstract_frames import _cog_cache_write for gpath in passed_fpaths: cache_gpath = ub.augpath(gpath, ext='.test.cli.cog') ub.delete(cache_gpath) # config = {'hack_use_cli': True} kwimage.imread(gpath) config = {'hack_use_cli': True, 'compress': 'JPEG'} _cog_cache_write(gpath, cache_gpath, config=config)
""" Requirements: pip install kwarray kwimage[headless] kwplot ubelt numpy scipy """ import kwarray import kwimage import kwplot import ubelt as ub import numpy as np from scipy import integrate fpath = ub.grabdata('https://i.redd.it/ywip9sbwysy71.jpg') data = kwimage.imread(fpath) subdata = data[242:-22, 22:300] img = subdata inty = integrate.cumtrapz(img, axis=0) intx = integrate.cumtrapz(img, axis=1) dery = np.gradient(img, axis=0) derx = np.gradient(img, axis=1) der_canvas = kwarray.normalize(kwimage.stack_images([dery, derx], axis=0)) int_canvas = kwarray.normalize(kwimage.stack_images([inty, intx], axis=0)) der_canvas = kwimage.ensure_uint255(der_canvas) int_canvas = kwimage.ensure_uint255(int_canvas) der_canvas = kwimage.draw_header_text(der_canvas, 'derivative', color='white') int_canvas = kwimage.draw_header_text(int_canvas,
def time_ondisk_crop(size=512, dim=3, region='small_random', num=24): """ Ignore: >>> from bench_subregion_imread import * # NOQA >>> import xdev >>> globals().update(xdev.get_func_kwargs(time_ondisk_crop)) """ enabled = { 'in_memory': False, 'memmap': True, 'PIL': False, 'OpenCV': True, 'VIPS': True, 'GDAL': True, 'HDF5': True, } print('\n---') # DATA = 'custom' DATA = 'random' if DATA == 'random': # data = (np.random.rand(500, 500, 3) * 255).astype(np.uint8) print('Generate random data, size={}, dim={}, mode={}'.format( size, dim, region)) x, y = np.meshgrid(np.arange(0, size), np.arange(0, size)) data = np.ascontiguousarray( (np.dstack([x] * dim) % 256).astype(np.uint8)) data = data.squeeze() elif DATA == 'custom': print('USE CUSTOM data, size={}, dim={}, mode={}'.format( size, dim, region)) assert False custom_fpath = '.ptif' import kwimage data = kwimage.imread(custom_fpath) else: raise KeyError(DATA) print('Make temp directory to prepare data') dpath = tempfile.mkdtemp() lossy_ext = ('.jpg', '.ptif', '.cog') img_fpaths = { # 'png': join(dpath, 'foo.png'), # 'jpg': join(dpath, 'foo.jpg'), # 'tif': join(dpath, 'foo.tif'), } pil_img = Image.fromarray(data) for k, v in img_fpaths.items(): print('DUMP v = {!r}'.format(v)) pil_img.save(v) img_fpaths['cog'] = join(dpath, 'foo.cog') # kwimage.imwrite(img_fpaths['cog'], data, backend='gdal', compress='LZW') kwimage.imwrite(img_fpaths['cog'], data, backend='gdal', compress='ZSTD') # imwrite_cloud_optimized_geotiff(img_fpaths['cog'], data) if DATA == 'custom': from os.path import splitext import shutil ext = splitext(custom_fpath)[1][1:] tmp_fpath = join(dpath, 'foo' + ext) shutil.copy2(custom_fpath, tmp_fpath) img_fpaths.update({ 'custom_' + ext: tmp_fpath, }) mem_fpaths = {} if enabled['memmap']: mem_fpaths = { 'npy': join(dpath, 'foo.npy'), } for key, fpath in mem_fpaths.items(): print('DUMP fpath = {!r}'.format(fpath)) np.save(fpath, data) h5_fpaths = {} if enabled['HDF5']: import h5py h5_params = { # 'basic': {}, # 'chunks': {'chunks': (32, 32, 1)}, # 'lzf': {'compression': 'lzf'}, # 'lzf_chunk32': {'compression': 'lzf', 'chunks': (32, 32, 1)}, 'lzf_chunk128': { 'compression': 'lzf', 'chunks': (128, 128, 1) }, } for key, kw in h5_params.items(): print('Dump h5 ' + key) fpath = h5_fpaths[key] = join(dpath, key + '.h5') with h5py.File(fpath, 'w') as h5_file: dset = h5_file.create_dataset('DATA', data.shape, data.dtype, **kw) dset[...] = data import netharn as nh bytes_on_disk = {} for k, v in mem_fpaths.items(): bytes_on_disk['mem_' + k] = nh.util.get_file_info(v)['filesize'] for k, v in img_fpaths.items(): bytes_on_disk['img_' + k] = nh.util.get_file_info(v)['filesize'] for k, v in h5_fpaths.items(): bytes_on_disk['hdf5_' + k] = nh.util.get_file_info(v)['filesize'] mb_on_disk = ub.map_vals(lambda x: str(round(x * 1e-6, 2)) + ' MB', bytes_on_disk) print('on-disk memory usage: ' + ub.repr2(mb_on_disk, nl=1)) result = {} def record_result(timer): ti = timer.parent val = ti.min(), ti.mean(), ti.std() result[ti.label] = val rng = np.random.RandomState() def get_index(): """ Get a subregion to load """ if region == 'small_random': # Small window size, but random location size = (172, 172) h, w = size a = rng.randint(0, data.shape[0] - h) b = rng.randint(0, data.shape[1] - w) index = tuple([slice(a, a + h), slice(b, b + w)]) elif region == 'random': a, b = sorted(rng.randint(0, data.shape[0], size=2)) c, d = sorted(rng.randint(0, data.shape[1], size=2)) index = tuple([slice(a, b + 1), slice(c, d + 1)]) elif region == 'corner': index = tuple([slice(0, 8), slice(0, 8)]) else: raise KeyError(index) # index = region if len(data.shape) > 2: index = index + tuple([slice(0, 3)]) area = (index[1].start, index[0].start, index[1].stop, index[0].stop) shape = tuple([s.stop - s.start for s in index]) return index, area, shape def TIMERIT(label): # Ensure each timer run uses the same random numbers rng.seed(0) return timerit.Timerit( num=num, bestof=1, label=label, # unit='us', unit='ms', ) print('Begin benchmarks\n') if enabled['in_memory']: for timer in TIMERIT('in-memory slice'): index, area, shape = get_index() want = data[index] with timer: got = data[index] record_result(timer) if enabled['memmap']: for key, fpath in mem_fpaths.items(): for timer in TIMERIT('np.memmap load+slice ' + key): index, area, shape = get_index() want = data[index] with timer: file1 = np.memmap(fpath, dtype=data.dtype.name, shape=data.shape, offset=128, mode='r') got = file1[index] assert np.all(got == want) record_result(timer) if enabled['memmap']: for key, fpath in mem_fpaths.items(): for timer in TIMERIT('np.load load+slice ' + key): index, area, shape = get_index() want = data[index] with timer: file2 = np.load(fpath, mmap_mode='r') got = file2[index] assert np.all(got == want) record_result(timer) if enabled['PIL']: for key, fpath in img_fpaths.items(): for timer in TIMERIT('PIL open+crop (minimal) ' + key): index, area, shape = get_index() want = data[index] with timer: core = Image.open(fpath).crop(area) record_result(timer) if enabled['PIL']: for key, fpath in img_fpaths.items(): for timer in TIMERIT('PIL open+crop+getdata+asarray ' + key): index, area, shape = get_index() want = data[index] with timer: core = Image.open(fpath).crop(area) got = np.asarray(core.getdata(), dtype=np.uint8) got.shape = shape assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) if enabled['PIL']: for key, fpath in img_fpaths.items(): for timer in TIMERIT('PIL open+asarray+slice ' + key): index, area, shape = get_index() want = data[index] with timer: got = np.asarray(Image.open(fpath))[index] assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) if enabled['OpenCV']: for key, fpath in img_fpaths.items(): for timer in TIMERIT('OpenCV imread+slice ' + key): index, area, shape = get_index() want = data[index] with timer: got = cv2.imread(fpath, flags=cv2.IMREAD_UNCHANGED)[index] if len(index) > 2: got = got[:, :, ::-1] assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) if enabled['GDAL']: for key, fpath in img_fpaths.items(): for timer in TIMERIT('GDAL subregion ' + key): index, area, shape = get_index() want = data[index] with timer: got = gdal_subregion_imread(fpath, index) assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) # pip install pyvips if enabled['VIPS']: import pyvips for key, fpath in img_fpaths.items(): for timer in TIMERIT('VIPS ' + key): index, area, shape = get_index() want = data[index] left, top = area[0:2] width, height = shape[0:2][::-1] vips_img = pyvips.Image.new_from_file( fpath, # access='sequential', access='random', # memory=False, # fail=True ) with timer: vips_sub = vips_img.crop(left, top, width, height) got = np.ndarray(buffer=vips_sub.write_to_memory(), dtype=np.uint8, shape=[ vips_sub.height, vips_sub.width, vips_sub.bands ]) assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) if enabled['HDF5']: for key, fpath in h5_fpaths.items(): for timer in TIMERIT('HDF5 ' + key): with h5py.File(fpath, 'r') as file: dset = file['DATA'] index, area, shape = get_index() want = data[index] with timer: got = dset[index] assert fpath.endswith(lossy_ext) or np.all(got == want) record_result(timer) return result
def convert_camvid_raw_to_coco(camvid_raw_info): """ Converts the raw camvid format to an MSCOCO based format, ( which lets use use kwcoco's COCO backend). Example: >>> # xdoctest: +REQUIRES(--download) >>> camvid_raw_info = grab_raw_camvid() >>> # test with a reduced set of data >>> del camvid_raw_info['img_paths'][2:] >>> del camvid_raw_info['mask_paths'][2:] >>> dset = convert_camvid_raw_to_coco(camvid_raw_info) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> plt = kwplot.autoplt() >>> kwplot.figure(fnum=1, pnum=(1, 2, 1)) >>> dset.show_image(gid=1) >>> kwplot.figure(fnum=1, pnum=(1, 2, 2)) >>> dset.show_image(gid=2) """ import re import kwimage import kwcoco print('Converting CamVid to MS-COCO format') dset_root, img_paths, label_path, mask_paths = ub.take( camvid_raw_info, 'dset_root, img_paths, label_path, mask_paths'.split(', ')) img_infos = { 'img_fname': img_paths, 'mask_fname': mask_paths, } keys = list(img_infos.keys()) next_vals = list(zip(*img_infos.values())) image_items = [{k: v for k, v in zip(keys, vals)} for vals in next_vals] dataset = { 'img_root': dset_root, 'images': [], 'categories': [], 'annotations': [], } lines = ub.readfrom(label_path).split('\n') lines = [line for line in lines if line] for line in lines: color_text, name = re.split('\t+', line) r, g, b = map(int, color_text.split(' ')) color = (r, g, b) # Parse the special camvid format cid = (r << 16) + (g << 8) + (b << 0) cat = { 'id': cid, 'name': name, 'color': color, } dataset['categories'].append(cat) for gid, img_item in enumerate(image_items, start=1): img = { 'id': gid, 'file_name': img_item['img_fname'], # nonstandard image field 'segmentation': img_item['mask_fname'], } dataset['images'].append(img) dset = kwcoco.CocoDataset(dataset) dset.rename_categories({'Void': 'background'}) assert dset.name_to_cat['background']['id'] == 0 dset.name_to_cat['background'].setdefault('alias', []).append('Void') if False: _define_camvid_class_hierarcy(dset) if 1: # TODO: Binarize CCs (and efficiently encode if possible) import numpy as np bad_info = [] once = False # Add images dset.remove_annotations(list(dset.index.anns.keys())) for gid, img in ub.ProgIter(dset.imgs.items(), desc='parse label masks'): mask_fpath = join(dset_root, img['segmentation']) rgb_mask = kwimage.imread(mask_fpath, space='rgb') r, g, b = rgb_mask.T.astype(np.int64) cid_mask = np.ascontiguousarray(rgb_to_cid(r, g, b).T) cids = set(np.unique(cid_mask)) - {0} for cid in cids: if cid not in dset.cats: if gid == 618: # Handle a known issue with image 618 c_mask = (cid == cid_mask).astype(np.uint8) total_bad = c_mask.sum() if total_bad < 32: if not once: print( 'gid 618 has a few known bad pixels, ignoring them' ) once = True continue else: raise Exception('more bad pixels than expected') else: raise Exception( 'UNKNOWN cid = {!r} in gid={!r}'.format(cid, gid)) # bad_rgb = cid_to_rgb(cid) # print('bad_rgb = {!r}'.format(bad_rgb)) # print('WARNING UNKNOWN cid = {!r} in gid={!r}'.format(cid, gid)) # bad_info.append({ # 'gid': gid, # 'cid': cid, # }) else: ann = { 'category_id': cid, 'image_id': gid # 'segmentation': mask.to_coco() } assert cid in dset.cats c_mask = (cid == cid_mask).astype(np.uint8) mask = kwimage.Mask(c_mask, 'c_mask') box = kwimage.Boxes([mask.get_xywh()], 'xywh') # box = mask.to_boxes() ann['bbox'] = ub.peek(box.to_coco()) ann['segmentation'] = mask.to_coco() dset.add_annotation(**ann) if 0: bad_cids = [i['cid'] for i in bad_info] print(sorted([c['color'] for c in dataset['categories']])) print(sorted(set([cid_to_rgb(i['cid']) for i in bad_info]))) gid = 618 img = dset.imgs[gid] mask_fpath = join(dset_root, img['segmentation']) rgb_mask = kwimage.imread(mask_fpath, space='rgb') r, g, b = rgb_mask.T.astype(np.int64) cid_mask = np.ascontiguousarray(rgb_to_cid(r, g, b).T) cid_hist = ub.dict_hist(cid_mask.ravel()) bad_cid_hist = {} for cid in bad_cids: bad_cid_hist[cid] = cid_hist.pop(cid) import kwplot kwplot.autompl() kwplot.imshow(rgb_mask) if 0: import kwplot plt = kwplot.autoplt() plt.clf() dset.show_image(1) import xdev gid_list = list(dset.imgs) for gid in xdev.InteractiveIter(gid_list): dset.show_image(gid) xdev.InteractiveIter.draw() dset._build_index() dset._build_hashid() return dset
def after_initialize(harn): STYLE_IMAGE_PATH = ub.grabdata( 'https://raw.githubusercontent.com/iamRusty/fast-neural-style-pytorch/master/images/mosaic.jpg' ) device = harn.xpu.device harn.MSELoss = nn.MSELoss().to(device) vgg_path = ub.grabdata( 'https://web.eecs.umich.edu/~justincj/models/vgg16-00b39a1b.pth') # TODO: should be tracked harn.vgg = VGG16(**{'vgg_path': vgg_path}) harn.vgg = harn.xpu.move(harn.vgg) def itot(img, max_size=None): # Rescale the image if (max_size is None): itot_t = transforms.Compose([ # transforms.ToPILImage(), transforms.ToTensor(), transforms.Lambda(lambda x: x.mul(255)) ]) else: H, W, C = img.shape image_size = tuple( [int((float(max_size) / max([H, W])) * x) for x in [H, W]]) itot_t = transforms.Compose([ transforms.ToPILImage(), transforms.Resize(image_size), transforms.ToTensor(), transforms.Lambda(lambda x: x.mul(255)) ]) # Convert image to tensor tensor = itot_t(img) # Add the batch_size dimension tensor = tensor.unsqueeze(dim=0) return tensor # Get Style Features imagenet_neg_mean = torch.tensor([-103.939, -116.779, -123.68], dtype=torch.float32).reshape( 1, 3, 1, 1).to(device) style_image = kwimage.imread(STYLE_IMAGE_PATH) style_tensor = itot(style_image).to(device) style_tensor = style_tensor.add(imagenet_neg_mean) B, C, H, W = style_tensor.shape harn.imagenet_neg_mean = imagenet_neg_mean harn.style_tensor = style_tensor batch_size = harn.script_config['batch_size'] im = style_tensor.expand([batch_size, C, H, W]) style_features = harn.vgg(im) style_gram = {} for key, value in style_features.items(): style_gram[key] = gram(value) harn.style_gram = style_gram