Пример #1
0
def run(input_image_path: Path,
        output_directory: Path,
        identfier: str,
        num_lines: int,
        start_column: int = 0,
        show: bool = True):
    """"""
    trace_image = read_image(input_image_path)

    if len(trace_image.image.shape) > 2:
        trace_image.bgr_to_gray()
    trace_image = trace_image.image

    new_image = np.zeros(trace_image.shape)
    # point_list = []
    x_list: tp.List[float] = []
    y_list: tp.List[tp.List[float]] = []

    for i, new_y in find_datapoints(image=trace_image,
                                    start_column=start_column,
                                    num_lines=num_lines,
                                    show=show):

        y_list.append(new_y)
        for y in new_y:
            new_image[int(new_y), i] = 255
        x_list.append(i)
        y_list.append(int(new_y))

    x_arr = np.asarray(x_list, dtype=np.float_)
    y_arr = np.asarray(y_list, dtype=np.float_)

    y_arr -= y_arr.mean()  # mean zero
    y_arr *= -1  # flip

    if show:
        fig, (ax1, ax2) = plt.subplots(2)
        ax1.imshow(new_image)
        ax2.plot(x_arr, y_arr)
        plt.show()

    out_array = np.zeros((x_arr.size, 2))
    out_array[:, 0] = x_arr
    out_array[:, 1] = y_arr

    output_directory.mkdir(exist_ok=True, parents=True)
    np.save(output_directory / f"{identfier}_trace", out_array)
Пример #2
0
def run(input_image_path: Path,
        output_directory: Path,
        name: str,
        *,
        debug: bool = False,
        compute_scale: bool = True,
        kernel_length: int = 9,
        num_iterations: int = 4,
        blur_size: int = 9,
        thresh_val: float = 175,
        dx: float = 2.5e-4,
        dy: float = 2.5e-4):
    image = read_image(input_image_path)
    image_list = split_image(image,
                             kernel_length=kernel_length,
                             blur_kernel_size=blur_size,
                             threshold_value=thresh_val,
                             num_iterations=num_iterations)

    if debug:
        debug_path = get_debug_path("split_image")
        save(image.image, debug_path, "input")

    scale_dict = {}
    for i, image in enumerate(image_list):
        image.bgr_to_gray()
        # TODO: debug each split
        rectangles = markers(image,
                             kernel_length=kernel_length,
                             blur_kernel_size=blur_size,
                             threshold_value=thresh_val,
                             num_iterations=num_iterations,
                             debug=debug)
        if len(rectangles) >= 2:
            axis, scale = get_axis(image, rectangles)
            image.set_axis(axis)
            image.set_scale(scale)
            image.reset_image()
            resample(image, step_x=dx, step_y=dy)
            image.checkpoint()
        else:
            print(f"skipping split {i}")
            continue

        if compute_scale:  # Recompute scale
            image.bgr_to_gray()
            rectangles = markers(image,
                                 kernel_length=kernel_length,
                                 blur_kernel_size=blur_size,
                                 threshold_value=thresh_val,
                                 num_iterations=num_iterations,
                                 debug=debug)
            if len(rectangles) < 2:
                logger.info(
                    f"Cannot compute scale of split {i} -- using average of previous scales"
                )
                if len(scale_dict) > 0:
                    scale_dict[i] = sum(scale_dict.values()) / len(scale_dict)
            else:
                axis, scale = get_axis(image, rectangles)
                image.set_axis(axis)
                image.set_scale(scale)
                scale_dict[i] = scale

    output_directory.mkdir(exist_ok=True, parents=True)

    for i, image in enumerate(image_list):
        logger.info(f"Scale: {image.scale}")
        save_image(output_directory / f"{name}_split{i}.png", image)
        # dump_image(output_directory / f"split{i}_{identifier}.pkl", image)

    with open(output_directory / "scales.txt", "a") as output_handle:
        for case, scale in scale_dict.items():
            output_handle.write(f"Case: {case}, Scale: {scale}\n")
Пример #3
0
def run(
    input_image_path: Path,
    output_directory: Path,
    identifier: str,
    scale: float = None,
    start_column: int = 0,
    show: bool = False,
    show_step: bool = False
):
    """Digitise *a single* eeg trace.

    input_image_path:
        Path to segmented EEG trace.
    output_directory:
        Path to directory where time series is stored.
    identifier:
        'Name' of the trace.
    start_column:
        The column from which to start digitising.
    show:
        Display peaks selection for each column and the final result.
    """
    trace_image = read_image(input_image_path)

    # Make sure image is grayscale
    if len(trace_image.image.shape) > 2:
        trace_image.bgr_to_gray()
    trace_image = trace_image.image

    new_image = np.zeros(trace_image.shape)

    x_list: tp.List[int] = []
    y_list: tp.List[float] = []

    for i, new_y in find_datapoints(
        image=trace_image,
        start_column=start_column,
        show=show_step
    ):
        y_list.append(new_y)
        x_list.append(i)
        try:
            new_image[int(new_y), i] = 255      # For quality control
        except IndexError as e:
            logging.info(f"{new_y}, {i}")
            logging.info(f"{new_image.shape}")
            import sys; sys.exit(1)

    x_arr = np.asarray(x_list, dtype=np.float_)
    y_arr = np.asarray(y_list, dtype=np.float_)

    # TODO: Why do I do this? This can be done later I think
    # y_arr -= y_arr.mean()      # mean zero
    # y_arr *= -1                # flip

    # TODO: Save image for later review
    fig, (ax1, ax2) = plt.subplots(2)
    ax2.plot(x_arr, y_arr)
    output_directory.mkdir(exist_ok=True, parents=True)
    # fig.savefig(output_directory / f"trace{identifier}_imageQC.png")
    if show:
        plt.show()
        plt.close(fig)

    out_array = np.zeros((x_arr.size, 2))
    out_array[:, 0] = x_arr
    out_array[:, 1] = y_arr

    if scale is not None:
        out_array *= 15/scale

    output_directory.mkdir(exist_ok=True, parents=True)
    np.save(output_directory / f"trace{identifier}", out_array)
Пример #4
0
def run(
    *,
    input_image_path: Path,
    output_directory: Path,
    identifier: str,
    scale: float = None,
    debug: bool = False,
):
    """Segment the contours from a black and white image and save the segmented lines."""
    image = read_image(input_image_path)
    if debug:
        debug_path = get_debug_path("remove_background")
        save(image.image, debug_path, "input")
    image.bgr_to_gray()

    if debug:
        save(image.iamge, debug_path, "match_contours")
    contours = get_contours(image=image)
    features = match_contours(matcher=get_graph_matcher(), contours=contours)

    if debug:
        debug_path = get_debug_path("extract_contours_bw")
        save(image.image, debug_path, "input")

    output_directory.mkdir(exist_ok=True, parents=True)

    for i, c in enumerate(features):
        tmp_image = image.copy_image()
        filter_contours(image_array=tmp_image, contours=[c])
        clipped_contour = tmp_image[~np.all(tmp_image == 0, axis=1)]
        save_image(output_directory / f"{identifier}_trace{i}.png",
                   Image(clipped_contour))

    ############################
    ### Make annotated image ###
    ############################

    fig, ax = plt.subplots(1, figsize=(15, 10), dpi=500)
    tmp_image = image.image_orig

    color_iterator = itertools.cycle(mtableau_brg())

    for i, c in enumerate(features):
        color = next(color_iterator)
        tmp_image = cv2.drawContours(tmp_image, features, i,
                                     color_to_256_RGB(color), cv2.FILLED)
        polygon = Polygon(c.reshape(-1, 2))
        x0, y0, x1, y1 = polygon.bounds

        ann = ax.annotate(
            f"Contour {i}",
            xy=(x1, y1),  # (x0, y1)
            xycoords="data",
            xytext=(0, 35),
            textcoords="offset points",
            size=10,
            bbox=dict(
                boxstyle="round",
                fc=color  # normalised color
            ))

    ax.imshow(tmp_image)
    ax.set_title("A digitised paper strip")
    if scale is not None:  # multiply by distance between black sqaures?
        ax.set_xticklabels(
            ["{:.1f} cm".format(15 * i / scale) for i in ax.get_xticks()])
        ax.set_yticklabels(
            ["{:.1f} cm".format(15 * i / scale) for i in ax.get_yticks()])
    ax.set_ylabel("Voltage")
    ax.set_xlabel("Time")
    fig.savefig(output_directory / f"{identifier}_annotated.png", dpi=500)
Пример #5
0
    plot_img = image.image.copy()
    plot_img[:, 399:402] = 0

    print(plot_img)
    ax1.imshow(plot_img)

    values = image.image[:, 400]
    x = np.linspace(0, 1, values.size)
    t, c, k = interpolate.splrep(x, values, s=10, k=3)

    xnew = np.linspace(0, 1, 10000)
    splev = interpolate.BSpline(t, c, k)

    ax2.plot(x, values, "--", alpha=0.75)
    ax2.plot(xnew, splev(xnew))
    plt.show()


if __name__ == "__main__":
    filepath = Path("../data/scan4.png")
    image = read_image(filepath)
    # plt.imshow(image.image)
    # image.show()

    preprocess(image)
    markers(image)
    graphs(image)

    # extract(image)
Пример #6
0
def run(
    input_image_path: Path,
    output_directory: Path,
    identifier: str,
    scale: float = None,
    debug:bool
):
    """Remove the background, segment the contours and save the segmented lines as pngs."""
    image = read_image(input_image_path)
    if debug:
        debug_path = get_debug_path("prepare_lines")
        save(np.ndarray, debug_path, "input")

    image.bgr_to_gray()
    image.checkpoint("resampled")

    remove_background(image=image, smooth_kernel_size=3)
    features = extract_contours(image=image, blur_kernel_size=3)
    if debug:
        save(np.ndarray, debug_path, "remove_background")
    image.invert()


    image.reset_image("resampled")
    image.invert()

    output_directory.mkdir(exist_ok=True, parents=True)

    for i, c in enumerate(features):
        tmp_image = image.copy_image()
        filter_contours(image_array=tmp_image, contours=[c])
        clipped_contour = tmp_image[~np.all(tmp_image == 0, axis=1)]
        save_image(output_directory / f"{identifier}_trace{i}.png", Image(clipped_contour))

    ##################
    ### Make image ###
    ##################

    tmp_image = np.ones((*image.image.shape, 3), dtype=np.uint8)
    tmp_image[:] = (255, 255, 255)      # White

    fig, ax = plt.subplots(1)
    ax.imshow(tmp_image)

    color_iterator = itertools.cycle(mtableau_brg())

    for i, c in enumerate(features):
        color = next(color_iterator)
        tmp_image = cv2.drawContours(tmp_image, features, i, color_to_256_RGB(color), cv2.FILLED)
        polygon = Polygon(c.reshape(-1, 2))
        x0, y0, x1, y1 = polygon.bounds

        tmp_image2 = np.zeros(tuple(map(math.ceil, (y1, x1))), dtype=np.uint8)
        tmp_image2 = cv2.drawContours(tmp_image2, features, i, 255, cv2.FILLED)

        ann = ax.annotate(
            f"Contour {i}",
            xy=(x0, y1),
            xycoords="data",
            xytext=(0, 35),
            textcoords="offset points",
            size=10,
            bbox=dict(
                boxstyle="round",
                fc=color       # normalised color
            )
        )

    ax.imshow(tmp_image)
    ax.set_title("A digitised paper strip")
    if scale is not None:       # multiply by distance between black sqaures?
        ax.set_xticklabels(["{:.1f} cm".format(15*i/scale) for i in ax.get_xticks()])
        ax.set_yticklabels(["{:.1f} cm".format(15*i/scale) for i in ax.get_yticks()])
    ax.set_ylabel("Voltage")
    ax.set_xlabel("Time")
    fig.savefig(output_directory / f"{identifier}_annotated.png")
Пример #7
0
def run(*,
        input_image_path: Path,
        output_directory: Path,
        identifier: str,
        smooth_kernel_size: int = 3,
        threshold_value: int = 100,
        background_kernel_size=5,
        scale: float = None,
        debug: bool = False,
        blue_color_filter: tp.Sequence[int] = None,
        red_color_filter: tp.Sequence[int] = None,
        horisontal_kernel_length: int = None,
        x_interval: tp.Tuple[int, int] = None):
    """Remove the background, segment the contours and save the segmented lines as pngs."""
    image = read_image(input_image_path)

    if debug:
        debug_path = get_debug_path("prepare_lines")
        save(image.image, debug_path, "input")

    if blue_color_filter is not None:
        lower = tuple(map(int, blue_color_filter[:3]))
        upper = tuple(map(int, blue_color_filter[3:]))
        print(lower, upper)
        blue_mask = cv2.inRange(image.image, lower, upper)
        image.image[blue_mask == 255] = 255
    if red_color_filter is not None:
        lower = tuple(map(int, red_color_filter[:3]))
        upper = tuple(map(int, red_color_filter[3:]))
        red_mask = cv2.inRange(image.image, lower, upper)
        image.image[red_mask == 255] = 255

    image.invert()
    image.bgr_to_gray()
    image.checkpoint("resampled")

    if horisontal_kernel_length is not None:
        horisontal_kernel = cv2.getStructuringElement(
            cv2.MORPH_RECT, (horisontal_kernel_length, 1))

        x0, x1 = x_interval
        if x1 == -1:  # Set -1 to be inclusive last element
            x1 = None
        detected_lines = cv2.morphologyEx(image.image[x0:x1, :],
                                          cv2.MORPH_OPEN,
                                          horisontal_kernel,
                                          iterations=1)

        # findContours returns (contours, hierarchy)
        contours = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL,
                                    cv2.CHAIN_APPROX_SIMPLE)[0]
        for c in contours:
            cv2.drawContours(image.image[x0:x1, :], [c], -1, 0, -10)

    remove_background(image=image,
                      smooth_kernel_size=smooth_kernel_size,
                      threshold_value=threshold_value,
                      background_kernel_size=background_kernel_size,
                      debug=debug)
    image.checkpoint("remove_background")

    if debug:
        save(image.image, debug_path, "match_contours")
    contours = get_contours(image=image)
    features = match_contours(matcher=get_graph_matcher(), contours=contours)
    if features is None:  # In case of a blank image
        return

    quality_control_image = image.draw(features, show=False)
    cv2.imwrite(str(output_directory / f"QC_{identifier}.png"),
                quality_control_image)

    if debug:
        save(image.image, debug_path, "remove_background")

    # image.reset_image("resampled")
    image.reset_image("remove_background")
    # image.invert()

    output_directory.mkdir(exist_ok=True, parents=True)

    for i, c in enumerate(features):
        tmp_image = image.copy_image()
        filter_contours(image_array=tmp_image, contours=[c])
        clipped_contour = tmp_image[~np.all(tmp_image == 0, axis=1)]
        save_image(output_directory / f"{identifier}_trace{i}.png",
                   Image(clipped_contour))

    ############################
    ### Make annotated image ###
    ############################

    fig, ax = plt.subplots(1, figsize=(15, 10), dpi=500)
    tmp_image = image.image_orig

    color_iterator = itertools.cycle(mtableau_brg())

    for i, c in enumerate(features):
        color = next(color_iterator)
        tmp_image = cv2.drawContours(tmp_image, features, i,
                                     color_to_256_RGB(color), cv2.FILLED)
        polygon = Polygon(c.reshape(-1, 2))
        x0, y0, x1, y1 = polygon.bounds

        ann = ax.annotate(
            f"Contour {i}",
            xy=((x0 + x1) / 2, y1),  # (x0, y1)
            size=5,
            color=color,
            arrowprops=dict(arrowstyle='->',
                            connectionstyle="arc3,rad=-0.5",
                            color=color))

    ax.imshow(tmp_image)
    ax.set_title("A digitised paper strip")
    if scale is not None:  # multiply by distance between black sqaures?
        ax.set_xticklabels(
            ["{:.1f} cm".format(15 * i / scale) for i in ax.get_xticks()])
        ax.set_yticklabels(
            ["{:.1f} cm".format(15 * i / scale) for i in ax.get_yticks()])
    ax.set_ylabel("Voltage")
    ax.set_xlabel("Time")
    fig.savefig(output_directory / f"{identifier}_annotated.png", dpi=500)