Opencv mouse events and specialized class thread classes. Window wont respond

I cant get opencv to recognize mouse events with a simple program with no threads and classes, but I need to have two inputs open to the user, one window with a simple click twice to select a portion of the image, while at the same time responding to the command line text window for additional user input. Basically is command line driven, but the input I need really requires a mouse.

So my problem is I cant get mouse events from setMouseCallBack to activate the assigned function(from within my thread class). I can use the command line to cycle through the frames, but no mouse event is being noticed.


from DB_utilities import bbdb
import cv2
import threading
import time

class classificationGUI(threading.Thread):
	#A thread class to take in and store a video feed, splitting it up into regular sized file chunks
	def __init__(self, *args, **kwargs):
		super(classificationGUI, self).__init__(None, **kwargs)
		self._stop = threading.Event()
		self.bbv = args[0] #The BBVideo, the dbfilename to open a new db connection and the frameIndex to work on
		self.dbFileName = args[2]
		self.frameIndex = args[1]
		self.db = bbdb(self.dbFileName)

		self.windowTitle = "Frame {} classification".format(self.frameIndex)
		cv2.namedWindow(self.windowTitle)
		cv2.setMouseCallback(self.windowTitle, self.mouse_click)

		self.setFrame(self.frameIndex)
		self.updateImage = True

	def __str__(self):
		ret = "Classifier window {} in {}".format(self.frameIndex, self.bbv.path)
		return ret
	# function using _stop function
	def stop(self):
		self._stop.set()
 
	def stopped(self):
		return self._stop.isSet()
 
	def run(self):
		print("Starting Classifier thread")

		while True:
			if self.stopped():
				#close the window
				cv2.destroyWindow(self.windowTitle)
				break
			if self.updateImage:
				self.drawUserSelection()
				self.updateImage = False
			cv2.waitKey(100)
			
	def setP1(self, newx1, newy1):
		self.p1 = (newx1,newy1)
		self.updateImage = True

	def setP2(self, newx2, newy2):
		self.p2 = (newx2, newy2)
		self.updateImage = True

	def drawUserSelection(self):
		frame = self.frame #Get the original unadultered frame
		#Draw in the tracking boxes
		for (TrackingObjectID, rect) in self.trackingBoxes.items():
			x = int(rect[0])
			y = int(rect[1])
			w = int(rect[2])
			h = int(rect[3])
			start = (x, y) #Take the 4 points x y w h and make it rectangles for openbcv
			end = (x+w,y+h)
			cv2.rectangle(frame, start, end, (255, 255, 255), 2)
			cv2.putText(frame,str(TrackingObjectID),(int(x+w/2), int(y+h/2)),cv2.FONT_HERSHEY_SIMPLEX,0.5,(255, 255, 255),2)

		#Draw the user selection
		for (coords, description) in self.classifications.items():
			start = coords[0] #Get the user classification
			end = coords[1]
			cv2.rectangle(self.frame, start, end, (255, 255, 255), 2)
			cv2.putText(self.frame,description,start,cv2.FONT_HERSHEY_SIMPLEX,0.5,(255, 255, 255),2)
		cv2.imshow(self.windowTitle, frame)
		cv2.waitKey(1)

	def setFrame(self, frameindex):
		#Change the frame being displayed and worked on
		self.frameIndex = frameindex
		try:
			self.trackingBoxes =  self.bbv.TrackingBoxes[frameindex] #rectangles showing observed movement by the BB algorithm
			self.classifications = {((50,50), (75,75)): "Test Classification"} # {(P1, P2): "classified as"}
			self.p1 = (0,0)
			self.p2 = (0,0)
		except Exception as E:
			print("no tracking boxes")
		(path, self.frame) = self.bbv.getHRImagePath(self.db, self.frameIndex)
		self.drawUserSelection() #Display all the data
		self.updateImage = False

	def mouse_click(event, x, y, flags, param):
		# to check if left mouse 
		# button was clicked
		if event == cv2.EVENT_LBUTTONDOWN:
			# font for left click event
			font = cv2.FONT_HERSHEY_TRIPLEX
			LB = 'Left Button'
			# display that left button 
			# was clicked.
			cv2.putText(img, LB, (x, y), font, 1, (255, 255, 0), 2) 
			self.setP1((x,y))
		# to check if right mouse 
		# button was clicked
		if event == cv2.EVENT_RBUTTONDOWN:
			# font for right click event
			font = cv2.FONT_HERSHEY_SCRIPT_SIMPLEX
			RB = 'Right Button'
			# display that right button 
			# was clicked.
			cv2.putText(img, RB, (x, y), font, 1, (0, 255, 255), 2)
			self.setP2((x,y))

I could use some help, I cant find a way to debug it to see where the mouse clicks are going, the window itself just freezes and says not responding.

Thanks!

unfortunately, opencv’s gui functions were not designed to work with multi-threading.

you either need to keep all namedWindow, imshow, waitKey, etc calls on the main thread,
or use an entirely different gui toolkit like pyqt

Thanks for the reply. Interestingly cv2.VideoCapture works just fine its own thread capturing video from an rtsp camera, but this is clearly not going to work.

I’ve put it into the main thread where I’ve also realized waiting for keyboard input from msvcrt.getch() also ties it up and blocks mouse events until it gets a keypress, otherwise works like a charm.

Long story short I’ll just make the user press a key to start selecting regions from the frame. Onwards and Upwards.
Larry