2015-03-24 3 views
3

Я загрузил изображение с использованием 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

Я не хочу такого поведения, я просто хочу, чтобы один прямоугольник не для каждого движения. Я знаю, что мне нужно изменить код в событии перемещения мыши, но проблема в том, как это сделать, чтобы, когда человек двигает мышь, он может видеть полный прямоугольник, и когда он отпускает кнопку, прямоугольник должен быть исправлен?

+1

OpenCv рисует линию непосредственно в ваши данные изображения. Либо скопируйте и восстановите для каждого нового прямоугольника, либо используйте подходящий Gui Toolkit. – Mailerdaimon

+0

Я действительно не знаю, как это сделать в Python (отсюда комментарий), но идея состоит в том, чтобы рисовать каждый промежуточный прямоугольник, выполняя XOR между цветом линии и цветом изображения на каждом пикселе. Затем, прежде чем нарисовать следующий прямоугольник, XOR снова с цветом линии, чтобы отменить предыдущий прямоугольник. В C++ вы сделаете это с помощью [LineIterator] (http://docs.opencv.org/modules/core/doc/drawing_functions.html#lineiterator). Лишь на последнем прямоугольнике вы обычно рисуете в конечном цвете. – beaker

ответ

2

Вы можете представить процесс как рендеринг в любом другом API-интерфейсе рендеринга, таком как OpenGL: поставить что-то на экран, который вы его очистите, а затем нарисовать на чистой области.

В этом контексте очистка означает возврат оригинального изображения. Опираясь на это означает добавление ваших прямоугольников или что-то еще.

Итак, я рекомендую создать метод draw, который только позаботится об этом. Вызывайте его всякий раз, когда требуется изменить цель рендеринга.

Быстрый фрагмент (не настоящий питон, просто псевдокод):

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

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 
0

мне удалось добиться того, что в черном фоне со следующим кодом: -

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/

0

Мне всегда нужен способ легко перетаскивать прямоугольник на изображении при использовании opencv. Поэтому я, наконец, написал эту простую библиотеку в python, используя opencv, чтобы сделать именно это. Проверьте реализацию here.

https://github.com/arccoder/opencvdragrect

Если кто-то пытается его. Я был бы рад услышать некоторые комментарии о том, как я могу улучшить его или любые проблемы, которые вы нашли в нем.

Смежные вопросы