Can't convert video to grayscale - python

I'm trying to convert a video from my camera feed, which has low fps to gray. I have successfully fetched the video now I want to convert it to grayscale.
I've tried basic opencv operations and it isn't working. I get a video file when I open it there is no video.
import cv2
import time
cap = cv2.VideoCapture('output.avi')
fourcc = cv2.VideoWriter_fourcc(*'XVID')
print(fourcc)
out = cv2.VideoWriter('grey.avi',fourcc, 30.0, (800,600))
while True:
ret, frame = cap.read()
time.sleep(0.1)
cv2.imshow('frame1',frame)
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
out.write(frame)
cv2.imwrite('img.jpg',frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()

You need to change the isColor flag in cv2.VideoWriter. Currently the video writer setting is set to color instead of gray scale. You're incorrectly attempting to save a 3-channel color image (OpenCV default is BGR) as a gray scale image.
Change
out = cv2.VideoWriter('grey.avi',fourcc, 30.0, (800,600))
to
out = cv2.VideoWriter('grey.avi',fourcc, 30.0, (800,600), isColor=False)
Also your overall goal seems to capture video from a stream/camera feed and save the captured video in gray scale format. Here's an 'all in one' widget that reads frames from a camera stream link (RTSP), converts each frame to gray scale, and saves it as a video. Change video_src to your camera stream link.
from threading import Thread
import cv2
class VideoToGrayscaleWidget(object):
def __init__(self, src=0):
# Create a VideoCapture object
self.capture = cv2.VideoCapture(src)
# Default resolutions of the frame are obtained (system dependent)
self.frame_width = int(self.capture.get(3))
self.frame_height = int(self.capture.get(4))
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('X','V','I','D')
self.output_video = cv2.VideoWriter('output.avi', self.codec, 30, (self.frame_width, self.frame_height), isColor=False)
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
def show_frame(self):
# Convert to grayscale and display frames
if self.status:
self.gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('grayscale frame', self.gray)
# Press 'q' on keyboard to stop recording
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
self.output_video.release()
cv2.destroyAllWindows()
exit(1)
def save_frame(self):
# Save grayscale frame into video output file
self.output_video.write(self.gray)
if __name__ == '__main__':
video_src = 'Your video stream link!'
video_stream_widget = VideoToGrayscaleWidget(video_src)
while True:
try:
video_stream_widget.show_frame()
video_stream_widget.save_frame()
except AttributeError:
pass

Related

Failed to save video using OpenCV

Using OpenCV, I have been extracting the frames from a video and after working on the frames, I have been trying to save them to a new video file. But the new video file is not being saved properly. It gets saved as 0 KB in size and throws the following error when I try to open it.
OpenCV Error
My code is as follows:
import cv2
cap = cv2.VideoCapture("Path to source video")
out = cv2.VideoWriter("Path to save video", cv2.VideoWriter_fourcc(*"VIDX"), 5, (1000, 1200))
print(cap.isOpened())
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Write the video
out.write(frame)
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
I tried to follow the solution Can't save a video in opencv but it did not help in my case.
when saving the file, your width and height should match with frame's width and height, so in order to get the width and height of the frame automatically, use
import cv2
cap = cv2.VideoCapture(0)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # to get width of the frame
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # to get height of the frame
out = cv2.VideoWriter("dummy_video.mp4", cv2.VideoWriter_fourcc(*"VIDX"), 5, (width, height))
print(cap.isOpened())
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# Write the video
out.write(frame)
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()

Python OpenCV multiprocessing cv2.VideoCapture mp4

I want to run some mp4 videos inside a process but only camera feed works. The software gets stuck with no error message. I already tried both and I found this doesn't run. The print is where the code gets stuck.
import cv2
import multiprocessing
dispW=640
dispH=480
# Camera inputs
cap=cv2.VideoCapture('/home/kc/Downloads/darknet/1.mp4')
cap.set(cv2.CAP_PROP_FRAME_WIDTH, dispW)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, dispH)
#cv2.namedWindow("Window")
def c1():
global cap
while True:
print('here')
success, img = cap.read()
#ret, frame1 = cap1.read()
#frame2 = numpy.hstack((frame,frame1))
print('here')
cv2.imshow("Window2", img)
#This breaks on 'q' key
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
tCap1 = multiprocessing.Process(target=c1)
tCap1.start()
this runs.
import cv2
import multiprocessing
dispW=640
dispH=480
# Camera inputs
cap=cv2.VideoCapture('/dev/video0')
cap.set(cv2.CAP_PROP_FRAME_WIDTH, dispW)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, dispH)
#cv2.namedWindow("Window")
def c1():
global cap
while True:
success, img = cap.read()
#ret, frame1 = cap1.read()
#frame2 = numpy.hstack((frame,frame1))
print('here')
cv2.imshow("Window2", img)
#This breaks on 'q' key
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
tCap1 = multiprocessing.Process(target=c1)
tCap1.start()
I need an example of mp4 file run in a multiprocessing way.
Here's a minimal working example with optional FPS control. If you need to extract frames from your process back to the main program, you can use multiprocessing.Queue() to transfer frames since multiprocesses have an independent memory stack.
import multiprocessing as mp
import cv2, time
def capture_frames():
src = 'test.mp4'
capture = cv2.VideoCapture(src)
capture.set(cv2.CAP_PROP_BUFFERSIZE, 2)
# FPS = 1/X, X = desired FPS
FPS = 1/120
FPS_MS = int(FPS * 1000)
while True:
# Ensure camera is connected
if capture.isOpened():
(status, frame) = capture.read()
# Ensure valid frame
if status:
cv2.imshow('frame', frame)
else:
break
if cv2.waitKey(1) & 0xFF == ord('q'):
break
time.sleep(FPS)
capture.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
print('Starting video stream')
capture_process = mp.Process(target=capture_frames, args=())
capture_process.start()
Related camera/IP/RTSP/streaming, FPS, video, threading, and multiprocessing posts
Python OpenCV streaming from camera - multithreading, timestamps
Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture
How to capture multiple camera streams with OpenCV?
OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time?
Storing RTSP stream as video file with OpenCV VideoWriter
OpenCV video saving
Python OpenCV multiprocessing cv2.VideoCapture mp4

OpenCv - output video is not playing

I want to write a video using OpenCv and process every frames in different seconds.
I am using cv2.VideoWriter, but the output file shows only the first frame of my video and it is not playing. I wanted to add text on the first frame and it did it, but it doesn't continue with the rest of the video.
As you can see from the code below, it creates a new output file for the new processed video.
It does create the mp4 file, but only showing first frame with the added text and it is not playing.
Any suggestion why this is happening?
Here is my code, I am using Spyder and windows.
fps = int(round(cap.get(5)))
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_video_file,fourcc,fps,(frame_width,frame_height))
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
if cv2.waitKey(28) & 0xFF == ord('q'):
break
if between(cap, 0, 10000):
font = cv2.FONT_HERSHEY_COMPLEX_SMALL
cv2.putText(frame,'hello',org=(10,600),fontFace=font,fontScale=10,color=(255,0,0),thickness=4)
pass
# Our operations on the frame come here
out.write(frame)
# Display the resulting frame
cv2.imshow('frame',frame)
Exactly I could not find the problem in your code because you did not give the between function. However you may try following snippet:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
if (cap.isOpened() == False):
print("Unable to read camera feed")
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
fps = int(round(cap.get(5)))
out = cv2.VideoWriter('output.mp4', cv2.VideoWriter_fourcc(*'mp4v'), fps, (frame_width, frame_height))
while (True):
ret, frame = cap.read()
if ret == True:
cv2.putText(frame, 'hello',
org=(10, 300),
fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=5,
color=(255, 0, 0),
thickness=4)
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()

How to capture video in python with opencv and multithread (logitech c920)

I'm trying to capture a video of a duration of X seconds every Y hours with python3.8 and opencv(4.2.0) in Manjaro XFCE. I'd like to get at least 20-30fps with a resolution of 720p or 1080p. I'm using a Logitech c920, but with a good resolution (eg 1920x1080) I'm stack at 5fps. I can set the fps at 30 but then the video is about 6 times shorter (python takes video at ~5fps but records it as it was 30fps). Thus, to improve the fps I should use multithreading, although I can't get to implement in my code any of the examples I've seen. Any idea how to do it?
Here is my code:
import numpy as np
import cv2
import time
#choose resolution and fps:
x=1920
y=1080
fps=30
# The duration in seconds of the video captured (s)
capture_duration = 5
# Lapse of time between videos (s), from beginning to beginning
vids_lapse=10
# Name of videos
data_string= time.strftime("%m-%d-%H-%M-%S")
for i in range (0,2): #Let's say I only want to do this process twice, to simplify
cap = cv2.VideoCapture(2) #my camera is 2, but could be 0
fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
#set resolution and fps
cap.set(3,int(x))
cap.set(4,int(y))
cap.set(cv2.CAP_PROP_FPS, int(fps))
#set name of video
out = cv2.VideoWriter(data_string+"_vid"+str(i).zfill(2)+".avi",fourcc, fps, (x,y))
start_time = time.time()
#start recording for a determined duration
while( int(time.time() - start_time) < capture_duration+1 ):
ret, frame = cap.read()
if ret==True:
#frame = cv2.flip(frame,0)
out.write(frame)
cv2.imshow('frame',frame)
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
#Here I added time.sleep to wait for the next capture
time.sleep(vids_lapse-capture_duration)
With this code above, my video of 30fps is shorter than expected, as it cannot take more than ~5fps.
I've seen I can use multithread, and I'm able to record a video with 30fps (at least that's what ffprobe says, although I'm not sure it is) with the following code:
from threading import Thread
import cv2, time
#again define resolution and fps
x=1920
y=1080
fps=30
class VideoStreamWidget(object):
def __init__(self, src=2):
self.capture = cv2.VideoCapture(src)
self.capture.set(3,int(x))
self.capture.set(4,int(y))
self.capture.set(cv2.CAP_PROP_FPS, int(fps))
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
time.sleep(.03)
def show_frame(self):
out.write(self.frame)
# Display frames in main program
cv2.imshow('frame', self.frame)
key = cv2.waitKey(1)
if key == ord('q'):
self.capture.release()
out.release()
cv2.destroyAllWindows()
exit(1)
if __name__ == '__main__':
fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
out = cv2.VideoWriter("output.avi",fourcc, fps, (x,y))
video_stream_widget = VideoStreamWidget()
while True:
try:
video_stream_widget.show_frame()
except AttributeError:
pass
The problem of this second code is that I don't really know how to introduce my arguments of (recording during 5 seconds, wait 10 seconds, and so on) or how many threads I'm using (I can specify number of buffers from my camera using V4L2 tools, don't know how relevant is it).
So my question is: Any idea how could I do it? Is it possible to merge both codes? Or is there a better way?
Here are some guides I've checked but couldn't get it working with my code:
https://www.pyimagesearch.com/2015/12/21/increasing-webcam-fps-with-python-and-opencv/
https://github.com/gilbertfrancois/video-capture-async
Thanks a lot in advance!
cheers!
EDIT
I finally got something to work. Nevertheless, even if my video is 30fps, it still looks like a 5fps video... Seems like all the pictures captured are almost the same... Any idea how to solve this?
Here the code:
rom threading import Thread, Lock
import cv2, time
#choose resolution
x=1920
y=1080
fps=60
# The duration in seconds of the video captured (s)
capture_duration = 5
# Days
Days=1
# Lapse of time between videos (s), from beginning to beginning
vids_lapse=10
data_string= time.strftime("%m-%d-%H-%M-%S")
class CameraStream(object):
def __init__(self, src=0):
self.stream = cv2.VideoCapture(src)
self.stream.set(3,int(x))
self.stream.set(4,int(y))
self.stream.set(cv2.CAP_PROP_FPS,int(fps))
self.video_file_name = data_string+"_vid"+str(i).zfill(2)+".avi"
(self.grabbed, self.frame) = self.stream.read()
self.started = False
self.read_lock = Lock()
# Set up codec and output video settings
self.codec = cv2.VideoWriter_fourcc('M','J','P','G')
self.out = cv2.VideoWriter(self.video_file_name, self.codec, fps, (x, y))
def start(self):
if self.started:
print("already started!!")
return None
self.started = True
self.thread = Thread(target=self.update, args=())
self.thread.start()
return self
def update(self):
while self.started:
(grabbed, frame) = self.stream.read()
self.read_lock.acquire()
self.grabbed, self.frame = grabbed, frame
self.read_lock.release()
# ~ time.sleep(1/fps)
def read(self):
self.read_lock.acquire()
frame = self.frame.copy()
self.read_lock.release()
self.save_frame()
return frame
def save_frame(self):
# Save obtained frame into video output file
self.out.write(self.frame)
def stop(self):
self.started = False
self.thread.join()
self.stream.release()
self.out.release()
def __exit__(self, exc_type, exc_value, traceback):
self.stream.release()
if __name__ == "__main__" :
for i in range (0,2):
start_time = time.time()
cap = CameraStream(0).start()
while (int(time.time() - start_time) < capture_duration):
frame = cap.read()
cv2.imshow('webcam', frame)
# ~ if cv2.waitKey(1) == 27 :
cap.stop()
cv2.destroyAllWindows()
time.sleep(vids_lapse-capture_duration)
The issue is with FOURCC, you should set cv2.CAP_PROP_FOURCC, try this example:
import cv2
HIGH_VALUE = 10000
WIDTH = HIGH_VALUE
HEIGHT = HIGH_VALUE
capture = cv2.VideoCapture(-1)
capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M', 'J', 'P', 'G'))
capture.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = capture.get(cv2.CAP_PROP_FPS)
print(width, height, fps)
while True:
ret, frame = capture.read()
if ret:
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
capture.release()
cv2.destroyAllWindows()

How to fix imshow() showing grey image

I'm trying to show the webcam capture on screen in my raspberry pi. It shows first frame with no problem but next ones are displayed as grey frames.
This works on windows but not on raspberry.
import cv2 as cv
cap = cv.VideoCapture(0)
ret, frame = cap.read()
cv.imshow('frame0',frame)
while True:
ret, frame = cap.read()
cv.imshow('frame',frame)
if cv.waitKey(1) == ord('q'):
break
cap.release()
cv.destroyAllWindows()
First install the Picamera module and then try:
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))
# allow the 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, then initialize the timestamp
# and occupied/unoccupied text
image = frame.array
# show the frame
cv2.imshow("Frame", image)
key = cv2.waitKey(1) & 0xFF
# clear the stream in preparation for the next frame
rawCapture.truncate(0)
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
Source: https://www.pyimagesearch.com/2015/03/30/accessing-the-raspberry-pi-camera-with-opencv-and-python/

Categories

Resources