Editing video frames on Raspberry Pi - python

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.

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.

How to make videocapture stream in a for loop to stram multiple cameras

I am trying to make this videocapture opencv2 python script allow me to do multiple video streams from my laptop cam and USB cams and I succeeded (with help of youtube) to do so only every time I add a camera I have to edit the line of code and add another videocapture line and another frame and another cv2.imshow. But I want to edit the video capture code in a way that allows me to stream as many cameras as detected without the need to add a line every time there is a camera using a loop. I'm obviously new here so accept my apologies if the solution is too simple.
This is the code that allows me to stream multiple cameras but with adding a line for each camera.
import urllib.request
import time
import numpy as np
import cv2
# Defining URL for camera
video_capture_0 = cv2.VideoCapture(0)
video_capture_1 = cv2.VideoCapture(1)
while True:
# Capture frame-by-frame
ret0, frame0 = video_capture_0.read()
ret1, frame1 = video_capture_1.read()
if (ret0):
# Display the resulting frame
cv2.imshow('Cam 0', frame0)
if (ret1):
# Display the resulting frame
cv2.imshow('Cam 1', frame1)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything is done, release the capture
video_capture_0.release()
video_capture_1.release()
cv2.destroyAllWindows()
I tried making a list camlist = [i for i in range(100)] and then adding that to a for loop that keeps adding it to videocapture. But I believe that's a mess so I deleted the code plus that doesn't seem so effective.
If you want to work with many cameras then first you should keep them on list - and then you can use for-loop to get all frame. And frames you should also keep on list so later you can use for-loop to display them. And finally you can use for-loop to release cameras
import cv2
#video_captures = [cv2.VideoCapture(x) for x in range(2)]
video_captures = [
cv2.VideoCapture(0),
#cv2.VideoCapture(1),
cv2.VideoCapture('https://imageserver.webcamera.pl/rec/krupowki-srodek/latest.mp4'),
cv2.VideoCapture('https://imageserver.webcamera.pl/rec/krakow4/latest.mp4'),
cv2.VideoCapture('https://imageserver.webcamera.pl/rec/warszawa/latest.mp4'),
]
while True:
results = []
for cap in video_captures:
ret, frame = cap.read()
results.append( [ret, frame] )
for number, (ret, frame) in enumerate(results):
if ret:
cv2.imshow(f'Cam {number}', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
for cap in video_captures:
cap.release()
cv2.destroyAllWindows()
And now if you even add new camera to list then you don't have to change rest of code.
But for many cameras it is good to run every camera in separated thread - but still keep all on lists.
Few days ago was question: How display multi videos with threading using tkinter in python?

super slow opencv cv2.VideoCapture('rtsp://) 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)

Encode/decode image data after changing to/from string/bytes

The end goal of this is to create a program running on a Raspberry Pi that can stream video data to a remote client. To do this I (believe) I need to change the frame data to raw bytes in order for them to be sent over sockets. Before deploying this into the real world, I'm simply checking to make sure I can do the transformation to and from bytes. I do get output and it is reading data from the camera in real-time, but the way it's displayed is in a 1 pixel wide vertical left-aligned line. (When using the default full screen button on the OpenCV window it increases to about 5 pixels wide.) Also just to clarify, the tostring() function apparently transforms the given data into raw bytes and not a string? In checking, Python said the new variable was bytes.
My previous attempts were focused on just taking the raw image data and attempting to encode and decode that, but I was met with an error. I think I'm on the right track but this is a bump in the road.
import cv2
import numpy as np
vid = cv2.VideoCapture(0)
while True:
empty, frame = vid.read()
frameString = frame.tostring()
# Intermediary socket stuffs.
newFrame = np.frombuffer(frameString)
cv2.imshow("s", newFrame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vid.release()
Considering this is all working through Numpy I would expect to have equal results on either end of the transformation but something goes wrong and I'm not even sure where to start looking.(Standard and full screen screenshots: https://imgur.com/a/BIPxr50)
You can use cv2.imencode() to encode the frame and then turn it into a string. From there you can send it through your socket. On the receiving end, you can decode it using np.fromString() and cv2.imdecode().
import cv2
import numpy as np
vid = cv2.VideoCapture(0)
while True:
if vid.isOpened():
empty, frame = vid.read()
data = cv2.imencode('.jpg', frame)[1].tostring()
# Intermediary socket stuffs
nparr = np.fromstring(data, np.uint8)
newFrame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
cv2.imshow("s", newFrame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vid.release()

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()

Categories