from functools import wraps import cv2 import numpy as np from matplotlib import pyplot as plt MAX_VALUES_BY_DTYPE = { np.dtype('uint8'): 255, np.dtype('uint16'): 65535, np.dtype('uint32'): 4294967295, np.dtype('float32'): 1.0, } UNKNOWN_FLOW_THRESH = 1e7 SMALLFLOW = 0.0 LARGEFLOW = 1e8 def flow2rgb(flow_map, max_value): if isinstance(flow_map,np.ndarray): if flow_map.shape[2] == 2: flow_map = flow_map.transpose(2,0, 1) flow_map_np = flow_map else: if flow_map.shape[2] == 2: # shape is HxWx2 flow_map = flow_map.permute(2, 0, 1) flow_map_np = flow_map.detach().cpu().numpy() _, h, w = flow_map_np.shape flow_map_np[:,(flow_map_np[0] == 0) & (flow_map_np[1] == 0)] = float('nan') rgb_map = np.ones((3,h,w)).astype(np.float32) if max_value is not None: normalized_flow_map = flow_map_np / max_value else: normalized_flow_map = flow_map_np / (np.abs(flow_map_np).max()) rgb_map[0] += normalized_flow_map[0] rgb_map[1] -= 0.5*(normalized_flow_map[0] + normalized_flow_map[1]) rgb_map[2] += normalized_flow_map[1] return rgb_map.clip(0,1) def flow_to_image(flow, maxrad=None): """ Convert flow into middlebury color code image :param flow: optical flow map :return: optical flow image in middlebury color """ h,w, _ = flow.shape u = flow[:, :, 0] v = flow[:, :, 1] maxu = -999. maxv = -999. minu = 999. minv = 999. idxUnknow = (abs(u) > UNKNOWN_FLOW_THRESH) | (abs(v) > UNKNOWN_FLOW_THRESH) u[idxUnknow] = 0 v[idxUnknow] = 0 if maxrad is None: rad = np.sqrt(u ** 2 + v ** 2) maxrad = max(-1, np.max(rad)) #print("max flow: %.4f\nflow range:\nu = %.3f .. %.3f\nv = %.3f .. %.3f" % (maxrad, minu,maxu, minv, maxv)) u = u/(maxrad + np.finfo(float).eps) v = v/(maxrad + np.finfo(float).eps) img = compute_color(u, v) idx = np.repeat(idxUnknow[:, :, np.newaxis], 3, axis=2) img[idx] = 0 valid = np.ones((h,w), np.uint8) valid[np.logical_and(u == 0 , v == 0)] = 0 return np.uint8(img)*np.expand_dims(valid, axis=2) def show_flow(flow): """ visualize optical flow map using matplotlib :param filename: optical flow file :return: None """ img = flow_to_image(flow) plt.imshow(img) plt.show() def visualize_flow(flow, mode='Y'): """ this function visualize the input flow :param flow: input flow in array :param mode: choose which color mode to visualize the flow (Y: Ccbcr, RGB: RGB color) :return: None """ if mode == 'Y': # Ccbcr color wheel img = flow_to_image(flow) plt.imshow(img) plt.show() elif mode == 'RGB': (h, w) = flow.shape[0:2] du = flow[:, :, 0] dv = flow[:, :, 1] valid = flow[:, :, 2] max_flow = max(np.max(du), np.max(dv)) img = np.zeros((h, w, 3), dtype=np.float64) # angle layer img[:, :, 0] = np.arctan2(dv, du) / (2 * np.pi) # magnitude layer, normalized to 1 img[:, :, 1] = np.sqrt(du * du + dv * dv) * 8 / max_flow # phase layer img[:, :, 2] = 8 - img[:, :, 1] # clip to [0,1] small_idx = img[:, :, 0:3] < 0 large_idx = img[:, :, 0:3] > 1 img[small_idx] = 0 img[large_idx] = 1 # convert to rgb img = cl.hsv_to_rgb(img) # remove invalid point img[:, :, 0] = img[:, :, 0] * valid img[:, :, 1] = img[:, :, 1] * valid img[:, :, 2] = img[:, :, 2] * valid # show plt.imshow(img) plt.show() def compute_color(u, v): """ compute optical flow color map :param u: optical flow horizontal map :param v: optical flow vertical map :return: optical flow in color code """ [h, w] = u.shape img = np.zeros([h, w, 3]) nanIdx = np.isnan(u) | np.isnan(v) u[nanIdx] = 0 v[nanIdx] = 0 colorwheel = make_color_wheel() ncols = np.size(colorwheel, 0) rad = np.sqrt(u**2+v**2) a = np.arctan2(-v, -u) / np.pi fk = (a+1) / 2 * (ncols - 1) + 1 k0 = np.floor(fk).astype(int) k1 = k0 + 1 k1[k1 == ncols+1] = 1 f = fk - k0 for i in range(0, np.size(colorwheel,1)): tmp = colorwheel[:, i] col0 = tmp[k0-1] / 255 col1 = tmp[k1-1] / 255 col = (1-f) * col0 + f * col1 idx = rad <= 1 col[idx] = 1-rad[idx]*(1-col[idx]) notidx = np.logical_not(idx) col[notidx] *= 0.75 img[:, :, i] = np.uint8(np.floor(255 * col*(1-nanIdx))) return img def make_color_wheel(): """ Generate color wheel according Middlebury color code :return: Color wheel """ RY = 15 YG = 6 GC = 4 CB = 11 BM = 13 MR = 6 ncols = RY + YG + GC + CB + BM + MR colorwheel = np.zeros([ncols, 3]) col = 0 # RY colorwheel[0:RY, 0] = 255 colorwheel[0:RY, 1] = np.transpose(np.floor(255*np.arange(0, RY) / RY)) col += RY # YG colorwheel[col:col+YG, 0] = 255 - np.transpose(np.floor(255*np.arange(0, YG) / YG)) colorwheel[col:col+YG, 1] = 255 col += YG # GC colorwheel[col:col+GC, 1] = 255 colorwheel[col:col+GC, 2] = np.transpose(np.floor(255*np.arange(0, GC) / GC)) col += GC # CB colorwheel[col:col+CB, 1] = 255 - np.transpose(np.floor(255*np.arange(0, CB) / CB)) colorwheel[col:col+CB, 2] = 255 col += CB # BM colorwheel[col:col+BM, 2] = 255 colorwheel[col:col+BM, 0] = np.transpose(np.floor(255*np.arange(0, BM) / BM)) col += + BM # MR colorwheel[col:col+MR, 2] = 255 - np.transpose(np.floor(255 * np.arange(0, MR) / MR)) colorwheel[col:col+MR, 0] = 255 return colorwheel def show_flow(disp_x, disp_y): norm_flow=np.sqrt(np.power(disp_x,2) + np.power(disp_y,2) ) return norm_flow def diff_neighboring_OF(disp_x, disp_y): diff=np.zeros((disp_x.shape[0], disp_x.shape[1],5), dtype=np.float32) print(disp_x.shape[0]) for y in range(2, disp_x.shape[0]-2): for x in range(2, disp_x.shape[1]-2): diff[y, x, 0] = np.sqrt((disp_x[y, x] - disp_x[y+1, x])**2 + (disp_y[y,x]-disp_y[y+1, x])**2) diff[y, x, 1] = np.sqrt((disp_x[y, x] - disp_x[y - 1, x]) ** 2 + (disp_y[y, x] - disp_y[y - 1, x]) ** 2 ) diff[y, x, 2] = np.sqrt((disp_x[y, x] - disp_x[y, x+1]) ** 2 + (disp_y[y, x] - disp_y[y, x+1]) ** 2 ) diff[y, x, 3] = np.sqrt((disp_x[y, x] - disp_x[y, x-1]) ** 2 + (disp_y[y, x] - disp_y[y, x-1]) ** 2 ) diff[y,x,4]=1/4*(diff[y, x, 1]+diff[y, x, 2]+diff[y, x, 3]+diff[y, x, 0]) return diff def preserve_shape(func): """Preserve shape of the image.""" @wraps(func) def wrapped_function(img, *args, **kwargs): shape = img.shape result = func(img, *args, **kwargs) result = result.reshape(shape) return result return wrapped_function def preserve_channel_dim(func): """Preserve dummy channel dim.""" @wraps(func) def wrapped_function(img, *args, **kwargs): shape = img.shape result = func(img, *args, **kwargs) if len(shape) == 3 and shape[-1] == 1 and len(result.shape) == 2: result = np.expand_dims(result, axis=-1) return result return wrapped_function def center_crop(img, size): """ Get the center crop of the input image Args: img: input image [BxCxHxW] size: load_size of the center crop (tuple) Output: img_pad: center crop x, y: coordinates of the crop """ if not isinstance(size, tuple): size = (size, size) img = img.copy() #w, h = img.shape[1::-1] w, h=img.shape[:2] pad_w = 0 pad_h = 0 if w < size[0]: pad_w = np.uint16((size[0] - w) / 2) if h < size[1]: pad_h = np.uint16((size[1] - h) / 2) img_pad = cv2.copyMakeBorder(img, pad_h, pad_h, pad_w, pad_w, cv2.BORDER_CONSTANT, value=[0, 0, 0]) w, h = img_pad.shape[1::-1] x1 = w // 2 - size[0] // 2 y1 = h // 2 - size[1] // 2 img_pad = img_pad[y1:y1 + size[1], x1:x1 + size[0], :] return img_pad, x1, y1 def crop_images_and_rescale_OF(I, I_prime, map_x, map_y, size): I_cropped, x1, y1=center_crop(I, size) I_prime_cropped, x1, y1=center_crop(I_prime, size) map_x=map_x-x1 # warped image starts at a new index x1 in horizontal direction map_y=map_y-y1 map_x_modified=map_x[y1:y1 + size[1], x1:x1 + size[0]] map_y_modified = map_y[y1:y1 + size[1], x1:x1 + size[0]] return I_cropped, I_prime_cropped, map_x_modified, map_y_modified @preserve_channel_dim def pad(img, min_height, min_width, border_mode=cv2.BORDER_REFLECT_101, value=None): height, width = img.shape[:2] if height < min_height: h_pad_top = int((min_height - height) / 2.0) h_pad_bottom = min_height - height - h_pad_top else: h_pad_top = 0 h_pad_bottom = 0 if width < min_width: w_pad_left = int((min_width - width) / 2.0) w_pad_right = min_width - width - w_pad_left else: w_pad_left = 0 w_pad_right = 0 img = pad_with_params(img, h_pad_top, h_pad_bottom, w_pad_left, w_pad_right, border_mode, value) assert img.shape[0] == max(min_height, height) assert img.shape[1] == max(min_width, width) return img @preserve_channel_dim def pad_with_params(img, h_pad_top, h_pad_bottom, w_pad_left, w_pad_right, border_mode=cv2.BORDER_REFLECT_101, value=None): img = cv2.copyMakeBorder(img, h_pad_top, h_pad_bottom, w_pad_left, w_pad_right, border_mode, value=value) return img def crop(img, x_min, y_min, x_max, y_max): height, width = img.shape[:2] if x_max <= x_min or y_max <= y_min: raise ValueError( 'We should have x_min < x_max and y_min < y_max. But we got' ' (x_min = {x_min}, y_min = {y_min}, x_max = {x_max}, y_max = {y_max})'.format( x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max ) ) if x_min < 0 or x_max > width or y_min < 0 or y_max > height: raise ValueError( 'Values for crop should be non negative and equal or smaller than image sizes' '(x_min = {x_min}, y_min = {y_min}, x_max = {x_max}, y_max = {y_max}' 'height = {height}, width = {width})'.format( x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max, height=height, width=width ) ) return img[y_min:y_max, x_min:x_max] def get_center_crop_coords(height, width, crop_height, crop_width): y1 = (height - crop_height) // 2 y2 = y1 + crop_height x1 = (width - crop_width) // 2 x2 = x1 + crop_width return x1, y1, x2, y2 def center_crop(img, crop_height, crop_width): height, width = img.shape[:2] if height < crop_height or width < crop_width: raise ValueError( 'Requested crop load_size ({crop_height}, {crop_width}) is ' 'larger than the image load_size ({height}, {width})'.format( crop_height=crop_height, crop_width=crop_width, height=height, width=width, ) ) x1, y1, x2, y2 = get_center_crop_coords(height, width, crop_height, crop_width) img = img[y1:y2, x1:x2] return img def get_random_crop_coords(height, width, crop_height, crop_width, h_start, w_start): y1 = int((height - crop_height) * h_start) y2 = y1 + crop_height x1 = int((width - crop_width) * w_start) x2 = x1 + crop_width return x1, y1, x2, y2 def random_crop(img, crop_height, crop_width, h_start, w_start): height, width = img.shape[:2] if height < crop_height or width < crop_width: raise ValueError( 'Requested crop load_size ({crop_height}, {crop_width}) is ' 'larger than the image load_size ({height}, {width})'.format( crop_height=crop_height, crop_width=crop_width, height=height, width=width, ) ) x1, y1, x2, y2 = get_random_crop_coords(height, width, crop_height, crop_width, h_start, w_start) img = img[y1:y2, x1:x2] return img def clamping_crop(img, x_min, y_min, x_max, y_max): h, w = img.shape[:2] if x_min < 0: x_min = 0 if y_min < 0: y_min = 0 if y_max >= h: y_max = h - 1 if x_max >= w: x_max = w - 1 return img[int(y_min):int(y_max), int(x_min):int(x_max)]