예제 #1
0
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
예제 #2
0
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)
예제 #5
0
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()
예제 #6
0
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()