super slow opencv cv2.VideoCapture('rtsp://) python - python

im trying to read a IP camera stream trought rtps.
I can open the stream inside opencv but its stremly slow and its generating a huge delay from real movement and screen movment.
there is my code ( its simple )
import cv2
stream = cv2.VideoCapture('rtsp://root:root#192.168.0.2/media.amp')
while True:
frame = stream.read()
cv2.imshow("Frame",frame)
cv2.waitKey(1)

Related

I am trying to capture still images from RTSP feed in Python; however the image keeps 'hanging/freezing'

So I've been scouring GitHub looking for answers but haven't yet found the solution, so I will be grateful for any help!
I am trying to make a DIY trail camera; and I have an IP camera providing me an RTSP feed, I want to capture this feed and take photos based on a PIR motion sensor (HC-SR50);
I am running this off a raspberry PI remotely; However the image is stuck on the first frame, and saves the first image from RTSP feed; and then saves and outputs the same image over and over; whilst imshow() shows the live feed fine (this is commented out below asit was interrupting the code)
I figured out that when I do imshow() it was alsostuck- and managed to resolve this by searching this site; (see code)
I am using the TAPO cameras.
the issue seems to be in the While loop where the pir_wait_for_motion begins;
thanks in advance for any help!!
from gpiozero import MotionSensor
import cv2
from datetime import datetime
import time
import getpass
**SO THIS PART WORKS OK
**
rtsp in
rtsp_url = 'rtsp://user:pass#IP/stream2'
#vlc-in
#output
writepath = "OUTPUTPATH"
pir = MotionSensor(4)
cap = cv2.VideoCapture(rtsp_url)
frameRate = cap.get(5)
Just to show that the RTSP feed was working, all ok so commented out for now as it blocked the rest of the code from running. (Below) So this part isn't so necessary for now.
- while cap.isOpened():
- flags, frame = cap.read()
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
- cv2.startWindowThread()
- cv2.imshow('RGB OUTPUT', gray)
- key = cv2.waitKey(1)
- cv2.destroyAllWindows()
The below part is where the problem seems to be, however I can't figure out how to keep the frames moving from RTSP feed.
#Image Capture while cap.isOpened():
pir.wait_for_motion()
print("Motion")
ret, frame = cap.read()
if (ret != True):
break
cc1 = datetime.now()
c2 = cc1.strftime("%Y")
c3 = cc1.strftime("%M")
c4 = cc1.strftime("%D")
c5 = cc1.strftime("%H%M%S")
hello = "image"+c2+c3+c5
hellojoin = "".join(hello.split())
#photo write
cv2.imwrite(f'{writepath}/{hellojoin}.png', frame)
print("image saved!")
pir.wait_for_no_motion()
cap.release() cv2.destroyAllWindows()
I wanted a PIR motion sensor to capture images from RTSP based on activity infront of sensor; basically acting as a trail camera/camera trap would.

OpenCV & Python - Real time image (frame) processing

We're doing a project in school where we need to do basic image processing. Our goal is to use every video frame for the Raspberry Pi and do real time image processing.
We've tried to include raspistill in our python-program but so far nothing has worked. The goal of our project is to design a RC-car which follows a blue/red/whatever coloured line with help from image processing.
We thought it would be a good idea to make a python-program which does all image processing necessary, but we currently struggle with the idea of bringing recorded images into the python program. Is there a way to do this with picamera or should we try a different way?
For anyone curious, this is how our program currently looks
while True:
#camera = picamera.PiCamera()
#camera.capture('image1.jpg')
img = cv2.imread('image1.jpg')
width = img.shape[1]
height = img.shape[0]
height=height-1
for x in range (0,width):
if x>=0 and x<(width//2):
blue = img.item(height,x,0)
green = img.item(height,x,1)
red = img.item(height,x,2)
if red>green and red>blue:
OpenCV already contains functions to process live camera data.
This OpenCV documentation provides a simple example:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Of course, you do not want to show the image but all your processing can be done there.
Remember to sleep a few hundred milliseconds so the pi does not overheat that much.
Edit:
"how exactly would I go about it though. I used "img = cv2.imread('image1.jpg')" all the time. What do I need to use instead to get the "img" variable right here? What do I use? And what is ret, for? :)"
ret indicates whether the read was successful. Exit program if not.
The read frame is nothing other than your img = cv2.imread('image1.jpg') so your detection code should work exactly the same.
The only difference is that your image does not need to be saved and reopened. Also for debugging purposes you can save the recorded image, like:
import cv2, time
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
if ret:
cv2.imwrite(time.strftime("%Y%m%d-%H%M%S"), frame)
cap.release()
You can use picamera to acquire images.
To make it "real time", you can acquire data each X milliseconds. You need to set X depending on the power of your hardware (and the complexity of the openCV algorithm).
Here's an example (from http://picamera.readthedocs.io/en/release-1.10/api_camera.html#picamera.camera.PiCamera.capture_continuous) how to acquire 60 images per second using picamera:
import time
import picamera
with picamera.PiCamera() as camera:
camera.start_preview()
try:
for i, filename in enumerate(camera.capture_continuous('image{counter:02d}.jpg')):
print(filename)
time.sleep(1)
if i == 59:
break
finally:
camera.stop_preview()

Sending OpenCV output to VLC stream

This has been keeping me busy for a good part of the afternoon and I haven't been able to get it to work but I feel like I'm really close.
I've got openCV set up which takes the videofeed from a webcam. To be able to access this video feed (with openCV overlay) I want to pipe the output of the openCV python script to a VLC stream. I managed to get the stream up and running and can connect to it. VLC resizes to the correct aspect ratio and resolution so it gets some correct data but the image I get is just Jitter;
python opencv.py | cvlc --demux=rawvideo --rawvid-fps=30 --rawvid-width=320 --rawvid-height=240 --rawvid-chroma=RV24 - --sout "#transcode{vcodec=h264,vb=200,fps=30,width=320,height=240}:std{access=http{mime=video/x-flv},mux=ffmpeg{mux=flv},dst=:8081/stream.flv}" &
The output of the script is a constant video feed sent to stdout as follows
from imutils.video import WebcamVideoStream
vs = WebcamVideoStream(src=0)
while True:
frame = vs.read()
sys.stdout.write(frame.tostring())
Above example is a dumbed down version of the script I'm using; Also as seen I'm making use of the imutils library; https://github.com/jrosebr1/imutils
If anyone could give me a nudge in the right direction I would appreciate it greatly. My guess is the stdout.write(frame.tostring()) is not what vlc expects but I haven't been able to figure it out myself.
The following works for me under Python 3
import numpy as np
import sys
import cv2
cap = cv2.VideoCapture(0)
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
sys.stdout.buffer.write(frame.tobytes())
else:
break
cap.release()
And the command line (my webcam has a different resolution, and I only display the result, but you did not have problems with that)
python opencv.py | vlc --demux=rawvideo --rawvid-fps=25 --rawvid-width=640 --rawvid-height=480 --rawvid-chroma=RV24 - --sout "#display"
Of course this requires a conversion from BGR to RGB as the former is default in OpenCV.
This worked for me, though I am sending to RTSP stream and not using imutils library:
import numpy as np
import sys
import cv2
input_rtsp = "rtsp://10.10.10.9:8080"
cap = cv2.VideoCapture(input_rtsp)
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
sys.stdout.write(frame.tostring())
else:
break
cap.release()
Then in command line:
python opencv.py | cvlc --demux=rawvideo --rawvid-fps=25 --rawvid-width=1280 --rawvid-height=720 --rawvid-chroma=RV24 - --sout "#transcode{vcodec=h264,vb=200,fps=25,width=1280,height=720}:rtp{dst=10.10.10.10,port=8081,sdp=rtsp://10.10.10.10:8081/test.sdp}"
Note that you do not need to convert opencv BGR to RGB.

Editing video frames on Raspberry Pi

I have the following code:
# Import packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
X_RESOLUTION = 640
Y_RESOLUTION = 480
# Initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (X_RESOLUTION, Y_RESOLUTION)
camera.framerate = 10
rawCapture = PiRGBArray(camera, size = (X_RESOLUTION, Y_RESOLUTION))
# Allow camera to warmup
time.sleep(0.1)
#Capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
# Grab the raw NumPy array representing the image
image = frame.array
# Show the frame
cv2.imshow("Frame", image)
key = cv2.waitKey(1) & 0xFF
# Clear the stream so it is ready to receive the next frame
rawCapture.truncate(0)
# If the 'q' key was pressed, break from the loop
if(key == ord('q')):
break
It is all fine and dandy. It captures video and displays it on my screen and it exits when I press 'q'. However, if I wanted to manipulate the frames somehow, say for example I wanted to set every pixels R value in each frame to 255 to make the image red. How would I do that?
My end goal is to write software that detects movement on a static background. I understand the theory and the actual data manipulation that needs to be done to make this happen, I just cant figure out how to access each frame's pixel data and operate on it. I attempted to change some values in 'image', but it says the array is immutable and cannot be written to, only read from.
Thanks for your time.
I have accessed each pixel{R,G,B values accessed separately } value randomly and have changed the value of it in the image. You can do it on an video by extracting each frame of it. It is implemented in c++ with opencv. Go through this link https://stackoverflow.com/a/32664968/3853072 you will get an idea.

Read Frames from RTSP Stream in Python

I have recently set up a Raspberry Pi camera and am streaming the frames over RTSP. While it may not be completely necessary, here is the command I am using the broadcast the video:
raspivid -o - -t 0 -w 1280 -h 800 |cvlc -vvv stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554/output.h264}' :demux=h264
This streams the video perfectly.
What I would now like to do is parse this stream with Python and read each frame individually. I would like to do some motion detection for surveillance purposes.
I am completely lost on where to start on this task. Can anyone point me to a good tutorial? If this is not achievable via Python, what tools/languages can I use to accomplish this?
Using the same method listed by "depu" worked perfectly for me.
I just replaced "video file" with "RTSP URL" of actual camera.
Example below worked on AXIS IP Camera.
(This was not working for a while in previous versions of OpenCV)
Works on OpenCV 3.4.1 Windows 10)
import cv2
cap = cv2.VideoCapture("rtsp://root:pass#192.168.0.91:554/axis-media/media.amp")
while(cap.isOpened()):
ret, frame = cap.read()
cv2.imshow('frame', frame)
if cv2.waitKey(20) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Bit of a hacky solution, but you can use the VLC python bindings (you can install it with pip install python-vlc) and play the stream:
import vlc
player=vlc.MediaPlayer('rtsp://:8554/output.h264')
player.play()
Then take a snapshot every second or so:
while 1:
time.sleep(1)
player.video_take_snapshot(0, '.snapshot.tmp.png', 0, 0)
And then you can use SimpleCV or something for processing (just load the image file '.snapshot.tmp.png' into your processing library).
use opencv
video=cv2.VideoCapture("rtsp url")
and then you can capture framse. read openCV documentation visit: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_video_display/py_video_display.html
Depending on the stream type, you can probably take a look at this project for some ideas.
https://code.google.com/p/python-mjpeg-over-rtsp-client/
If you want to be mega-pro, you could use something like http://opencv.org/ (Python modules available I believe) for handling the motion detection.
Here is yet one more option.
It's much more complicated than the other answers.
But this way, with just one connection to the camera, you could "fork" the same stream simultaneously to several multiprocesses, to the screen, recast it into multicast, write it to disk, etc.
Of course, just in the case you would need something like that (otherwise you'd prefer the earlier answers)
Let's create two independent python programs:
Server program (rtsp connection, decoding) server.py
Client program (reads frames from shared memory) client.py
Server must be started before the client, i.e.
python3 server.py
And then in another terminal:
python3 client.py
Here is the code:
(1) server.py
import time
from valkka.core import *
# YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
image_interval=1000
# define rgb image dimensions
width =1920//4
height =1080//4
# posix shared memory: identification tag and size of the ring buffer
shmem_name ="cam_example"
shmem_buffers =10
shmem_filter =RGBShmemFrameFilter(shmem_name, shmem_buffers, width, height)
sws_filter =SwScaleFrameFilter("sws_filter", width, height, shmem_filter)
interval_filter =TimeIntervalFrameFilter("interval_filter", image_interval, sws_filter)
avthread =AVThread("avthread",interval_filter)
av_in_filter =avthread.getFrameFilter()
livethread =LiveThread("livethread")
ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://user:password#192.168.x.x", 1, av_in_filter)
avthread.startCall()
livethread.startCall()
avthread.decodingOnCall()
livethread.registerStreamCall(ctx)
livethread.playStreamCall(ctx)
# all those threads are written in cpp and they are running in the
# background. Sleep for 20 seconds - or do something else while
# the cpp threads are running and streaming video
time.sleep(20)
# stop threads
livethread.stopCall()
avthread.stopCall()
print("bye")
(2) client.py
import cv2
from valkka.api2 import ShmemRGBClient
width =1920//4
height =1080//4
# This identifies posix shared memory - must be same as in the server side
shmem_name ="cam_example"
# Size of the shmem ringbuffer - must be same as in the server side
shmem_buffers =10
client=ShmemRGBClient(
name =shmem_name,
n_ringbuffer =shmem_buffers,
width =width,
height =height,
mstimeout =1000, # client timeouts if nothing has been received in 1000 milliseconds
verbose =False
)
while True:
index, isize = client.pull()
if (index==None):
print("timeout")
else:
data =client.shmem_list[index][0:isize]
img =data.reshape((height,width,3))
img =cv2.GaussianBlur(img, (21, 21), 0)
cv2.imshow("valkka_opencv_demo",img)
cv2.waitKey(1)
If you got interested, check out some more in https://elsampsa.github.io/valkka-examples/
Hi reading frames from video can be achieved using python and OpenCV . Below is the sample code. Works fine with python and opencv2 version.
import cv2
import os
#Below code will capture the video frames and will sve it a folder (in current working directory)
dirname = 'myfolder'
#video path
cap = cv2.VideoCapture("your rtsp url")
count = 0
while(cap.isOpened()):
ret, frame = cap.read()
if not ret:
break
else:
cv2.imshow('frame', frame)
#The received "frame" will be saved. Or you can manipulate "frame" as per your needs.
name = "rec_frame"+str(count)+".jpg"
cv2.imwrite(os.path.join(dirname,name), frame)
count += 1
if cv2.waitKey(20) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Use in this
cv2.VideoCapture("rtsp://username:password#IPAddress:PortNO(rest of the link after the IPAdress)").

Categories