I have a class for opening up an image and drawing circles. The entire code can be found here:
p1 and p2 store diametrically opposing points on a circle. These are capture with click and drag actions in _on_mouse_interact.
import sys
import math
import cv2
class DrawCircle:
def __init__(self):
self.p1 = None
self.p2 = None
self.clicked = False
def __call__(self, img):
self.img = img
self.redraw()
return self.p1, self.p2
def redraw(self):
drawn = self.img.copy()
if self.p1 is not None and self.p2 is not None:
center = (int(round((self.p1[0] + self.p2[0]) / 2)),
int(round((self.p1[1] + self.p2[1]) / 2)))
radius = int(math.sqrt(
(self.p1[0] - self.p2[0])**2 + (self.p1[1] - self.p2[1])**2) / 2)
cv2.circle(drawn, center, radius, (0, 0, 255), thickness=1)
window_name = 'draw circle'
cv2.imshow(window_name, drawn)
cv2.setMouseCallback(window_name, self._on_mouse_interact)
k = cv2.waitKey(0)
if k == ord('q'):
cv2.destroyAllWindows()
return
def _on_mouse_interact(self, event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
self.clicked = True
self.p1 = [x, y]
self.p2 = None
if event == cv2.EVENT_MOUSEMOVE:
if self.clicked:
self.p2 = [x, y]
self.redraw()
if event == cv2.EVENT_LBUTTONUP:
self.clicked = False
self.p2 = [x, y]
self.redraw()
if __name__ == '__main__':
draw_tool = DrawCircle()
img = cv2.imread(sys.argv[1])
draw_tool(img)
It can be run with
python script.py path/to/image/file
My issue is that I get
Traceback (most recent call last):
File "utils/realtime_draw.py", line 47, in _on_mouse_interact
self.redraw()
File "utils/realtime_draw.py", line 24, in redraw
drawn = self.img.copy()
RecursionError: maximum recursion depth exceeded while calling a Python object
Where is the recursion here?
Advertisement
Answer
Found some time… Apparently, it’s the waitKey stuff. I moved some lines from the redraw to the __call__, and now, I don’t get the error anymore:
import sys
import math
import cv2
class DrawCircle:
def __init__(self):
self.p1 = None
self.p2 = None
self.clicked = False
def __call__(self, img):
self.img = img
self.window_name = 'draw circle'
cv2.imshow(self.window_name, self.img)
cv2.setMouseCallback(self.window_name, self._on_mouse_interact)
self.redraw()
k = cv2.waitKey(0)
if k == ord('q'):
cv2.destroyAllWindows()
return
return self.p1, self.p2
def redraw(self):
drawn = self.img.copy()
if self.p1 is not None and self.p2 is not None:
center = (int(round((self.p1[0] + self.p2[0]) / 2)),
int(round((self.p1[1] + self.p2[1]) / 2)))
radius = int(math.sqrt(
(self.p1[0] - self.p2[0])**2 + (self.p1[1] - self.p2[1])**2) / 2)
cv2.circle(drawn, center, radius, (0, 0, 255), thickness=1)
cv2.imshow(self.window_name, drawn)
def _on_mouse_interact(self, event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
self.clicked = True
self.p1 = [x, y]
self.p2 = None
if event == cv2.EVENT_MOUSEMOVE:
if self.clicked:
self.p2 = [x, y]
self.redraw()
if event == cv2.EVENT_LBUTTONUP:
self.clicked = False
self.p2 = [x, y]
self.redraw()
if __name__ == '__main__':
draw_tool = DrawCircle()
img = cv2.imread(sys.argv[1])
draw_tool(img)
Could you please check, whether that works for you?