0

I want to be able to drag free shape selection with a mouse cursor over the image displayed in my program and to store the coordinates of the points inside the selected region in order to use for other function. How do I do it in Python 3? In general to store the pixel coordinates i use the function ginput.

fig, ax=plt.subplots()
ax.imshow(img,cmap="gray")
plt.show()

yroi = plt.ginput(0,0)
yroi = np.array(yroi)
yroi = yroi.astype(int)

yroi will contain the coordinates of the selected points. A faster way should be to use the mouse to create a free shape region and store the pixel coordinates inside that region. Some suggestions? Thanks in advance

vittorio
  • 143
  • 3
  • 14

1 Answers1

1

You can use OpenCV Contours and masking algorithms and by using Bitwise AND operation between this bounding rectangle(counter) and mask, we can crop out polygon from Image.
Here are few points to look at before taking and running this code.

Links are for images

cv2.boundingRect => It will create bounding rectangle look at image for best visualization
With and Without Bounding Rectangle

cv2.drawContours => It will update mask where ever points lie inside our counter.
Mask with and Without Contours extract

cv2.bitwise_and => For this you can refer to :
Stackoverflow Discussion over cv2.bitwise_and(img,img,mask = mask)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as img
import matplotlib.patches as patches 
import cv2

image_file = 'photo.jpg'

def selection(s):
    plt.title(s, fontsize=16)
    plt.axis('off')
    plt.draw()

# =========   Saving Click Point using ginput method   =========
while True:
    data = []
    while len(data) < 3:
        image = img.imread(image_file)
        fig, ax=plt.subplots()
        ax.imshow(image,cmap="gray")
        selection('Free Form Selection')
        data = np.asarray(plt.ginput(0, timeout=-1))
        if len(data) < 3:
            selection('Free Form Selection')
    
    # =========   Counter-Dimension   =========        
    minXY = data.min(axis= 0)
    maxXY = data.max(axis= 0)
    delXY = maxXY - minXY
    
    # =========   Counter with Free-Form Selection   =========
    counter = plt.fill(data[:, 0], data[:, 1], '#f0f0f0', edgecolor='#000000', linewidth= 0.5)
    rect = patches.Rectangle(minXY, delXY[0], delXY[1], linewidth= 0.5, edgecolor='#000000', facecolor="none") 
    
    # =========   Add the patch to the Axes   ========= 
    ax.add_patch(rect) 

    selection('          ')

    if plt.waitforbuttonpress():
        break

    # Get rid of fill
    for c in counter:
        c.remove()

# ========= Saving Point of Polygon to CSV file =========
np.savetxt('data.csv', data, delimiter=',')


# =========   Using OpenCV We can crop polygon of Image  =========
img = cv2.imread(image_file)
pts = np.array(data, dtype='int32')             # => datatype should be int32

# =========    Crop the Bounding Rectangle  =========
rect = cv2.boundingRect(pts)
x,y,w,h = rect
croped = img[y:y+h, x:x+w].copy()

# =========   Making Mask  =========
pts = pts - pts.min(axis=0)
mask = np.zeros(croped.shape[:2], np.uint8)
cv2.drawContours(mask, [pts], -1, (255, 255, 255), -1, cv2.LINE_AA)

# =========   BitWise Operation   =========
dst = cv2.bitwise_and(croped, croped, mask=mask)

# =========   Final Result  =========
cv2.imwrite("dst.png", dst)
img = cv2.imread('dst.png')
cv2.imshow('Image', img)
cv2.waitKey(0)
Davinder Singh
  • 2,060
  • 2
  • 7
  • 22