I would like to simply make a bounding box that uses points(any amount) to follow my mouse around.
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()
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()