0

I'm working on a python image processing file, in which I need to generate a ROI image from a starting one.

To do that, I want that the user can either manually input the point coordinates of the ROI with top-left to bottom-right logic or use 2 left mouse clicks pressed into the matplotlib-pyplot plot of the starting image shown.

For shortening reasons I omitted the manual ROI creation part and the ROI plot because my question is only related to the mouse click point coordinates extraction.

Searching on the website I came across this question, which shows how to store point coordinates tuple of a pair of points by clicking on the plot. The fact is that it's done within a simple plot, not into an image, and I can't figure out at the moment how to implement the same feature for an image plot.

The question found on the site is this: Store mouse click event coordinates with matplotlib

The code I tried to implement, based on what I found on the link posted is this:

# import the necessary packages
import cv2 as cv
import matplotlib.pyplot as plt

image=".\\Esercizi_da_consegnare\\Avanzato\\aaa\\DSCF0336.jpg"

# Simple mouse click function to store coordinates
def onclick(event):
    global ix, iy
    ix, iy = event.xdata, event.ydata
    x_int=int(ix)
    y_int=int(iy)

    # print 'x = %d, y = %d'%(
    #     ix, iy)

    # assign global variable to access outside of function
    global coords
    coords.append((x_int,y_int))
    

    # Disconnect after 2 clicks
    if len(coords) == 2:
        image.mpl_disconnect(cid)
        plt.close(1)
    return

cv.imread(image, cv.IMREAD_GRAYSCALE)
plt.imshow(image, cmap="gray")
plt.show()

coords = []

# Call click func
cid = image.mpl_connect('button_press_event', onclick)

plt.show()
print(coords)

Obviously, .mpl_connect(...) and .mpl_disconnect(...), which make the store action work, do not work with plt.imshow(...). I expect to make this work for an image, which is loaded as a matrix so I expect that is possible to extract pixel coordinates, which are the rows/columns indexes of each pixel, which is then converted to an integer if the click is made in a float coordinate point position, as the same way as the fig.ax(...) method.

Prof.Plague
  • 649
  • 10
  • 20

1 Answers1

0

I found the solution by myself digging into the event handling and interactive figures (but I assume that if I read the basic figure coding I'd have reached the same result) documentation of matplotlib:

https://matplotlib.org/stable/users/explain/event_handling.html

https://matplotlib.org/stable/users/explain/interactive.html

The key is to initialize a figure, then create a subplot with a single plot and then load the image into that plot, so you can use the .canvas.mpl_connect() and disconnect().

Here is the code:

# import the necessary packages
import cv2 as cv
import matplotlib.pyplot as plt

image_path=".\\Esercizi_da_consegnare\\Avanzato\\aaa\\DSCF0336.jpg"

image=cv.imread(image_path, cv.IMREAD_GRAYSCALE)
fig,ax=plt.subplots()
plt.subplot(1,1,1)
plt.imshow(image, cmap="gray")

coords = []

# Simple mouse click function to store coordinates
def onclick(event):
    global ix, iy
    ix, iy = event.xdata, event.ydata
    x_int=int(ix)
    y_int=int(iy)
    
    # assign global variable to access outside of function
    global coords
    coords.append((x_int,y_int))
    
    # Disconnect after 2 clicks
    if len(coords) == 2:
        fig.canvas.mpl_disconnect(cid)
        plt.close(1)
    return
# Call click func
cid = fig.canvas.mpl_connect('button_press_event', onclick)

plt.show(block=True)
print(coords)