I have a python script that contains a class which creates a interactive draggable and movable bounding box. I want to use this to create a region of interest.
I am attempting to run this on a video file. To draw the rectangle, the left mouse button is used and then released to finish drawing. During this, the frame is freezed. To confirm the box, double clicking with left button is implemented. When I do this, my program crashes with seg fault.
I don't know how I can debug this and I suspect this is some version issue?
I am running OpenCV 4.5.5
My code for the region box selector is below:
import cv2
class Rect:
x = None
y = None
w = None
h = None
def printit(self):
print(str(self.x) + ',' + str(self.y) + ',' + str(self.w) + ',' + str(self.h))
class DragRectangle:
keepWithin = Rect()
# To store rectangle
outRect = Rect()
anchor = Rect()
sBlk = 4
initialized = False
image = None
wname = ""
returnflag = False
active = False
drag = False
TL = False
TM = False
TR = False
LM = False
RM = False
BL = False
BM = False
BR = False
hold = False
def __init__(self, Img, windowName, windowWidth, windowHeight):
self.image = Img
self.wname = windowName
self.keepWithin.x = 0
self.keepWithin.y = 0
self.keepWithin.w = windowWidth
self.keepWithin.h = windowHeight
self.outRect.x = 0
self.outRect.y = 0
self.outRect.w = 0
self.outRect.h = 0
def dragrect(event, x, y, flags, dragObj):
if x < dragObj.keepWithin.x:
x = dragObj.keepWithin.x
if y < dragObj.keepWithin.y:
y = dragObj.keepWithin.y
if x > (dragObj.keepWithin.x + dragObj.keepWithin.w - 1):
x = dragObj.keepWithin.x + dragObj.keepWithin.w - 1
if y > (dragObj.keepWithin.y + dragObj.keepWithin.h - 1):
y = dragObj.keepWithin.y + dragObj.keepWithin.h - 1
if event == cv2.EVENT_LBUTTONDOWN:
mouseDown(x, y, dragObj)
if event == cv2.EVENT_LBUTTONUP:
mouseUp(dragObj)
if event == cv2.EVENT_MOUSEMOVE:
mouseMove(x, y, dragObj)
if event == cv2.EVENT_LBUTTONDBLCLK:
mouseDoubleClick(x, y, dragObj)
def pointInRect(pX, pY, rX, rY, rW, rH):
if rX <= pX <= (rX + rW) and rY <= pY <= (rY + rH):
return True
else:
return False
def mouseDoubleClick(eX, eY, dragObj):
if dragObj.active:
if pointInRect(eX, eY, dragObj.outRect.x, dragObj.outRect.y, dragObj.outRect.w, dragObj.outRect.h):
dragObj.returnflag = True
cv2.destroyWindow(dragObj.wname)
def mouseDown(eX, eY, dragObj):
if dragObj.active:
if pointInRect(eX, eY, dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.TL = True
return
if pointInRect(eX, eY, dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.TR = True
return
if pointInRect(eX, eY, dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.BL = True
return
if pointInRect(eX, eY, dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.BR = True
return
if pointInRect(eX, eY, dragObj.outRect.x + dragObj.outRect.w / 2 - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.TM = True
return
if pointInRect(eX, eY, dragObj.outRect.x + dragObj.outRect.w / 2 - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.BM = True
return
if pointInRect(eX, eY, dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h / 2 - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.LM = True
return
if pointInRect(eX, eY, dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h / 2 - dragObj.sBlk,
dragObj.sBlk * 2, dragObj.sBlk * 2):
dragObj.RM = True
return
if pointInRect(eX, eY, dragObj.outRect.x, dragObj.outRect.y, dragObj.outRect.w, dragObj.outRect.h):
dragObj.anchor.x = eX - dragObj.outRect.x
dragObj.anchor.w = dragObj.outRect.w - dragObj.anchor.x
dragObj.anchor.y = eY - dragObj.outRect.y
dragObj.anchor.h = dragObj.outRect.h - dragObj.anchor.y
dragObj.hold = True
return
else:
dragObj.outRect.x = eX
dragObj.outRect.y = eY
dragObj.drag = True
dragObj.active = True
return
def mouseMove(eX, eY, dragObj):
if dragObj.drag & dragObj.active:
dragObj.outRect.w = eX - dragObj.outRect.x
dragObj.outRect.h = eY - dragObj.outRect.y
clearCanvasNDraw(dragObj)
return
if dragObj.hold:
dragObj.outRect.x = eX - dragObj.anchor.x
dragObj.outRect.y = eY - dragObj.anchor.y
if dragObj.outRect.x < dragObj.keepWithin.x:
dragObj.outRect.x = dragObj.keepWithin.x
if dragObj.outRect.y < dragObj.keepWithin.y:
dragObj.outRect.y = dragObj.keepWithin.y
if (dragObj.outRect.x + dragObj.outRect.w) > (dragObj.keepWithin.x + dragObj.keepWithin.w - 1):
dragObj.outRect.x = dragObj.keepWithin.x + dragObj.keepWithin.w - 1 - dragObj.outRect.w
if (dragObj.outRect.y + dragObj.outRect.h) > (dragObj.keepWithin.y + dragObj.keepWithin.h - 1):
dragObj.outRect.y = dragObj.keepWithin.y + dragObj.keepWithin.h - 1 - dragObj.outRect.h
clearCanvasNDraw(dragObj)
return
if dragObj.TL:
dragObj.outRect.w = (dragObj.outRect.x + dragObj.outRect.w) - eX
dragObj.outRect.h = (dragObj.outRect.y + dragObj.outRect.h) - eY
dragObj.outRect.x = eX
dragObj.outRect.y = eY
clearCanvasNDraw(dragObj)
return
if dragObj.BR:
dragObj.outRect.w = eX - dragObj.outRect.x
dragObj.outRect.h = eY - dragObj.outRect.y
clearCanvasNDraw(dragObj)
return
if dragObj.TR:
dragObj.outRect.h = (dragObj.outRect.y + dragObj.outRect.h) - eY
dragObj.outRect.y = eY
dragObj.outRect.w = eX - dragObj.outRect.x
clearCanvasNDraw(dragObj)
return
if dragObj.BL:
dragObj.outRect.w = (dragObj.outRect.x + dragObj.outRect.w) - eX
dragObj.outRect.x = eX
dragObj.outRect.h = eY - dragObj.outRect.y
clearCanvasNDraw(dragObj)
return
if dragObj.TM:
dragObj.outRect.h = (dragObj.outRect.y + dragObj.outRect.h) - eY
dragObj.outRect.y = eY
clearCanvasNDraw(dragObj)
return
if dragObj.BM:
dragObj.outRect.h = eY - dragObj.outRect.y
clearCanvasNDraw(dragObj)
return
if dragObj.LM:
dragObj.outRect.w = (dragObj.outRect.x + dragObj.outRect.w) - eX
dragObj.outRect.x = eX
clearCanvasNDraw(dragObj)
return
if dragObj.RM:
dragObj.outRect.w = eX - dragObj.outRect.x
clearCanvasNDraw(dragObj)
return
def mouseUp(dragObj):
dragObj.drag = False
disableResizeButtons(dragObj)
straightenUpRect(dragObj)
if dragObj.outRect.w == 0 or dragObj.outRect.h == 0:
dragObj.active = False
clearCanvasNDraw(dragObj)
def disableResizeButtons(dragObj):
dragObj.TL = dragObj.TM = dragObj.TR = False
dragObj.LM = dragObj.RM = False
dragObj.BL = dragObj.BM = dragObj.BR = False
dragObj.hold = False
def straightenUpRect(dragObj):
"""
Make sure x, y, w, h of the Rect are positive
"""
if dragObj.outRect.w < 0:
dragObj.outRect.x = dragObj.outRect.x + dragObj.outRect.w
dragObj.outRect.w = -dragObj.outRect.w
if dragObj.outRect.h < 0:
dragObj.outRect.y = dragObj.outRect.y + dragObj.outRect.h
dragObj.outRect.h = -dragObj.outRect.h
def clearCanvasNDraw(dragObj):
# Draw
tmp = dragObj.image.copy()
cv2.rectangle(tmp, (dragObj.outRect.x, dragObj.outRect.y),
(dragObj.outRect.x + dragObj.outRect.w,
dragObj.outRect.y + dragObj.outRect.h), (0, 255, 0), 2)
drawSelectMarkers(tmp, dragObj)
cv2.imshow(dragObj.wname, tmp)
cv2.waitKey()
def drawSelectMarkers(image, dragObj):
"""
Draw markers on the dragged rectangle
"""
# Top-Left
cv2.rectangle(image, (dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk),
(dragObj.outRect.x - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Top-Rigth
cv2.rectangle(image, (dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk),
(dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Bottom-Left
cv2.rectangle(image, (dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk),
(dragObj.outRect.x - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Bottom-Right
cv2.rectangle(image, (dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk),
(dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Top-Mid
cv2.rectangle(image, (dragObj.outRect.x + int(dragObj.outRect.w / 2) - dragObj.sBlk,
dragObj.outRect.y - dragObj.sBlk),
(dragObj.outRect.x + int(dragObj.outRect.w / 2) - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Bottom-Mid
cv2.rectangle(image, (dragObj.outRect.x + int(dragObj.outRect.w / 2) - dragObj.sBlk,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk),
(dragObj.outRect.x + int(dragObj.outRect.w / 2) - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y + dragObj.outRect.h - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Left-Mid
cv2.rectangle(image, (dragObj.outRect.x - dragObj.sBlk,
dragObj.outRect.y + int(dragObj.outRect.h / 2) - dragObj.sBlk),
(dragObj.outRect.x - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y + int(dragObj.outRect.h / 2) - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
# Right-Mid
cv2.rectangle(image, (dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk,
dragObj.outRect.y + int(dragObj.outRect.h / 2) - dragObj.sBlk),
(dragObj.outRect.x + dragObj.outRect.w - dragObj.sBlk + dragObj.sBlk * 2,
dragObj.outRect.y + int(dragObj.outRect.h / 2) - dragObj.sBlk + dragObj.sBlk * 2),
(255,0 , 0), 2)
This is my inference:
import cv2
import sys
import numpy as np
# capture frames from a camera
sys.setrecursionlimit(10 ** 9)
import regionselector
cap = cv2.VideoCapture('Blcak-fila.avi')
wName = "Original"
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
while(1):
# reads frames from a camera
ret, frame = cap.read()
rectI = regionselector.DragRectangle(frame, wName, width, height)
cv2.namedWindow(rectI.wname)
cv2.setMouseCallback(rectI.wname, regionselector.dragrect, rectI)
blur = cv2.GaussianBlur(frame,(5,5),0)
# converting BGR to HSV 239237 2952
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
# define range of red color in HSV
lower_red = np.array([30,150,50])
upper_red = np.array([255,255,180])
# create a red HSV colour boundary and
# threshold HSV image
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(blur,blur, mask= mask)
# Display an original image
cv2.imshow(wName,frame)
# Wait for Esc key to stop
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
# Close the window
cap.release()
# De-allocate any associated memory usage
cv2.destroyAllWindows()
After some digging around I found out the existence of a built in module called faulthandler that can give a tracedump of the seg fault.
This can be enabled in Python using:
import faulthandler
faulthandler.enable()
You can also enable it CLI/shell.
It gave me this dump:
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 227 in mouseUp
File "/home/user/Desktop/tests/regionselector.py", line 70 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 227 in mouseUp
File "/home/user/Desktop/tests/regionselector.py", line 70 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
File "/home/user/Desktop/tests/regionselector.py", line 156 in mouseMove
File "/home/user/Desktop/tests/regionselector.py", line 72 in dragrect
File "/home/user/Desktop/tests/regionselector.py", line 257 in clearCanvasNDraw
I am running on ArchLinux. I tried running this on OpenCV 3.4 in conda environment and got the same result.
I tried on my Mac machine and weirdly, I didn't get a segmentation fault. The window closed but it didnt return any coordinates or error message. I have not yet tested on a Windows machine.
Going further, I debugged with gdb and got this stacktrace:
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
0x00007ffff0c772aa in QtOpenCVPython::QWidget::mouseDoubleClickEvent(QtOpenCVPython::QMouseEvent*) () from /home/user/.local/lib/python3.10/site-packages/cv2/../opencv_contrib_python.libs/libQt5Widgets-e69d94fb.so.5.15.0