one entrance for loop in threading - python-2.7

I am using pyqt4 , python2.7. opencv3 , raspbian
I create Function with name Vision_thread()to search faces in every frame. and create funcation with name start_thread() to execute Vision_thread()Function by thread. look here:
def start_thread():
t1 = threading.Thread(target=Vision_thread)
t1.start()
#t1.join()
now I call Funcation by button created by PYqt4 as way:
self.pushButtonStart.setText(_translate("MainWindow", "Start Vision", None))
# program event click for start Vision button
self.pushButtonStart.clicked.connect(start_thread)
my problem is : when click on button . the loop in function Vision_thread() execute for first entrance only . and do not continuous .
but when I write:
t1 = threading.Thread(target=Vision_thread())
insted of
t1 = threading.Thread(target=Vision_thread)
the function Vision_thread() execute without any problem . but this is no thread .
what is problem??????
Vision_thread() code is :
def Vision_thread():
print("Vision")
print (search)
GPIO.output(32,True)
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
image = frame.array
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)
face = gray[y:y + h, x:x + w]
face_resize = cv2.resize(face, (width, height))
#Try to recognize the face
prediction = model.predict(face_resize)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 3)
x_left=160
if prediction[1]<500:
cv2.putText(image,'%s - %.0f' % (names[prediction[0]],prediction[1]),(x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
if names[prediction[0]]==search:
x_left = x-width
x_right = width - w - x
sum_final=x_left+x_right
if x_left>180:
Left_thread()
if x_left<140:
Right_thread()
print "left={0}\nright={1}\nsum={2}".format(x_left, x_right,sum_final)
else:
cv2.putText(image,'not recognized',(x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
cv2.imshow('OpenCV', image)
key = cv2.waitKey(10)
rawCapture.truncate(0)
if key == 27:
GPIO.output(32,False)
break

Related

how can I select object from image and replace it with other one by using c++ and opencv

enter image description here
for example if i need to select the Ipad and I need to replace it by other thing with the same size
Let's say, we want to put an Android tablet from another image over the iPad.
Knowing corner coordinates of both objects on both images, you can use OpenCV getPerspectiveTransform function to create the transformation matrix. Make an empty mask, use fillPoly to draw a quadrangle on it, corresponding to the Android corner points, fill it with 1-s, it's going to be the binary mask. Apply the perspective transform, calculated earlier, to both the mask and the android image (warpPerspective). Copy the transformed Android image over the original iPad image with copyTo function, using the transformed mask. Done.
Here's a 'proof of concept' Python implementation, just because I did something not so different not so long ago. Click all the Android corners in order, then the iPad corners in the same order, press A key to apply the transform. Don't expect miracles from it, of course - it's not going to paint missing edges for you, etc.
import cv2
import numpy as np
def on_mouse_click_from(event, x, y, flags, param):
global image_from, points_from
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(image_from, (x, y), 2, (255, 0, 0), cv2.FILLED)
points_from.append([x, y])
cv2.imshow("Image1", image_from)
def on_mouse_click_to(event, x, y, flags, param):
global image_to, points_to
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(image_to, (x, y), 2, (255, 0, 0), cv2.FILLED)
points_to.append([x, y])
cv2.imshow("Image2", image_to)
points_from = []
points_to = []
image_from = cv2.imread("android.jpg")
image_to = cv2.imread("ipad.jpg")
max_dim = [max(x, y) for x, y in zip(image_from.shape[:2], image_to.shape[:2])][::-1]
max_dim = tuple(max_dim)
image_from = cv2.resize(image_from, max_dim)
image_to = cv2.resize(image_to, max_dim)
clone_from = image_from.copy()
cv2.namedWindow("Image1")
cv2.setMouseCallback("Image1", on_mouse_click_from)
clone_to = image_to.copy()
cv2.namedWindow("Image2")
cv2.setMouseCallback("Image2", on_mouse_click_to)
image_res = None
cv2.namedWindow("Result")
while True:
cv2.imshow("Image1", image_from)
cv2.imshow("Image2", image_to)
key = cv2.waitKey(1) & 0xFF
if key == ord("r"):
image_from = clone_from.copy()
image_to = clone_to.copy()
points_from = []
points_to = []
elif key == ord("a"):
trans = cv2.getPerspectiveTransform(np.array(points_from, dtype='f4'), np.array(points_to, dtype='f4'))
height, width, n_colors = clone_from.shape
stencil = np.zeros((height, width, n_colors))
contours = [np.array(points_from)]
color = [1, 1, 1]
cv2.fillPoly(stencil, contours, color)
stencil = cv2.warpPerspective(stencil, trans, (width, height))
img_from_transformed = cv2.warpPerspective(clone_from, trans, (width, height))
cnd = (stencil != 0)
image_res = clone_to.copy()
image_res[cnd] = img_from_transformed[cnd]
cv2.imwrite("result.jpg", image_res)
cv2.imshow("Result", image_res)
elif key == ord("q"):
break
cv2.destroyAllWindows()
Follow these steps:
1) First, select the object to be replaced using Mousecallback fuction from opencv. You can find a simple demo here
2) When selecting the object, save the 4 coordinates of the object being selected. Find the size of the rectangle by using these coordinates.
3) Use Resize function to resize the image(with which you want to replace the original)
4) Now You can simply use copyTo function to do the replacement. Check here
Hope this helps!

Issue with script using Pygame

I'm writing a small game in my spare time. This is what I have so far:
from pygame import * #import relevant modules
from PIL import Image
import os, sys
init() #initialise
class sprite:
def __init__(self, object, x = 0, y = 0, w = 0, h = 0):
self.image = image.load(object).convert()
self.posx = x
self.posy = y
self.position = ((x, y, w, h))
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
return self.image
def move(self, window, background, right, down):
self.posx = x + right
self.posy = y + down
window.blit(background, self.position, self.position)
self.position.move(right, down)
window.blit(self, self.position)
window.update()
os.chdir('C:\\Users\\alesi\\Documents\\Pygame\\Project\\') #current folder change
win = display.set_mode((736, 552))#load window
Clock = time.Clock() #handy clock
background = image.load('background.jpg').convert()#load images
player = sprite('ball.png', 350, 275, 20, 20)
player = player.resize(20, 20)
win.blit(background, (0, 0))
win.blit(player, (350, 275))
display.update()
while True:
event.pump()
keys = key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
elif keys[K_RIGHT]:
player.move(win, background, 20, 0)
elif keys[K_LEFT]:
player.move(win, background, -20, 0)
elif keys[K_DOWN]:
player.move(win, background,0, 20)
elif keys[K_UP]:
player.move(win, background, 0, -20)
In short, it should create an object on a background and allow you to move the object using the arrow keys. However, I get the error:
C:\Users\alesi\Documents\Pygame\Project>python2 game2.py
Traceback (most recent call last):
File "game2.py", line 51, in <module>
player.move(win, background, -20, 0)
AttributeError: 'pygame.Surface' object has no attribute 'move'
I'm struggling to understand why my player instance of the sprite class is not recognising the move method. Also, I'm confused by why during the win.blit() function, I have to give the argument player instead of player.image, the attribute which I've stored the image.
Any advice would be appreciated.
In code
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
return self.image
you returns image which is Surface instance - so in line
player = player.resize(20, 20)
you replace sprite instance with Surface instance
But you don't have to assign it to player again.
Do:
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
# without return
# without player =
player.resize(20, 20)
After that player.move(...) will work again.
And again you will have to use player.image in blit()

Clicking on images with PyGame

I am currently developing a game using Python and PyGame. I have made image sprites for the main option buttons, but I cannot seem to figure out how to make the images clickable which will take me to a different screen. Source code:
import os
import sys
import pygame
import time
class Colors:
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
dark_red = (102, 0, 0)
grey = (128, 128, 128)
dark_grey = (51, 51, 51)
class Variables:
screen_w = 1000
screen_h = 600
battleButton = pygame.image.load("Images/battle_button.png")
shopButton = pygame.image.load("Images/shop_button.png")
saveButton = pygame.image.load("Images/save_button.png")
equippedItem = pygame.image.load("Images/equipped.png")
creditsButton = pygame.image.load("Images/credits_button.png")
baseballBat = pygame.image.load("Images/baseball_bat.png")
baseballBat = pygame.transform.scale(baseballBat, (250, 250))
playerHealthMax = 100
playerHealthMin = 0
playerHealth = playerHealthMax
playerCash = 0
pygame.font.init()
gameFont = pygame.font.SysFont("Tweaky", 70)
title = gameFont.render("Causatum", 1, (Colors.black))
mainFont = pygame.font.SysFont("Arial Rounded MT Bold", 50)
equippedWeap = mainFont.render("Equipped", 1, (Colors.black))
cash = mainFont.render("Cash: ${}".format(playerCash), 1,
(Colors.black))
health = mainFont.render("Health: {}".format(playerHealth), 1,
(Colors.black))
gameVersion = mainFont.render("v1.0.0", 1, (Colors.black))
screen = pygame.display.set_mode((Variables.screen_w, Variables.screen_h))
pygame.display.set_caption("Causatum")
screen.fill(Colors.black)
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(Colors.grey)
screen.blit(Variables.battleButton, (0, 170))
screen.blit(Variables.shopButton, (0, 240))
screen.blit(Variables.saveButton, (0, 310))
screen.blit(Variables.title, (330, 0))
screen.blit(Variables.equippedItem, (645, 250))
screen.blit(Variables.baseballBat, (735, 230))
screen.blit(Variables.equippedWeap, (723, 215))
screen.blit(Variables.creditsButton, (0, 380))
screen.blit(Variables.cash, (0, 50))
screen.blit(Variables.health, (0, 0))
screen.blit(Variables.gameVersion, (905, 0))
pygame.display.flip()
Any kind of help is appreciated. Thanks.
Try something like this:
#in 'Variables' add this line
battleButton_rect = battleButton.get_rect(centerx = 0, centery = 170)
#new function, outside any classes
def collide(mouseX, mouseY, rect): #new function for checking the collision of the mouse with a button
return (mouseX >= rect.x-rect.width/2 and mouseX <= rect.x+rect.width/2 and mouseY >= rect.y-rect.height/2 and mouseY <= rect.y+rect.height/2)
# in 'while running'
if pygame.mouse.get_pressed()[0]: #0 for left button, 1 for right, 2 for middle
mouse_pos = pygame.mouse.get_pos()
if collide(mouse_pos[0], mouse_pos[1], Variables.battleButton_rect):
#code for battle button clicked here
#replace
screen.blit(Variables.battleButton, (0, 170))
#with
screen.blit(Variables.battleButton, Variables.battleButton_rect)
This, of course, is only for the battle button. You need to add a Rect for every button you use. Also, I would suggest making a button class with the collision function inside and having an array of those buttons that you can iterate through without convoluting your code. But the above is a quick and dirty solution.
Hope this helps!

Pygame: Movement Stops When Running a function twice [duplicate]

I have made a list of bullets and a list of sprites using the classes below. How do I detect if a bullet collides with a sprite and then delete that sprite and the bullet?
#Define the sprite class
class Sprite:
def __init__(self,x,y, name):
self.x=x
self.y=y
self.image = pygame.image.load(name)
self.rect = self.image.get_rect()
def render(self):
window.blit(self.image, (self.x,self.y))
# Define the bullet class to create bullets
class Bullet:
def __init__(self,x,y):
self.x = x + 23
self.y = y
self.bullet = pygame.image.load("user_bullet.BMP")
self.rect = self.bullet.get_rect()
def render(self):
window.blit(self.bullet, (self.x, self.y))
In PyGame, collision detection is done using pygame.Rect objects. The Rect object offers various methods for detecting collisions between objects. Even the collision between a rectangular and circular object such as a paddle and a ball can be detected by a collision between two rectangular objects, the paddle and the bounding rectangle of the ball.
Some examples:
pygame.Rect.collidepoint:
Test if a point is inside a rectangle
repl.it/#Rabbid76/PyGame-collidepoint
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(100, 100)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
point = pygame.mouse.get_pos()
collide = rect.collidepoint(point)
color = (255, 0, 0) if collide else (255, 255, 255)
window.fill(0)
pygame.draw.rect(window, color, rect)
pygame.display.flip()
pygame.quit()
exit()
pygame.Rect.colliderect
Test if two rectangles overlap
See also How to detect collisions between two rectangular objects or images in pygame
repl.it/#Rabbid76/PyGame-colliderect
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
rect1 = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
rect2 = pygame.Rect(0, 0, 75, 75)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
rect2.center = pygame.mouse.get_pos()
collide = rect1.colliderect(rect2)
color = (255, 0, 0) if collide else (255, 255, 255)
window.fill(0)
pygame.draw.rect(window, color, rect1)
pygame.draw.rect(window, (0, 255, 0), rect2, 6, 1)
pygame.display.flip()
pygame.quit()
exit()
Furthermore, pygame.Rect.collidelist and pygame.Rect.collidelistall can be used for the collision test between a rectangle and a list of rectangles. pygame.Rect.collidedict and pygame.Rect.collidedictall can be used for the collision test between a rectangle and a dictionary of rectangles.
The collision of pygame.sprite.Sprite and pygame.sprite.Group objects, can be detected by pygame.sprite.spritecollide(), pygame.sprite.groupcollide() or pygame.sprite.spritecollideany(). When using these methods, the collision detection algorithm can be specified by the collided argument:
The collided argument is a callback function used to calculate if two sprites are colliding.
Possible collided callables are collide_rect, collide_rect_ratio, collide_circle, collide_circle_ratio, collide_mask
Some examples:
pygame.sprite.spritecollide()
repl.it/#Rabbid76/PyGame-spritecollide
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((75, 75))
sprite1.image.fill((255, 0, 0))
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((75, 75))
sprite2.image.fill((0, 255, 0))
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, test_group, False)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
pygame.display.flip()
pygame.quit()
exit()
For a collision with masks, see How can I make a collision mask? or Pygame mask collision
See also Collision and Intersection
pygame.sprite.spritecollide() / collide_circle
repl.it/#Rabbid76/PyGame-spritecollidecollidecircle
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(sprite1.image, (255, 0, 0), (40, 40), 40)
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite1.radius = 40
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((80, 89), pygame.SRCALPHA)
pygame.draw.circle(sprite2.image, (0, 255, 0), (40, 40), 40)
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite2.radius = 40
all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, test_group, False, pygame.sprite.collide_circle)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.circle(window, (255, 255, 255), s.rect.center, s.rect.width // 2, 5)
pygame.display.flip()
pygame.quit()
exit()
What does this all mean for your code?
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument. For example, the centre of the rectangle can be specified with the keyword argument center. These keyword arguments are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a list of the keyword arguments).
See *Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
You do not need the x and y attributes of Sprite and Bullet at all. Use the position of the rect attribute instead:
#Define the sprite class
class Sprite:
def __init__(self, x, y, name):
self.image = pygame.image.load(name)
self.rect = self.image.get_rect(topleft = (x, y))
def render(self):
window.blit(self.image, self.rect)
# Define the bullet class to create bullets
class Bullet:
def __init__(self, x, y):
self.bullet = pygame.image.load("user_bullet.BMP")
self.rect = self.bullet.get_rect(topleft = (x + 23, y))
def render(self):
window.blit(self.bullet, self.rect)
Use pygame.Rect.colliderect() to detect collisions between instances of Sprite and Bullet.
See How to detect collisions between two rectangular objects or images in pygame:
my_sprite = Sprite(sx, sy, name)
my_bullet = Bullet(by, by)
while True:
# [...]
if my_sprite.rect.colliderect(my_bullet.rect):
printe("hit")
From what I understand of pygame you just need to check if the two rectangles overlap using the colliderect method. One way to do it is to have a method in your Bullet class that checks for collisions:
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
Then you can call it like:
sprite = Sprite(10, 10, 'my_sprite')
bullet = Bullet(20, 10)
if bullet.is_collided_with(sprite):
print('collision!')
bullet.kill()
sprite.kill()
There is a very simple method for what you are trying to do using built in methods.
here is an example.
import pygame
import sys
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = pos
def main():
pygame.init()
clock = pygame.time.Clock()
fps = 50
bg = [255, 255, 255]
size =[200, 200]
screen = pygame.display.set_mode(size)
player = Sprite([40, 50])
player.move = [pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN]
player.vx = 5
player.vy = 5
wall = Sprite([100, 60])
wall_group = pygame.sprite.Group()
wall_group.add(wall)
player_group = pygame.sprite.Group()
player_group.add(player)
# I added loop for a better exit from the game
loop = 1
while loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = 0
key = pygame.key.get_pressed()
for i in range(2):
if key[player.move[i]]:
player.rect.x += player.vx * [-1, 1][i]
for i in range(2):
if key[player.move[2:4][i]]:
player.rect.y += player.vy * [-1, 1][i]
screen.fill(bg)
# first parameter takes a single sprite
# second parameter takes sprite groups
# third parameter is a do kill command if true
# all group objects colliding with the first parameter object will be
# destroyed. The first parameter could be bullets and the second one
# targets although the bullet is not destroyed but can be done with
# simple trick bellow
hit = pygame.sprite.spritecollide(player, wall_group, True)
if hit:
# if collision is detected call a function in your case destroy
# bullet
player.image.fill((255, 255, 255))
player_group.draw(screen)
wall_group.draw(screen)
pygame.display.update()
clock.tick(fps)
pygame.quit()
# sys.exit
if __name__ == '__main__':
main()
Make a group for the bullets, and then add the bullets to the group.
What I would do is this:
In the class for the player:
def collideWithBullet(self):
if pygame.sprite.spritecollideany(self, 'groupName'):
print("CollideWithBullet!!")
return True
And in the main loop somewhere:
def run(self):
if self.player.collideWithBullet():
print("Game Over")
Hopefully that works for you!!!
Inside the Sprite class, try adding a self.mask attribute with
self.mask = pygame.mask.from_surface(self.image)
and a collide_mask function inside of the Sprite class with this code:
def collide_mask(self, mask):
collided = False
mask_outline = mask.outline()
self.mask_outline = self.mask.outline()
for point in range(len(mask_outline)):
mask_outline[point] = list(mask_outline[point])
mask_outline[point][0] += bullet.x
mask_outline[point][1] += bullet.y
for point in range(len(self.mask_outline)):
self.mask_outline[point] = list(mask_outline[point])
self.mask_outline[point][0] += self.x
self.mask_outline[point][1] += self.y
for point in mask_outline:
for self_mask_point in self.mask_outline:
if point = self_mask_point:
collided = True
return collided

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?
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.
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
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)
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()
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)
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.
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)
If anyone wants a multi-process-based GUI for drawing points and dragging to move them, here is a single file script for same.