【问题标题】:drawing rectangle in openCV python在openCV python中绘制矩形
【发布时间】:2018-05-08 13:11:44
【问题描述】:

我正在尝试在 python 中使用鼠标作为 Opencv 的输入来绘制矩形。我从 opencv 文档制作了这段代码。绘制矩形时出现问题,即当您尝试从起点拖动矩形时一直绘制到终点。就像我在图片中展示的那样。

如何绘制干净的未填充矩形?我可以看到绘制一个实际的矩形。就像我们在 Paint 中所做的一样

import cv2
import numpy as np

drawing = False 
ix,iy = -1,-1

def draw_rect(event,x,y,flags,param):
global ix,iy,drawing,mode

if event == cv2.EVENT_LBUTTONDOWN:
    drawing = True
    ix,iy = x,y

elif event == cv2.EVENT_MOUSEMOVE:
    if drawing == True:
            cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)


elif event == cv2.EVENT_LBUTTONUP:
    drawing = False
    cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)



img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_rect)

while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
    break

cv2.destroyAllWindows()

谁能告诉我为什么会这样?有什么解决办法吗??

【问题讨论】:

  • this C++ answer...移植到python应该不难
  • 发生这种情况是因为当您在event == cv2.EVENT_MOUSEMOVE 期间移动鼠标时,您同时也在绘制重新定位cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
  • @JeruLuke 是的,完全正确... :D 任何解决方案...?谢谢!!
  • @Niranjankulkarni 你没看到答案吗?

标签: python-3.x opencv


【解决方案1】:

当您在event == cv2.EVENT_MOUSEMOVE 期间移动鼠标时,您也会同时在cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1) 中绘制recatngle。

试试下面的代码。

import cv2
import numpy as np

drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle.
ix,iy = -1,-1

# mouse callback function
def draw_circle(event,x,y,flags,param):
  global ix,iy,drawing,mode

  if event == cv2.EVENT_LBUTTONDOWN:
      drawing = True
      ix,iy = x,y

  elif event == cv2.EVENT_MOUSEMOVE:
    if drawing == True:
        if mode == True:
            cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),3)
            a=x
            b=y
            if a != x | b != y:
                 cv2.rectangle(img,(ix,iy),(x,y),(0,0,0),-1)
        else:
            cv2.circle(img,(x,y),5,(0,0,255),-1)

  elif event == cv2.EVENT_LBUTTONUP:
    drawing = False
    if mode == True:
        cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)

    else:
        cv2.circle(img,(x,y),5,(0,0,255),-1)

img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)

while(1):
 cv2.imshow('image',img)
 k = cv2.waitKey(1) & 0xFF
 if k == ord('m'):
    mode = not mode
 elif k == 27:
    break

cv2.destroyAllWindows()   

希望它能解决您的问题。干杯。

预期输出:


更新


以上代码仅适用于黑色背景图像。但是我们可以在任何图像上绘制矩形 -

试试下面的代码。

# import the necessary packages
import cv2
import argparse

# now let's initialize the list of reference point
ref_point = []

def shape_selection(event, x, y, flags, param):
    # grab references to the global variables
    global ref_point, crop

    # if the left mouse button was clicked, record the starting
    # (x, y) coordinates and indicate that cropping is being performed
    if event == cv2.EVENT_LBUTTONDOWN:
        ref_point = [(x, y)]

    # check to see if the left mouse button was released
    elif event == cv2.EVENT_LBUTTONUP:
        # record the ending (x, y) coordinates and indicate that
        # the cropping operation is finished
        ref_point.append((x, y))

        # draw a rectangle around the region of interest
        cv2.rectangle(image, ref_point[0], ref_point[1], (0, 255, 0), 2)
        cv2.imshow("image", image)


# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="Path to the image")
args = vars(ap.parse_args())

# load the image, clone it, and setup the mouse callback function
image = cv2.imread(args["image"])
clone = image.copy()
cv2.namedWindow("image")
cv2.setMouseCallback("image", shape_selection)


# keep looping until the 'q' key is pressed
while True:
    # display the image and wait for a keypress
    cv2.imshow("image", image)
    key = cv2.waitKey(1) & 0xFF

    # press 'r' to reset the window
    if key == ord("r"):
        image = clone.copy()

    # if the 'c' key is pressed, break from the loop
    elif key == ord("c"):
        break

# close all open windows
cv2.destroyAllWindows() 


将文件另存为capture_events.py,为了测试,我们选择了位于同一目录下的演示图片。现在按照以下方式运行代码 -

python capture_events.py --image demo.jpg

预期输出:

如果出于某种原因我们想要重新选择图像的任何部分,我们可以简单地按“r”来摆脱错误的选择来尝试新的选择。

希望,它会帮助更多。检查此gist,您可以在此实现更多功能。干杯。

【讨论】:

  • @iPhoton 你能解释一下你的代码发生了什么吗?!= x | b!= y 这行代码在做什么??
  • @iPhoton 您的代码仅适用于具有黑色背景的图像......不适用于任何图片。我们怎么能这样做。??
  • @Niranjankulkarni 嗨,抱歉回复晚了,这几天身体不适。但是,请检查给定的答案一次,它是更新的。欢迎您查看我的repository 了解更多精彩内容。
  • @iPhoton 嘿,谢谢.. 我在等待回复......是的,这也很好......我会重新检查代码。非常感谢。
【解决方案2】:

你可以把你的按下鼠标事件改成这样的

elif event == cv2.EVENT_MOUSEMOVE:
if drawing==True:
    copy = image.copy()
    cv2.rectangle(copy,(ix,iy),(x,y),(0,255,0),1)
    cv2.imshow("image", copy)

脚本将根据当前的 x 和 y 创建带有矩形的图像副本并显示实时效果

【讨论】:

    【解决方案3】:

    我设法通过使用副本解决了这个问题。现在只需一个 imshow() 更新即可工作。使用全局变量可能不是最好的。

    import cv2 as cv
    
    
    drawing = False
    ix, iy = -1, -1
    
    
    def draw_markers(event, x, y, flags, param):
        global ix, iy, drawing, frame, frame_copy
        if flags == cv.EVENT_FLAG_ALTKEY + cv.EVENT_FLAG_LBUTTON:
            if event == cv.EVENT_LBUTTONDOWN:
                print("Alt + lmouse down")
                drawing = True
                ix, iy = x, y
                frame_copy = frame.copy()
            elif event == cv.EVENT_MOUSEMOVE:
                if drawing:
                    frame = cv.rectangle(
                        frame_copy.copy(), (ix, iy), (x, y), (0, 255, 0), 2)
            elif event == cv.EVENT_LBUTTONUP:
                print("Alt + lmouse up")
                drawing = False
                cv.rectangle(frame, (ix, iy), (x, y), (0, 255, 0), 2)
    
        elif event == cv.EVENT_LBUTTONUP:
            print("Draw crosshair")
            cv.drawMarker(frame, (x, y), (255, 0, 0), 0, 16, 2, 8)
    
    
    cap = cv.VideoCapture('video.avi')
    cap.set(cv.CAP_PROP_POS_FRAMES, 1)
    ret, frame = cap.read()
    frame_copy = frame.copy()
    cv.namedWindow('frame')
    cv.setMouseCallback('frame', draw_markers)
    
    while(True):
        cv.imshow('frame', frame)
        if cv.waitKey(1) & 0xFF == ord('q'):
            break
    
    cap.release()
    cv.destroyAllWindows()
    

    【讨论】:

      【解决方案4】:

      在以前的答案的基础上,我设法创建了一个脚本,可以在图像上绘制矩形和任意大小的圆形。当您在按住鼠标左键的同时四处移动鼠标时,矩形会更新。分别按 r 或 t,圆圈变大或变小。按“m”在模式之间切换。按“x”重置图像(删除您绘制的所有内容)。 这是代码,显然它可以进行更多优化,我将继续努力。

      import cv2
      import numpy as np
      drawing = False # true if mouse is pressed
      mode = True # if True, draw rectangle. Press 'm' to toggle to curve
      ix,iy = -1,-1
      x_, y_ = 0,0
      r = 15 #circle radius
      # mouse callback function
      def draw_shape(event,x,y,flags,param):
          print(event)
          global ix,iy,drawing,mode,x_,y_, r
      
          if event == cv2.EVENT_LBUTTONDOWN:
              print('inside mouse lbutton event....')
              drawing = True
              ix,iy = x,y
              x_,y_ = x,y
          elif event == cv2.EVENT_MOUSEMOVE and drawing:
              copy = img.copy()
              x_,y_ = x,y
              if mode:
                  cv2.rectangle(copy,(ix,iy),(x_,y_),(0,255,0),1)
                  cv2.imshow("image", copy)
              else:
                  cv2.circle(copy,(x,y),r,(0,0,255),1)
                  cv2.imshow('image', copy)
          #
          elif event == cv2.EVENT_LBUTTONUP:
              print('inside mouse button up event')
              drawing = False
              if mode:
                  cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),1)
              else:
                  cv2.circle(img,(x,y),r,(0,0,255),1)
      
      
      img = np.zeros((512,512,3), np.uint8)
      temp_img = np.copy(img)
      cv2.namedWindow('image')
      cv2.setMouseCallback('image',draw_shape)
      while(1):
          # print('inside while loop...')
          cv2.imshow('image',img)
          if not cv2.EVENT_MOUSEMOVE:
              copy = img.copy()
              # print('x_: , y_ : '.format(x_,y_))
              print(x_)
              if mode == True:
                  cv2.rectangle(copy,(ix,iy),(x_,y_),(0,255,0),1)
                  cv2.imshow('image',copy)
              else:
                  cv2.circle(copy,(x_,y_),r,(0,0,255),1)
                  cv2.imshow('image',copy)
          k = cv2.waitKey(1) & 0xFF
          if k == ord('m'): #toggle between circle and rectangle
              mode = not mode
              x_,y_ = -10,-10
              ix,iy = -10,-10
          elif k == ord('r') and not mode: #make circle bigger
              r += 1
          elif k == ord('t') and not mode: #make circle smaller
              if r <=2:
                  r = 1
              else:
                  r -= 1
          elif k == ord('x'): #resets the image (removes circles and rectangles)
              img = np.copy(temp_img)
              x_,y_ = -10,-10
              ix,iy = -10,-10
          elif k == 27:
              break
      cv2.destroyAllWindows()
      

      【讨论】:

        【解决方案5】:

        您将需要 2 个图像变量来绘制:

        • draw_img 以完整的矩形显示图像。
        • tmp_imgdraw_img 与新矩形的当前草稿。

        这是我的代码:

          def catch_point(event, x, y, flags, param):
            global draw, cur_x, cur_y, tmp_img, draw_img
            if event == cv.EVENT_LBUTTONDOWN:
                draw = True
                cur_x = x
                cur_y = y
            elif event == cv.EVENT_MOUSEMOVE:
                if draw == True:
                    tmp_img = draw_img.copy()
                    cv.rectangle(tmp_img, (cur_x, cur_y), (x, y), (36,255,12), 2)
                    cv.imshow("draw_img", tmp_img)
            elif event == cv.EVENT_LBUTTONUP:
                draw_img = cv.rectangle(draw_img, (cur_x, cur_y), (x, y), (36,255,12), 2)
                draw = False
        
          draw_img = img.copy()
          tmp_img = img.copy()
          cv.namedWindow("draw_img", cv.WINDOW_NORMAL)
          cv.setMouseCallback("draw_img", catch_point)
          while True:
              if draw == False:
                  cv.imshow("draw_img", draw_img)
              key = cv.waitKey(1) & 0xFF
              if key == ord("s"):
                  cv.destroyAllWindows()
                  break
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-30
          • 2018-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-01
          • 2016-08-23
          • 2017-03-05
          相关资源
          最近更新 更多