Opencv: detect mouse position clicking over a picture
Asked Answered
S

9

28

I have this code in which I simply display an image using OpenCV:

    import numpy as np 
    import cv2

    class LoadImage:
        def loadImage(self):
            self.img=cv2.imread('photo.png')
            cv2.imshow('Test',self.img)

            self.pressedkey=cv2.waitKey(0)

            # Wait for ESC key to exit
            if self.pressedkey==27:
                cv2.destroyAllWindows()

    # Start of the main program here        
    if __name__=="__main__":
        LI=LoadImage()
        LI.loadImage()

Once the window displayed with the photo in it, I want to display on the console (terminal) the position of the mouse when I click over the picture. I have no idea how to perform this. Any help please?

Shamrock answered 4/2, 2015 at 16:55 Comment(2)
@berak it is not same question , i am beginner in python and opencvShamrock
just go there again, print out all values, and see..Frankenstein
B
43

Here is an example mouse callback function, that captures the left button double-click

def draw_circle(event,x,y,flags,param):
    global mouseX,mouseY
    if event == cv2.EVENT_LBUTTONDBLCLK:
        cv2.circle(img,(x,y),100,(255,0,0),-1)
        mouseX,mouseY = x,y

You then need to bind that function to a window that will capture the mouse click

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

then, in a infinite processing loop (or whatever you want)

while(1):
    cv2.imshow('image',img)
    k = cv2.waitKey(20) & 0xFF
    if k == 27:
        break
    elif k == ord('a'):
        print mouseX,mouseY

What Does This Code Do?

It stores the mouse position in global variables mouseX & mouseY every time you double click inside the black window and press the a key that will be created.

elif k == ord('a'):
    print mouseX,mouseY

will print the current stored mouse click location every time you press the a button.


Code "Borrowed" from here.

Buddleia answered 4/2, 2015 at 20:29 Comment(6)
@MasoudPourbozorg press the escape keyBuddleia
also @MasoudPourbozorg I have provided a link to the source where I have taken the code from as it provides much more additional detail to my answer along with attribution to the original code author as well as detail such as any potential licensing issues.Buddleia
@Buddleia thanks for providing the link but I am unable to open it. Therefore, I suggest an updated link or removing it altogether. Please check the source link.Archenteron
In the first block of code, within line global mouseX,mouseY you might want to add img as well. Otherwise you will not be able to pass it to cv2.circle(img,(x,y),100,(255,0,0),-1)Anastaciaanastas
This is really helpful. Suggested edit: if you double click in the image, and press the letter a, the system will print the mouse coordinates.Rigidify
@Buddleia Yes, now I see it. Perhaps use highlighting or quotes to emphasize that it is the "a" button, not a typo.Rigidify
N
15

Below is my implementation:

No need to store the click position, ONLY display it:

def onMouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
       # draw circle here (etc...)
       print('x = %d, y = %d'%(x, y))
cv2.setMouseCallback('WindowName', onMouse)

If you want to use the positions in other places of your code, you can use below way to obtain the coordinates:

posList = []
def onMouse(event, x, y, flags, param):
   global posList
   if event == cv2.EVENT_LBUTTONDOWN:
        posList.append((x, y))
cv2.setMouseCallback('WindowName', onMouse)
posNp = np.array(posList)     # convert to NumPy for later use
Navarrete answered 17/3, 2018 at 14:56 Comment(0)
V
5
import cv2

cv2.imshow("image", img)
cv2.namedWindow('image')
cv2.setMouseCallback('image', on_click)

def on_click(event, x, y, p1, p2):
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(lastImage, (x, y), 3, (255, 0, 0), -1)
Vanillin answered 3/10, 2019 at 18:56 Comment(1)
Welcome to SO. Please can you explain why this is the answer in addition to the code you shared.Burned
D
1

You can detect mouse position clicking over a picture via performing the various mouse click events.

You just to remember one thing while performing the mouse clicks events is that, you should have to use the same window name at all places wherever you are using the cv2.imshow or cv2.namedWindow

I given the working code in answer that uses python 3.x and opencv in the following the stackoverflow post: https://mcmap.net/q/503387/-get-pixel-location-using-mouse-click-events

You can refer the above link for better explanation.

Code:

import cv2
import numpy as np

#This will display all the available mouse click events  
events = [i for i in dir(cv2) if 'EVENT' in i]
print(events)

#This variable we use to store the pixel location
refPt = []

#click event function
def click_event(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print(x,",",y)
        refPt.append([x,y])
        font = cv2.FONT_HERSHEY_SIMPLEX
        strXY = str(x)+", "+str(y)
        cv2.putText(img, strXY, (x,y), font, 0.5, (255,255,0), 2)
        cv2.imshow("image", img)

    if event == cv2.EVENT_RBUTTONDOWN:
        blue = img[y, x, 0]
        green = img[y, x, 1]
        red = img[y, x, 2]
        font = cv2.FONT_HERSHEY_SIMPLEX
        strBGR = str(blue)+", "+str(green)+","+str(red)
        cv2.putText(img, strBGR, (x,y), font, 0.5, (0,255,255), 2)
        cv2.imshow("image", img)


#Here, you need to change the image name and it's path according to your directory
img = cv2.imread("D:/pictures/abc.jpg")
cv2.imshow("image", img)

#calling the mouse click event
cv2.setMouseCallback("image", click_event)

cv2.waitKey(0)
cv2.destroyAllWindows()
Dilks answered 28/2, 2020 at 4:14 Comment(0)
S
1

Here is class based implementation of OpenCV mouse call back for getting point on an image,

import cv2
import numpy as np
#events = [i for i in dir(cv2) if 'EVENT' in i]
#print (events)

class MousePts:
    def __init__(self,windowname,img):
        self.windowname = windowname
        self.img1 = img.copy()
        self.img = self.img1.copy()
        cv2.namedWindow(windowname,cv2.WINDOW_NORMAL)
        cv2.imshow(windowname,img)
        self.curr_pt = []
        self.point   = []

    def select_point(self,event,x,y,flags,param):
        if event == cv2.EVENT_LBUTTONDOWN:
            self.point.append([x,y])
            #print(self.point)
            cv2.circle(self.img,(x,y),5,(0,255,0),-1)
        elif event == cv2.EVENT_MOUSEMOVE:
            self.curr_pt = [x,y]
            #print(self.point)

    def getpt(self,count=1,img=None):
        if img is not None:
            self.img = img
        else:
            self.img = self.img1.copy()
        cv2.namedWindow(self.windowname,cv2.WINDOW_NORMAL)
        cv2.imshow(self.windowname,self.img)
        cv2.setMouseCallback(self.windowname,self.select_point)
        self.point = []
        while(1):
            cv2.imshow(self.windowname,self.img)
            k = cv2.waitKey(20) & 0xFF
            if k == 27 or len(self.point)>=count:
                break
            #print(self.point)
        cv2.setMouseCallback(self.windowname, lambda *args : None)
        #cv2.destroyAllWindows()
        return self.point, self.img

if __name__=='__main__':
    img = np.zeros((512,512,3), np.uint8)
    windowname = 'image'
    coordinateStore = MousePts(windowname,img)

    pts,img = coordinateStore.getpt(3)
    print(pts)

    pts,img = coordinateStore.getpt(3,img)
    print(pts)

    cv2.imshow(windowname,img)
    cv2.waitKey(0)
Shibboleth answered 19/4, 2020 at 17:7 Comment(0)
M
0

I have ported the PyIgnition library from Pygame to opencv2. Find the code at https://github.com/bunkahle/particlescv2 There also several examples on how to use the particle engine for Python.

Miniaturize answered 18/2, 2019 at 2:42 Comment(0)
C
0

In case, you want to get the coordinates by hovering over the image in Python 3, you could try this:

import numpy as np
import cv2 as cv
import os
import sys

# Reduce the size of image by this number to show completely in screen
descalingFactor = 2

# mouse callback function, which will print the coordinates in console
def print_coord(event,x,y,flags,param):
    if event == cv.EVENT_MOUSEMOVE:
        print(f'{x*descalingFactor, y*descalingFactor}\r', end="")

img = cv.imread(cv.samples.findFile('TestImage.png'))
imgheight, imgwidth = img.shape[:2]
resizedImg = cv.resize(img,(int(imgwidth/descalingFactor), int(imgheight/descalingFactor)), interpolation = cv.INTER_AREA)
cv.namedWindow('Get Coordinates')
cv.setMouseCallback('Get Coordinates',print_coord)
cv.imshow('Get Coordinates',resizedImg)
cv.waitKey(0)
Coccid answered 25/9, 2020 at 12:8 Comment(0)
S
0

If anyone wants a multi-process-based GUI for drawing points and dragging to move them, here is a single file script for same.

Shibboleth answered 5/2, 2022 at 17:42 Comment(0)
C
0
import cv2 as cv

class UiImage():
    def __init__(self, ui_name='image', param={}):
        self.ui_name = ui_name
        cv.namedWindow(self.ui_name)
        cv.setMouseCallback(self.ui_name, lambda *args:self.on_mouse(*args), param)
    def __call__(self, img, flags=cv.IMREAD_UNCHANGED):
        if isinstance(img, str):
            img = cv.imread(img,flags)
        self.img = img
        cv.imshow(self.ui_name, img)
    def wait(self, delay=0):
        cv.waitKey(delay) #ms
        if cv.getWindowProperty(self.ui_name, cv.WND_PROP_VISIBLE):
            cv.destroyWindow(self.ui_name)
    def on_mouse(self,event,x,y,flags,param):
        '''
        MouseEventTypes:
            EVENT_MOUSEMOVE
            EVENT_LBUTTONDOWN
            EVENT_RBUTTONDOWN
            EVENT_MBUTTONDOWN
            EVENT_LBUTTONUP
            EVENT_RBUTTONUP
            EVENT_MBUTTONUP
            EVENT_LBUTTONDBLCLK
            EVENT_RBUTTONDBLCLK
            EVENT_MBUTTONDBLCLK
            EVENT_MOUSEWHEEL
            EVENT_MOUSEHWHEEL
        MouseEventFlags:
            EVENT_FLAG_LBUTTON
            EVENT_FLAG_RBUTTON
            EVENT_FLAG_MBUTTON
            EVENT_FLAG_CTRLKEY
            EVENT_FLAG_SHIFTKEY
            EVENT_FLAG_ALTKEY
        '''
        print(event,x,y,flags,param)

use:

ui = UiImage(ui_name='image')

def on_mouse(event,x,y,flags,param):
    def is_down(flag):
        return flags & flag
    if event == cv.EVENT_LBUTTONDOWN:
        print('Left button down',x,y)
    if is_down(cv.EVENT_FLAG_ALTKEY):
        print('alt is down')
ui.on_mouse = on_mouse

img = cv.imread('./test.png',cv.IMREAD_UNCHANGED)
img = './test.png'
ui(img, flags=cv.IMREAD_UNCHANGED)

ui.wait(delay=0)

https://docs.opencv.org/4.x/d7/dfc/group__highgui.html

Crave answered 15/3 at 13:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.