def _parse_labels(self, labels): if etau.is_str(labels): video_labels = etav.VideoLabels.from_json(labels) elif isinstance(labels, dict): video_labels = etav.VideoLabels.from_dict(labels) else: video_labels = labels if video_labels is None: return None frames = {} for frame_number in video_labels: frame = fof.Frame() image_labels = fol.ImageLabels( labels=etai.ImageLabels.from_frame_labels( video_labels[frame_number])) if self.expand: frame.update_fields( image_labels.expand( prefix=self.prefix, labels_dict=self.labels_dict, multilabel=self.multilabel, skip_non_categorical=self.skip_non_categorical, )) else: frame["labels"] = image_labels frames[frame_number] = frame return frames
def __init__(self, sample_ids): if etau.is_str(sample_ids): self._sample_ids = [sample_ids] else: self._sample_ids = list(sample_ids) self._validate_params()
def to_mongo(self): """Returns the MongoDB version of the stage. Returns: a MongoDB aggregation pipeline (list of dicts) """ order = DESCENDING if self._reverse else ASCENDING field_or_expr = self._get_mongo_field_or_expr() if etau.is_str(field_or_expr): return [{"$sort": {field_or_expr: order}}] return [ { "$addFields": { "_sort_field": field_or_expr } }, { "$sort": { "_sort_field": order } }, { "$unset": "_sort_field" }, ]
def _parse_label(self, labels): if etau.is_str(labels): labels = etai.ImageLabels.from_json(labels) elif isinstance(labels, dict): labels = etai.ImageLabels.from_dict(labels) return fol.ImageLabels(labels=labels)
def validate_fields_exist(self, field_or_fields): """Validates that the collection has fields with the given names. If ``field_or_fields`` contains an embedded field name such as ``field_name.document.field``, only the root ``field_name`` is checked for existence. Args: field_or_fields: a field name or iterable of field names Raises: ValueError: if one or more of the fields do not exist """ if etau.is_str(field_or_fields): field_or_fields = [field_or_fields] schema = self.get_field_schema() default_fields = set( default_sample_fields(DatasetSampleDocument, include_private=True, include_id=True)) for field in field_or_fields: # We only validate that the root field exists field_name = field.split(".", 1)[0] if field_name not in schema and field_name not in default_fields: raise ValueError("Field '%s' does not exist" % field_name)
def export_sample(self, image_or_path, image_labels, metadata=None): is_image_path = self._is_image_path(image_or_path) if is_image_path: image_path = image_or_path out_image_path = self._filename_maker.get_output_path(image_path) else: img = image_or_path out_image_path = self._filename_maker.get_output_path() name, ext = os.path.splitext(os.path.basename(out_image_path)) new_image_filename = name + ext new_labels_filename = name + ".json" _image_labels = _parse_image_labels(image_labels) if etau.is_str(image_or_path): image_labels_path = os.path.join(self._labels_dir, new_labels_filename) _image_labels.write_json(image_labels_path, pretty_print=self.pretty_print) self._labeled_dataset.add_file( image_path, image_labels_path, new_data_filename=new_image_filename, new_labels_filename=new_labels_filename, ) else: self._labeled_dataset.add_data( img, _image_labels, new_image_filename, new_labels_filename, )
def build_for(cls, image_or_path): """Builds an :class:`ImageMetadata` object for the given image. Args: image_or_path: an image or the path to the image on disk Returns: an :class:`ImageMetadata` """ if etau.is_str(image_or_path): # From image on disk m = etai.ImageMetadata.build_for(image_or_path) return cls( size_bytes=m.size_bytes, mime_type=m.mime_type, width=m.frame_size[0], height=m.frame_size[1], num_channels=m.num_channels, ) # From in-memory image height, width = image_or_path.shape[:2] try: num_channels = image_or_path.shape[2] except IndexError: num_channels = 1 return cls(width=width, height=height, num_channels=num_channels)
def parse_serializable(obj, cls): """Parses the given object as an instance of the given ``eta.core.serial.Serializable`` class. Args: obj: an instance of ``cls``, or a serialized string or dictionary representation of one cls: a ``eta.core.serial.Serializable`` class Returns: an instance of ``cls`` """ if isinstance(obj, cls): return obj if etau.is_str(obj): return cls.from_str(obj) if isinstance(obj, dict): return cls.from_dict(obj) raise ValueError( "Unable to load '%s' as an instance of '%s'" % (obj, etau.get_class_name(cls)) )
def _expand_with_prefix( image_labels, prefix, multilabel, skip_non_categorical ): if prefix is None: prefix = "" labels = {} if multilabel: # Store frame attributes as multilabels # pylint: disable=no-member labels[prefix + "attrs"] = Classifications.from_attributes( image_labels.labels.attrs, skip_non_categorical=skip_non_categorical, ) else: # Store each frame attribute separately for attr in image_labels.labels.attrs: # pylint: disable=no-member if skip_non_categorical and not etau.is_str(attr.value): continue labels[prefix + attr.name] = Classification.from_attribute(attr) objects_map = defaultdict(etao.DetectedObjectContainer) for dobj in image_labels.labels.objects: objects_map[prefix + (dobj.name or "objs")].add(dobj) for name, objects in objects_map.items(): # pylint: disable=no-member labels[name] = Detections.from_detected_objects(objects) return labels
def __getattr__(cls, name): # This is here to prevent Sphinx from getting confused... # https://github.com/sphinx-doc/sphinx/issues/6859 if not etau.is_str(name) or name.startswith("_"): return super().__getattr__(name) return ViewField(name)
def get_image_path(self): image_or_path = self.current_sample[0] if etau.is_str(image_or_path): return image_or_path raise ValueError( "Cannot extract image path from samples that contain images")
def _parse_image_or_path(image_or_path, filename=None): if etau.is_str(image_or_path): image_path = image_or_path if filename is None: filename = os.path.basename(image_path) img_bytes = tf.io.read_file(image_path) img = tf.image.decode_image(img_bytes) else: img = image_or_path if filename is None: raise ValueError( "`filename` must be provided when `image_or_path` is an " "image" ) if filename.endswith((".jpg", ".jpeg")): img_bytes = tf.image.encode_jpeg(img) elif filename.endswith(".png"): img_bytes = tf.image.encode_png(img) else: raise ValueError( "Unsupported image format '%s'" % os.path.splitext(filename)[1] ) img_shape = img.shape return img_bytes, img_shape, filename
def _parse_label(self, target, img=None): if target is None: return None if etau.is_str(target): target = etas.load_json(target) return fol.Detections( detections=[self._parse_detection(obj, img=img) for obj in target])
def _is_image_path(image_or_path): """Determines whether the input is the path to an image on disk Args: image_or_path: an image or the path to the image on disk Returns: True/False """ return etau.is_str(image_or_path)
def _escape_regex_chars(str_or_strs): # Must escape `[`, `]`, `-`, and `\` because they have special meaning # inside the `[]` that will be used in the replacement regex regex_chars = r"\[\]{}()*+\-?.,\\^$|#" _escape = lambda s: re.sub(r"([%s])" % regex_chars, r"\\\1", s) if etau.is_str(str_or_strs): return _escape(str_or_strs) return [_escape(s) for s in str_or_strs]
def _parse_label(self, target, img=None): if target is None: return None if etau.is_str(target): annotation = VOCAnnotation.from_xml(target) else: annotation = VOCAnnotation.from_dict(target) return annotation.to_detections()
def __init__(self, field_names=None): default_fields = default_sample_fields() if field_names: if etau.is_str(field_names): field_names = [field_names] self._field_names = list(set(field_names) | set(default_fields)) else: self._field_names = list(default_fields)
def validate(self, sample_collection): field_or_expr = self._get_mongo_field_or_expr() # If sorting by a field, not an expression if etau.is_str(field_or_expr): # Make sure the field exists sample_collection.validate_fields_exist(field_or_expr) # Create an index on the field, if necessary, to make sorting # more efficient sample_collection.create_index(field_or_expr)
def _parse_attribute(self, value): if etau.is_str(value): return fol.CategoricalAttribute(value=value) if isinstance(value, bool): return fol.BooleanAttribute(value=value) if etau.is_numeric(value): return fol.NumericAttribute(value=value) return fol.Attribute(value=value)
def is_in(self, values): """Creates an expression that returns a boolean indicating whether ``self in values``. Args: values: a value or iterable of values Returns: a :class:`ViewExpression` """ if etau.is_str(values): values = [values] return ViewExpression({"$in": [self, list(values)]})
def _parse_label(self, labels): if etau.is_str(labels): labels = etai.ImageLabels.from_json(labels) elif isinstance(labels, dict): labels = etai.ImageLabels.from_dict(labels) label = fol.ImageLabels(labels=labels) if label is not None and self.expand: label = label.expand( prefix=self.prefix, labels_dict=self.labels_dict, multilabel=self.multilabel, skip_non_categorical=self.skip_non_categorical, ) return label
def execute(parser, args): if args.locate: if os.path.isfile(foc.FIFTYONE_CONFIG_PATH): print(foc.FIFTYONE_CONFIG_PATH) else: print("No config file found at '%s'.\n" % foc.FIFTYONE_CONFIG_PATH) return if args.field: field = getattr(fo.config, args.field) if etau.is_str(field): print(field) else: print(etas.json_to_str(field)) else: print(fo.config)
def _expand_with_labels_dict( image_labels, labels_dict, multilabel, skip_non_categorical ): labels = {} if multilabel: # Store frame attributes as multilabels attrs_map = defaultdict(etad.AttributeContainer) for attr in image_labels.labels.attrs: if attr.name not in labels_dict: continue attrs_map[labels_dict[attr.name]].add(attr) for name, attrs in attrs_map.items(): labels[name] = Classifications.from_attributes( attrs, skip_non_categorical=skip_non_categorical ) else: # Store each frame attribute separately for attr in image_labels.labels.attrs: # pylint: disable=no-member if skip_non_categorical and not etau.is_str(attr.value): continue if attr.name not in labels_dict: continue labels[labels_dict[attr.name]] = Classification.from_attribute( attr ) objects_map = defaultdict(etao.DetectedObjectContainer) for dobj in image_labels.labels.objects: if dobj.name not in labels_dict: continue objects_map[labels_dict[dobj.name]].add(dobj) for name, objects in objects_map.items(): # pylint: disable=no-member labels[name] = Detections.from_detected_objects(objects) return labels
def _parse_label(self, labels, img): if labels is None: return None if etau.is_str(labels): labels = etas.load_json(labels) frame_size = etai.to_frame_size(img=img) label = _parse_bdd_annotation(labels, frame_size) if label is not None and self.expand: label = label.expand( prefix=self.prefix, labels_dict=self.labels_dict, multilabel=self.multilabel, skip_non_categorical=self.skip_non_categorical, ) return label
def matches_str(self, str_or_strs, case_sensitive=True): """Determines whether the string expression exactly matches the given string (or any of a list of strings). Args: str_or_strs: a string or iterable of strings case_sensitive (True): whether to perform a case sensitive match Returns: a :class:`ViewExpression` """ str_or_strs = _escape_regex_chars(str_or_strs) if etau.is_str(str_or_strs): regex = "^" + str_or_strs + "$" else: regex = "^(%s)$" % ("|".join(str_or_strs)) options = None if case_sensitive else "i" return self.re_match(regex, options=options)
def from_attributes(cls, attrs, skip_non_categorical=False): """Creates a :class:`Classifications` instance from a list of attributes. Args: attrs: an iterable of :class:`Attribute` or ``eta.core.data.Attribute`` instances skip_non_categorical (False): whether to skip non-categorical attributes (True) or cast all attribute values to strings (False) Returns: a :class:`Classifications` """ classifications = [] for attr in attrs: if skip_non_categorical and not etau.is_str(attr.value): continue classifications.append(Classification.from_attribute(attr)) return cls(classifications=classifications)
def _parse_image(self, image_or_path): if etau.is_str(image_or_path): return etai.read(image_or_path) return np.asarray(image_or_path)
def __init__(self, field_names=None): if etau.is_str(field_names): field_names = [field_names] self._field_names = field_names
def __init__(self, field_names): if etau.is_str(field_names): field_names = [field_names] self._field_names = list(field_names) self._validate_params()
def get_image(self): image_or_path = self.current_sample if etau.is_str(image_or_path): return etai.read(image_or_path) return np.asarray(image_or_path)