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
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()