How to use mouseclick to change a variable using OpenCV and Python? - python

I'm a noobie at programming and this question may sound easy and dumb but I really can not do it! The goal here is to change the color between green, blue and red everytime I click. I'm sorry if that's obvious, but I'm for hours stuck at this. That's the code I have, that prints everytime the same color. Now, I want to add something to change colors everytime I click.
import cv2
import numpy as np
def draw_circle(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img,(x,y),100,color=(0,255,0),thickness=10)
cv2.namedWindow(winname='my_drawing')
cv2.setMouseCallback('my_drawing', draw_circle)
img = np.zeros((512,512,3),np.int8)
while True:
cv2.imshow('my_drawing', img)
if cv2.waitKey(20) &0xFF == 27:
break
cv2.destroyAllWindows
I've tried a lot of stuff that I don't even know where to start, but I've tried creating a variable inside the function that each time it enters on the function, it sums, and depending on the value(using if) it goes to a different color, but the variable doesn't seem to change if it enters the loop again, then I've tried returning the variable as well. No success. Adding a Paramater. No Success as well. I believe it's such a simple thing that my head cannot think at this point.

Here's one way... make a list of the colours you want to cycle through. Have a global variable that you use as the index into the list to get the next colour. Each time you use it, add 1 to it and reduce it modulo the length of the list of colours. Colour the circle with value from the colour list as indexed by the index.
#!/usr/bin/env python3
import cv2
import numpy as np
index = 0
colours = [[255,0,0], [0,255,0], [0,0,255]]
def draw_circle(event,x,y,flags,param):
global index
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img,(x,y),100,color=colours[index],thickness=10)
index = (index+1) % len(colours)
cv2.namedWindow(winname='my_drawing')
cv2.setMouseCallback('my_drawing', draw_circle)
img = np.zeros((512,512,3),np.int8)
while True:
cv2.imshow('my_drawing', img)
if cv2.waitKey(20) &0xFF == 27:
break
cv2.destroyAllWindows

Related

Changing variable value in tkinter loop doesn't update

I'm working on a program and I ran into a problem I'm not sure how to fix.
I'm gonna try to give a simplified example below.
The purpose of the code is to read data from a device and display the stream live. However in the GUI You can select what stream of data You wish to display.
import tkinter
import datastream.py
dataselector = 3
def ReDraw(dataselector):
if dataselector == 0:
#draw a certain stream
if dataselector == 1:
#draw another stream
#draw a bunch of other streams in other displays
canvas.after(10,ReDraw,dataselector)
def SelectData(mouseevent):
if event.clickedbutton == 0:
#thatbuttonbecomesred
dataselector = 0
if event.clickedbutton == 1:
#thatotherbuttonbecomesred
dataselector = 1
return dataselector
ReDraw(dataselector)
SelectData()
Sorry for the pseudo-code, but it's the simplest way to explain the problem.
The behavior I get is that everything draws and redraw correctly, the buttons do interact and become red BUT the ReDraw function only takes the original dataselector value and doesn't take the new one given by the SelectData function even if, testing with some prints, it indeed changes it.
It's like the ReDraw function takes the original value and store it secretly, ignoring any changes to that value!
I also tried using a global dataselector in the SelectData function instead, but it doesn't change anything.
Any suggestions how to fix this?
Just for clarifications, #PaulM. solved it in the comments above.
Here is a version of the pseudo-code that would work correctly.
import tkinter
import datastream.py
dataselector = 3
def ReDraw():
if dataselector == 0:
#draw a certain stream
if dataselector == 1:
#draw another stream
#draw a bunch of other streams in other displays
canvas.after(10,ReDraw)
def SelectData(mouseevent):
global dataselector
if event.clickedbutton == 0:
#thatbuttonbecomesred
dataselector = 0
if event.clickedbutton == 1:
#thatotherbuttonbecomesred
dataselector = 1
ReDraw()
SelectData()
Not sure why I didn't see it before, but thanks for the help!

Kinematic study application. Python and opencv

Im trying to develop a simple code using opencv and python. My idea is the following:
I have a video with a moving object(free falling or parabolic) and I've managed to separate the video in frames. What I need (and I'm a total newby in this aaaand have little time) is to extract coordinates of the object frame by frame. So the idea is to click on the moving object, and get the (x, y) coordinate and the number of frame and open the next frame so I can do the same. So basically something with clicks over the foto and extracting the data in a csv and showing the next frame. Thus I could study its movement through space with its velocity and acelerations and stuff.
Haven't written any code yet.
Thanks in advance.
Look at docs example with using mouse input in opencv w python:
mouse example - opencv
You can define callback reading the click coordinates:
def get_clic_point(event,x,y,flags,param):
if event == cv.EVENT_LBUTTONDBLCLK: # on left double click
print(x,y) # here goes Your sepcific code, using x, y as click coordinates
In main loop, You need to create window and supply it with callback method
cv.namedWindow('main_win')
cv.setMouseCallback('main_win',get_clic_point)
Then using window name (in this case 'main_win') as Your window handle, You can
show image, calling cv.imshow('main_win',img), where img is loaded image.
You can write simple loop like this:
cv.namedWindow('main_win')
cv.setMouseCallback('main_win',get_clic_point)
images = []
# read images to this list
# ...
i = 0
while(1):
cv.imshow('main_win',images[i])
k = cv.waitKey(1) & 0xFF
if k == ord('n'): # n for next
# change image
i = i + 1
i = i % len(images)
elif k == 27:
break
cv.destroyAllWindows()
then just substitiute call back with desired logic

Need help loading images using a for loop in PyGame [duplicate]

This question already has answers here:
What would be the output of range(x, y) if x > y?
(3 answers)
Closed last year.
I'm trying to load images in PyGame based on a value, like when the value is 6 it sets the image to be image number 6.
def bar():
global ink
global screen
global barImg
ink = 0
for ink in range(0,100):
barImg = pygame.image.load(f'inkbar\load{ink}.png')
screen.blit(barImg,(100,100))
pygame.display.update()
The value of ink gets changed in another function and I know that part works. Each image is called load0.png, load1.png and so on until 100, but the image never appears on the screen. I have tested putting the image on the screen by commenting out the for loop and just setting barImg to a specific image and it did put the image on the screen.
px, py = pygame.mouse.get_pos()
if pygame.mouse.get_pressed() == (1,0,0):
pygame.draw.rect(screen, (255,255,255), (px,py,10,10))
ink+=0.5
math.ceil(ink)
print(ink)
this is part of a function that allows the user to draw. This part detects mouse click and increases the value of ink. I tried calling bar() underneath the ink increase, but that decreased the rate of drawing.
I have removed the function bar()
ink+=1
math.ceil(ink)
print(ink)
for ink in range(1,100):
barImg = pygame.image.load(f'inkbar\load{ink}.png')
screen.blit(barImg,(100,100))
This is what I have used as a replacement, but now ink does not increase by one, it goes from 1 to 100 immediately, and causes large amounts of lag.
Maybe the images having "load" in the name is messing with something?
I have some code for running through frames of an animation which I know works
The code:
frame_index += animation_speed
if frame_index >= len(animation):
self.frame_index = 0
image = pygame.image.load(f'Ink ({int(frame_index)}).png')
screen.blit(image, (0,0))
pygame.display.update()
Essentially you want to have two variables, a frame index and an animation speed. The index is the number of the first image you are loading. In this case Ink 0.png or whatever it's called. So your frame index will be 0. This will increment by your animation speed variable. The higher this is, the faster your animation will be. The lower, the slower. After it loops it will go back to 0 if thats what you want. If you don't want that then you can simply remove the if statement.
Also check that you aren't filling the screen AFTER doing this as whatever you're wanting to see will just be covered instantly. Let me know if this works.

cv2.createTrackbar call-back function

I have simple program for creating trackbar using cv2 and python 3.7. I am using a callback function that prints the trackbar value. The issue is, it prints the (same) value twice. Why is that?
import cv2
def print_value(x):
print(x)
cv2.namedWindow('Tracking', cv2.WINDOW_NORMAL)
cv2.createTrackbar('Value', 'Tracking', 0, 255, print_value)
while True:
key = cv2.waitKey(1)
if key == 27: # ESC key to quit
break
cv2.destroyAllWindows()
I just want one value to be printed out. Preferably the one of the new position. Thanks...

I am trying to build Motion Detector using openCV and python but display window is not responding when I terminate program

Here is the code for the same, have a look at it. In this, below code I am creating a Motion Detector and with this I will be recording the timings of when the various objects appeared and disappeared for which I am using dataframe.
The issue with this is that the program executes but when the output is displayed in the form of a Window, it freezes when I try to terminate.
import cv2, pandas
from datetime import datetime
first_frame = None
status_list = [None,None]
times = []
df = pandas.DataFrame(columns=["Start", "End"]) #Dataframe to store the time values during which object detection and movement appears.
video = cv2.VideoCapture(0)#VideoCapture object is used to record video using web cam
while True:
#check is a bool data type, returns true if VideoCapture object is read
check,frame = video.read()
status = 0
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) # For converting the frame color to gray scale
gray = cv2.GaussianBlur(gray,(21,21),0) # For converting the gray scale frame to GaussianBlur
if first_frame is None:
first_frame = gray # used to store the first image/frame of the video
continue
delta_frame = cv2.absdiff(first_frame,gray)#calculates the difference between first and other frames
thresh_delta = cv2.threshold(delta_frame,30,255,cv2.THRESH_BINARY)[1]
thresh_delta = cv2.dilate(thresh_delta,None,iterations=0) #Provides threshold value, so if the difference is <30 it will turn to black otherwise if >30 pixels will turn to white
(_,cnts,_) = cv2.findContours(thresh_delta.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #Define the contour area,i.e. adding borders
#Removing noises and shadows, any part which is greater than 1000 pixels will be converted to white
for contour in cnts:
if cv2.contourArea(contour) < 1000:
continue
status = 1 #change in status when the object is detected
#Creating a rectangular box around the object in frame
(x,y,w,h) = cv2.boundingRect(contour)
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),3)
#list of status for every frame
status_list.append(status)
status_list=status_list[-2:]
#Record datetime in a list when change occurs
if status_list[-1]==1 and status_list[-2]==0:
times.append(datetime.now())
if status_list[-1]==0 and status_list[-2]==1:
times.append(datetime.now())
cv2.imshow('frame',frame)
#cv2.imshow('Capturing',gray)
#cv2.imshow('delta',delta_frame)
#cv2.imshow('thresh',thresh_delta)
key = cv2.waitKey(1) #changing the frame after 1 millisecond
#Used for terminating the loop once 'q' is pressed
if key == ord('q'):
break
print(status_list)
print(times)
for i in range(0,len(times),2):
df = df.append({"Start":times[i],"End":times[i+1]},ignore_index=True)
df.to_csv("Times.csv")
video.release()
cv2.destroyAllWindows #will be closing all the windows
Try this:
if cv2.waitKey(1) & 0xFF == ord('q'):
break
For a brief explanation about what "& 0xFF" is, see: What's 0xFF for in cv2.waitKey(1)?
It is basically a bit mask that takes the portion of 'waitKey' value(32 bit) that can be compared to ASCII (8 bit).
You can try this.
k = cv2.waitKey(1) & 0xFF
if k == 27 :
break
where k can be any ASCII code on the keyboard ASCII code help
In this case 27 is 'Esc' button.
However, the problem you're having where it is freezing, have you tried continuously pressing any button besides q? I had a similar problem when I was testing out OpenCV's tutorial code here
but i figured it out by playing around and then realizing i needed to hold down any button besides the 'exit' button.
I had faced the same issue bcz of this piece of code from geeksforgeeks
Please chck the last line of the code:
cv2.destroyAllWindows #will be closing all the windows
Add parenthesis, it shud b:
cv2.destroyAllWindows()
Please try this, rest looks fine
Well you can also pass a particular frame that you want to close like:
cv2.destroyAllWindows("frame")

Categories