So I've been messing around with opencv, and am trying to figure out how to capture an image on a mouse click. I've looked around a bit, but I just can't seem to find an answer. Here's the code that I have so far.
import numpy as np
import cv2
def captureFrame(event,frame):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.imwrite('pictures/testFrame.png',frame) # want to save frame here
def main():
cv2.setMouseCallback('frame',captureFrame)
cap = cv2.VideoCapture(0)
cv2.namedWindow('frame',cv2.CV_WINDOW_AUTOSIZE)
while(True):
ret, frame = cap.read()
if ret:
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
The problem is that I want to pass the frame to the callback function captureFrame, but I'm not sure how to do that. Thanks!
Okay. So I figured out how to do this and I'm posting the fix below.
import numpy as np
import cv2
def main():
cap = cv2.VideoCapture(0)
cv2.namedWindow('frame',cv2.CV_WINDOW_AUTOSIZE)
count = 1
while(True):
ret, frame = cap.read()
cv2.setMouseCallback('frame',captureFrame,frame)
if ret:
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
def captureFrame(event,x,y,flags,frame):
if event == cv2.EVENT_LBUTTONDBLCLK:
cv2.imwrite('pictures/test.png',frame) # want to save frame here
if __name__ == "__main__":
main()
However, it is pretty unresponsive (as in I have to click multiple times to get a saved image, this may be because of a bad mouse though and i'll have to test that at a later time) and I haven't figured out why just yet. If anyone can explain why please do!
Related
I am creating a GUI application (EXE) in Python 2.7 on Win 10 platform.
The application is supposed to plot a graph (using matplotlib) with user provided parameters. When the user changes the values and presses the plot button again, new graph should be plotted on the same figure retaining the previous curves for ease of comparison (also a requirement).
I had to use plt.show() at the end of the script to show the graph when running the exe file of my program.
Problem: Application freezes and crashes when the plot button is pressed the second time. For the first time, everything goes fine and the graph is displayed.
Solutions tried:
Going thru so many threads, I tried following solutions without luck:
Used plt.draw() instead of plt.show() because the later blocks program execution. But draw() does not display the graphs.
Tried plt.pause(), the application gives RunTime error and crashes.
Also played with ion() / ioff().
Tried plt.show(block = False), the application crashes on second click on plot button.
I came across various backends that can be used with matplotlib and suspected that plt.show() might work well with other backends. Tried TkAgg, WxAgg, and others but no luck.
I would really appreciate if someone can help me with this...already tried for 3 days!!
Code sample:
from PyQt4 import QtCore, QtGui
import numpy as np
import matplotlib
matplotlib.use('TkAgg') #Trying different backends
import matplotlib.pyplot as plt
plt.rc('xtick', labelsize = 16)
plt.rc('ytick', labelsize = 16)
import FileDialog #These three imports needed for EXE
import tkFileDialog
import tkMessageBox
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
#UI elements code...
def retranslateUi(self, MainWindow):
#Other code lines
def my_Plot_Function():
#Some calculations
plt.figure('My title')
plt.plot(x, y, label = 'My Label')
plt.grid(True)
plt.axhline(y = 0, color = 'k')
plt.xlabel(' X ', fontsize = 16)
plt.ylabel(' Y ', fontsize = 16)
plt.legend(prop={'size': 14})
plt.show()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I am trying to save the mouse hover positions in a given video. I need to load the video on a 'Load Video' button press. When the mouse is outside the canvas no (x,y) should be saved. I also want the video to streamed at much lower rate (say, 4 times slower). Presently, I have the following code:`
import Tkinter as tk
from Tkinter import *
import PIL.Image,PIL.ImageTk
import time
import cv2
class App:
def __init__(self, window, window_title, video_source=0):
self.window = window
self.window.title(window_title)
self.video_source = video_source
self.video_loaded=False
# open video source (by default this will try to open the computer webcam)
self.vid = MyVideoCapture(self.video_source)
# Create a canvas that can fit the above video source size
self.canvas = tk.Canvas(window, width = self.vid.width, height =
self.vid.height)
self.canvas.pack()
self.canvas.bind('<Motion>',self.canvas.motion)
#self.canvas.bind("<Enter>", self.on_enter)
#self.canvas.bind("<Leave>", self.on_leave)
# Button that lets the user take a snapshot
self.btn_snapshot=tk.Button(window, text="Snapshot", width=50,
command=self.snapshot)
self.btn_snapshot.pack(anchor=tk.CENTER, expand=True)
self.btn_collapse=tk.Button(window, text="Collapse", width=50,
command=self.collapse)
self.btn_collapse.pack(anchor=tk.CENTER, expand=True)
self.btn_load_video=tk.Button(window, text="Load Video", width=50,
command=self.load_video)
self.btn_load_video.pack(anchor=tk.CENTER, expand=True)
#if self.video_loaded==True:
# After it is called once, the update method will be automatically
called every delay milliseconds
self.delay = 15
self.update()
self.window.mainloop()
def load_video(self):
# open video source (by default this will try to open the computer
webcam)
self.vid = MyVideoCapture(self.video_source)
self.video_loaded=True
def snapshot(self):
# Get a frame from the video source
ret, frame = self.vid.get_frame()
if ret:
cv2.imwrite("frame-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg",
cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
def collapse(self):
self.window.quit()
def motion(self):
self.x=self.canvas.winfo_pointerx
self.y=self.canvas.winfo_pointery
print('{},{}'.format(self.x, self.y))
#self.canvas.itemconfigure(text='({x},{y})'.format(x = self.x,
y=self.y))
#print('{},{}'.format(self.x, self.y))
#def motion(self):
# x, y = self.x, self.y
# print('{}, {}'.format(x, y))
#def on_enter(self, event):
# self.l2.configure(text="Hello world")
#def on_leave(self, enter):
# self.l2.configure(text="")
def update(self):
# Get a frame from the video source
ret, frame = self.vid.get_frame()
if ret:
self.photo = PIL.ImageTk.PhotoImage(image =
PIL.Image.fromarray(frame))
self.canvas.create_image(0, 0, image = self.photo, anchor = tk.NW)
self.window.after(self.delay, self.update)
class MyVideoCapture:
def __init__(self, video_source=0):
# Open the video source
video_source='./videofilename.wmv'
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
# Get video source width and height
self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
def get_frame(self):
if self.vid.isOpened():
ret, frame = self.vid.read()
if ret:
# Return a boolean success flag and the current frame converted
to BGR
return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
else:
return (ret, None)
else:
return (ret, None)
# Release the video source when the object is destroyed
def __del__(self):
if self.vid.isOpened():
self.vid.release()
# Create a window and pass it to the Application object
root = tk.Tk()
App(root, "Tkinter and OpenCV")
When I run this, I get the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/home/anaconda2/envs/my_env/lib/python2.7/lib-tk/Tkinter.py", line
1541, in __call__
return self.func(*args)
TypeError: motion() takes exactly 1 argument (2 given)
I want the function motion() to return the mouse hover positions. Appreciate help. Thanks in advance.
Here is the link from which the I got the main code.
The bind() function sends an event object to the callback function, but the motion() function only accepts self. Try:
def motion(self, event):
self.x=event.x
self.y=event.y
Binding the function for saving mouse positions can be done as in teh example below.
from tkinter import *
root = Tk()
root.geometry('300x200+800+50')
c = Canvas(root, bg='tan')
c.pack(fill='both', expand='yes')
def motion(event):
if follow:
print(event.x, event.y)
follow = False
def follow_motion(event):
global follow
follow = not follow
c.bind('<Motion>', motion)
c.bind('<Button-1>', follow_motion)
root.mainloop()
Click the left mouse button on the canvas and the function motion() is enabled. One more click disables it.
please im working on using face detection as a captcha system. how do i make the system print an error message if a face is not detected in the webcam. and also make the number of attempts to detect a face is 3 such that after 3 attempts it closes in python
from Tkinter import *
import numpy as np
import cv2
import Tkinter as tk
import tkMessageBox
import random
import webbrowser
def Request_1(event):
#messagebox gestures
trials = 0
while trials<3:
tkMessageBox.showinfo("ATTENTION!!!", "press letter a when you see the yellow box on your nose")
#this aspect is to generate random requests for the captcha system
detector2= cv2.CascadeClassifier('haarcascade_mcs_nose.xml')
cap = cv2.VideoCapture(0)
access = True
while(access):
#reads the image
ret2, img2 = cap.read()
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# Detect faces in the image . the image is read and convertedd to grayscale
faces2 = detector2.detectMultiScale(gray2, 1.3, 5)
if(len(faces2)!=0):
for (x,y,w,h) in faces2:
cv2.rectangle(img2,(x,y),(x+w,y+h),(0,255,255),1)
cv2.imshow('frame',img2)
break
if cv2.waitKey(1) & 0xFF == ord('a'):
#grant access to webpage
cap.release()
cv2.destroyAllWindows()
new=2
url="file:///C:/Users/jayrush/Desktop/lmarku/index.html";
webbrowser.open(url, new=new);
break
if(len(faces2)==0):
trials=trials+1
print("Access Denied")
#defining the interface of the captcha
#INTERFACE
root = Tk()
root.title("Face Detection CAPTCHA")
root.geometry("350x50")
bottomFrame = Frame(root)
bottomFrame.pack()
button_1 = Button(bottomFrame, fg="blue", text="I am not a robot")
button_1.bind("<Button-1>", Request_1)
button_1.pack()
status = Label(root, fg="red", text="Starting captcha...", bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)
root.mainloop()
I use library pygame in python to stream video from webcam of RasberryPi to my computer.
But I have a problem when receive image. It's not convert true image.
I've replaced my cam's ip adress with a placeholder <my_ip>.
This is my code:
Server:
import socket,os
from PIL import *
import pygame,sys
import pygame.camera
from pygame.locals import *
#Create server:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((<my_ip>,5000))
server.listen(5)
#Start Pygame
pygame.init()
pygame.camera.init()
screen = pygame.display.set_mode((320,240))
cam = pygame.camera.Camera("/dev/video0",(320,240),"RGB")
cam.start()
#Send data
while True:
s,add = server.accept()
print "Connected from",add
image = cam.get_image()
screen.blit(image,(0,0))
data = cam.get_raw()
s.sendall(data)
pygame.display.update()
#Interupt
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
Client:
import socket,sys
import pygame
from PIL import Image
#Create a var for storing an IP address:
ip = <my_ip>
#Start PyGame:
pygame.init()
screen = pygame.display.set_mode((320,240))
pygame.display.set_caption('Remote Webcam Viewer')
font = pygame.font.SysFont("Arial",14)
clock = pygame.time.Clock()
timer = 0
previousImage = ""
image = ""
#Main program loop:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#Receive data
if timer < 1:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((str(ip),5000))
data = client_socket.recv(1024000)
timer = 30
else:
timer -= 1
previousImage = image
#Convert image
try:
image = Image.fromstring("RGB",(120,90),data)
image = image.resize((320,240))
image = pygame.image.frombuffer(image.tostring(),(320,240),"RGB")
#Interupt
except:
image = previousImage
output = image
screen.blit(output,(0,0))
clock.tick(60)
pygame.display.flip()
But this is result after tranfer:
You are reassembling an image from the raw data received, but because you are sending a bigger resolution that you are re-creating, the pixels are 'overflowing' creating this effect.
the offending line is:
image = Image.fromstring("RGB",(120,90),data)
which should be:
image = Image.fromstring("RGB",(320,240),data)
*Not tested but should work.
I've taken the code to draw a rectangle over image form here, and modified it a little bit to suite my purposes. The only problem I have, it doesn't appear to be full screen, even though I make fr.ShowFullScreen(True). There is a grey area around the image.
Edited code is below (the rectangle part is not relevant):
# Use the wxPython backend of matplotlib
import matplotlib
matplotlib.use('WXAgg')
# Matplotlib elements used to draw the bounding rectangle
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
# wxPython stuff for the demo
import wx
class RectangleSelectImagePanel(wx.Panel):
def __init__(self, parent, pathToImage=None):
# Initialise the parent
wx.Panel.__init__(self, parent)
# Intitialise the matplotlib figure
self.figure = Figure(figsize=(20,15), dpi=80)
# Create an axes, turn off the labels and add them to the figure
self.axes = self.figure.add_subplot(1, 1, 1)
self.axes.set_axis_off()
# Add the figure to the wxFigureCanvas
self.canvas = FigureCanvas(self, -1, self.figure)
# Sizer to contain the canvas
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 0, wx.ALL)
self.SetSizer(self.sizer)
self.Fit()
def setImage(self, pathToImage):
'''Sets the background image of the canvas'''
import matplotlib.image as mpimg
# Load the image into matplotlib
image = matplotlib.image.imread(pathToImage)
# left in as anchor for image size
self.imageSize = image.shape[0:2]
print self.imageSize
#
# Add the image to the figure and redraw the canvas. Also ensure the aspect ratio of the image is retained.
self.axes.imshow(image, interpolation="quadric", aspect='auto')
self.canvas.draw()
if __name__ == "__main__":
# Create an demo application
app = wx.App()
# Create a frame and a RectangleSelectorPanel
fr = wx.Frame(None, title='test')
panel = RectangleSelectImagePanel(fr)
# Set the image in the panel
from matplotlib.cbook import get_sample_data
imgpath = get_sample_data('logo2.png', asfileobj=False)
panel.setImage(imgpath)
# Start the demo app
fr.ShowFullScreen(True)
app.MainLoop()
probably what you need is subplots_adjust.
from pylab import *
from matplotlib.cbook import get_sample_data
imgpath = get_sample_data('logo2.png', asfileobj=False)
image = matplotlib.image.imread(imgpath)
imshow(image, aspect='auto')
subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
This will produce a plot that has no margin around the image.
So, if you put
self.figure.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
after imshow line, you will get something closer to what you need.
Then, you will probably have to adjust the figsize parameter too. for my 1920 x 1080 display, I will need 1920.0/80 inch by 1080.0/80 inch so (24,13.5)