def _devcheck_sample_full_image(): """ """ import kwimage import numpy as np sampler = grab_camvid_sampler() cid_to_cidx = sampler.catgraph.id_to_idx classes = sampler.catgraph # Try loading an entire image img, annots = sampler.load_image_with_annots(1) file = img['imdata'] imdata = file[:] aids = [ann['id'] for ann in annots] _annots = sampler.dset.annots(aids) sseg_list = [] for s in _annots.lookup('segmentation'): m = kwimage.MultiPolygon.coerce(s) sseg_list.append(m) aids = _annots.aids cids = _annots.cids boxes = _annots.boxes segmentations = kwimage.PolygonList(sseg_list) class_idxs = np.array([cid_to_cidx[cid] for cid in cids]) dets = kwimage.Detections( aids=aids, boxes=boxes, class_idxs=class_idxs, segmentations=segmentations, classes=classes, datakeys=['aids'], ) if 1: print('dets = {!r}'.format(dets)) print('dets.data = {!r}'.format(dets.data)) print('dets.meta = {!r}'.format(dets.meta)) if ub.argflag('--show'): import kwplot with ub.Timer('dets.draw_on'): canvas = imdata.copy() canvas = dets.draw_on(canvas) kwplot.imshow(canvas, pnum=(1, 2, 1), title='dets.draw_on') with ub.Timer('dets.draw'): kwplot.imshow(imdata, pnum=(1, 2, 2), docla=True, title='dets.draw') dets.draw()
def fastfill_multipolygon(): kwplot.autompl() shape = (1208, 1208) self = kwimage.MultiPolygon.random(10).scale(shape) ti = ub.Timerit(3, bestof=1, verbose=2, unit='us') for timer in ti.reset('draw_on'): with timer: mask = np.zeros(shape, dtype=np.uint8) mask = self.draw_on(mask) for timer in ti.reset('custom'): with timer: mask = np.zeros(shape, dtype=np.uint8) for p in self.data: if p is not None: p.fill(mask, value=255) for timer in ti.reset('to_mask'): with timer: self.to_mask(shape) kwplot.imshow(mask)
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, 'antiderivative', color='white') canvas = kwimage.stack_images([der_canvas, int_canvas], axis=1) # kwimage.imwrite('ftfy.jpg', canvas) kwplot.autompl() kwplot.imshow(canvas)
def _devcheck_load_sub_image(): import kwimage import numpy as np sampler = grab_camvid_sampler() cid_to_cidx = sampler.catgraph.id_to_idx classes = sampler.catgraph # Try loading a subregion of an image sample = sampler.load_positive(2) imdata = sample['im'] annots = sample['annots'] aids = annots['aids'] cids = annots['cids'] boxes = annots['rel_boxes'] class_idxs = np.array([cid_to_cidx[cid] for cid in cids]) segmentations = annots['rel_ssegs'] raw_dets = kwimage.Detections( aids=aids, boxes=boxes, class_idxs=class_idxs, segmentations=segmentations, classes=classes, datakeys=['aids'], ) # Clip boxes to the image boundary input_dims = imdata.shape[0:2] raw_dets.data['boxes'] = raw_dets.boxes.clip(0, 0, input_dims[1], input_dims[0]) keep = [] for i, s in enumerate(raw_dets.data['segmentations']): # TODO: clip polygons m = s.to_mask(input_dims) if m.area > 0: keep.append(i) dets = raw_dets.take(keep) heatmap = dets.rasterize(bg_size=(1, 1), input_dims=input_dims) if 1: print('dets = {!r}'.format(dets)) print('dets.data = {!r}'.format(dets.data)) print('dets.meta = {!r}'.format(dets.meta)) if ub.argflag('--show'): import kwplot kwplot.autompl() heatmap.draw() draw_boxes = 1 kwplot.figure(doclf=True) with ub.Timer('dets.draw_on'): canvas = imdata.copy() # TODO: add logic to color by class canvas = dets.draw_on(canvas, boxes=draw_boxes, color='random') kwplot.imshow(canvas, pnum=(1, 2, 1), title='dets.draw_on') with ub.Timer('dets.draw'): kwplot.imshow(imdata, pnum=(1, 2, 2), docla=True, title='dets.draw') dets.draw(boxes=draw_boxes, color='random')
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 demo_flip_orientations(): import ubelt as ub from kwcoco.demo.toypatterns import Rasters img = Rasters.eff()[0] import kwplot kwplot.autompl() kwplot.imshow(img) flips = [ [], [0], [1], [0, 1], ] import numpy as np toshow = [] for axis in flips: img_ = img img_ = np.flip(img_, axis=axis) for k in [0, 1, 2, 3]: img_ = np.rot90(img_, k=k) row = {'img': img_, 'label': f'rot(flip({axis}), k={k})'} row['params'] = [f'axis={axis}, k={k}'] toshow.append(row) # for k in [0, 1, 2, 3]: # img_ = img # img_ = np.rot90(img_, k=k) # for axis in flips: # img_ = np.flip(img_, axis=axis) # row = {'img': img_, 'label': f'flip(rot(k={k}), {axis})'} # row['params'] = [f'k={k}, axis={axis}'] # toshow.append(row) for row in toshow: row['hash'] = ub.hash_data(row['img']) pnum_ = kwplot.PlotNums(nSubplots=len(toshow)) groups = ub.group_items(toshow, lambda x: x['hash']) # Only 8 possibiliteis for k, group in groups.items(): print('\n\nk = {!r}'.format(k)) for g in group: print(g['params']) row = g kwplot.imshow(row['img'], pnum=pnum_(), fnum=1, title=row['label']) unique_fliprots = [ { 'k': 0, 'axis': [] }, { 'k': 1, 'axis': [] }, { 'k': 2, 'axis': [] }, { 'k': 3, 'axis': [] }, { 'k': 0, 'axis': [0] }, { 'k': 1, 'axis': [0] }, { 'k': 2, 'axis': [0] }, { 'k': 3, 'axis': [0] }, ] s = [] for params in unique_fliprots: k = params['k'] axis = params['axis'] img_ = np.rot90(np.flip(img, axis=axis), k=k) s.append(ub.hash_data(img_)) assert len(set(s)) == len(s)
imdata = np.asarray(pil_img) return imdata # This circuit creates the "Bell State" # which maximally entangles two input qubits. num_qubits = 2 bell_circuit = qutip.QubitCircuit(num_qubits, input_states=["e1", "e2", "c1", "c2"], num_cbits=2) bell_circuit.add_gate("SNOT", targets=0) # snot is Hadamard bell_circuit.add_gate("CNOT", controls=[0], targets=[1]) bell_circuit.add_measurement("M0", targets=[0], classical_store=0) bell_circuit.add_measurement("M1", targets=[1], classical_store=1) kwplot.imshow(draw_circuit(bell_circuit)) # qutip.qubit_states() # Create a system of two electrons e1 = qutip.basis(dimensions=2, n=0) e2 = qutip.basis(dimensions=2, n=1) # This state represents two electrons input_state = qutip.tensor(e1, e2) # We can measure, these. It wont matter because we are going to make the # bell State initial_measurement = qutip.Measurement("start", targets=[0]) collapsed1, probs1 = initial_measurement.measurement_comp_basis(e1) collapsed2, probs2 = initial_measurement.measurement_comp_basis(e2) collapsed3, probs3 = initial_measurement.measurement_comp_basis(input_state)
import kwplot import numpy as np import kwimage kwplot.autompl() f = 8 blank_key = np.zeros((64 * f, 54 * f, 3)) blank_key[:, :, :] = np.array(kwimage.Color('darkgray').as255())[None, None, :] blank_key[0:f * 2, :] = (3, 3, 3) blank_key[-f * 2:, :] = (3, 3, 3) blank_key[:, 0:f * 2] = (3, 3, 3) blank_key[:, -f * 2:] = (3, 3, 3) key = kwimage.draw_text_on_image(blank_key.copy(), text='!\n1', halign='center', valign='center', color='white') kwplot.imshow(key) tab_symbol = '->' left_rows = [] alt_text0 = [None, None, None, None, None, None, None, None] row_text0 = ['esc', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'caps'] left_rows += [(alt_text0, row_text0)] alt_text1 = [None, '~', '!', '@', '#', '$', '%', None] row_text1 = ['tab', '`', '1', '2', '3', '4', '5', 'win'] left_rows += [(alt_text1, row_text1)] alt_text2 = ['|', '?', None, None, None, None, None, None]
def check_fill_poly_properties(): """ Notes: It seems as if cv2.fillPoly will draw multiple polygons, but it will toggle between drawing holes and filling depending on if the next polygon is inside of a previous one. skimage.draw.polygon is very slow PIL is very slow for floats, but ints aren't too bad. cv2 is better. """ kwplot.autompl() shape = (1208, 1208) self = kwimage.Polygon.random(n=10, n_holes=1, convex=False).scale(1208) cv_contours = self._to_cv_countours() value = 1 mask = np.zeros((128, 128), dtype=np.uint8) value = 1 line_type = cv2.LINE_8 mask = np.zeros((128, 128), dtype=np.uint8) # Modification happens inplace cv2.fillPoly(mask, cv_contours, value, line_type, shift=0) kwplot.autompl() kwplot.imshow(mask) extra = cv_contours[1] + 40 cv_contours3 = cv_contours + [extra, extra + 2] mask = np.zeros((128, 128), dtype=np.uint8) cv2.fillPoly(mask, cv_contours3, value, line_type, shift=0) kwplot.imshow(mask) geom = shapely.geometry.Polygon( shell=self.data['exterior'].data, holes=[c.data for c in self.data['interiors']]) xs, ys = self.data['exterior'].data.T rr, cc = skimage.draw.polygon(xs, ys) mask = np.zeros(shape, dtype=np.uint8) ti = ub.Timerit(10, bestof=3, verbose=2, unit='us') if False: # Not general enough for timer in ti.reset('fillConvexPoly'): mask[:, :] = 0 with timer: cv_contours = self._to_cv_countours() cv2.fillConvexPoly(mask, cv_contours[0], value) for timer in ti.reset('fillPoly'): mask[:, :] = 0 with timer: cv_contours = self._to_cv_countours() cv2.fillPoly(mask, cv_contours[0:1], value) for timer in ti.reset('skimage.draw.polygon'): mask = np.zeros(shape, dtype=np.uint8) with timer: xs, ys = self.data['exterior'].data.T rr, cc = skimage.draw.polygon(xs, ys) from PIL import Image, ImageDraw for timer in ti.reset('PIL'): height, width = shape pil_img = Image.new('L', (width, height), 0) with timer: draw_obj = ImageDraw.Draw(pil_img) pil_poly = self.data['exterior'].data.astype( np.int).ravel().tolist() pil_poly = pil_poly + pil_poly[0:2] draw_obj.polygon(pil_poly, outline=0, fill=255) mask = np.array(pil_img)
def main(cls, cmdline=True, **kw): """ TODO: - [ ] Visualize auxiliary data Example: >>> # xdoctest: +SKIP >>> kw = {'src': 'special:shapes8'} >>> cmdline = False >>> cls = CocoShowCLI >>> cls.main(cmdline, **kw) """ import kwcoco import kwimage import kwplot config = cls.CLIConfig(kw, cmdline=cmdline) print('config = {}'.format(ub.repr2(dict(config), nl=1))) if config['src'] is None: raise Exception('must specify source: {}'.format(config['src'])) dset = kwcoco.CocoDataset.coerce(config['src']) print('dset.fpath = {!r}'.format(dset.fpath)) plt = kwplot.autoplt() gid = config['gid'] aid = config['aid'] out_fpath = config['dst'] if gid is None and aid is None: gid = ub.peek(dset.imgs) if config['mode'] == 'matplotlib': show_kw = { 'show_annots': config['show_annots'], 'channels': config['channels'], } if config['show_annots'] == 'both': show_kw.pop('show_annots') show_kw['title'] = '' ax = dset.show_image(gid=gid, aid=aid, pnum=(1, 2, 1), show_annots=False, **show_kw) ax = dset.show_image(gid=gid, aid=aid, pnum=(1, 2, 2), show_annots=True, **show_kw) else: ax = dset.show_image(gid=gid, aid=aid, **show_kw) if out_fpath is None: if 1: try: import xdev except Exception: pass else: gids = [gid] + list(set(dset.imgs.keys()) - {gid}) for gid in xdev.InteractiveIter(gids): ax = dset.show_image(gid=gid, aid=aid, **show_kw) xdev.InteractiveIter.draw() plt.show(block=False) plt.show() else: ax.figure.savefig(out_fpath) elif config['mode'] == 'opencv': canvas = dset.draw_image(gid, channels=config['channels']) if out_fpath is None: kwplot.imshow(canvas) plt.show() else: kwimage.imwrite(out_fpath, canvas) else: raise KeyError(config['mode'])
def plot_convolutional_features(conv, limit=144, colorspace='rgb', fnum=None, nCols=None, voxels=False, alpha=.2, labels=False, normaxis=None, _hack_2drows=False): """Plots the convolutional layers to a matplotlib pyplot. The convolutional filters (kernels) are stored into a grid and saved to disk as a Maplotlib figure. The convolutional filters, if it has one channel, will be stored as an intensity imgage. If a colorspace is specified and there are three input channels, the convolutional filters will be represented as an RGB image. In the event that 2 or 4+ filters are displayed, the different channels will be flattened and showed as distinct outputs in the grid. TODO: - [ ] refactor to use make_conv_images Args: conv (torch.nn.ConvNd): torch convolutional layer with weights to draw limit (int, optional): the limit on the number of filters drawn in the figure, achieved by simply dropping any filters past the limit starting at the first filter. Detaults to 144. colorspace (str): the colorspace seen by the convolutional filter (if applicable), so we can convert to rgb for display. voxels (bool): if True, and we have a 3d conv, show the voxels alpha (float): only applicable if voxels=True stride (list): only applicable if voxels=True Returns: matplotlib.figure.Figure: fig - a Matplotlib figure References: https://matplotlib.org/devdocs/gallery/mplot3d/voxels.html Example: >>> # xdoctest: +REQUIRES(module:torch) >>> conv = torch.nn.Conv2d(3, 9, (5, 7)) >>> plot_convolutional_features(conv, colorspace=None, fnum=None, limit=2) Example: >>> # xdoctest: +REQUIRES(--comprehensive) >>> # xdoctest: +REQUIRES(module:torch) >>> import torchvision >>> # 2d uncolored gray-images >>> conv = torch.nn.Conv3d(1, 2, (3, 4, 5)) >>> plot_convolutional_features(conv, colorspace=None, fnum=1, limit=2) >>> # 2d colored rgb-images >>> conv = torch.nn.Conv3d(3, 2, (6, 4, 5)) >>> plot_convolutional_features(conv, colorspace='rgb', fnum=1, limit=2) >>> # 2d uncolored rgb-images >>> conv = torch.nn.Conv3d(3, 2, (6, 4, 5)) >>> plot_convolutional_features(conv, colorspace=None, fnum=1, limit=2) >>> # 3d gray voxels >>> conv = torch.nn.Conv3d(1, 2, (6, 4, 5)) >>> plot_convolutional_features(conv, colorspace=None, fnum=1, voxels=True, >>> limit=2) >>> # 3d color voxels >>> conv = torch.nn.Conv3d(3, 2, (6, 4, 5)) >>> plot_convolutional_features(conv, colorspace='rgb', fnum=1, >>> voxels=True, alpha=1, limit=3) >>> # hack the nice resnet weights into 3d-space >>> # xdoctest: +REQUIRES(--network) >>> import torchvision >>> model = torchvision.models.resnet50(pretrained=True) >>> conv = torch.nn.Conv3d(3, 1, (7, 7, 7)) >>> weights_tohack = model.conv1.weight[0:7].data.numpy() >>> # normalize each weight for nice colors, then place in the conv3d >>> for w in weights_tohack: ... w[:] = (w - w.min()) / (w.max() - w.min()) >>> weights_hacked = weights_tohack.transpose(1, 0, 2, 3)[None, :] >>> conv.weight.data[:] = torch.FloatTensor(weights_hacked) >>> plot_convolutional_features(conv, colorspace='rgb', fnum=1, voxels=True, alpha=.6) >>> plot_convolutional_features(conv, colorspace='rgb', fnum=2, voxels=False, alpha=.9) Example: >>> # xdoctest: +REQUIRES(--network) >>> # xdoctest: +REQUIRES(module:torch) >>> import torchvision >>> model = torchvision.models.resnet50(pretrained=True) >>> conv = model.conv1 >>> plot_convolutional_features(conv, colorspace='rgb', fnum=None) """ import kwplot kwplot.autompl() import matplotlib.pyplot as plt # get relavent data out of pytorch module weights = conv.weight.data.cpu().numpy() in_channels = conv.in_channels # out_channels = conv.out_channels kernel_size = conv.kernel_size conv_dim = len(kernel_size) # TODO: use make_conv_images in the 2d case here if voxels: # use up to 3 spatial dimensions spatial_axes = list(kernel_size[-3:]) else: # use only 2 spatial dimensions spatial_axes = list(kernel_size[-2:]) color_axes = [] output_axis = 0 # If there are 3 input channels, we can visualize features in a colorspace if colorspace is not None and in_channels == 3: # Move colorable channels to the end (handle 1, 2 and 3d convolution) axes = [0] + list(range(2, 2 + conv_dim)) + [1] weights = weights.transpose(*axes) color_axes = [in_channels] output_axis = 0 else: pass # Normalize layer weights between 0 and 1 if normaxis is None: minval = weights.min() maxval = weights.max() else: # if normaxis=0 norm over output channels minval = weights.min(axis=output_axis, keepdims=True) maxval = weights.max(axis=output_axis, keepdims=True) weights_norm = (weights - minval) / (maxval - minval) if _hack_2drows: # To agree with jason's visualization for a paper figure if not voxels: weights_norm = weights_norm.transpose(1, 0, 2, 3) # flatten everything but the spatial and requested color dims weights_flat = weights_norm.reshape(-1, *(spatial_axes + color_axes)) num_plots = min(weights_flat.shape[0], limit) dim = int(np.ceil(np.sqrt(num_plots))) if voxels: from mpl_toolkits.mplot3d import Axes3D # NOQA filled = np.ones(spatial_axes, dtype=np.bool) # np.ones(spatial_axes) # d, h, w = np.indices(spatial_axes) fnum = kwplot.ensure_fnum(fnum) fig = kwplot.figure(fnum=fnum) fig.clf() if nCols is None: nCols = dim pnum_ = kwplot.PlotNums(nCols=nCols, nSubplots=num_plots) def plot_kernel3d(i): img = weights_flat[i] # fig = kwplot.figure(fnum=fnum, pnum=pnum_[i]) ax = fig.add_subplot(*pnum_[i], projection='3d') # ax = fig.gca(projection='3d') alpha_ = (filled * alpha)[..., None] colors = img if not color_axes: import kwimage # transform grays into colors grays = kwimage.atleast_nd(img, 4) colors = np.concatenate([grays, grays, grays], axis=3) if colorspace and color_axes: import kwimage # convert into RGB for d in range(len(colors)): colors[d] = kwimage.convert_colorspace(colors[d], src_space=colorspace, dst_space='rgb') facecolors = np.concatenate([colors, alpha_], axis=3) # shuffle dims so height is upwards and depth move away from us. dim_labels = ['d', 'h', 'w'] axes = [2, 0, 1] dim_labels = list(ub.take(dim_labels, axes)) facecolors = facecolors.transpose(*(axes + [3])) filled_ = filled.transpose(*axes) spatial_axes_ = list(ub.take(spatial_axes, axes)) # ax.voxels(filled_, facecolors=facecolors, edgecolors=facecolors) if False: ax.voxels(filled_, facecolors=facecolors, edgecolors='k') else: # hack to show "occluded" voxels # stride = [1, 3, 1] stride = [2, 2, 2] slices = tuple(slice(None, None, s) for s in stride) spatial_axes2 = list(np.array(spatial_axes_) * stride) filled2 = np.zeros(spatial_axes2, dtype=np.bool) facecolors2 = np.empty(spatial_axes2 + [4], dtype=np.float32) filled2[slices] = filled_ facecolors2[slices] = facecolors edgecolors2 = [0, 0, 0, alpha] # 'k' # edgecolors2 = facecolors2 # Shrink the gaps, which let you see occluded voxels x, y, z = np.indices(np.array(filled2.shape) + 1).astype(float) // 2 x[0::2, :, :] += 0.05 y[:, 0::2, :] += 0.05 z[:, :, 0::2] += 0.05 x[1::2, :, :] += 0.95 y[:, 1::2, :] += 0.95 z[:, :, 1::2] += 0.95 ax.voxels(x, y, z, filled2, facecolors=facecolors2, edgecolors=edgecolors2) for xyz, dlbl in zip(['x', 'y', 'z'], dim_labels): getattr(ax, 'set_' + xyz + 'label')(dlbl) for xyz in ['x', 'y', 'z']: getattr(ax, 'set_' + xyz + 'ticks')([]) ax.set_aspect('equal') if not labels or i < num_plots - 1: # show axis only on the last plot ax.grid(False) plt.axis('off') for i in ub.ProgIter(range(num_plots), desc='plot conv layer', enabled=False): if voxels: plot_kernel3d(i) else: img = weights_flat[i] kwplot.imshow(img, fnum=fnum, pnum=pnum_[i], interpolation='nearest', colorspace=colorspace) return fig
def warp_image_test(image, transform, dsize=None): """ from kwimage.transform import Affine import kwimage image = kwimage.grab_test_image('checkerboard', dsize=(2048, 2048)).astype(np.float32) image = kwimage.grab_test_image('astro', dsize=(2048, 2048)) transform = Affine.random() @ Affine.scale(0.01) """ from kwimage.transform import Affine import kwimage import numpy as np import ubelt as ub # Choose a random affine transform that probably has a small scale # transform = Affine.random() @ Affine.scale((0.3, 2)) # transform = Affine.scale((0.1, 1.2)) # transform = Affine.scale(0.05) transform = Affine.random() @ Affine.scale(0.01) # transform = Affine.random() image = kwimage.grab_test_image('astro') image = kwimage.grab_test_image('checkerboard') image = kwimage.ensure_float01(image) from kwimage import im_cv2 import kwarray import cv2 transform = Affine.coerce(transform) if 1 or dsize is None: h, w = image.shape[0:2] boxes = kwimage.Boxes(np.array([[0, 0, w, h]]), 'xywh') poly = boxes.to_polygons()[0] warped_poly = poly.warp(transform.matrix) warped_box = warped_poly.to_boxes().to_ltrb().quantize() dsize = tuple(map(int, warped_box.data[0, 2:4])) import timerit ti = timerit.Timerit(10, bestof=3, verbose=2) def _full_gauss_kernel(k0, sigma0, scale): num_downscales = np.log2(1 / scale) if num_downscales < 0: return 1, 0 # Define b0 = kernel size for one downsample operation b0 = 5 # Define sigma0 = sigma for one downsample operation sigma0 = 1 # The kernel size and sigma doubles for each 2x downsample k = int(np.ceil(b0 * (2 ** (num_downscales - 1)))) sigma = sigma0 * (2 ** (num_downscales - 1)) if k % 2 == 0: k += 1 return k, sigma def pyrDownK(a, k=1): assert k >= 0 for _ in range(k): a = cv2.pyrDown(a) return a for timer in ti.reset('naive'): with timer: interpolation = 'nearest' flags = im_cv2._coerce_interpolation(interpolation) final_v5 = cv2.warpAffine(image, transform.matrix[0:2], dsize=dsize, flags=flags) # -------------------- # METHOD 1 # for timer in ti.reset('resize+warp'): with timer: params = transform.decompose() sx, sy = params['scale'] noscale_params = ub.dict_diff(params, {'scale'}) noscale_warp = Affine.affine(**noscale_params) h, w = image.shape[0:2] resize_dsize = (int(np.ceil(sx * w)), int(np.ceil(sy * h))) downsampled = cv2.resize(image, dsize=resize_dsize, fx=sx, fy=sy, interpolation=cv2.INTER_AREA) interpolation = 'linear' flags = im_cv2._coerce_interpolation(interpolation) final_v1 = cv2.warpAffine(downsampled, noscale_warp.matrix[0:2], dsize=dsize, flags=flags) # -------------------- # METHOD 2 for timer in ti.reset('fullblur+warp'): with timer: k_x, sigma_x = _full_gauss_kernel(k0=5, sigma0=1, scale=sx) k_y, sigma_y = _full_gauss_kernel(k0=5, sigma0=1, scale=sy) image_ = image.copy() image_ = cv2.GaussianBlur(image_, (k_x, k_y), sigma_x, sigma_y) image_ = kwarray.atleast_nd(image_, 3) # image_ = image_.clip(0, 1) interpolation = 'linear' flags = im_cv2._coerce_interpolation(interpolation) final_v2 = cv2.warpAffine(image_, transform.matrix[0:2], dsize=dsize, flags=flags) # -------------------- # METHOD 3 for timer in ti.reset('pyrDown+blur+warp'): with timer: temp = image.copy() params = transform.decompose() sx, sy = params['scale'] biggest_scale = max(sx, sy) # The -2 allows the gaussian to be a little bigger. This # seems to help with border effects at only a small runtime cost num_downscales = max(int(np.log2(1 / biggest_scale)) - 2, 0) pyr_scale = 1 / (2 ** num_downscales) # Does the gaussian downsampling temp = pyrDownK(image, num_downscales) rest_sx = sx / pyr_scale rest_sy = sy / pyr_scale partial_scale = Affine.scale((rest_sx, rest_sy)) rest_warp = noscale_warp @ partial_scale k_x, sigma_x = _full_gauss_kernel(k0=5, sigma0=1, scale=rest_sx) k_y, sigma_y = _full_gauss_kernel(k0=5, sigma0=1, scale=rest_sy) temp = cv2.GaussianBlur(temp, (k_x, k_y), sigma_x, sigma_y) temp = kwarray.atleast_nd(temp, 3) interpolation = 'cubic' flags = im_cv2._coerce_interpolation(interpolation) final_v3 = cv2.warpAffine(temp, rest_warp.matrix[0:2], dsize=dsize, flags=flags) # -------------------- # METHOD 4 - dont do the final blur for timer in ti.reset('pyrDown+warp'): with timer: temp = image.copy() params = transform.decompose() sx, sy = params['scale'] biggest_scale = max(sx, sy) num_downscales = max(int(np.log2(1 / biggest_scale)), 0) pyr_scale = 1 / (2 ** num_downscales) # Does the gaussian downsampling temp = pyrDownK(image, num_downscales) rest_sx = sx / pyr_scale rest_sy = sy / pyr_scale partial_scale = Affine.scale((rest_sx, rest_sy)) rest_warp = noscale_warp @ partial_scale interpolation = 'linear' flags = im_cv2._coerce_interpolation(interpolation) final_v4 = cv2.warpAffine(temp, rest_warp.matrix[0:2], dsize=dsize, flags=flags) if 1: def get_title(key): from ubelt.timerit import _choose_unit value = ti.measures['mean'][key] suffix, mag = _choose_unit(value) unit_val = value / mag return key + ' ' + ub.repr2(unit_val, precision=2) + ' ' + suffix final_v2 = final_v2.clip(0, 1) final_v1 = final_v1.clip(0, 1) final_v3 = final_v3.clip(0, 1) final_v4 = final_v4.clip(0, 1) final_v5 = final_v5.clip(0, 1) import kwplot kwplot.autompl() kwplot.imshow(final_v5, pnum=(1, 5, 1), title=get_title('naive')) kwplot.imshow(final_v2, pnum=(1, 5, 2), title=get_title('fullblur+warp')) kwplot.imshow(final_v1, pnum=(1, 5, 3), title=get_title('resize+warp')) kwplot.imshow(final_v3, pnum=(1, 5, 4), title=get_title('pyrDown+blur+warp')) kwplot.imshow(final_v4, pnum=(1, 5, 5), title=get_title('pyrDown+warp'))