在图像opencv上绘制矩形?

时间:2015-03-24 15:40:45

标签: python opencv

我在python中使用opencv库加载了一个图像,现在我想用鼠标绘制一个矩形,但是在绘制矩形时,矩形应该是可见的,这样绘制它的人就可以放置它了兴趣是完全在矩形,但我的代码产生不是所需的输出

我的代码是

import os
import sys
import numpy as np
import cv2

baseDir = '/home/aman/Downloads/shirt/'

filenames = next(os.walk(baseDir))[2]

drawing = False # true if mouse is pressed
mode = True # if True, draw rectangle. Press 'm' to toggle to curve
ix,iy = -1,-1
tx,ty = -1,-1

def draw_circle(event,x,y,flags,param):
    global ix,iy,drawing,mode
    print 'aman'
    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),-1)
            cv2.line(img, (ix,iy),(ix,y), 255, 1, 8, 0)
            cv2.line(img, (ix,iy),(x,iy), 255, 1, 8, 0)

            cv2.line(img, (ix,y),(x,y), 255, 1, 8, 0)
            cv2.line(img, (x,iy),(x,y), 255, 1, 8, 0)
        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),-1)
        cv2.rectangle(img,(ix,y),(x,y),(0,255,0),-1)
        cv2.rectangle(img,(x,iy),(x,y),(0,255,0),-1)
    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()        

`

但产生的输出是这样的 enter image description here

我不想要这种行为我只想要一个矩形而不是每一个动作。我知道我应该修改鼠标移动事件中的代码,但问题是如何做到这一点,当人移动鼠标时,他能够看到完整的矩形,当他释放按钮时,矩形应该被修复?

4 个答案:

答案 0 :(得分:2)

您可以将过程视为在任何其他渲染API(如OpenGL)中渲染:在屏幕上放置一些东西,然后清理它,然后在干净的区域上绘制。

在此上下文中,清洁意味着恢复原始图像。借鉴它意味着添加你的矩形或其他什么。

所以,我建议创建一个draw方法,只处理这个问题。每当要对渲染目标进行更改时,请调用它。

一个快速片段(不是真正的python,只是伪代码):

source_image = Mat()
image = Mat()
rect = Rect()

# general logic and stuff ...

# set a mouseCallbackListener
def listener(evt):
    rect.x = evt.x   # uptade de rect properly (...)
    draw()

# apply the drawing logic
def draw():
    image = source_image.clone()
    rectangle(image, rect, Scalar(0,255,0), 1, 8, 0)
    imshow(WINDOW_NAME, image)

如果你想看一个真实的例子,这里有一个C ++ 11代码,你可以绘制多个三角形,然后将它们的中心作为输出来响应键盘输入:https://gist.github.com/cirocosta/9f7a57bddb40c4e5cbca

Example of Rectangle Selection

答案 1 :(得分:1)

我能够使用以下代码在黑色背景中实现: -

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

# 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)
            q=x
            w=y
            if q!=x|w!=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()            

This was achieved by overlapping older rectangles with solid fill

虽然如果你想要它超过图像,我可以建议水印

  

http://www.pyimagesearch.com/2016/03/07/transparent-overlays-with-opencv/

答案 2 :(得分:0)

我只是在解决同样的问题。我找到的解决方案基于:

http://www.pyimagesearch.com/2015/03/09/capturing-mouse-click-events-with-python-and-opencv/

一切正常,但我对全局变量有点不满意。

# initialize the list of points for the rectangle bbox,
# the temporaray endpoint of the drawing rectangle
# the list of all bounding boxes of selected rois
# and boolean indicating wether drawing of mouse
# is performed or not
rect_endpoint_tmp = []
rect_bbox = []
bbox_list_rois = []
drawing = False

def select_rois(img):
"""
Interactive select rectangle ROIs and store list of bboxes.

Parameters
----------
img :
    image 3-dim.

Returns
-------
bbox_list_rois : list of list of int
    List of bboxes of rectangle rois.
"""
# mouse callback function
def draw_rect_roi(event, x, y, flags, param):
        # grab references to the global variables
        global rect_bbox, rect_endpoint_tmp, drawing

        # if the left mouse button was clicked, record the starting
        # (x, y) coordinates and indicate that drawing is being
        # performed. set rect_endpoint_tmp empty list.
        if event == cv2.EVENT_LBUTTONDOWN:
            rect_endpoint_tmp = []
            rect_bbox = [(x, y)]
            drawing = True

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

            # draw a rectangle around the region of interest
            p_1, p_2 = rect_bbox
            cv2.rectangle(img, p_1, p_2, color=(0, 255, 0),thickness=1)
            cv2.imshow('image', img)

            # for bbox find upper left and bottom right points
            p_1x, p_1y = p_1
            p_2x, p_2y = p_2

            lx = min(p_1x, p_2x)
            ty = min(p_1y, p_2y)
            rx = max(p_1x, p_2x)
            by = max(p_1y, p_2y)

            # add bbox to list if both points are different
            if (lx, ty) != (rx, by):
                bbox = [lx, ty, rx, by]
                bbox_list_rois.append(bbox)

        # if mouse is drawing set tmp rectangle endpoint to (x,y)
        elif event == cv2.EVENT_MOUSEMOVE and drawing:
            rect_endpoint_tmp = [(x, y)]


# clone image img and setup the mouse callback function
img_copy = img.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_rect_roi)

# keep looping until the 'c' key is pressed
while True:
    # display the image and wait for a keypress
    if not drawing:
        cv2.imshow('image', img)
    elif drawing and rect_endpoint_tmp:
        rect_cpy = img.copy()
        start_point = rect_bbox[0]
        end_point_tmp = rect_endpoint_tmp[0]
        cv2.rectangle(rect_cpy, start_point, end_point_tmp,(0,255,0),1)
        cv2.imshow('image', rect_cpy)

    key = cv2.waitKey(1) & 0xFF
    # if the 'c' key is pressed, break from the loop
    if key == ord('c'):
        break
# close all open windows
cv2.destroyAllWindows()

return bbox_list_rois

答案 3 :(得分:0)

我一直想要一种在使用opencv时在图像上轻松拖动矩形的方法。所以我最终使用opencv在python中编写了这个简单的库来做到这一点。查看实施here

https://github.com/arccoder/opencvdragrect

如果有人试过它。我很高兴听到一些关于我如何改进它或你在其中发现的任何问题的评论。