I am trying to encode and decode a video losslessly using the DCPM technique which states that you send the first frame of a video as it is and then you calculate the difference to the next frame as currentFrame - previousFrame and you send this sequence until the video has been fully encoded. In the first file I do this and it seems to work fine.
Now when I try to decode, I display the first frame and then compute `firstFrame + nextFrame' and display this sequence until the end which should result in the real video since the first frame is sent intact and the next one is the difference between the second frame and the first frame. But as I do this process I get a bunch of noise and the video isn't decoded losselessly. Why is that?
Below is the encoder
import cv2
import numpy as np
video = cv2.VideoCapture('video.mp4')
previous_frame = None
video_codec = cv2.VideoWriter_fourcc(*'XVID')
# Setup the output
output = cv2.VideoWriter('dpcm_encoded_video.avi', video_codec, int(video.get(5)),
(int(video.get(3)), int(video.get(4))), False)
if not video.isOpened():
print("Error while trying to play the video.")
i = 0
while video.isOpened():
not_exception, current_frame = video.read()
if not_exception:
if previous_frame is None: # First iteration
current_frame = cv2.cvtColor(current_frame, cv2.COLOR_RGB2GRAY)
previous_frame = current_frame
output.write(current_frame)
continue
if i <= 217: #Video is 217 frames
current_frame = cv2.cvtColor(current_frame, cv2.COLOR_RGB2GRAY)
i += 1
difference = current_frame - previous_frame
cv2.imshow('Error frames', difference)
output.write(difference)
previous_frame = current_frame
if cv2.waitKey(10) == ord('q'):
break
else:
break
video.release()
cv2.destroyAllWindows()
And the decoder
import cv2
# Load video
video = cv2.VideoCapture('dpcm_encoded_video.avi')
# Load the first frame of the video
success, first_frame = video.read()
first_frame = cv2.cvtColor(first_frame, cv2.COLOR_BGR2GRAY)
# Set video codec
video_codec = cv2.VideoWriter_fourcc(*'XVID')
# Setup the output
output = cv2.VideoWriter('dpcm_decoded_video.avi', video_codec, int(video.get(5)), (int(video.get(3)), int(video.get(4))), False)
output.write(first_frame)
frame_num = 0
previous_frame = first_frame
while video.isOpened():
# Skip the first frame because we load it outside the loop
if frame_num == 0:
#success, current_frame = video.read()
frame_num += 1
continue
success, current_frame = video.read()
frame_num += 1
if not success:
break
# Frame to BW
current_frame = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY)
# Sum frames
current_frame = previous_frame + current_frame
previous_frame = current_frame
output.write(current_frame)
video.release()
output.release()
Related
Used: OpenCV and Python3
I am using Python 3.8.2
Operating System: macOS Big Sur 11.2.3
I tried this code on VScode, it does show a video with changed speed with the cv2.imshow command but I don't know how to save that changed video in my folder:
import cv2
cap = cv2.VideoCapture('Pothole testing.mp4')
frameTime = 100
while(cap.isOpened()):
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(frameTime) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Can anyone tell me what should I add to this code so that the changed video gets saved? And preferably in the .mp4 format itself.
You can use the fps parameter of the cv2.VideoWriter() method. The fps can be calculated by simple diving your frameTime variable by 1000, as the cv2.waitKey() method takes in a number and uses it as a thousandth of a second.
Note that if the cap never closed during the while loop, the while cap.isOpened() won't be any better than while True, meaning by the time the last frame is read, an error would occur, causing the writer.release() method to never be called, thus making the resulting file unreadable.
Here is how I would do it:
import cv2
cap = cv2.VideoCapture('Pothole testing.mp4')
ret, frame = cap.read() # Get one ret and frame
h, w, _ = frame.shape # Use frame to get width and height
frameTime = 100
fourcc = cv2.VideoWriter_fourcc(*"XVID") # XVID is the ID, can be changed to anything
fps = 1000 / frameTime # Calculate fps
writer = cv2.VideoWriter("Pothole testing 2.mp4", fourcc, fps, (w, h)) # Video writing device
while ret: # Use the ret to determin end of video
writer.write(frame) # Write frame
cv2.imshow("frame", frame)
if cv2.waitKey(frameTime) & 0xFF == ord('q'):
break
ret, frame = cap.read()
writer.release()
cap.release()
cv2.destroyAllWindows()
If all you need is the resulting file and not the progress window, you can omit a few lines:
import cv2
cap = cv2.VideoCapture('Pothole testing.mp4')
ret, frame = cap.read()
h, w, _ = frame.shape
frameTime = 100
fourcc = cv2.VideoWriter_fourcc(*"XVID")
fps = 1000 / frameTime
writer = cv2.VideoWriter("Pothole testing 2.mp4", fourcc, fps, (w, h))
while ret:
writer.write(frame)
ret, frame = cap.read()
writer.release()
cap.release()
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()
my problem is the camera so slow and not smooth and that makes me a problem to realtime extract text from the label. I want to know how to make a preview of the camera more smooth like a video camera, there is a big lag between live and stream?
here is my code
index = 0
#while test_vid.isOpened():
#make_480p()
while True:
frames += 1
test_vid = cv2.VideoCapture(0)
test_vid.set(cv2.CAP_PROP_FRAME_WIDTH, 720)
test_vid.set(cv2.CAP_PROP_FRAME_HEIGHT, 640)
test_vid.set(cv2.CAP_PROP_FPS,1)
fps = test_vid.get(cv2.CAP_PROP_FPS)
print ("Frames per second using video.get(cv2.cv.CV_CAP_PROP_FPS): {0}".format(fps))
ret,frame = test_vid.read()
start = time.time()
ret, frame = test_vid.read()
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
end = time.time()
print ("time to read a frame : {} seconds".format(end-start))
print(frame)
frame = cv2.flip(frame, 10, 0)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow("LIVE", gray)
key = cv2.waitKey(1)
if key == ord('q'):
break
name = './image_frames/frame' + str(index) + '.png'
print ('Extracting frames...' + name)
cv2.imshow('frame',frame)
cv2.imwrite(name, frame)
test_vid.release()
cv2.destroyAllWindows()
demo = Image.open("./image_frames/frame0.png")
text = pytesseract.image_to_string(demo, lang = 'eng')
print(text)
One issue is that you're recreating the VideoCapture object every frame. Move that setup code outside the loop and you should see a speedup.
# setup the video capture device
test_vid = cv2.VideoCapture(0)
test_vid.set(cv2.CAP_PROP_FRAME_WIDTH, 720)
test_vid.set(cv2.CAP_PROP_FRAME_HEIGHT, 640)
test_vid.set(cv2.CAP_PROP_FPS,1)
fps = test_vid.get(cv2.CAP_PROP_FPS)
print ("Frames per second using video.get(cv2.cv.CV_CAP_PROP_FPS): {0}".format(fps))
while test_vid.isOpened():
ret,frame = test_vid.read()
# do frame processing...
# calculate wait time based on the camera fps
# (as an extension, measure and subtract the image processing time)
key = cv2.waitKey(int(1000/fps))
if key == ord('q'):
break
I have a video that I built using OpenCV VideoWriter.
I want to change a specific frame with a different one.
Is there a way to do it without rebuilding the entire video?
I am changing the third frame by making all pixels to zeros.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
frame_number = -1
while(True):
frame_number += 1
ret, frame = cap.read()
if frame_number == 3: # if frame is the third frame than replace it with blank drame
change_frame_with = np.zeros_like(frame)
frame = change_frame_with
out.write(frame)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
If you do not want to go through all the frames again:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
frame_number = -1
while(True):
frame_number += 1
ret, frame = cap.read()
if frame_number == 3: # if frame is the third frame than replace it with blank drame
change_frame_with = np.zeros_like(frame)
frame = change_frame_with
out.write(frame)
break # add a break here
else:
out.write(frame)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
But the above solution will not write all the other frames after 3 to the whole new video
This might help you :)
import cv2 as cv
vid = cv.VideoCapture('input.mp4')
total_frames = last_frame_number = vid.get(cv.CAP_PROP_FRAME_COUNT)
fourcc = cv.VideoWriter_fourcc(*'avc1')
writer = cv.VideoWriter("output.mp4", apiPreference=0,fourcc=fourcc,fps=video_fps[0], frameSize=(width, height))
frame_number = -1
while(True):
frame_number += 1
vid.set(1,frame_number)
ret, frame = vid.read()
if not ret or frame_number >= last_frame_number: break
# check these two lines first
if frame_number == changeable_frame_number :
frame = new_img_to_be_inserted
writer.write(frame)
# frame = np.asarray(frame)
gray = cv.cvtColor(frame, cv.IMREAD_COLOR)
# cv.imshow('frame',gray)
if cv.waitKey(1) & 0xFF == ord('q'):
break
vid.release()
writer.release()
cv.destroyAllWindows()
I captured a video with my camera and fixed frame rate at 25 fps and tried to read it with OpenCV.
When I read video file with OpenCV, it plays but it plays very fast.
I want my program to play video at 25 fps. How to configure OpenCV to read video file at 25 fps?
My code:
import numpy as np
import cv2
cap = cv2.VideoCapture('vtest.avi')
while(cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
I found some solution.
I put a delay time to capture loop. I check delay before captures new image from video file. This is my solution code.
Thanks, everybody.
import numpy as np
import cv2
from time import time as timer
import sys
video = cv2.VideoCapture('2.avi')
fps = video.get(cv2.CAP_PROP_FPS)
fps /= 1000
framerate = timer()
elapsed = int()
cv2.namedWindow('ca1', 0)
while(video.isOpened()):
start = timer()
# print(start)
ret, frame = video.read()
cv2.imshow('ca1',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
diff = timer() - start
while diff < fps:
diff = timer() - start
elapsed += 1
if elapsed % 5 == 0:
sys.stdout.write('\r')
sys.stdout.write('{0:3.3f} FPS'.format(elapsed / (timer() - framerate)))
sys.stdout.flush()
video.release()
cv2.destroyAllWindows()
Here is a working solution for this problem:
fps = vid.get(cv2.CAP_PROP_FPS)
while True:
now = time.time()
_, frame = vid.read()
#Do your thing
timeDiff = time.time() - now
if (timeDiff < 1.0/(fps)):
time.sleep(1.0/(fps) - timeDiff)
Since this is an existing video file, you can not change its FPS. However when you read the video file, you can change the interval you read between each frame. Here is my solution to read at a fixed frame rate 25 fps. Here is the code:
import numpy as np
import cv2
import sys
cap = cv2.VideoCapture('C:/Media/videos/Wildlife.wmv')
# Check if camera opened successfully
if (cap.isOpened()== False):
print("Error opening video stream or file")
fps = 25
#if you want to have the FPS according to the video then uncomment this code
#fps = cap.get(cv2.CAP_PROP_FPS)
#calculate the interval between frame.
interval = int(1000/fps)
print("FPS: ",fps, ", interval: ", interval)
# Read the video
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('Frame',gray)
if cv2.waitKey(interval) & 0xFF == ord('q'):
break
# Break the loop
else:
break
cap.release()
cv2.destroyAllWindows()
Inspired by your answer:
while(cap.isOpened()):
ret, frame = cap.read()
now = time.time()
frameLimit = 2.0
#Do your stuff
timeDiff = time.time() - now
if (timeDiff < 1.0/(frameLimit)): time.sleep( 1.0/(frameLimit) - timeDiff )
you can add the required fps in place of 'fps' below
cap.set(cv2.cv.CV_CAP_PROP_FPS, fps)