I'm trying to pass a frame read from a camera using opencv as an argument to another python script but I cannot get it to work.
Running the following script stores a camera frame on my network every 5 seconds:
#!/usr/bin/python
import cv2
import threading
import subprocess
import time
import datetime
def camera():
camera = cv2.VideoCapture("/dev/video0")
if not camera.isOpened():
print("Cannot open camera.")
raise SystemExit
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 320)
camera.set(cv2.CAP_PROP_FPS, 15)
return camera
try:
camera = camera()
while True:
frame = camera.read()[1]
#subprocess.call(["python", "/home/user/test2.py", frame])
server = "/net/192.168.4.51/mnt/LAN4Storage/EC/Camera/"
cv2.imwrite(server "temp.jpg", frame)
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cv2.imwrite(server timestamp ".jpg", frame)
time.sleep(5)
except Exception as error:
print(error)
finally:
camera.release()
If I uncomment the subprocess.call line and comment the next 4 lines I expect the frame to be passed to my test2.py script:
`
#/usr/bin/env python
import cv2
import sys
import os
import time
import datetime
try:
frame = cv2.imread(sys.argv[1])
server = "/net/192.168.4.51/mnt/LAN4Storage/EC/Camera/"
cv2.imwrite(server "temp.jpg", frame)
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cv2.imwrite(server timestamp ".jpg", frame)
except Exception as error:
print(error)
finally:
pass
` But on starting test1.py, I get the following error:
`expected str, bytes or os.PathLike object, not ndarray`
CodePudding user response:
There seem to be a couple of misconceptions here that are leading things astray...
You can't sensibly pass images (i.e. their complete pixel data) as command-line arguments/parameters. They are generally too long and may contain nulls.
It is grossly inefficient to think about writing an image for every frame of a video. That's actually why we have video - because we can difference and do motion vectors between frames to enable better compression.
You can write an image file to RAM without causing wear to an SD card.
In light of what I understand so far, I would suggest either:
- writing your image to a
tmpfs
filesystem, a.k.a. RAM drive, or - look at this answer, and write the images to Redis where you can pick them up from any machine or process in your network, using Python, C/C , Ruby or bash scripts.
Note that if you use the file-based approach and unsynchronised access from multiple processes, you may get corruption if a file is overwritten during a read. One way to avoid this is to leverage the fact that renames are atomic. So, write the image to a file called something like InProgress.jpg
and when complete, rename InProgress.jpg
as Latest.jpg
and let readers always read Latest.jpg
. That way readers will always get one of the two files and never two inconsistent halves of different versions.
Also, bear in mind Dan's comment about buffering. More material here.
CodePudding user response:
the frame object is a ndarray, you need to convert to string. if you do:
subprocess.call(["python", "/home/user/test2.py", frame.tostring()]) should work.
but you shouldn't use cv2.imread, because you are not reading the image from a file, you are reading froma string in command
So you should use
frame = np.fromstring(sys.argv[1])
i'm not sure if the conversion from ndarray to string and in the other way work fine, probabbly you need to adjust the parameters