3

I need to selec a ROI (region of interest), or work area, on a live video from my webcam and take a snapshot of ONLY this work area or ROI, but I can't found how to do this.

In this page https://www.learnopencv.com/how-to-select-a-bounding-box-roi-in-opencv-cpp-python/ have a code for draw a ROI but only with images, not a live video.

import cv2
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
cv2.namedWindow("test")

img_counter = 0

while True:
    ret, frame = cam.read()
    cv2.imshow("test", frame)
    if not ret:
        break
    k = cv2.waitKey(1)

    if k % 256 == 27:
        # ESC pressed
        print("Escape hit, closing...")
        break
    elif k % 256 == 32:
        # SPACE pressed
        img_name = "opencv_frame_{}.png".format(img_counter)
        cv2.imwrite(img_name, frame)
        print("{} written!".format(img_name))
        img_counter += 1

cam.release()

cv2.destroyAllWindows()

This code take a snapshot with space key but not draw a ROI area. Thanks in advance!

nathancy
  • 42,661
  • 14
  • 115
  • 137
Augusto Meneses
  • 55
  • 1
  • 2
  • 7

1 Answers1

5

enter image description here

Here's a widget to select static ROIs from a video frame. Essentially the idea is to use cv2.setMouseCallback() and event handlers to detect if the mouse has been clicked or released. For this implementation, you can extract coordinates by holding down the left mouse button and dragging to select the desired ROI. You can reset the ROI using the right mouse button. To use the widget, press c to pause the video and start cropping. Then you are free to select the ROI. Once you have selected your ROI, press c again to crop the desired section. To resume the video, press r.

import cv2

class staticROI(object):
    def __init__(self):
        self.capture = cv2.VideoCapture('fedex.mp4')

        # Bounding box reference points and boolean if we are extracting coordinates
        self.image_coordinates = []
        self.extract = False
        self.selected_ROI = False

        self.update()

    def update(self):
        while True:
            if self.capture.isOpened():
                # Read frame
                (self.status, self.frame) = self.capture.read()
                cv2.imshow('image', self.frame)
                key = cv2.waitKey(2)

                # Crop image
                if key == ord('c'):
                    self.clone = self.frame.copy()
                    cv2.namedWindow('image')
                    cv2.setMouseCallback('image', self.extract_coordinates)
                    while True:
                        key = cv2.waitKey(2)
                        cv2.imshow('image', self.clone)

                        # Crop and display cropped image
                        if key == ord('c'):
                            self.crop_ROI()
                            self.show_cropped_ROI()

                        # Resume video
                        if key == ord('r'):
                            break
                # Close program with keyboard 'q'
                if key == ord('q'):
                    cv2.destroyAllWindows()
                    exit(1)
            else:
                pass

    def extract_coordinates(self, event, x, y, flags, parameters):
        # Record starting (x,y) coordinates on left mouse button click
        if event == cv2.EVENT_LBUTTONDOWN:
            self.image_coordinates = [(x,y)]
            self.extract = True

        # Record ending (x,y) coordintes on left mouse bottom release
        elif event == cv2.EVENT_LBUTTONUP:
            self.image_coordinates.append((x,y))
            self.extract = False

            self.selected_ROI = True

            # Draw rectangle around ROI
            cv2.rectangle(self.clone, self.image_coordinates[0], self.image_coordinates[1], (0,255,0), 2)

        # Clear drawing boxes on right mouse button click
        elif event == cv2.EVENT_RBUTTONDOWN:
            self.clone = self.frame.copy()
            self.selected_ROI = False

    def crop_ROI(self):
        if self.selected_ROI:
            self.cropped_image = self.frame.copy()

            x1 = self.image_coordinates[0][0]
            y1 = self.image_coordinates[0][1]
            x2 = self.image_coordinates[1][0]
            y2 = self.image_coordinates[1][1]

            self.cropped_image = self.cropped_image[y1:y2, x1:x2]

            print('Cropped image: {} {}'.format(self.image_coordinates[0], self.image_coordinates[1]))
        else:
            print('Select ROI to crop before cropping')

    def show_cropped_ROI(self):
        cv2.imshow('cropped image', self.cropped_image)

if __name__ == '__main__':
    static_ROI = staticROI()
nathancy
  • 42,661
  • 14
  • 115
  • 137
  • how you put video inside? I couldn`t figure out – Dr Yuan Shenghai Jun 06 '19 at 06:30
  • @DrYuanShenghai On the line 5, only change 'fedex.mp4' for your video. For use the webcam, I'm put the lines: `self.capture = cv2.VideoCapture(0)` – Augusto Meneses Jun 06 '19 at 15:18
  • sry I mean how to put video in stackoverflow post? – Dr Yuan Shenghai Jun 06 '19 at 15:21
  • @nathancy Thank u very much!, I'm try to use on a live video, without stop, because I need that the screenshots have the same dimension. – Augusto Meneses Jun 06 '19 at 15:23
  • @DrYuanShenghai Oh!, that's not a video is a .gif, the code is the same for an image, for example for the image above is `![](https://i.stack.imgur.com/GRKut.gif)`. You can also covert any video to a gif. – Augusto Meneses Jun 06 '19 at 15:31
  • @AugustoMeneses You can modify the code to allow it to take ROIs on live video but you may not get the exact frame capture since its moving so fast. Consider accepting the answer to let others know your problem has been solved :) – nathancy Jun 06 '19 at 19:38