user4519127
user4519127

Reputation: 497

Opencv: detect mouse position clicking over a picture

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?

Upvotes: 28

Views: 100355

Answers (9)

Civil
Civil

Reputation: 79

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

Upvotes: 0

Jerin Antony
Jerin Antony

Reputation: 383

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

Upvotes: 0

smh
smh

Reputation: 498

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

Upvotes: 15

Fawaz Ahmed
Fawaz Ahmed

Reputation: 1564

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)

Upvotes: 0

GPPK
GPPK

Reputation: 6666

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.

Upvotes: 44

Jerin Antony
Jerin Antony

Reputation: 383

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)

Upvotes: 1

Ankit Lad
Ankit Lad

Reputation: 419

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://stackoverflow.com/a/60445099/11493115

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()

Upvotes: 1

Omer Meshy
Omer Meshy

Reputation: 51

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)

Upvotes: 5

bunkus
bunkus

Reputation: 1025

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.

Upvotes: 0

Related Questions