Giter VIP home page Giter VIP logo

Comments (14)

SkalskiP avatar SkalskiP commented on May 22, 2024 2

... which reminds me, it'd be nice to have an export method for Detections. Particularly for merged Detections for a video, I'd like to export the detection data to a text file in the usual YOLO format. I have an "unauthorised" one for my own needs, but I'm sure it'd be useful for things like model-assisted labelling etc.

That one is definitely something I'd like to add. Could you create a separate issue (feature request) for that? 🙏🏻

from supervision.

SkalskiP avatar SkalskiP commented on May 22, 2024 1

@zburq Would it be possible that you to create a reproducible example resulting in that ValueError: tracker_id must be None or 1d np.ndarray with (n,) shape error? I would like to understand what is happening here. I think it is a bug.

from supervision.

SkalskiP avatar SkalskiP commented on May 22, 2024 1

Yes - this works too. But feels slightly counterintuitive to me. Ideally, I'd expect empty to conform to any non-empty thing that merges with it, no?

First of all. In my mind, there is a difference between empty detection - where we expect, for example, masks, but we didn't find any and cases where we don't expect masks at all. But I know that complicates things... The alternative is that Detections.merge and other methods that take Detections as an argument handle that internally. That will be harder to implement but easier for users.

As for extending Detections with your own fields, you can do it like with any other Python class, but I personally hate inheritance. And I think creating separate Detections objects is a cleaner solution.

from supervision.

SkalskiP avatar SkalskiP commented on May 22, 2024

@zburq I assume that other Detections have tracker_id that is not None. And that information is lost after merge?

from supervision.

zburq avatar zburq commented on May 22, 2024

@SkalskiP , yes have a tracker_id is not None condition in the loop, and can print each tracker_id.

from supervision.

zburq avatar zburq commented on May 22, 2024

@SkalskiP , I tried adding an empty np.ndarray to my det_initial = Detections.empty():

det_initial = Detections.empty()
det_initial.tracker_id = np.empty(shape, dtype=np.int64)

but this failed a validation.

For now I have a hacky workaround:

dets_all = None
for det in ...:
    if dets_all is None:
        dets_all = det
    else:
        dets_all = Detections.merge([dets_all, det])

from supervision.

SkalskiP avatar SkalskiP commented on May 22, 2024

What do you mean by but this failed a validation? Could you share the error?

from supervision.

zburq avatar zburq commented on May 22, 2024

Yes certainly.
I instantiate an empty Detections object with the intention of appending other detection objects to it using Detections.merge.

dets_all = Detections.empty()
dets_all.tracker_id = np.ndarray([])

I also tried dets_all.tracker_id = np.empty_like([0]).
Next, I generate a sequence of detections from a YOLO V8 output object:

results = volo_v8_model.track(source=my_vid.mp4, 
                          tracker='bytetrack.yaml', 
                          stream=True, 
                          classes=
for result in results:
    dets = Detections.from_yolov8(result)
    if result.boxes.id is not None: 
        dets.tracker_id = result.boxes.id.cpu().numpy().astype(int)
        dets_all = Detections.merge([dets_all, dets])

At the first call of merge, i.e., Detections.merge([empty_det, non_empty_det]), I get this error from merge:

---> 33             dets_all = Detections.merge([dets_all, det])
     34             print(dets_all.tracker_id)
     35 

/tmp/ipykernel_32267/3054824891.py in concat_detections(detections_list)
     36         tracker_id = np.hstack(tracker_id) if all_not_none(tracker_id) else None
     37 
---> 38         return Detections(
     39             xyxy=xyxy,
     40             mask=mask,

~/anaconda3/envs/cvc_env/lib/python3.9/site-packages/supervision/detection/core.py in __init__(self, xyxy, mask, confidence, class_id, tracker_id)

~/anaconda3/envs/cvc_env/lib/python3.9/site-packages/supervision/detection/core.py in __post_init__(self)
     72         _validate_class_id(class_id=self.class_id, n=n)
     73         _validate_confidence(confidence=self.confidence, n=n)
---> 74         _validate_tracker_id(tracker_id=self.tracker_id, n=n)
     75 
     76     def __len__(self):

~/anaconda3/envs/cvc_env/lib/python3.9/site-packages/supervision/detection/core.py in _validate_tracker_id(tracker_id, n)
     45     )
     46     if not is_valid:
---> 47         raise ValueError("tracker_id must be None or 1d np.ndarray with (n,) shape")
     48 
     49 

ValueError: tracker_id must be None or 1d np.ndarray with (n,) shape

from supervision.

zburq avatar zburq commented on May 22, 2024

Hi @SkalskiP - apologies, I got preoccupied with another aspect of the project. I made a fix to my local copy of supervision and got it working. The bug is in Detections.empty():

Here's a working example:

det = Detections(xyxy=np.array([[146.8, 69.878, 198.65, 107.57],
                                [652.06, 81.007, 710.15, 122.01]], dtype=np.float32), 
                 mask=None, 
                 confidence=np.array([0.83976, 0.82391], dtype=np.float32), 
                 class_id=np.array([2, 2]), 
                 tracker_id=np.array([1, 2]))
           
e = Detections.empty()

e prints out like this:

Detections(xyxy=array([], shape=(0, 4), dtype=float32), 
           mask=None, confidence=array([], dtype=float32), 
           class_id=array([], dtype=int64), 
           tracker_id=None)

Detections.merge([e, det]) returns

Detections(xyxy=array([[146.8, 69.878, 198.65, 107.57],
           [652.06, 81.007, 710.15, 122.01]], dtype=float32), 
           mask=None, 
           confidence=array([0.83976, 0.82391], dtype=float32), 
           class_id=array([2, 2]), 
           tracker_id=None)

tracker_id has gone missing.

But if I modify e as:

e = Detections.empty()
e.tracker_id = np.array([], dtype=np.int64)

then Detections.merge([e, det]) keeps the tracker_id:
image

from supervision.

zburq avatar zburq commented on May 22, 2024

I made a temporary fix for immediate needs:

image

from supervision.

SkalskiP avatar SkalskiP commented on May 22, 2024

Hi, @zburq 👋🏻! That's what I suspected. The problem was the interaction between Detections.empty and Detections.merge. My proposed solution would be to introduce additional arguments Detections.empty. This way, you could create an empty class according to your needs. Does it look reasonable?

    @classmethod
    def empty(
        cls,
        with_confidence: bool = False,
        with_class_id: bool = False,
        with_tracker_id: bool = False,
        with_mask_wh: Optional[Tuple[int, int]] = None
    ) -> Detections:
        xyxy = np.empty((0, 4), dtype=np.float32)
        confidence = np.array([], dtype=np.float32) if with_confidence else None
        class_id = np.array([], dtype=int) if with_class_id else None
        tracker_id = np.array([], dtype=int) if with_tracker_id else None

        mask = None
        if with_mask_wh:
            w, h = with_mask_wh
            mask = np.empty((0, w, h), dtype=bool)

        return cls(
            xyxy=xyxy,
            confidence=confidence,
            class_id=class_id,
            tracker_id=tracker_id,
            mask=mask
        )

from supervision.

zburq avatar zburq commented on May 22, 2024

@SkalskiP 🙏

Yes - this works too. But feels slightly counterintuitive to me. Ideally, I'd expect empty to conform to any non-empty thing that merges with it, no?

The reason this would be desirable for me is that sometimes I want to extend Detections and add some more attributes on the fly. For example, if I call two models simultaneously (champion vs challenger), and want to store two class_id and confidence values for each box, (eg. YOLO_class_id & CLIP_class_id etc).

For now, I'm creating two seperate Detection objects, YOLO_det = sv.Detections() and CLIP_det = sv.Detections(). I'm running YOLO V8 on a video, storing results in YOLO_det, then calling CLIP on the cropped bounding boxes, and storing CLIP's output in aCLIP_det.

But would still like to add frame_id. This is so that I can save the bounding boxes and classes in text files like this: YOLO export , and then open it in CVAT and have someone manually check/correct the model's work (I'm starting with an unlabelled video).

Again, this is a patch based on my immediate needs. For optimal general design, I trust your judgement.

🖖

from supervision.

zburq avatar zburq commented on May 22, 2024

... which reminds me, it'd be nice to have an export method for Detections. Particularly for merged Detections for a video, I'd like to export the detection data to a text file in the usual YOLO format. I have an "unauthorised" one for my own needs, but I'm sure it'd be useful for things like model-assisted labelling etc.

from supervision.

zburq avatar zburq commented on May 22, 2024

Makes sense. Thank you.

from supervision.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.