Search code examples
pythonopencvcomputer-visiondrawing

cv2.rectangle() draws improper rectangle on image


The idea is simple: user clicks on the image at some point P(x,y) then the app takes this coordinate which determine center of a square. The square then should appear around P(x,y). But instead of it I get rectangle with improper shape. My code below.

Create event of clicking: window.fig.canvas.mpl_connect('button_press_event', onclick) (https://matplotlib.org/stable/users/explain/event_handling.html)

Then:

frameSize = 64
ix, iy = 0, 0
def onclick(event):
    global ix, iy

# take the coordinates of user`s click
    ix, iy = event.xdata, event.ydata
    print (f'Center:\tx = {ix}, y = {iy} frameSize = {frameSize}')
   

#print coordinates
    print ("----------------------")
    left_TOP_x = int(ix - frameSize/2)
    left_TOP_y = int(iy - frameSize/2)
    right_BOTTOM_x = int(ix + frameSize/2)
    right_BOTTOM_y = int(iy + frameSize/2)
    print (f'to int\t left_TOP_x = {left_TOP_x}, left_TOP_y = {left_TOP_y}')
    print (f'to int\t right_BOTTOM_x = {right_BOTTOM_x}, right_BOTTOM_y = {right_BOTTOM_y}')
    print ("----------------------\n")

#draw the square
    cv2.rectangle(img, (left_TOP_x,left_TOP_y,right_BOTTOM_x, right_BOTTOM_y ), color=(255, 0, 0), thickness= 2)
    window.ax.imshow(img)
    window.canvas.draw()

I make first click and recieve this:

(image size is 254x199) improper rectangle

But the coordinates always are fine!

Center: x = 131.67556141774892, y = 111.16829004329006 frameSize = 64
----------------------
to int   left_TOP_x = 99, left_TOP_y = 79
to int   right_BOTTOM_x = 163, right_BOTTOM_y = 143
----------------------

I made GUI via QtDesigner (maybe it is important)

self.plotWidget = QtWidgets.QWidget(self.verticalLayoutWidget)
        self.verticalLayout.addWidget(self.plotWidget)
       
        self.plotWidget.setStyleSheet("")
        self.plotWidget.setObjectName("plotWidget")
        self.plotLayout = QtWidgets.QVBoxLayout(self.plotWidget)
        self.plotLayout.setContentsMargins(0, 0, 0, 0)  
        self.plotLayout.setObjectName("plotLayout")

I've tryed to crop the image with this coords. I get image that I need

 crop_img = img[left_TOP_y:right_BOTTOM_y, left_TOP_x:right_BOTTOM_x]
    crop_img = cv2.cvtColor(crop_img, cv2.COLOR_BGR2RGB)
   
    cv2.imshow("imagggge", crop_img)
    test_image(crop_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

But I have not solved the problem of drawing square yet.


Solution

  • cv2.rectangle has two forms:

    cv.rectangle(img, pt1, pt2, color, ...)
    cv.rectangle(img, rec, color, ...)
    

    The first form takes the top left and the bottom right corners as parameters describing the rectangle. The second form takes a (C++ type) cv::Rect as parameter describing the rectangle. The Rect is derived as (x, y, width, height), with (x, y) corresponding to pt1 in the first form.

    So your square drawing line should be either

    cv2.rectangle(img, (left_TOP_x, left_TOP_y, frameSize, frameSize), color=(255, 0, 0), thickness= 2)
    

    or

    cv2.rectangle(img, (left_TOP_x, left_TOP_y), (right_BOTTOM_x, right_BOTTOM_y), color=(255, 0, 0), thickness= 2)