예제 #1
0
def test_get_cells():
    cells = cell_io.get_cells(xml_path)
    assert len(cells) == 65
    assert Cell([2536, 523, 1286], 1) == cells[64]

    cells = cell_io.get_cells(cubes_dir)
    assert len(cells) == 4
    assert natsorted(cubes_cells) == natsorted(cells)

    cells = cell_io.get_cells(roi_sorter_output_dir)
    assert len(cells) == 4
    assert natsorted(roi_sorter_cells) == natsorted(cells)

    with pytest.raises(NotImplementedError):
        assert cell_io.get_cells("misc_format.abc")
예제 #2
0
 def __load_cells(self):
     self.cells = get_cells(self.cells_file)
     if not self.cells:
         logging.error(f"No cells found, exiting. "
                       f"Please check the file: {self.cells_file}")
         raise ValueError(f"No cells found, exiting. "
                          f"Please check the file: {self.cells_file}")
예제 #3
0
def cells_to_brainrender(
    cells_file,
    output_filename,
    pixel_size_x=10,
    pixel_size_y=10,
    pixel_size_z=10,
    max_z=13200,
    key="df",
):
    print(f"Converting file: {cells_file}")
    cells = cells_io.get_cells(cells_file)
    cells = cells_io.cells_to_dataframe(cells)

    cells["x"] = cells["x"] * pixel_size_x
    cells["y"] = cells["y"] * pixel_size_y
    cells["z"] = cells["z"] * pixel_size_z

    cells.columns = ["z", "y", "x", "type"]

    cells["x"] = max_z - cells["x"]

    print(f"Saving to: {output_filename}")
    cells.to_hdf(output_filename, key=key, mode="w")

    print("Finished")
예제 #4
0
def get_cells_data(xml_file_path, structures_file_path, cells_only=True):
    cells = get_cells(xml_file_path, cells_only=cells_only)
    if not cells:
        raise summary_tools.CellCountMissingCellsException(
            "No cells found in file: {}".format(xml_file_path))
    structures = get_structures_tree(structures_file_path)
    root = structures[0]
    return root, cells
예제 #5
0
def test_detection_full(tmpdir):
    tmpdir = str(tmpdir)

    cellfinder_args = [
        "cellfinder_run",
        "-s",
        signal_data,
        "-b",
        background_data,
        "-o",
        tmpdir,
        "-x",
        x_pix,
        "-y",
        y_pix,
        "-z",
        z_pix,
        "--n-free-cpus",
        "0",
        "--no-standard-space",
        "--save-planes",
    ]
    sys.argv = cellfinder_args
    cellfinder_run()

    cells_test_xml = os.path.join(tmpdir, "cell_classification.xml")

    cells_validation = cell_io.get_cells(cells_validation_xml)
    cells_test = cell_io.get_cells(cells_test_xml)

    num_non_cells_validation = sum(
        [cell.type == 1 for cell in cells_validation]
    )
    num_cells_validation = sum([cell.type == 2 for cell in cells_validation])

    num_non_cells_test = sum([cell.type == 1 for cell in cells_test])
    num_cells_test = sum([cell.type == 2 for cell in cells_test])

    assert isclose(
        num_non_cells_validation,
        num_non_cells_test,
        abs_tol=DETECTION_TOLERANCE,
    )
    assert isclose(
        num_cells_validation, num_cells_test, abs_tol=DETECTION_TOLERANCE
    )
예제 #6
0
def xml_scale(
    xml_file,
    x_scale=1,
    y_scale=1,
    z_scale=1,
    output_directory=None,
    integer=True,
):
    # TODO: add a csv option
    """
    To rescale the cell positions within an XML file. For compatibility with
    other software, or if  data has been scaled after cell detection.
    :param xml_file: Any cellfinder xml file
    :param x_scale: Rescaling factor in the first dimension
    :param y_scale: Rescaling factor in the second dimension
    :param z_scale: Rescaling factor in the third dimension
    :param output_directory: Directory to save the rescaled XML file.
    Defaults to the same directory as the input XML file
    :param integer: Force integer cell positions (default: True)
    :return:
    """
    if x_scale == y_scale == z_scale == 1:
        raise CommandLineInputError("All rescaling factors are 1, "
                                    "please check the input.")
    else:
        input_file = Path(xml_file)
        start_time = datetime.now()
        cells = cio.get_cells(xml_file)

        for cell in cells:
            cell.transform(
                x_scale=x_scale,
                y_scale=y_scale,
                z_scale=z_scale,
                integer=integer,
            )

        if output_directory:
            output_directory = Path(output_directory)
        else:
            output_directory = input_file.parent

        ensure_directory_exists(output_directory)
        output_filename = output_directory / (input_file.stem + "_rescaled")
        output_filename = output_filename.with_suffix(input_file.suffix)

        cio.save_cells(cells, output_filename)

        print("Finished. Total time taken: {}".format(datetime.now() -
                                                      start_time))
예제 #7
0
def get_cell_location_array(
    cell_file,
    cell_position_scaling=[None, None, None],
    cells_only=False,
    type_str="type",
    integer=True,
):
    """
    Loads a cell file, and converts to an array, with 3 columns of x,y,z
    positions
    :param cell_file: Any supported cell file, e.g. xml
    :param cell_position_scaling: list of cell scaling (raw -> final) for
    [x, y, z]
    :param cells_only: If only cells (rather than unknown or artifacts)
    should be included
    :param str type_str: String defining the title of the cell type column
    in the dataframe. Used to remove non cells (artifacts), and then to clean
    up the dataframe to be converted into a numpy array.
    :param integer: Force integer cell positions (default: True)
    :return: Array of cell positions, with x,y,z columns
    """

    logging.debug("Loading cells")
    cells = cell_io.get_cells(cell_file)

    if cell_position_scaling != [None, None, None]:
        for cell in cells:
            cell.transform(
                x_scale=cell_position_scaling[0],
                y_scale=cell_position_scaling[1],
                z_scale=cell_position_scaling[2],
                integer=integer,
            )

    cells = cell_io.cells_to_dataframe(cells)
    num_cells = len(cells[cells[type_str] == Cell.CELL])
    num_non_cells = len(cells[cells[type_str] == Cell.NO_CELL])
    logging.debug("{} cells, and {} non-cells".format(num_cells,
                                                      num_non_cells))
    if cells_only:
        logging.debug("Removing non cells")
        cells = cells[cells[type_str] == Cell.CELL]

    logging.debug("Tidying up dataframe to convert to array")
    cells.drop(type_str, axis=1, inplace=True)
    return cells.to_numpy()
예제 #8
0
def run_xml_scale(xml_file, x_scale, y_scale, z_scale, output_dir):
    cellfinder_xml_scale_args = [
        "cellfinder_xml_scale",
        xml_file,
        "-x",
        str(x_scale),
        "-y",
        str(y_scale),
        "-z",
        str(z_scale),
        "-o",
        str(output_dir),
    ]

    sys.argv = cellfinder_xml_scale_args
    cellfinder_xml_scale_run()

    scaled_cells = get_cells(os.path.join(output_dir, SCALED_XML_FILE_NAME))
    return scaled_cells
예제 #9
0
def transform_cells_to_standard_space(args):
    if args.registration_config is None:
        args.registration_config = source_custom_config()

    reg_params = RegistrationParams(
        args.registration_config,
        affine_n_steps=args.affine_n_steps,
        affine_use_n_steps=args.affine_use_n_steps,
        freeform_n_steps=args.freeform_n_steps,
        freeform_use_n_steps=args.freeform_use_n_steps,
        bending_energy_weight=args.bending_energy_weight,
        grid_spacing_x=args.grid_spacing_x,
        smoothing_sigma_reference=args.smoothing_sigma_reference,
        smoothing_sigma_floating=args.smoothing_sigma_floating,
        histogram_n_bins_floating=args.histogram_n_bins_floating,
        histogram_n_bins_reference=args.histogram_n_bins_reference,
    )

    generate_deformation_field(args, reg_params)
    cells_only = not args.transform_all
    cells = get_cells(args.paths.classification_out_file,
                      cells_only=cells_only)

    logging.info("Loading deformation field")
    deformation_field = load_any_image(args.paths.tmp__deformation_field)
    scales = get_scales(args, reg_params)
    field_scales = get_deformation_field_scales(reg_params)

    logging.info("Transforming cell positions")
    transformed_cells = transform_cell_positions(cells, deformation_field,
                                                 field_scales, scales)

    logging.info("Saving transformed cell positions")

    save_cells(
        transformed_cells,
        args.paths.cells_in_standard_space,
        save_csv=args.save_csv,
    )

    if not args.debug:
        logging.info("Removing standard space transformation temp files")
        tools.delete_temp(args.paths.standard_space_output_folder, args.paths)
예제 #10
0
def test_classify(tmpdir):
    tmpdir = str(tmpdir)
    tmpdir = os.path.join(os.getcwd(), tmpdir)
    new_cubes_dir = os.path.join(tmpdir, "cubes")

    # copying so we can test the removal of intermediate files with debug set
    # to false. Otherwise will delete cubes in tests/data
    shutil.copytree(cubes_dir, new_cubes_dir)

    args = ClassifyArgs(tmpdir, new_cubes_dir)
    args = prep_classification(args)

    classify.main(args)

    cells_test = cell_io.get_cells(args.paths.classification_out_file)

    cells_test.sort(key=lambda x: x.z)
    cells_validation.sort(key=lambda x: x.z)

    assert cells_validation == cells_test
예제 #11
0
def test_xml_scale_cli(tmpdir):
    scaled_cells = run_xml_scale(orig_xml_path, 0.5, 0.5, 1, tmpdir)
    assert scaled_cells == get_cells(half_scale_scaled_xml_path)

    scaled_cells = run_xml_scale(orig_xml_path, 10, 100, 1000, tmpdir)
    assert scaled_cells == get_cells(order_magnitude_scaled_xml_path)
예제 #12
0
def test_cells_to_xml(tmpdir):
    cells = cell_io.get_cells(xml_path)
    tmp_cells_out_path = os.path.join(str(tmpdir), "cells.xml")
    cell_io.cells_to_xml(cells, tmp_cells_out_path)
    assert cells == cell_io.get_cells(tmp_cells_out_path)
예제 #13
0
def main(args):

    start_time = datetime.now()

    cells = get_cells(args.paths.cells_file_path)
    if not cells:
        logging.error("No cells found, exiting. Please check your "
                      "cell xml file path: {}"
                      " or verify your cell types "
                      "(maybe use cells-only option to disable)".format(
                          args.paths.cells_file_path))
        raise ValueError("No cells found, exiting. Please check your "
                         "cell xml file path: {}"
                         " or verify your cell types "
                         "(maybe use cells-only option to disable)".format(
                             args.paths.cells_file_path))

    if args.z_pixel_um != args.z_pixel_um_network:
        plane_scaling_factor = args.z_pixel_um_network / args.z_pixel_um
        num_planes_needed_for_cube = round(args.cube_depth *
                                           plane_scaling_factor)
    else:
        num_planes_needed_for_cube = args.cube_depth

    planes_paths = {}
    # Use args.paths for this
    all_channel_ids = args.signal_ch_ids + [args.background_ch_id]
    for idx, planes_paths_file_path in enumerate(args.all_planes_paths):
        channel = all_channel_ids[idx]

        if args.cube_extract_cli:
            channel_list = all_channel_ids
            args.signal_channel = all_channel_ids[0]
        else:
            # only extract those channels that are necessary for classification
            channel_list = [args.signal_channel, args.background_ch_id]
        if channel in channel_list:
            planes_paths[channel] = system.get_sorted_file_paths(
                planes_paths_file_path, file_extension="tif")

    if num_planes_needed_for_cube > len(planes_paths[0]):
        raise StackSizeError("The number of planes provided is not sufficient "
                             "for any cubes to be extracted. Please check the "
                             "input data")

    first_plane = tifffile.imread(list(planes_paths.values())[0][0])

    planes_shape = first_plane.shape
    brain_depth = len(list(planes_paths.values())[0])

    # TODO: use to assert all centre planes processed
    center_planes = sorted(list(set([cell.z for cell in cells])))

    # REFACTOR: rename (clashes with different meaning of planes_to_read below)
    planes_to_read = np.zeros(brain_depth, dtype=np.bool)

    if tools.is_even(num_planes_needed_for_cube):
        half_nz = num_planes_needed_for_cube // 2
        # WARNING: not centered because even
        for p in center_planes:
            planes_to_read[p - half_nz:p + half_nz] = 1
    else:
        half_nz = num_planes_needed_for_cube // 2
        # centered
        for p in center_planes:
            planes_to_read[p - half_nz:p + half_nz + 1] = 1

    planes_to_read = np.where(planes_to_read)[0]

    if not planes_to_read.size:
        logging.error(
            f"No planes found, you need at the very least "
            f"{num_planes_needed_for_cube} "
            f"planes to proceed (i.e. cube z size)"
            f"Brain z dimension is {brain_depth}.",
            stack_info=True,
        )
        raise ValueError(f"No planes found, you need at the very least "
                         f"{num_planes_needed_for_cube} "
                         f"planes to proceed (i.e. cube z size)"
                         f"Brain z dimension is {brain_depth}.")
    # TODO: check if needs to flip args.cube_width and args.cube_height
    cells_groups = cell_tools.group_cells_by_z(cells)

    # copies=2 is set because at all times there is a plane queue (deque)
    # and an array passed to `Cube`
    ram_per_process = get_ram_requirement_per_process(
        planes_paths[args.signal_channel][0],
        num_planes_needed_for_cube,
        copies=2,
    )
    n_processes = system.get_num_processes(
        min_free_cpu_cores=args.n_free_cpus,
        ram_needed_per_process=ram_per_process,
        n_max_processes=len(planes_to_read),
        fraction_free_ram=0.2,
        max_ram_usage=system.memory_in_bytes(args.max_ram, "GB"),
    )
    # TODO: don't need to extract cubes from all channels if
    #  n_signal_channels>1
    with ProcessPoolExecutor(max_workers=n_processes) as executor:
        n_planes_per_chunk = len(planes_to_read) // n_processes
        for i in range(n_processes):
            start_idx = i * n_planes_per_chunk
            end_idx = (start_idx + n_planes_per_chunk +
                       num_planes_needed_for_cube - 1)
            if end_idx > planes_to_read[-1]:
                end_idx = None
            sub_planes_to_read = planes_to_read[start_idx:end_idx]

            executor.submit(
                save_cubes,
                cells_groups,
                planes_paths,
                sub_planes_to_read,
                planes_shape,
                args.x_pixel_um,
                args.y_pixel_um,
                args.x_pixel_um_network,
                args.y_pixel_um_network,
                num_planes_for_cube=num_planes_needed_for_cube,
                cube_width=args.cube_width,
                cube_height=args.cube_height,
                cube_depth=args.cube_depth,
                thread_id=i,
                output_dir=args.paths.tmp__cubes_output_dir,
                save_empty_cubes=args.save_empty_cubes,
            )

    total_cubes = system.get_number_of_files_in_dir(
        args.paths.tmp__cubes_output_dir)
    time_taken = datetime.now() - start_time
    logging.info("All cubes ({}) extracted in: {}".format(
        total_cubes, time_taken))
예제 #14
0
def test_group_cells_by_z():
    z_planes_validate = [
        1272,
        1273,
        1274,
        1275,
        1276,
        1277,
        1278,
        1279,
        1280,
        1281,
        1282,
        1283,
        1284,
        1285,
        1286,
        1287,
        1288,
        1289,
        1290,
        1291,
        1292,
        1294,
        1295,
        1296,
        1297,
        1298,
    ]

    cell_numbers_in_groups_validate = [
        1,
        3,
        7,
        8,
        3,
        1,
        4,
        3,
        1,
        2,
        2,
        1,
        1,
        2,
        5,
        2,
        2,
        2,
        3,
        1,
        1,
        6,
        1,
        1,
        1,
        1,
    ]

    cells = get_cells(xml_path)
    cells_groups = cell_tools.group_cells_by_z(cells)
    z_planes_test = list(cells_groups.keys())
    z_planes_test.sort()

    assert z_planes_validate == z_planes_test

    cell_numbers_in_groups_test = [
        len(cells_groups[plane]) for plane in z_planes_test
    ]
    assert cell_numbers_in_groups_validate == cell_numbers_in_groups_test