ultralytics / ultralytics

NEW - YOLOv8 šŸš€ in PyTorch > ONNX > OpenVINO > CoreML > TFLite
https://docs.ultralytics.com
GNU Affero General Public License v3.0
28.73k stars 5.7k forks source link

Index of the stream from the file in multistream #6357

Closed epigraphe closed 10 months ago

epigraphe commented 10 months ago

Search before asking

Question

After detections and annotations, Iā€™m trying to display three threads separately in Django. As a result, it turns out that all streams are output in one place, one after another, the frame from the first changes to the second, third, etc. How to separate them? Is there any index I can use as a guide? I tried

initial_results = model("list.streams", stream=True, classes=0, conf=0.9)
for initial_result in initial_results:
    print(initial_result)

and didn't find anything similar to thread index.

ultralytics.engine.results.Results object with attributes:

boxes: ultralytics.engine.results.Boxes object
keypoints: None
masks: None
names: {0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 5: 'bus', 6: 'train', 7: 'truck', 8: 'boat', 9: 'traffic light', 10: 'fire hydrant', 11: 'stop sign', 12: 'parking meter', 13: 'bench', 14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe', 24: 'backpack', 25: 'umbrella', 26: 'handbag', 27: 'tie', 28: 'suitcase', 29: 'frisbee', 30: 'skis', 31: 'snowboard', 32: 'sports ball', 33: 'kite', 34: 'baseball bat', 35: 'baseball glove', 36: 'skateboard', 37: 'surfboard', 38: 'tennis racket', 39: 'bottle', 40: 'wine glass', 41: 'cup', 42: 'fork', 43: 'knife', 44: 'spoon', 45: 'bowl', 46: 'banana', 47: 'apple', 48: 'sandwich', 49: 'orange', 50: 'broccoli', 51: 'carrot', 52: 'hot dog', 53: 'pizza', 54: 'donut', 55: 'cake', 56: 'chair', 57: 'couch', 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet', 62: 'tv', 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone', 68: 'microwave', 69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 73: 'book', 74: 'clock', 75: 'vase', 76: 'scissors', 77: 'teddy bear', 78: 'hair drier', 79: 'toothbrush'}
orig_img: array([[[192, 186, 177],
        [189, 183, 174],
        [194, 188, 179],
        ...,
        [ 46,  49,  59],
        [ 46,  49,  59],
        [ 46,  49,  59]],

       [[196, 190, 181],
        [188, 182, 173],
        [191, 185, 176],
        ...,
        [ 46,  49,  59],
        [ 46,  49,  59],
        [ 46,  49,  59]],

       [[198, 192, 183],
        [192, 186, 177],
        [220, 214, 205],
        ...,
        [ 46,  49,  59],
        [ 46,  49,  59],
        [ 46,  49,  59]],

       ...,

       [[ 18,  14,  15],
        [ 18,  14,  15],
        [ 18,  14,  15],
        ...,
        [ 16,  15,  17],
        [ 16,  15,  17],
        [ 16,  15,  17]],

       [[ 18,  14,  15],
        [ 18,  14,  15],
        [ 18,  14,  15],
        ...,
        [ 16,  15,  17],
        [ 16,  15,  17],
        [ 16,  15,  17]],

       [[ 18,  14,  15],
        [ 18,  14,  15],
        [ 18,  14,  15],
        ...,
        [ 16,  15,  17],
        [ 16,  15,  17],
        [ 16,  15,  17]]], dtype=uint8)
orig_shape: (1440, 2560)
path: 'rtsp_//...cam/realmonitor_channel_1_subtype_00_authbasic_[AUTH]'
probs: None
save_dir: None
speed: {'preprocess': 0.8739630381266276, 'inference': 0.7646083831787109, 'postprocess': 0.15783309936523438}

This is also displayed - and the thread index is there. 0: 384x640 (no detections), 1: 384x640 (no detections), 2: 384x640 1 person, 6.3ms

How can I use it in my code? Thank you

def video_stream(request):
    def generate_frames():
        for i, result in enumerate(results):
            image = result.orig_img
            detection_results = model(image)[0]
            detections = sv.Detections.from_ultralytics(detection_results)
            detections = tracker.update_with_detections(detections)

            annotated_frame = process_frame(image)  # Pass stream_index to process_frame
            resized_image = cv2.resize(annotated_frame, (1024, 768))

            _, frame = cv2.imencode('.jpg', resized_image)
            frame = frame.tobytes()

            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
    return StreamingHttpResponse(generate_frames(), content_type='multipart/x-mixed-replace; boundary=frame')

Additional

No response

glenn-jocher commented 10 months ago

@epigraphe hello,

It seems you are working on a project where you wish to process multiple video streams separately in a Django application using YOLOv8. You've noticed that the streams are being output sequentially and are looking for a way to distinguish between different streams for parallel processing.

From your description, it appears that you are trying to process streams in a loop and are looking for a unique identifier or index that can separate frames from different streams. In typical YOLOv8 usage, if you're processing multiple streams, each stream will have associated metadata that can be used as an index or identifier.

You mentioned seeing output such as 0: 384x640 (no detections), 1: 384x640 (no detections), 2: 384x640 1 person, 6.3ms. This indicates that the model is indeed processing multiple streams and is providing a stream index before each frame's details. This index is the key to separating your results.

When you process each frame, you should carry this index forward and use it within your generate_frames function to create separate frames for each stream index. Ensure that when you call model(image) within your loop, you are also keeping track of this index so that each yielded frame is tagged with the correct stream identifier.

Inside the generate_frames function, you would then have a way to match the frame being processed to the specific stream it belongs to. This identifier will be crucial when incorporating the frames back into your Django application, especially if your goal is to display each stream in a separate thread or a distinct page section.

Make sure that for each frame processed, the identifier is passed along so that any further processing or display logic can reference this identifier to keep your streams separate.

I hope this explanation helps guide you to a solution for processing your multiple video streams within your Django application. If you need more detailed guidance regarding the best practices for implementation, I encourage you to explore the Ultralytics documentation, as it may provide further insights into handling streams and processing results with YOLOv8.

Happy coding, and I wish you success with your implementation!

epigraphe commented 10 months ago

Thank you for your help

glenn-jocher commented 10 months ago

@epigraphe you're welcome! If you have any more questions or need further assistance in the future, feel free to ask. Good luck with your project using YOLOv8, and I hope it turns out great!

Happy detecting! šŸš€šŸ˜Š