J Dow
J Dow

Reputation: 3

How can I select ROI in a separate image in opencv-python?

I'm using python 2.7.13 and opencv 3.4.0. I have a videostream with 2 green dots. I'm tracking them using color detection. I need to select a two ROIs(region of interest), each of which will contain one dot, in two separate images for further processing. I wrote a program which detects them and creates ROIs, but problem is that it selects only one region, while there are two dots. Also, it gives me error: "line 47, in cv2.imshow ("area1",area1) NameError: name 'area1' is not defined"

But if I replace img=frame.array line with img=cv2.imread("image.jpg") then it works but only with picture. Here how program works now

import cv2
import numpy as np
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import sys

lowerBound=np.array([33,80,40])
upperBound=np.array([102,255,255]) #ranges for green color

camera = PiCamera()
camera.rotation = 180
camera.resolution = (320, 240)
camera.framerate = 30
font=cv2.FONT_HERSHEY_SIMPLEX

rawCapture = PiRGBArray(camera, size=(320, 240))

time.sleep(0.1)
kernelOpen=np.ones((5,5))
kernelClose=np.ones((20,20))

for frame in camera.capture_continuous(rawCapture, format="bgr",         use_video_port=True): # capture frames from the camera
    img = frame.array #works only if I change this with img =cv2.imread("image.jpg")
    imgHSV= cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(imgHSV,lowerBound,upperBound)

    maskOpen=cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernelOpen)
    maskClose=cv2.morphologyEx(maskOpen,cv2.MORPH_CLOSE,kernelClose) #apply morphology for greater accuracy
    maskFinal=maskClose
    _, conts, _=cv2.findContours(maskFinal.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

    for i in range(len(conts)):
        x,y,w,h=cv2.boundingRect(conts[i])
        area1=img[y:y+h, x:x+w] #selecting my ROI
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255), 2)
    cv2.imshow("maskClose",maskClose)
    cv2.imshow("maskOpen",maskOpen)
    cv2.imshow("mask",mask)
    cv2.imshow("cam",img)
    cv2.imshow ("area1",area1) #Showing my ROI

    key = cv2.waitKey(1) & 0xFF
    rawCapture.truncate(0)
    if key == ord("q"):
            break

Upvotes: 0

Views: 6064

Answers (1)

J.D.
J.D.

Reputation: 4561

In the for loop you keep setting/overwriting area1, so the output will always be just one image. You can solve this easily by moving the imshow() into the for loop.

At the top of your code add:
prevNrOfContours = 0

Alter the frame-loop with this code:

    # create a window for each roi
    nrOfContours = len(conts)
    for i in range(nrOfContours):
        x,y,w,h=cv2.boundingRect(conts[i])
        area=img[y:y+h, x:x+w] #selecting my ROI
        cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255), 2)
        cv2.imshow("area" + str(i), area)

    # if there are more open windows then roi's
    # then close the windows that will not be refreshed
    if prevNrOfContours > nrOfContours:
        for i in range(nrOfContours, prevNrOfContours):
            cv2.destroyWindow("area" + str(i))

    # store the number of roi's in this frame, so it can 
    # be used in the next frame
    prevNrOfContours = nrOfContours

Edit: extended code to remove unnecessary opened windows

Edit2: to only select the 2 largest contours:

    # instantiate list
    contour_list = []

    for cnt in contours:
            # get contour size
            area = cv2.contourArea(cnt)
            # add tuple of the contour and its size to the list
            contour_list.append((cnt, area))

    # sort list on size
    sorted_list = sorted(contour_list, key=lambda x: x[1])
    # create a window for the 2 largest contours
    for i in range(-2,0):
            x,y,w,h=cv2.boundingRect(sorted_list[i][0])
            roi=img[y:y+h, x:x+w] #selecting my ROI
            cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255), 2)
            cv2.imshow("area" + str(i), roi)

Upvotes: 0

Related Questions