def get_analysis_domain(time, y, stack): """ Get analysis spatial domain from mouse clicks. ---------- Args: time (Mandatory [np.array]): Time array [s]. y (Mandatory [np.array]): Space array [m]. stk (Mandatory [np.array]): [time,space,3] timestack array. Used for plotting only. ---------- Return: swash_zone (Mandatory [Float]): onshore limit of the swash zone surf_zone (Mandatory [Float]): offshore limit of the surf zone """ # Get analysis start location from GUI plt.ion() fig, ax = plt.subplots(figsize=(12, 4)) # plt.show() ax.set_title( "Click in the start of swash zone and in the end of the surf zone...") im = ax.pcolormesh(time, y, stack.mean(axis=2).T) # set timestack to to true color rgba = construct_rgba_vector(np.rollaxis(stack, 1, 0), n_alpha=0) rgba[rgba > 1] = 1 im.set_array(None) im.set_edgecolor('none') im.set_facecolor(rgba) plt.draw() # location from click point = plt.ginput(n=2, timeout=1000000) swash_zone = point[0][1] surf_zone = point[1][1] # plt.show() plt.close() return swash_zone, surf_zone
def get_training_data(rgb, regions=3, region_names=["sand", "foam", "water"], nclicks=3, iwin=2, jwin=2): """ Get training color data based on user input. ---------- Args: rgb (Mandatory [np.array]): [time,space,3] timestack array. regions (Optional [int]): Number of regions in the timestack. Default is 3 region_names (Optional [int]): NUmber of regions in the timestack. Default is ["sand", "foam", "water"]. nclicks (Optional [int]): Number of clicks. Default is 3. iwin (Optional [int]): Window size in the u-direction. Default is 2. jwin (Optional [int]): Window size in the u-direction. Default is 2. ---------- Returns: df_colour (Mandatory [pd.DataFrame]): Dataframe with training colour information. """ # get pixel centers in the time-space domain i = 0 I_center = [] J_center = [] Labels = [] Regions = [] for label, region in zip(range(regions), region_names): # GUI plt.ion() fig, ax = plt.subplots(figsize=(12, 4)) ax.set_title("Click in {} points in the {}".format(nclicks, region)) im = plt.pcolormesh(np.mean(rgb, axis=2).T) # set timestack to to true color rgba = construct_rgba_vector(np.rollaxis(rgb, 1, 0), n_alpha=0) rgba[rgba > 1] = 1 im.set_array(None) im.set_edgecolor('none') im.set_facecolor(rgba) plt.draw() # get the i,j coordnates points = np.array( plt.ginput(n=nclicks, show_clicks=True, timeout=1000000)) # append to output for k in range(points.shape[0]): I_center.append(points[k, 0]) J_center.append(points[k, 1]) Labels.append(label) Regions.append(region) # iterate over regions i += 1 plt.close() # loop over pixel centers and build the pixel windows i_pixels_all = [] j_pixels_all = [] l_pixels_all = [] r_pixels_all = [] for x, y, region, label in zip(I_center, J_center, Regions, Labels): # get the pixel window i_all, j_all = pixel_window(rgb, x, y, iwin=iwin, jwin=jwin) # append to output for i in range(len(i_all)): i_pixels_all.append(np.int(i_all[i])) j_pixels_all.append(np.int(j_all[i])) l_pixels_all.append(label) r_pixels_all.append(region) # get RGB values rgb_training = rgb[i_pixels_all, j_pixels_all, :] # get individual tristimulus values r = rgb_training[:, 0] g = rgb_training[:, 1] b = rgb_training[:, 2] # build training dataset df_colour = pd.DataFrame(np.vstack([r, g, b]).T, columns=["r", "g", "b"]) # add label and region names df_colour["label"] = l_pixels_all df_colour["region"] = r_pixels_all return df_colour
f = interpolate.interp1d(tsurf, xsurf, kind="linear") xsurfp = f(tshore) # process mergings df = pd.read_csv(merging) xmerge = df["intersection"].values tmerge = df["time"].values # open a new figure fig, ax = plt.subplots(figsize=(12, 6)) # plot stack im = ax.pcolormesh(t, sx, rgb.mean(axis=2).T) im.set_array(None) im.set_edgecolor('none') im.set_facecolor(construct_rgba_vector(np.rollaxis(rgb, 1, 0))) # plot wavepaths n = 8 k = 0 cmcolors = plt.cm.get_cmap("Dark2", n) colors = [] for n in range(len(X)): if k > n: k = 0 colors.append(cmcolors(k)) k += 1 k = 0 for _t, _x in zip(T, X):
def plot_timestack(): """Plot timestack. All variables are global.""" # plot timestack im = ax.pcolormesh(t, x, rgb.mean(axis=2).T, cmap="Greys_r") im.set_array(None) im.set_edgecolor('none') im.set_facecolor(construct_rgba_vector(np.rollaxis(rgb, 1, 0))) # plot wave paths colors = plt.cm.get_cmap("tab20", len(X)) k = 0 for _t, _x in zip(T, X): ax.plot(_t, _x, lw=3, color=colors(k), ls="--") ax.plot(_t - (0.3 * _t.std()), _x, lw=1, color="k", ls="--") ax.plot(_t + (0.3 * _t.std()), _x, lw=1, color="k", ls="--") k += 1 # plot shoreline ax.plot(ds["time"], ds["shoreline"], lw=3, color="k", label="Shoreline") # plot stats ax.axhline(xshore.mean(), lw=3, color="darkgreen", ls="-", label=r"Shoreline $\mu$") ax.axhline(xshore.mean() - (1 * xshore.std()), lw=3, color="navy", ls="-", label=r"$\mu$+$\sigma$") ax.axhline(xshore.mean() - (2 * xshore.std()), lw=3, color="r", ls="-", label=r"$\mu$+$2\sigma$") ax.axhline(Xwm.mean(), lw=3, color="gold", ls="--", label=r"Capture $\mu$") ax.axhline(Xnm.mean(), lw=3, color="dodgerblue", ls="--", label=r"Non-capture $\mu$") # plot mergers ax.scatter(tm, xm, 120, marker="s", edgecolor="r", facecolor="none", linewidths=3, zorder=50, label="Captured wave") # plot extreme events ax.scatter(Twm, Xwm, 120, marker="v", edgecolor="gold", facecolor="none", linewidths=3, zorder=55, label="Capture maxima") ax.scatter(Tnm, Xnm, 120, marker="o", edgecolor="dodgerblue", facecolor="none", linewidths=3, zorder=50, label="Non-capure maxima") ax.scatter(Txx, Xxx, 280, marker="o", edgecolor="crimson", facecolor="none", linewidths=3, zorder=50, label="Extreme events") lg = ax.legend(loc=1, ncol=5, fontsize=13) lg.get_frame().set_color("0.75") lg.get_frame().set_edgecolor('k') for handle in lg.legendHandles: try: handle.set_sizes([120.0]) except Exception: pass ax.set_xlim(0, t.max()) ax.set_ylim(0, 75) sns.despine(ax=ax) ax.set_xlabel(r"Time $[s]$") ax.set_ylabel(r"Distance $[m]$") # add letter bbox = dict(boxstyle="square", ec="none", fc="1", lw=1, alpha=0.7) ax.text(0.010, 0.965, "a)", transform=ax.transAxes, ha="left", va="top", bbox=bbox, zorder=100)
def main(): # read frame img = os.path.isfile(args.frame[0]) if img: Ir = skimage.io.imread(args.frame[0]) h, w = Ir.shape[:2] else: raise ValueError("Could not find input frame.") # camera matrix K, DC = ipwl.camera_parser(args.camera[0]) # read XYZ coords dfxyz = pd.read_csv(args.xyzfile[0]) XYZ = dfxyz[["x", "y", "z"]].values gcp_x = XYZ[0, 0] gcp_y = XYZ[0, 1] # read UV coords dfuv = pd.read_csv(args.uvfile[0]) UV = dfuv[["u", "v"]].values # horizon hor = float(args.horizon[0]) # rotation Angle theta = float(args.theta[0]) # translations xt = float(args.X[0]) yt = float(args.Y[0]) # projection height z = float(args.Z[0]) # undistort image Kn, roi = cv2.getOptimalNewCameraMatrix(K, DC, (w, h), 1, (w, h)) Ir = cv2.undistort(Ir, K, DC, None, Kn) # homography H = ipwl.find_homography(UV, XYZ, K, z=z, distortion=0) # rectify coordinates X, Y = ipwl.rectify_image(Ir, H) # find the horizon limits horizon = ipwl.find_horizon_offset(X, Y, max_distance=hor) # rotate and translate Xr, Yr = ipwl.rotate_translate(X, Y, rotation=theta, translation=[xt, yt]) # final arrays if hor == -999: Xc = Xr Yc = Yr Ic = Ir else: Xc = Xr[horizon:, :] Yc = Yr[horizon:, :] Ic = Ir[horizon:, :, :] # new image dimensions hc, wc = Ic.shape[:2] # flattened coordinates XYc = np.dstack([Xc.flatten(), Yc.flatten()])[0] # build timestack line without GUI if args.x1 and args.x2 and args.y1 and args.y2: x1 = float(args.x1[0]) x2 = float(args.x2[0]) y1 = float(args.y1[0]) y2 = float(args.y2[0]) # start GUI else: # coords=[] plt.ion() fig, ax = plt.subplots() im = plt.pcolormesh(Xc, Yc, np.mean(Ic, axis=2)) rgba = ipwl.construct_rgba_vector(Ic, n_alpha=0) im.set_array(None) # remove the array im.set_edgecolor('none') im.set_facecolor(rgba) ax.set_aspect("equal") points = plt.ginput(n=2, timeout=100, show_clicks=True) # cid = fig.canvas.mpl_connect('button_press_event', _onclick) plt.show() plt.close() # organizing data x1 = points[0][0] x2 = points[1][0] y1 = points[0][1] y2 = points[1][1] # build the timestack line npoints = np.int(args.stackpoints[0]) xline = np.linspace(x1, x2, npoints) yline = np.linspace(y1, y2, npoints) points = np.vstack([xline, yline]).T # do KDTree in the cliped array _, IDXc = scipy.spatial.KDTree(XYc).query(points) # points in metric coordinates xc = XYc[IDXc, 0] yc = XYc[IDXc, 1] # create a line of pixel centers i_stack_center = np.unravel_index(IDXc, Xr.shape)[0] j_stack_center = np.unravel_index(IDXc, Yr.shape)[1] # pixel centes in metric coordinates x_stack_center = Xc[i_stack_center, j_stack_center] y_stack_center = Yc[i_stack_center, j_stack_center] # loop over pixel centers and get all pixels insed the window Ipx = [] Jpx = [] win = int(args.window[0]) for i, j in zip(i_stack_center, j_stack_center): # find surrounding pixels isurrounding, jsurrounding = ipwl.pixel_window(Ic, i, j, win, win) # final pixel arrays iall = np.hstack([isurrounding, i]) jall = np.hstack([jsurrounding, j]) # apppend for plotting for val in isurrounding: Ipx.append(val) for val in jsurrounding: Jpx.append(val) # translate to metric coordinates Xpixels = Xc[Ipx, Jpx] Ypixels = Yc[Ipx, Jpx] # plot if args.show: fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 10)) # pixel coords ax1.imshow(Ic) ax1.scatter(Jpx, Ipx, 20, facecolor="darkgreen", edgecolor="k", lw=1) ax1.scatter(j_stack_center, i_stack_center, 50, facecolor="deepskyblue", edgecolor="w", lw=1) # metric coords im = ax2.pcolormesh(Xc, Yc, Ic.mean(axis=2)) im.set_array(None) im.set_edgecolor('none') im.set_facecolor(ipwl.construct_rgba_vector(Ic, n_alpha=0)) ax2.scatter(Xpixels, Ypixels, 20, facecolor="darkgreen", edgecolor="k", lw=1) ax2.scatter(x_stack_center, y_stack_center, 50, facecolor="deepskyblue", edgecolor="w", lw=1) ax2.set_xlim(-200, 200) ax2.set_ylim(-200, 200) ax2.set_aspect("equal") # ax2.legend() plt.show()
def main(): """ Run the main script """ # read parameters from JSON ## with open(args.input[0], 'r') as f: H = json.load(f) # input timestack ncin = H["data"]["ncin"] # output outputto = os.path.abspath(H["data"]["dataout"]) if not os.path.isdir(outputto): os.makedirs(outputto) basename = H["data"]["basename"] # get analysis parameters # which algorithm to use to detect breaking events brk_alg = H["parameters"]["breaking_algorithm"] if brk_alg not in ["colour", "peaks", "edges", "edges_and_colour"]: raise ValueError("Breaking detection algorithm should be \ either \'colour\', \'peaks\', \'edges\' or \ \'edges_and_colour\'.") # metric to use for pixel intensity px_mtrc = H["parameters"]["pixel_metric"] if px_mtrc not in ["lightness", "intensity"]: raise ValueError("Pixel metric should be either \'lightness\' \ or \'intensity\'.") # colour quantization qnt_cl = H["parameters"]["colour_quantization"] n_clrs = H["parameters"]["quantization_colours"] # peak detection method pxp_mtd = H["parameters"]["peak_detection_algorithm"] # threshold for peak detection px_trsh = H["parameters"]["pixel_threshold"] # pixel window for denoise_bilateral px_wndw = H["parameters"]["pixel_window"] # time window for peak detection ts_wndw = H["parameters"]["time_window"] # minimum number of samples to be used for the DBSCAN clustering step dbs_msp = H["parameters"]["min_samples"] # minimum distance be used for the DBSCAN clustering step dbs_eps = H["parameters"]["eps"] # distance metric for the DBSCAN clustering step dbs_mtc = H["parameters"]["dbscan_metric"] scipy_dists.append(['cityblock', 'cosine', 'euclidean', 'l1', 'l2', 'manhattan']) if dbs_mtc not in scipy_dists: raise ValueError("Distance \'{}\' is not valid. Please check \ scipy.spatial.distance for valid \ options.".format(dbs_mtc)) # resample rule for timeseries rs_rule = H["parameters"]["resample_rule"] # surf zone limits from input parameters file, if False, will call GUI. sz_lims = H["parameters"]["surf_zone_lims"] if not sz_lims[0]: sz_gui = True else: sz_gui = False # sand colour from input parameter file, if False, will call GUI s_color = H["parameters"]["sand_colour"] if not s_color[0]: sand_colour_gui = True else: sand_colour_gui = False sand = np.array(s_color) # water colour from input parameter file, if False, will call GUI w_color = H["parameters"]["water_colour"] if not w_color[0]: water_colour_gui = True else: water_colour_gui = False water = np.array(w_color) # foam colour from input parameter file, if False, will call GUI f_color = H["parameters"]["foam_colour"] if not f_color[0]: foam_colour_gui = True else: foam_colour_gui = False foam = np.array(f_color) # number of clicks for GUI n_clks = H["parameters"]["nclicks"] # pixel window for GUI px_wind = H["parameters"]["gui_window"] # try to fix bad pixel values gap_val = H["parameters"]["gap_value"] # plot? plot = H["parameters"]["plot"] # process timestack # read timestack ds = xr.open_dataset(ncin) # load timestack variables # x = ds["x"].values y = ds["y"].values # compute distance from shore stk_len = np.sqrt(((x.max() - x.min()) * (x.max() - x.min())) + ((y.max() - y.min()) * (y.max() - y.min()))) crx_dist = np.linspace(0, stk_len, len(x)) # get timestack times stk_time = pd.to_datetime(ds["time"].values).to_pydatetime() stk_secs = ellapsedseconds(stk_time) # get RGB values rgb = ds["rgb"].values # try to fix vertical grey strips, if any ifix, jfix = np.where(np.all(rgb == gap_val, axis=-1)) rgb[ifix, jfix, :] = rgb[ifix-2, jfix-2, :] # get analysis limits if sz_gui: crx_start, crx_end = get_analysis_domain(stk_secs, crx_dist, rgb) else: crx_start = sz_lims[0] crx_end = sz_lims[1] # run the analysis if brk_alg in ["colour", "edges_and_colour"]: # sand if sand_colour_gui: df_sand = get_training_data(rgb, regions=1, region_names=["sand"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, sand = get_dominant_colour(df_sand, n_colours=8) sand = sand[0] # water if water_colour_gui: df_water = get_training_data(rgb, regions=1, region_names=["water"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, water = get_dominant_colour(df_water, n_colours=8) water = water[0] # foam if foam_colour_gui: df_foam = get_training_data(rgb, regions=1, region_names=["foam"], iwin=px_wind, jwin=px_wind, nclicks=n_clks) _, _, foam = get_dominant_colour(df_foam, n_colours=8) foam = foam[0] # build colour structures train_colours = {'labels': [0, 1, 2], 'aliases': ["sand", "water", "foam"], 'rgb': [sand, water, foam], 'target': 2} else: train_colours = None # detect breaking events times, breakers = detect_breaking_events(stk_time, crx_dist, rgb, crx_start=crx_start, crx_end=crx_end, tswindow=ts_wndw, pxwindow=px_wndw, px_mtrc=px_mtrc, resample_rule=rs_rule, algorithm=brk_alg, peak_detection=pxp_mtd, posterize=qnt_cl, ncolours=n_clrs, threshold=px_trsh, colours=train_colours, fix_constrast=True) # DBSCAN print(" + >> clustering wave paths") df_dbscan = dbscan(times, breakers, dbs_eps, dbs_msp, dbs_mtc) # Outputs print(" + >> writting output") if os.path.isfile(os.path.join(outputto, basename+".csv")): overwrite = input(" |- >> overwrite output?") if overwrite[0] == "y": write_outputs(outputto, basename, stk_secs, crx_dist, rgb, df_dbscan) else: print(" - >> warning: not writing outputs") else: write_outputs(outputto, basename, stk_secs, crx_dist, rgb, df_dbscan) if plot: print(" + >> plotting") fig = plt.figure(figsize=(16, 6)) ax1 = fig.add_axes([0.1, 0.1, 0.7, 0.8]) ax2 = fig.add_axes([0.85, 0.1, 0.1, 0.8]) # get unique colours for each wave colors = plt.cm.get_cmap("Set1", len(np.unique(df_dbscan["wave"].values))) # get traning colours if train_colours: for label, region, color in zip(train_colours["labels"], train_colours["aliases"], train_colours["rgb"]): ax2.scatter(1, label, 1000, marker="s", color=color/255, label=region, edgecolor="k", lw=2) # set axis ax2.set_yticks(train_colours["labels"]) ax2.set_yticklabels(train_colours["aliases"]) ax2.set_ylim(-0.25, len(train_colours["aliases"])-1+0.25) for tick in ax2.get_yticklabels(): tick.set_rotation(90) ax2.xaxis.set_major_locator(plt.NullLocator()) else: for label, region, color in zip([0, 1, 2], ['N/A', 'N/A', 'N/A'], [[1, 1, 1], [1, 1, 1], [1, 1, 1]]): ax2.scatter(1, label, 1000, marker="s", color=[1, 1, 1], label=region, edgecolor="k", lw=2) # set axis ax2.set_yticks([0, 1, 2]) ax2.set_yticklabels(['N/A', 'N/A', 'N/A']) ax2.set_ylim(-0.25, len([0, 1, 2])-1+0.25) for tick in ax2.get_yticklabels(): tick.set_rotation(90) ax2.xaxis.set_major_locator(plt.NullLocator()) ax2.set_title("Training colours") # plot timestack im = ax1.pcolormesh(stk_secs, crx_dist, rgb.mean(axis=2).T) # set timestack to to true color rgba = construct_rgba_vector(np.rollaxis(rgb, 1, 0), n_alpha=0) rgba[rgba > 1] = 1 im.set_array(None) im.set_edgecolor('none') im.set_facecolor(rgba) # plot analysis limits ax1.axhline(y=crx_start, lw=3, color="darkred", ls="--") ax1.axhline(y=crx_end, lw=3, color="darkred", ls="--") # plot all identified breaking events ax1.scatter(times, breakers, 20, color="k", alpha=0.5, marker="+", lw=1, zorder=10) # DBSCAN plot k = 0 for label, group in df_dbscan.groupby("wave"): if label > -1: # get x and y for regression xwave = group["time"].values ywave = group["breaker"].values # scatter points ax1.scatter(xwave, ywave, 40, label="wave " + str(label), c=colors(k), alpha=0.5, marker="o", edgecolor="k") bbox = dict(boxstyle="square", ec="k", fc="w", alpha=0.5) ax1.text(xwave.min(), ywave.max(), "wave " + str(k), rotation=45, fontsize=8, zorder=10, bbox=bbox) k += 1 # set axes limits ax1.set_xlim(xmin=stk_secs.min(), xmax=stk_secs.max()) ax1.set_ylim(ymin=crx_dist.min(), ymax=crx_dist.max()) # set axes labels ax1.set_ylabel(r"Cross-shore distance $[m]$", fontsize=16) ax1.set_xlabel(r"Time $[s]$", fontsize=16) # seaborn despine sns.despine(ax=ax2, bottom=True) sns.despine(ax=ax1) # fig.tight_layout() plt.show()