Skip to content
Advertisement

Repeated drawings of bounding box

I would like to simply make a bounding box that uses points(any amount) to follow my mouse around.

Error being when I draw the bounding box currently it repeats all the previous drawings and have repeated bounding boxes enter image description here

import cv2
import numpy as np

width=60
height=80

    
class BoundingBoxWidget(object):
    def __init__(self):
        self.original_image = cv2.imread('parking_lot.png')
        self.clone = self.original_image.copy()
        cv2.namedWindow('image')
        cv2.setMouseCallback('image', self.extract_coordinates)

        # Bounding box reference points
        self.image_coordinates = []

    def extract_coordinates(self, event, x, y, flags, parameters):
        self.image_coordinates=[[x,y],[x+width,y],[x+(2*width),y+height],[(x+width),y+height]]
        print(self.image_coordinates)
        points = np.array(self.image_coordinates)
        #points = points.reshape((-1, 1, 2))
        cv2.polylines(self.clone,[points] ,True,(255,0,0),2)
        cv2.imshow("image", self.clone) 
    def show_image(self):
        return self.clone

def main():
    boundingbox_widget = BoundingBoxWidget()

    while True:
        cv2.imshow('image', boundingbox_widget.show_image())
        key = cv2.waitKey(1)

        # Close program with keyboard 'q'
        if key == ord('q'):
            cv2.destroyAllWindows()
            exit(1)
if __name__ == '__main__':
    main()

Advertisement

Answer

You had already the right idea creating a clone from the original image, but just forgot to set the clone back to the original image before painting the new bounding-box upon it. Adding one line at the position as below solves the problem:

        self.clone = self.original_image.copy()
        cv2.polylines(self.clone,[points] ,True,(255,0,0),2)
        cv2.imshow("image", self.clone) 

The code you have provided has along with the issue described in your question and solved by above described change also some other issues you haven’t addressed in your question. The most annoying one is that it unnecessary heats up the CPU because it updates the screen in both, the keyboard and the mouse events loops with highest possible rate for mouse events and a very high rate for keyboard events. This causes heating up the CPU even in case the mouse stands still.

The code provided below does not heat up the CPU. It uses the time module for own time queries and sets the frame rate to 25 frames per second for mouse events. The keyboard input loop runs at a rate of 4 queries per second and raises the window again if closed by Alt-F4 or clicking [x]. The only way to quit the program is therefore pressing [q] on the keyboard (this is the same behavior as in the code you have posted).

To make things simpler the code below flattens the depth of function calls by getting rid of the class handling the bounding box widget using global variables in the mouse handler function, the only function in the code. See comments, changed variable names (in order to better mirror their actual purpose) and the way function parameter are set in the code for further explanations.

Comprehend the behavior of both the mouse and keyboard loops checking out what the code prints to stdout:

import cv2                    as cv
import numpy                  as np
from time import perf_counter as T

BB_BASE_WIDTH = 60
BB_HEIGHT     = 80
BB_SKEW_CORR  = 20
FRAMERATE     = 25.0

image = cv.imread('parking_lot.jpg')
clone = image.copy()
cv.namedWindow('image')
last_update_time = T()

def mouseCallbackHandler(event, x, y, flags, parameters):
    # mouse events query loop
    global BB_BASE_WIDTH, BB_HEIGHT, FRAMERATE
    global image, clone, last_update_time
    if T() - last_update_time > 1.0 / FRAMERATE: 
        bb_poly = [
            (x                             , y),
            (x+BB_BASE_WIDTH               , y),
            (x+2*BB_BASE_WIDTH+BB_SKEW_CORR, y+BB_HEIGHT),
            (x+BB_BASE_WIDTH+BB_SKEW_CORR  , y+BB_HEIGHT), 
        ]
        print(bb_poly)
        points = np.array(bb_poly)
        clone = image.copy()
        cv.polylines(
            clone, [points], True, (255,0,0), 2, cv.LINE_AA
        ) # [ cv.FILLED, cv.LINE_4, cv.LINE_8, cv.LINE_AA ]
        # LINE_4: 4-connected, LINE_8: 8-connected, LINE_AA: antialiased         
        cv.imshow('image', clone)
        last_update_time = T()
    # cv.imshow("image", clone) # show at mouse events framerate 
#:def mouseCallbackHandler()
cv.setMouseCallback('image', mouseCallbackHandler)

def main():
    while True: # keyboard input query loop
        cv.imshow('image', clone) # show if closed by Alt-F4 or [x]
        print('while True')
        last_update_time = T()
        key = cv.waitKey(250) # keyboard input query rate
        # Close program with keyboard 'q'
        if key == ord('q'):
            print('exit(1)')
            cv.destroyAllWindows()
            exit(1)

if __name__ == '__main__':
    main()
Advertisement