I am familiar with programming but not with python or linux. I am programming in python on a raspberry pi trying to create a security camera. Here is my code to test my current problem:
#!/usr/bin/python
import pygame, sys
from pygame.locals import *
from datetime import datetime
import pygame.camera
import time
pygame.init()
pygame.camera.init()
width = 640
height = 480
pic_root = "/root/cam/"
cam = pygame.camera.Camera("/dev/video0",(width,height),"RGB")
cam.start()
while True:
raw_input("press enter")
image = cam.get_image()
filename = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") +'.jpg'
filepath = pic_root+filename
pygame.image.save(image, filepath)
So when I press enter, an image is taken from the webcam and saved. But the image is always two images behind. No matter how long in between saving images, the first two are always very dim as if the webcam has just started up, then the rest are always two images late.
So if I took 5 images, one with one finger up, then next with two fingers, etc, I would end up with two dark images and then the first three images. 1,2 and 3 fingers. It is as if the images are being stored somewhere then when I try to save a live images it pulls up an old one.
Am I missing something here? What's the issue?
First, I'm not familiar with Pygame (but I do a lot of snapshot capturing with OpenCV -- here's one of my projects: http://vmlaker.github.io/wabbit.)
I changed your code so that on every iteration, you 1) start, 2) take snapshot, and 3) stop the camera. This works a little better, in that it is only one image behind (instead of two.) It's still pretty weird how the old image sticks around from the previous run... I haven't figured out how to flush the camera. Notice I also changed pic_root, and instead of the infinite loop I'm using 3 iterations only:
from datetime import datetime
import pygame
import pygame.camera
pygame.init()
pygame.camera.init()
width = 640
height = 480
pic_root = './'
cam = pygame.camera.Camera("/dev/video0",(width,height),"RGB")
#cam.start()
for ii in range(3):
raw_input("press enter")
cam.start()
image = cam.get_image()
cam.stop()
filename = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") +'.jpg'
filepath = pic_root+filename
pygame.image.save(image, filepath)
The OP's comment helped, but I actually have to pull the picture three times with get_image() before saving.
I also have a wakeup function which I call after a long standby time to wake the camera. Mine has the behavior to be black after a long time.
I guess, all this weird stuff has something to do with a buffer. But the multiple call did the trick for me.
Related
i've got a problem in python :
import pyautogui as a
while True:
pixel = a.locateOnScreen("example.png")
if pixel == None: continue
pixel = a.center(pixel)
data = [pixel.x , pixel.y]
a.moveTo(data[0],data[1])
in this code it finds the picture and move the mouse on it but its to slow because every time loop start from beginning it loads the file and it makes it too slow.
i want it to work lively.
i tried:
import pyautogui as a
from IPython.display import Image
f = Image("example.png")
while True:
pixel = a.locateOnScreen(f)
pixel = a.center(pixel)
data = [pixel.x , pixel.y]
a.moveTo(data[0],data[1])
but it says image don't have attribute named mode
I want to place pointer on the center of picture
You use IPython.display.Image object, but that is the wrong one. Use PIL.Image instead:
import pyautogui as a
from PIL import Image
f = Image.open("example.png")
while True:
pixel = a.locateOnScreen(f)
pixel = a.center(pixel)
data = [pixel.x , pixel.y]
a.moveTo(data[0],data[1])
I confirmed this works with pyautogui version 0.9.53
That said, I don't think that the loading of the image is your performance bottleneck here, but rather the search algorithm itself. Pyautogui's documentation states that locateOnScreen can take some time. You can try to search a smaller region on the screen. Citing:
These “locate” functions are fairly expensive; they can take a full
second to run. The best way to speed them up is to pass a region
argument (a 4-integer tuple of (left, top, width, height)) to only
search a smaller region of the screen instead of the full screen:
import pyautogui
pyautogui.locateOnScreen('someButton.png', region=(0,0, 300, 400))
I have a webcam that captures something I want to be able to monitor live. Every 30 seconds an operation needs to be done on the most recent frame of the video. To do this, I've set up a cv2.NamedWindow() in a daemon thread that allows me to see the webcam feed. Then using a scheduler, I can do the operation I need every 30 seconds. The problem is, the camera feed will randomly go black, and save an all black image. Sometimes this happens after 15 minutes of operation, sometimes after 4 hours of operation., so it's very inconsistent and there seems to be no pattern. Here is the code:
import time
import gc
import cv2
import threading
import schedule
import numpy
class operator():
def __init__(self):
print("Start")
def start_cam(self):
is_blurry = True
while is_blurry == True:
print("Start of start_cam")
self.camera = cv2.VideoCapture(0, cv2.CAP_DSHOW) # Make camera object with correct format, size, and autofocus. All of these appear to be necessary to get 4K resolution in OpenCV
self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 3840) #3840
self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 2160) #2160
self.camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('m','j','p','g'))
self.camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M','J','P','G'))
self.camera.set(cv2.CAP_PROP_AUTOFOCUS, 1)
self.camera.set(cv2.CAP_PROP_FPS, 60)
i=10
while i>0: # Takes 10 pictures and waits 1 sec in between each. This is done to make sure it has time to autofocus
i=i-1
cv2.waitKey(1000) #1000
ret, self.frame = self.camera.read()
if ret != True:
print("image error") # Check to make sure it actually took a picture and didn't fail
if ret != True and i == 1:
restart_loop = True
print("Image error, restarting loop") #
continue
laplace = cv2.Laplacian(self.frame, cv2.CV_64F).var() # Checks if image is blurry. If it is, it restarts the camera.
print(laplace)
if laplace < 20: # Blurry
print("Blurry image, reinitializing")
self.camera.release()
del(self.camera)
cv2.destroyAllWindows()
gc.collect()
time.sleep(2)
else:
print("image not blurry")
break
def live_loop(self):
loop_bool = True
cv2.namedWindow("Live Feed", cv2.WINDOW_NORMAL) # Creates a normal window so that the 4k image is scaled correctly for the live feed (I have a relatively small monitor)
while loop_bool == True:
ret, self.frame = self.camera.read()
if ret != True:
print("image error")
break
self.frame_rotate = cv2.rotate(self.frame, cv2.ROTATE_180)
cv2.imshow("Live Feed", self.frame_rotate)
k = cv2.waitKey(10)
gc.collect()
def data_operation(self):
print("Start data operation")
imgpath = "path where image is saved"
cv2.imwrite(imgpath, self.frame)
t = time.localtime() # If the image can't be read as a number, saves the image with a timestamp so that it can be examined later
timestamp = time.strftime('%b-%d-%Y_%H;%M', t)
print(timestamp)
if __name__== "__main__":
op = operator()
op.start_cam()
x = threading.Thread(target=op.live_loop, daemon = True)
x.start()
schedule.every(30).seconds.do(op.data_operation)
try:
while True:
schedule.run_pending()
time.sleep(1)
except KeyboardInterrupt:
print("Ended Program")
gc.collect()
This is the smallest amount of code I can reproduce the issue with. There is more going on just this, but this code block has been run and the issue persists. I have found that when I remove the line that saves the image in the data_operation function, which is the cv2.imwrite(imgpath, self.frame), the program seems to work and the camera never goes black and the issue is gone. So I think that is the problem, but I don't know how else to save the frame as an image every 30 seconds while also keeping the live feed up and running. As far as I know, the rest of the code works perfectly except for this, and I do need to be able to save and access the image.
I am not a programmer by trade so I've just been figuring this out as I go. If something is glaringly stupid let me know. If there is a much easier/safer way to display a live webcam feed while also automatically grabbing a picture every 30 seconds and doing stuff with that picture while keeping the live loop going, I would be happy to hear that too.
Any help would be appreciated, and let me know if you have further questions.
EDIT: I have updated the code to simplify and continue shrinking the smallest reproduceable sample. I realized the start_cam function was unnecessary, as all of the cv2 initialization can be done at the start of the live_loop function. The issue persists. I have tried adding a mutex, however that seems to not help (though it's possible I am implementing it wrong). Any info or working examples would be greatly appreciated.
EDIT 2: Another thing to note is that the exact same program running on my laptop (using the built-in webcam rather than the 4k Logitech Brio) doe not seem to have the same issue. Is the frame rate or resolution causing the issue perhaps? Testing is difficult since I need to keep a working program running while working on this one, but I will do more tests when I am able and keep this post updated if anything develops. Still, feel free to toss any ideas you have to me.
I am working on a project where we are using the Raspicam attached to a Raspberry Pi to capture (and process) images with python using the PiCamera module.
With our current implementation I am experiencing an unexpected behaviour.
The camera is configured to capture images with 15 frames per second. To simulate processing time the program waits 5 seconds.
Minimal example:
#!/usr/bin/env python
import cv2
from picamera import PiCamera
from picamera.array import PiRGBArray
class RaspiCamera:
def __init__(self, width, height, framerate):
self.camera = PiCamera()
self.camera.resolution = (width, height)
self.camera.framerate = framerate
self.rawCapture = PiRGBArray(self.camera, size=self.camera.resolution)
self.capture_continuous = self.camera.capture_continuous(self.rawCapture, format="bgr", use_video_port=True)
def capture(self):
frame = self.capture_continuous.next()
image = self.rawCapture.array
self.rawCapture.truncate(0)
return image
if __name__ == "__main__":
camera = RaspiCamera(640, 480, 15)
while True:
frame = camera.capture()
cv2.imshow("Image", frame)
if cv2.waitKey(5000) & 0xFF == ord('q'):
break
When capture() is called for the first time, self.capture_continuous.next() returns an up to date image. When calling capture() consecutively, it often happens that self.capture_continuous.next() does not return the latest image but one that is already a few seconds old (verified by pointing the camera at a clock). From time to time, it's even older than 10 seconds. On the other hand, sometimes self.capture_continuous.next() actually returns the latest image.
Since capture_continuous is an object of the type generator, my assumption is that it keeps generating camera images in the background that accumulate in a queue while the program waits and on the next call of self.capture_continuous.next() the next element in the queue is returned.
Anyway, I am only interested in the latest, most up to date image the camera has captured.
Some first attempts to get hold of the latest images failed. I tried to call self.capture_continuous.next() repeatedly in a while loop to get to the latest image.
Since a generator is apparently also an iterator I tried some methods mentioned in this post: Cleanest way to get last item from Python iterator.
Simply using the capture() function of the PiCamera class itself is not an option since it takes approx. 0.3 seconds till the image is captured what is too much for our use case.
Does anyone have a clue what might cause the delay described above and how it could be avoided?
I want to create a webcam streaming app that records webcam stream for, say about 30 seconds, and save it as myFile.wmv. Now To get live camera feed I know this code :-
import cv2
import numpy as np
c = cv2.VideoCapture(0)
while(1):
_,f = c.read()
cv2.imshow('e2',f)
if cv2.waitKey(5)==27:
break
cv2.destroyAllWindows()
But I have no idea off how to record for a given number of seconds and save it as a file in its current directory,
Please someone point me to the right direction
Thanks
ABOUT TIME
Why do not use the python time function? In particular time.time() Look at this answer about time in python
NB OpenCV should have (or had) its own timer but I can not tell you for sure if it works in current versions.
ABOUT RECORDING/SAVING
Look at this other answer
OpenCV allows you to record video, but not audio. There is this script I came across from JRodrigoF that uses openCV to record video and pyaudio to record audio. I used it for a while on a similar project; however, I noticed that sometimes the threads would hang and it would cause the program to crash. Another issue is that openCV does not capture video frames at a reliable rate and ffmpeg would distort the video when re-encoding.
https://github.com/JRodrigoF/AVrecordeR
I came up with a new solution that records much more reliably and with much higher quality. It presently only works for Windows because it uses pywinauto and the built-in Windows Camera app. The last bit of the script does some error-checking to confirm the video successfully recorded by checking the timestamp of the name of the video.
https://gist.github.com/mjdargen/956cc968864f38bfc4e20c9798c7d670
import pywinauto
import time
import subprocess
import os
import datetime
def win_record(duration):
subprocess.run('start microsoft.windows.camera:', shell=True) # open camera app
# focus window by getting handle using title and class name
# subprocess call opens camera and gets focus, but this provides alternate way
# t, c = 'Camera', 'ApplicationFrameWindow'
# handle = pywinauto.findwindows.find_windows(title=t, class_name=c)[0]
# # get app and window
# app = pywinauto.application.Application().connect(handle=handle)
# window = app.window(handle=handle)
# window.set_focus() # set focus
time.sleep(2) # have to sleep
# take control of camera window to take video
desktop = pywinauto.Desktop(backend="uia")
cam = desktop['Camera']
# cam.print_control_identifiers()
# make sure in video mode
if cam.child_window(title="Switch to Video mode", auto_id="CaptureButton_1", control_type="Button").exists():
cam.child_window(title="Switch to Video mode", auto_id="CaptureButton_1", control_type="Button").click()
time.sleep(1)
# start then stop video
cam.child_window(title="Take Video", auto_id="CaptureButton_1", control_type="Button").click()
time.sleep(duration+2)
cam.child_window(title="Stop taking Video", auto_id="CaptureButton_1", control_type="Button").click()
# retrieve vids from camera roll and sort
dir = 'C:/Users/michael.dargenio/Pictures/Camera Roll'
all_contents = list(os.listdir(dir))
vids = [f for f in all_contents if "_Pro.mp4" in f]
vids.sort()
vid = vids[-1]
# compute time difference
vid_time = vid.replace('WIN_', '').replace('_Pro.mp4', '')
vid_time = datetime.datetime.strptime(vid_time, '%Y%m%d_%H_%M_%S')
now = datetime.datetime.now()
diff = now - vid_time
# time different greater than 2 minutes, assume something wrong & quit
if diff.seconds > 120:
quit()
subprocess.run('Taskkill /IM WindowsCamera.exe /F', shell=True) # close camera app
print('Recorded successfully!')
win_record(2)
I need to take a single snapshot from webcam. I choice SimpleCV for this task.
Now i try to get a single image and show it:
from SimpleCV import Camera
cam = Camera()
img = cam.getImage()
img.show()
But i see only black image. I think camera is not ready at this moment, because if I call time.sleep(10) before cam.getImage() all works good.
What the right way for this? Thank you!
Have you installed PIL? I had similar problems, but on installing PIL everything works fine. Hope this helps.
You can download PIL from Pythonware
I ran into this same issue and came up with the following work-around. Basically it grabs an image, tests the middle pixel to see if it's black (0,0,0). If it is, then it waits 1 second and tries again.
import time
from SimpleCV import Camera
cam = Camera()
r = g = b = 0
while r + g + b < 0.01:
img = cam.getImage()
r, g, b = img[img.width/2, img.height/2]
print("r: {} g: {} b: {}".format(r,g,b))
time.sleep(1)
img.save(file_name)
Your problem may be that when the script ends the camera object doesn't seem to release the webcam for other programs. When you wait to run the script Windows frees it up (maybe?) so it will work again. If you use it will the old script still thinks it owns the webcam, it shows up as black. Anyway the solution here seems to work. Add "del cam" to the end of your script which will make the camera object go away and let you use the camera again.
try this
from SimpleCV import Camera
cam = Camera(0)
while True:
img = cam.getImage()
img.show()