示例#1
0
文件: hdf5.py 项目: stallam-unb/sleap
    def read_headers(
        cls,
        file: format.filehandle.FileHandle,
        video_search: Union[Callable, List[Text], None] = None,
        match_to: Optional[Labels] = None,
    ):
        f = file.file

        # Extract the Labels JSON metadata and create Labels object with just this
        # metadata.
        dicts = json_loads(
            f.require_group("metadata").attrs["json"].tostring().decode()
        )

        # These items are stored in separate lists because the metadata group got to be
        # too big.
        for key in ("videos", "tracks", "suggestions"):
            hdf5_key = f"{key}_json"
            if hdf5_key in f:
                items = [json_loads(item_json) for item_json in f[hdf5_key]]
                dicts[key] = items

        # Video path "." means the video is saved in same file as labels, so replace
        # these paths.
        for video_item in dicts["videos"]:
            if video_item["backend"]["filename"] == ".":
                video_item["backend"]["filename"] = file.filename

        # Use the video_callback for finding videos with broken paths:

        # 1. Accept single string as video search path
        if isinstance(video_search, str):
            video_search = [video_search]

        # 2. Accept list of strings as video search paths
        if hasattr(video_search, "__iter__"):
            # If the callback is an iterable, then we'll expect it to be a list of
            # strings and build a non-gui callback with those as the search paths.
            search_paths = [
                # os.path.dirname(path) if os.path.isfile(path) else path
                path
                for path in video_search
            ]

            # Make the search function from list of paths
            video_search = Labels.make_video_callback(search_paths)

        # 3. Use the callback function (either given as arg or build from paths)
        if callable(video_search):
            video_search(dicts["videos"])

        # Create the Labels object with the header data we've loaded
        labels = labels_json.LabelsJsonAdaptor.from_json_data(dicts, match_to=match_to)

        return labels
示例#2
0
    def read(
        cls,
        file: FileHandle,
        video_search: Union[Callable, List[Text], None] = None,
        match_to: Optional[Labels] = None,
        *args,
        **kwargs,
    ) -> Labels:
        pass
        """
        Deserialize JSON file as new :class:`Labels` instance.

        Args:
            filename: Path to JSON file.
            video_callback: A callback function that which can modify
                video paths before we try to create the corresponding
                :class:`Video` objects. Usually you'll want to pass
                a callback created by :meth:`make_video_callback`
                or :meth:`make_gui_video_callback`.
                Alternately, if you pass a list of strings we'll construct a
                non-gui callback with those strings as the search paths.
            match_to: If given, we'll replace particular objects in the
                data dictionary with *matching* objects in the match_to
                :class:`Labels` object. This ensures that the newly
                instantiated :class:`Labels` can be merged without
                duplicate matching objects (e.g., :class:`Video` objects ).
        Returns:
            A new :class:`Labels` object.
        """

        tmp_dir = None
        filename = file.filename

        # Check if the file is a zipfile for not.
        if zipfile.is_zipfile(filename):

            # Make a tmpdir, located in the directory that the file exists, to unzip
            # its contents.
            tmp_dir = os.path.join(
                os.path.dirname(filename),
                f"tmp_{os.getpid()}_{os.path.basename(filename)}",
            )
            if os.path.exists(tmp_dir):
                shutil.rmtree(tmp_dir, ignore_errors=True)
            try:
                os.mkdir(tmp_dir)
            except FileExistsError:
                pass

            # tmp_dir = tempfile.mkdtemp(dir=os.path.dirname(filename))

            try:

                # Register a cleanup routine that deletes the tmpdir on program exit
                # if something goes wrong. The True is for ignore_errors
                atexit.register(shutil.rmtree, tmp_dir, True)

                # Uncompress the data into the directory
                shutil.unpack_archive(filename, extract_dir=tmp_dir)

                # We can now open the JSON file, save the zip file and
                # replace file with the first JSON file we find in the archive.
                json_files = [
                    os.path.join(tmp_dir, file) for file in os.listdir(tmp_dir)
                    if file.endswith(".json")
                ]

                if len(json_files) == 0:
                    raise ValueError(
                        f"No JSON file found inside {filename}. Are you sure this is a valid sLEAP dataset."
                    )

                filename = json_files[0]

            except Exception as ex:
                # If we had problems, delete the temp directory and reraise the exception.
                shutil.rmtree(tmp_dir, ignore_errors=True)
                raise

        # Open and parse the JSON in filename
        with open(filename, "r") as file:

            # FIXME: Peek into the json to see if there is version string.
            # We do this to tell apart old JSON data from leap_dev vs the
            # newer format for sLEAP.
            json_str = file.read()
            dicts = json_loads(json_str)

            # If we have a version number, then it is new sLEAP format
            if "version" in dicts:

                # Cache the working directory.
                cwd = os.getcwd()
                # Replace local video paths (for imagestore)
                if tmp_dir:
                    for vid in dicts["videos"]:
                        vid["backend"]["filename"] = os.path.join(
                            tmp_dir, vid["backend"]["filename"])

                # Use the video_callback for finding videos with broken paths:

                # 1. Accept single string as video search path
                if isinstance(video_search, str):
                    video_search = [video_search]

                # 2. Accept list of strings as video search paths
                if hasattr(video_search, "__iter__"):
                    # If the callback is an iterable, then we'll expect it to be a
                    # list of strings and build a non-gui callback with those as
                    # the search paths.
                    # When path is to a file, use the path of parent directory.
                    search_paths = [
                        os.path.dirname(path) if os.path.isfile(path) else path
                        for path in video_search
                    ]

                    # Make the search function from list of paths
                    video_search = Labels.make_video_callback(search_paths)

                # 3. Use the callback function (either given as arg or build from paths)
                if callable(video_search):
                    abort = video_search(dicts["videos"])
                    if abort:
                        raise FileNotFoundError

                # Try to load the labels filename.
                try:
                    labels = cls.from_json_data(dicts, match_to=match_to)

                except FileNotFoundError:

                    # FIXME: We are going to the labels JSON that has references to
                    # video files. Lets change directory to the dirname of the json file
                    # so that relative paths will be from this directory. Maybe
                    # it is better to feed the dataset dirname all the way down to
                    # the Video object. This seems like less coupling between classes
                    # though.
                    if os.path.dirname(filename) != "":
                        os.chdir(os.path.dirname(filename))

                    # Try again
                    labels = cls.from_json_data(dicts, match_to=match_to)

                except Exception as ex:
                    # Ok, we give up, where the hell are these videos!
                    raise  # Re-raise.
                finally:
                    os.chdir(
                        cwd)  # Make sure to change back if we have problems.

                return labels

            else:
                frames = load_labels_json_old(data_path=filename,
                                              parsed_json=dicts)
                return Labels(frames)
示例#3
0
文件: convert.py 项目: rlinus/sleap
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("input_path", help="Path to input file.")
    parser.add_argument(
        "-o", "--output", default="", help="Path to output file (optional)."
    )
    parser.add_argument(
        "--format",
        default="slp",
        help="Output format. Default ('slp') is SLEAP dataset; "
        "'analysis' results in analysis.h5 file; "
        "'h5' or 'json' results in SLEAP dataset "
        "with specified file format.",
    )
    parser.add_argument(
        "--video", default="", help="Path to video (if needed for conversion)."
    )

    args = parser.parse_args()

    video_callback = Labels.make_video_callback([os.path.dirname(args.input_path)])
    try:
        labels = Labels.load_file(args.input_path, video_search=video_callback)
    except TypeError:
        print("Input file isn't SLEAP dataset so attempting other importers...")
        from sleap.io.format import read

        video_path = args.video if args.video else None

        labels = read(
            args.input_path,
            for_object="labels",
            as_format="*",
            video_search=video_callback,
            video=video_path,
        )

    if args.format == "analysis":
        from sleap.info.write_tracking_h5 import main as write_analysis

        if args.output:
            output_path = args.output
        else:
            output_path = args.input_path
            output_path = re.sub("(\.json(\.zip)?|\.h5|\.slp)$", "", output_path)
            output_path = output_path + ".analysis.h5"

        write_analysis(labels, output_path=output_path, all_frames=True)

    elif args.output:
        print(f"Output SLEAP dataset: {args.output}")
        Labels.save_file(labels, args.output)

    elif args.format in ("slp", "h5", "json"):
        output_path = f"{args.input_path}.{args.format}"
        print(f"Output SLEAP dataset: {output_path}")
        Labels.save_file(labels, output_path)

    else:
        print("You didn't specify how to convert the file.")
        print(args)