Search code examples
pythonopencvmatplotlibroi

Creating multiple ROI on webcam video


Im trying to create multiple ROIs over my webcam stream. Ive used this library called roipoly (https://github.com/jdoepfert/roipoly.py)

I modified the example code (examples/multi_roi_example.py) to work on webcam , which now looks like this

import logging
import cv2
import numpy as np
from matplotlib import pyplot as plt

from roipoly import MultiRoi

logging.basicConfig(format='%(levelname)s ''%(processName)-10s : %(asctime)s '
                           '%(module)s.%(funcName)s:%(lineno)s %(message)s',
                    level=logging.INFO)

cap = cv2.VideoCapture(1)

while cap.isOpened():

# Create image
    val,img =cap.read()

#img = np.ones((100, 100)) * range(0, 100)

# Show the image
    fig = plt.figure()
    plt.imshow(img, interpolation='nearest', cmap="Greys")
    plt.title("Click on the button to add a new ROI")

# Draw multiple ROIs
    multiroi_named = MultiRoi(roi_names=['My first ROI', 'My second ROI'])

# Draw all ROIs
    plt.imshow(img, interpolation='nearest', cmap="Greys")
    roi_names = []
    for name, roi in multiroi_named.rois.items():
        roi.display_roi()
        roi.display_mean(img)
        roi_names.append(name)
    plt.legend(roi_names, bbox_to_anchor=(1.2, 1.05))
    plt.show()
    # Let OpenCV manage window events
    key = cv2.waitKey(50)
    # If ESCAPE key pressed, stop
    if key == 27:
        cap.release()

But the issue is that after drawing the ROI, the video stream remains paused and never continues. How to resume the webcam stream along with the ROI on top of it


Solution

  • I see few problems.

    Main problem is that plt.show() is waiting until you close window and this is blocking rest of code.

    It needs plt.show(block=False) and this needs also plt.pause(0.001) so it would have time to update image in window.

        plt.show(block=False)    
        plt.pause(0.001)
    

    Other problem is that you run ROI in every loop - so you would have to use some boolean variable to skip it after selecting

    select_roi = True
    
    while cap.isOpened():
    
        # ... code ...
    
        if select_roi:
            fig = plt.figure()
            plt.imshow(img, interpolation='nearest', cmap="Greys")
            plt.title("Click on the button to add a new ROI")
    
            # Draw multiple ROIs
            multiroi_named = MultiRoi(roi_names=['My first ROI', 'My second ROI'])
            
            select_roi = False  
    
        # ... code ...
    

    or you should select ROI before loop

    fig = plt.figure()
    plt.imshow(img, interpolation='nearest', cmap="Greys")
    plt.title("Click on the button to add a new ROI")
    
    # Draw multiple ROIs
    multiroi_named = MultiRoi(roi_names=['My first ROI', 'My second ROI'])
    
    while cap.isOpened():
    
         # ... code ...
    

    Other problem is waitKey which works only if you display image with cv2.imshow(...) but you don't use it so waitKey will not get keys.

    Other problem is that cv2 gives image in colors BGR but matplotlib needs RGB - so you have to convert it.

    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    

    Full working code:

    version with boolean variable select_roi

    import cv2
    from matplotlib import pyplot as plt
    from roipoly import MultiRoi
    
    #cap = cv2.VideoCapture(0)  # my built-in webcam
    cap = cv2.VideoCapture(1)
    
    select_roi = True   # default value as start
    
    while cap.isOpened():
    
        val, img = cap.read()
    
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
        if select_roi:
            # Show the image
            fig = plt.figure()
            plt.imshow(img, interpolation='nearest', cmap="Greys")
            plt.title("Click on the button to add a new ROI")
    
            # Draw multiple ROIs
            multiroi_named = MultiRoi(roi_names=['My first ROI', 'My second ROI'])
            
            select_roi = False
       
        # --- after if ---
     
        # Draw all ROIs
        plt.imshow(img, interpolation='nearest', cmap="Greys")
        
        roi_names = []
        for name, roi in multiroi_named.rois.items():
            roi.display_roi()
            #roi.display_mean(img)
            roi_names.append(name)
            
        plt.legend(roi_names, bbox_to_anchor=(1.2, 1.05))
        plt.show(block=False)    
        plt.pause(0.001)
    

    version with ROI before loop

    import cv2
    from matplotlib import pyplot as plt
    from roipoly import MultiRoi
    
    #cap = cv2.VideoCapture(0)  # my built-in webcam
    cap = cv2.VideoCapture(1)
    
    val, img = cap.read()
    
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
    # Show the image
    fig = plt.figure()
    plt.imshow(img, interpolation='nearest', cmap="Greys")
    plt.title("Click on the button to add a new ROI")
    
    # Draw multiple ROIs
    multiroi_named = MultiRoi(roi_names=['My first ROI', 'My second ROI'])
    
    while cap.isOpened():
    
        val, img = cap.read()
    
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    
        # Draw all ROIs
        plt.imshow(img, interpolation='nearest', cmap="Greys")
        
        roi_names = []
        for name, roi in multiroi_named.rois.items():
            roi.display_roi()
            #roi.display_mean(img)
            roi_names.append(name)
            
        plt.legend(roi_names, bbox_to_anchor=(1.2, 1.05))
        plt.show(block=False)    
        plt.pause(0.001)
    

    BTW: if you need rectangle ROI then there is cv2.selectROI() to select one region and cv2.cv2.selectROIs() to select many regions

    results = cv2.selectROIs('image', img)
    

    and it doesn't need to convert from BGR to RGB.