Esempio n. 1
0
def main():
    # Hard-coded parameters
    prod = 'emdata4:8900'
    master = (prod, find_master(prod))
    master_seg = (*master, 'segmentation')

    # I accidentally corrupted the labelindex of bodies in this region
    patch_box = 20480 + np.array([[0, 0, 0], [1024, 1024, 1024]])

    with Timer("Fetching supervoxels", logger):
        boxes = boxes_from_grid(patch_box, Grid((64, 64, 6400)), clipped=True)
        sv_sets = compute_parallel(partial(_fetch_svs, master_seg),
                                   boxes,
                                   processes=32,
                                   ordered=False,
                                   leave_progress=True)
        svs = set(chain(*sv_sets)) - set([0])

    bodies = set(fetch_mapping(*master_seg, svs))

    with Timer(f"Repairing {len(bodies)} labelindexes", logger):
        compute_parallel(partial(_repair_index, master_seg),
                         bodies,
                         processes=32,
                         ordered=False,
                         leave_progress=True)

    print("DONE.")
Esempio n. 2
0
def copy_vnc_subvolume(box_zyx,
                       copy_grayscale=True,
                       copy_segmentation=True,
                       chunk_shape=(64, 64, 2048)):
    assert not (box_zyx % 64).any(), \
        "Only 64px block-aligned volumes can be copied."

    import numpy as np
    from neuclease.util import boxes_from_grid, tqdm_proxy, round_box
    from neuclease.dvid import find_master, fetch_raw, post_raw, fetch_subvol, post_labelmap_voxels

    vnc_master = ('emdata4:8200', find_master('emdata4:8200'))

    NUM_SCALES = 8
    num_voxels = np.prod(box_zyx[1] - box_zyx[0])

    if copy_grayscale:
        logger.info(
            f"Copying grayscale from box {box_zyx[:,::-1].tolist()} ({num_voxels/1e6:.1f} Mvox) for {NUM_SCALES} scales"
        )
        for scale in tqdm_proxy(range(NUM_SCALES)):
            if scale == 0:
                input_name = 'grayscalejpeg'
                output_name = 'local-grayscalejpeg'
            else:
                input_name = f'grayscalejpeg_{scale}'
                output_name = f'local-grayscalejpeg_{scale}'

            scaled_box_zyx = np.maximum(box_zyx // 2**scale, 1)
            scaled_box_zyx = round_box(scaled_box_zyx, 64, 'out')

            for chunk_box in tqdm_proxy(boxes_from_grid(scaled_box_zyx,
                                                        chunk_shape,
                                                        clipped=True),
                                        leave=False):
                chunk = fetch_subvol(*vnc_master,
                                     input_name,
                                     chunk_box,
                                     progress=False)
                post_raw(*vnc_master, output_name, chunk_box[0], chunk)

    if copy_segmentation:
        logger.info(
            f"Copying segmentation from box {box_zyx[:,::-1].tolist()} ({num_voxels/1e6:.2f} Mvox)"
        )
        for chunk_box in tqdm_proxy(
                boxes_from_grid(box_zyx, chunk_shape, clipped=True)):
            chunk = fetch_raw(*vnc_master,
                              'segmentation',
                              chunk_box,
                              dtype=np.uint64)
            post_labelmap_voxels(*vnc_master,
                                 'local-segmentation',
                                 chunk_box[0],
                                 chunk,
                                 downres=True)

        # TODO: Update label indexes?

    logger.info("DONE")
Esempio n. 3
0
def _generate_and_store_mesh():
    try:
        dvid = request.args['dvid']
        body = request.args['body']
    except KeyError as ex:
        return Response(f"Missing required parameter: {ex.args[0]}", 400)

    segmentation = request.args.get('segmentation', 'segmentation')
    mesh_kv = request.args.get('mesh_kv', f'{segmentation}_meshes')

    uuid = request.args.get('uuid') or find_master(dvid)
    if not uuid:
        uuid = find_master(dvid)

    scale = request.args.get('scale')
    if scale is not None:
        scale = int(scale)

    smoothing = int(request.args.get('smoothing', 2))

    # Note: This is just the effective desired decimation assuming scale-1 data.
    # If we're forced to select a higher scale than scale-1, then we'll increase
    # this number to compensate.
    decimation = float(request.args.get('decimation', 0.1))

    user = request.args.get('u')
    user = user or request.args.get('user', "UNKNOWN")

    # TODO: The global cache of DVID sessions should store authentication info
    #       and use it as part of the key lookup, to avoid creating a new dvid
    #       session for every single cloud call!
    dvid_session = default_dvid_session('cloud-meshgen', user)
    auth = request.headers.get('Authorization')
    if auth:
        dvid_session = copy.deepcopy(dvid_session)
        dvid_session.headers['Authorization'] = auth

    with Timer(f"Body {body}: Fetching coarse sparsevol"):
        svc_ranges = fetch_sparsevol_coarse(dvid,
                                            uuid,
                                            segmentation,
                                            body,
                                            format='ranges',
                                            session=dvid_session)

    #svc_mask, _svc_box = fetch_sparsevol_coarse(dvid, uuid, segmentation, body, format='mask', session=dvid_session)
    #np.save(f'mask-{body}-svc.npy', svc_mask)

    box_s6 = rle_ranges_box(svc_ranges)
    box_s0 = box_s6 * (2**6)
    logger.info(f"Body {body}: Bounding box: {box_s0[:, ::-1].tolist()}")

    if scale is None:
        # Use scale 1 if possible or a higher scale
        # if necessary due to bounding-box RAM usage.
        scale = max(1, select_scale(box_s0))

    if scale > 1:
        # If we chose a low-res scale, then we
        # can reduce the decimation as needed.
        decimation = min(1.0, decimation * 4**(scale - 1))

    with Timer(f"Body {body}: Fetching scale-{scale} sparsevol"):
        mask, mask_box = fetch_sparsevol(dvid,
                                         uuid,
                                         segmentation,
                                         body,
                                         scale=scale,
                                         format='mask',
                                         session=dvid_session)
        # np.save(f'mask-{body}-s{scale}.npy', mask)

        # Pad with a thin halo of zeros to avoid holes in the mesh at the box boundary
        mask = np.pad(mask, 1)
        mask_box += [(-1, -1, -1), (1, 1, 1)]

    with Timer(f"Body {body}: Computing mesh"):
        # The 'ilastik' marching cubes implementation supports smoothing during mesh construction.
        mesh = Mesh.from_binary_vol(mask,
                                    mask_box * VOXEL_NM * (2**scale),
                                    smoothing_rounds=smoothing)

        logger.info(f"Body {body}: Decimating mesh at fraction {decimation}")
        mesh.simplify(decimation)

        logger.info(f"Body {body}: Preparing ngmesh")
        mesh_bytes = mesh.serialize(fmt='ngmesh')

    if scale > 2:
        logger.info(f"Body {body}: Not storing to dvid (scale > 2)")
    else:
        with Timer(
                f"Body {body}: Storing {body}.ngmesh in DVID ({len(mesh_bytes)/MB:.1f} MB)"
        ):
            try:
                post_key(dvid,
                         uuid,
                         mesh_kv,
                         f"{body}.ngmesh",
                         mesh_bytes,
                         session=dvid_session)
            except HTTPError as ex:
                err = ex.response.content.decode('utf-8')
                if 'locked node' in err:
                    logger.info(
                        "Body {body}: Not storing to dvid (uuid {uuid[:4]} is locked)."
                    )
                else:
                    logger.warning("Mesh could not be cached to dvid:\n{err}")

    r = make_response(mesh_bytes)
    r.headers.set('Content-Type', 'application/octet-stream')
    return r
Esempio n. 4
0
def main():
    configure_default_logging()

    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument(
        '--use-mapping',
        action='store_true',
        help=
        'Use in-memory map + /exists instead of /missing, as described in the general help text above.'
    )
    parser.add_argument(
        '--output',
        '-o',
        default='missing-from-tsv.csv',
        help='Where to write the output CSV (default: missing-from-tsv.csv)')

    parser.add_argument(
        '--kafka-timestamp',
        '-k',
        type=str,
        help='Alternative to providing your own bodies list.\n'
        'Use the kafka log automatically determine the list of bodies that have changed after the given timestamp.\n'
        'Examples: -k="2018-11-22" -k="2018-11-22 17:34:00"')

    parser.add_argument('server', help='dvid server, e.g. emdata3:8900')
    parser.add_argument(
        'uuid',
        help=
        'dvid node to analyze or "master" for the latest master branch uuid')
    parser.add_argument(
        'tsv_instance',
        help="Name of a tarsupervoxels instance, e.g. segmentation_sv_meshes.\n"
        "Must be sync'd to a labelmap (segmentation) instance.")
    parser.add_argument(
        'bodies_csv',
        nargs='?',
        help='CSV containing a column named "body", which will be read.\n'
        'If no "body" column exists, the first column is used, regardless of the name.\n'
        '(Omit this arg if you are using --kafka-timestamp)')
    args = parser.parse_args()

    if not (bool(args.kafka_timestamp) ^ bool(args.bodies_csv)):
        print(
            "You must provide either --kafka-timestamp or a bodies list (not both)",
            file=sys.stderr)
        sys.exit(1)

    if args.uuid == "master":
        args.uuid = find_master(args.server)

    # Determine segmentation instance
    info = fetch_instance_info(args.server, args.uuid, args.tsv_instance)
    seg_instance = info["Base"]["Syncs"][0]

    kafka_msgs = None
    if args.bodies_csv:
        if 'body' in read_csv_header(args.bodies_csv):
            bodies = pd.read_csv(args.bodies_csv)['body'].drop_duplicates()
        else:
            # Just read the first column, no matter what it's named
            bodies = read_csv_col(args.bodies_csv, 0,
                                  np.uint64).drop_duplicates()
    elif args.kafka_timestamp:
        # Validate timestamp format before fetching kafka log, which takes a while.
        parse_timestamp(args.kafka_timestamp)

        kafka_msgs = read_kafka_messages(args.server, args.uuid, seg_instance)
        filtered_kafka_msgs = filter_kafka_msgs_by_timerange(
            kafka_msgs, min_timestamp=args.kafka_timestamp)

        new_bodies, changed_bodies, _removed_bodies, new_supervoxels, _deleted_svs = compute_affected_bodies(
            filtered_kafka_msgs)
        sv_split_bodies = set(
            fetch_mapping(args.server, args.uuid, seg_instance,
                          new_supervoxels)) - set([0])

        bodies = set(chain(new_bodies, changed_bodies, sv_split_bodies))
        bodies = np.fromiter(bodies, np.uint64)
        bodies.sort()
    else:
        raise AssertionError("Shouldn't get here.")

    if args.use_mapping:
        missing_entries = check_tarsupervoxels_status_via_exists(
            args.server,
            args.uuid,
            args.tsv_instance,
            bodies,
            seg_instance,
            kafka_msgs=kafka_msgs)
    else:
        missing_entries = check_tarsupervoxels_status_via_missing(
            args.server, args.uuid, args.tsv_instance, bodies)

    logger.info(f"Writing to {args.output}")
    missing_entries.to_csv(args.output, index=True, header=True)
    logging.info("DONE")
Esempio n. 5
0
from cloudvolume.lib import Bbox
from neuclease import dvid

from chunkflow.chunk import Chunk

# these example parameters are from the example of [neuclease](https://github.com/janelia-flyem/neuclease)
supervoxels = False
server = "http://hemibrain-dvid.janelia.org:80"
server = server.strip('/')
if ':' not in server[-5:]:
    # add a default port
    server += ':8000'

instance = "segmentation"
uuid = dvid.find_master(server)
# uuid =  "20631f"
print('server: ', server)
print('instance: ', instance)
print('uuid: ', uuid)


def execute(bbox: Bbox):
    print('bounding box: ', bbox)
    box = [tuple(bbox.minpt), tuple(bbox.maxpt)]
    subvol = dvid.fetch_labelmap_voxels(server,
                                        uuid,
                                        instance,
                                        box,
                                        scale=0,
                                        supervoxels=supervoxels)
    # print('cutout volume: \n', subvol)
Esempio n. 6
0
def locate_body():
    """
    Locate a body and return an arbitrary point that lies within it.

    Downloads the coarse sparsevol DVID, selects the "middle" (in the
    scan-order sense) block within the sparsevol representation,
    and downloads that block of segmentation at scale-0.
    Then selects the "middle" coordinate within the voxels of that
    block which match your body ID.

    Note: The returned point corresponds to the middle of the
    body's sparse representation, but is otherwise arbitrary.
    It is not the center of mass, nor is necessarily near the center
    of the body's bounding box.

    Pass DVID Authorization token via the 'Authorization' header,
    which will be forwarded to dvid requests.

    All other parameters should be passed via the query string.

    Parameters
    ----------
    dvid:
        dvid server. Required.

    uuid:
        Dvid uuid to read from and write to.

    segmentation:
        Name of the labelmap segmentation instance to read from.
        Default: 'segmentation'

    body:
        Body ID.

    user:
        The user name associated with this request.
        Will be forwarded to dvid requests.

    Returns:
        JSON [x,y,z]
    """
    try:
        dvid = request.args['dvid']
        body = request.args['body']
    except KeyError as ex:
        return Response(f"Missing required parameter: {ex.args[0]}", 400)

    body = int(body)

    uuid = request.args.get('uuid') or find_master(dvid)
    segmentation = request.args.get('segmentation', 'segmentation')
    try:
        supervoxels = request.args.get('segmentation', 'false').lower()
        supervoxels = {'true': True, 'false': False}[supervoxels]
    except KeyError:
        return Response(
            f"Invalid argument for 'supervoxels' parameter: '{supervoxels}'")

    user = request.args.get('u') or request.args.get('user', "UNKNOWN")

    # TODO: The global cache of DVID sessions should store authentication info
    #       and use it as part of the key lookup, to avoid creating a new dvid
    #       session for every single cloud call!
    dvid_session = default_dvid_session('cloud-meshgen', user)
    auth = request.headers.get('Authorization')
    if auth:
        dvid_session = copy.deepcopy(dvid_session)
        dvid_session.headers['Authorization'] = auth

    coord_zyx = generate_sample_coordinate(dvid,
                                           uuid,
                                           segmentation,
                                           body,
                                           supervoxels,
                                           session=dvid_session)
    coord_xyz = coord_zyx.tolist()[::-1]
    return jsonify(coord_xyz)
Esempio n. 7
0
def tag_soma_anchors(server,
                     uuid,
                     soma_instance,
                     seg_instance="segmentation",
                     ann_instance=None,
                     dry_run=False):
    """
    For every body with a soma, upgrade its body annotation to
    'Soma Anchor' unless it already has that status or better.

    Args:
        server:
            dvid server
        uuid:
            uuid to read and write to.
            The string "master" can be used as a shortcut for the most recent node on the master branch.
        soma_instance:
            keyvalue instance containing soma line annotations
        seg_instance:
            labelmap instance
        ann_instance:
            body annotation keyvalue instance
        dry_run:
            If True, determine which bodies to upgrade, but don't write the updates.

    """
    from neuclease.dvid import find_master, fetch_sphere_annotations, fetch_body_annotations, post_keyvalues, DEFAULT_BODY_STATUS_CATEGORIES

    if uuid == "master":
        uuid = find_master(server)

    if ann_instance is None:
        ann_instance = f"{seg_instance}_annotations"

    logger.info("Fetching soma annotations")
    soma_df = fetch_sphere_annotations(server, uuid, soma_instance,
                                       seg_instance)

    logger.info("Fetching body annotations")
    ann_df = fetch_body_annotations(server, uuid, ann_instance,
                                    soma_df['body'])

    soma_df = soma_df.query('body != 0')
    soma_df = soma_df.merge(ann_df['status'],
                            'left',
                            left_on='body',
                            right_index=True)
    soma_df['status'].fillna("", inplace=True)

    all_statuses = DEFAULT_BODY_STATUS_CATEGORIES
    keep_statuses = all_statuses[all_statuses.index('Soma Anchor'):]
    upgrade_df = soma_df.query('status not in @keep_statuses')

    new_data = {}
    for body in upgrade_df['body'].tolist():
        try:
            body_dict = copy.copy(ann_df.loc[body, 'json'])
        except KeyError:
            body_dict = {"body ID": body}

        body_dict["status"] = "Soma Anchor"
        new_data[str(body)] = body_dict

    status_counts = upgrade_df['status'].value_counts().rename(
        "count").rename_axis("status").to_frame().query("count > 0")
    logger.info(f"Upgrading {len(upgrade_df)} statuses from:\n" +
                str(status_counts))
    logger.info(f"Bodies: {' '.join(new_data.keys())}")

    if not dry_run:
        post_keyvalues(server, uuid, ann_instance, new_data)
    logger.info("DONE")

    upgrade_df[['body', 'status', *'xyz']].to_csv('upgraded-soma-bodies.csv',
                                                  header=True,
                                                  index=False)
    return upgrade_df