OpenCV is too slow for this - python

I want to overlay webcam captured video on another video in live. So I have tried the above code,but it's too slow.
Should I shift to another language or lib or something?
Any suggestion or help will be appreciated.
import numpy as np
from cv2 import cv2
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
# initialize the dimensions of the image to be resized and
# grab the image size
dim = None
(h, w) = image.shape[:2]
# if both the width and height are None, then return the
# original image
if width is None and height is None:
return image
# check to see if the width is None
if width is None:
# calculate the ratio of the height and construct the
# dimensions
r = height / float(h)
dim = (int(w * r), height)
# otherwise, the height is None
else:
# calculate the ratio of the width and construct the
# dimensions
r = width / float(w)
dim = (width, int(h * r))
# resize the image
resized = cv2.resize(image, dim, interpolation = inter)
# return the resized image
return resized
cap2 = cv2.VideoCapture('http://192.168.43.1:8080/video')
cap = cv2.VideoCapture('test.mp4')
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('sample3.mp4',fourcc,30, (640,480))
# watermark = logo
# cv2.imshow("watermark",watermark)
while(cap.isOpened()):
ret, frame = cap.read()
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2BGRA)
ret2 ,frame2 = cap2.read()
frame2 = cv2.cvtColor(frame2,cv2.COLOR_BGR2BGRA)
watermark = image_resize(frame2,height=177)
if ret==True:
frame_h, frame_w, frame_c = frame.shape
overlay = np.zeros((frame_h, frame_w, 4), dtype='uint8')
overlay[543:543+177,1044:1044+236] = watermark
cv2.addWeighted(frame, 0.25, overlay, 1.0, 0, frame)
frame = cv2.cvtColor(frame,cv2.COLOR_BGRA2BGR)
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
Requirement is to overlay webcam live video on another video at bottom smoothly.
Thanks.

Basically, if you want it to be fast, you may not iterate over an image using a python cycle. You are trying to copy the scaled-down image into the empty overlay using 2 nested cycles and that's terribly slow. I do not understand the condition
if watermark[i,j][3] != 0:
Also this part:
offset = 0
h_offset = frame_h - watermark_h -offset
w_offset = frame_w - watermark_w - offset
should be out of the cycle - they are all constants.
But most importantly instead of cycling over the image you can do:
offset[h_offset:h_offset+watermark_h,w_offset:w_offset+watermark_w] = watermark
After this, I am up from 9 fps to 28 fps.

Related

How to get the frame_width of an image with OpenCV?

I try to get the frame_width of an image with the following code:
"""Predict the gender of the faces showing in the image"""
# Read Input Image
img = cv2.imread(imag)
# resize the image, uncomment if you want to resize the image
img = cv2.resize(img, (frame_width, frame_height))
# Take a copy of the initial image and resize it
frame = img.copy()
print(frame.shape[1])
if frame.shape[1] > frame_width:
frame = image_resize(frame, width=frame_width)
# predict the faces
faces = get_faces(frame)
Following my main method were I call the method with an image:
if __name__ == '__main__':
predict_gender("/Users/$$$/Downloads/test.jpg")
I already tried to import tkinter because I thought I need tkinter for the frame but it was also not working. Here is my current error:
<ipython-input-10-2d047afa91e4> in predict_gender(imag)
4 img = cv2.imread(imag)
5 # resize the image, uncomment if you want to resize the image
----> 6 img = cv2.resize(img, (frame_width, frame_height))
7 # Take a copy of the initial image and resize it
8 frame = img.copy()
NameError: name 'frame_width' is not defined
You need to define frame_width and frame_height.
img = cv2.imread(imag)
frame_height, frame_width, _ = img.shape
# resize the image, uncomment if you want to resize the image
img = cv2.resize(img, (frame_width, frame_height))

Why are my video files getting bigger after converting to np.array?

I have video files around 700x200, and I'm using cv2 to perform preprocessing. The actual videos are .mp4 format and range from a couple mb depending on the length, but after scaling down the resolution, making the color videos grey, somehow my filesize almost 10x when I try to either save via Pickle or np.save.
Preprocessing code is:
def save_video(link):
frames = []
# Creating a VideoCapture object to read the video
# cap = cv2.VideoCapture('video.mp4')
cap = cv2.VideoCapture(link)
frameCount = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frameWidth = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frameHeight = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
buf_c = np.empty((frameCount, frameHeight, frameWidth, 3), np.dtype('uint8'))
buf = np.empty((frameCount, frameHeight, frameWidth), np.dtype('uint8'))
fc = 0
ret = True
# Resolution reduction
scale_percent = 30 # percent of original size
width = int(buf.shape[2] * scale_percent / 100)
height = int(buf.shape[1] * scale_percent / 100)
dim = (width, height)
while (fc < frameCount and ret):
ret, buf_c[fc] = cap.read()
buf[fc] = cv2.cvtColor(buf_c[fc], cv2.COLOR_BGR2GRAY)
resized = cv2.resize(buf[fc], dim, interpolation = cv2.INTER_AREA)
frames.append(resized)
fc += 1
cap.release()
cv2.destroyAllWindows()
return frames // or np.asarray(frames)
dimensions for video files as examples (after processing):
(844, 216, 121) (so 844 frames of 216x121 after scaling down)
(788, 216, 121)
Actual video files are 1-2MB before any preprocessing and the resulting pkl or npy are 10x+ in size. Is this what is supposed to happen?
A compressed video stream is decompressed by OpenCV and is saved as raw data. To reduce the size you need to encode the video stream. For example:
def opencv_replay(video_file: str, video_file_out: str):
import cv2
video_in = cv2.VideoCapture(video_file)
video_out = cv2.VideoWriter()
assert (video_out.open(
video_file_out,
cv2.VideoWriter_fourcc('a', 'v', 'c', '1'),
video_in.get(cv2.CAP_PROP_FPS),
(int(video_in.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video_in.get(cv2.CAP_PROP_FRAME_HEIGHT)))
))
while True:
res, frame = video_in.read()
if not res:
break
video_out.write(frame)
avc1 is used for h264 encoding in Linux.

Opencv-Overlay a Video on Webcam

Guys I am having problem on overlaying my video to webcam. I can open webcam without any issues or errors but my video is not being showed. I am trying to play my video in specific x-y coordinates.I take most of my code from an other stackoverflow question but I cannot find it know so that I cannot mention it here.
So can someone help me to solve this? Why my video is not being played in my webcam?
I have following code:
from os.path import sep
import cv2 as cv2
# load the overlay image. size should be smaller than video frame size
img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
# Start Capture
cap = cv2.VideoCapture(0)
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
frame_vid = img.read()
# Decide X,Y location of overlay image inside video frame.
# following should be valid:
# * image dimensions must be smaller than frame dimensions
# * x+img_width <= frame_width
# * y+img_height <= frame_height
# otherwise you can resize image as part of your code if required
x = 50
y = 50
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# add image to frame
frame[ y:y+width , x:x+height ] = img
'''
tr = 0.3 # transparency between 0-1, show camera if 0
frame = ((1-tr) * frame.astype(np.float) + tr * frame_vid.astype(np.float)).astype(np.uint8)
'''
# Display the resulting frame
cv2.imshow('frame',frame)
# Exit if ESC key is pressed
if cv2.waitKey(20) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()
Let me start analyzing the code step-by-step.
Step #1
img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
The above code look fine, but it would be better if you give as a string name
video_name = 'photos' + sep + 'Baslksz-3.mp4'
img = cv2.VideoCapture(video_name)
Step #2
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
Now what are width and height variables?
# Get Image dimensions
width = img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
height = img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
print(width)
print(height)
Result is:
False
False
It seems you want to set width and height to the dimension (150, 150). It would be better if you initialize them separately
# Get Image dimensions
img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
width = 150
height = 150
Step #3
# Start Capture
cap = cv2.VideoCapture(0)
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
Why do you initialize cap variable two-times?
Step #4
frame_vid = img.read()
Why do you initialize frame_vid you did not use anywhere in the code?
Step #5
while (True):
# Capture frame-by-frame
ret, frame = cap.read()
frame[y:y + width, x:x + height] = img
The above code is not making any sense, you want to display your video as long as your webcam open. You also did not check whether the current webcam frame returns or not. You also set VideoCapture variable to the array?
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
Now you are getting frames, as long as your webcam is open, then you need to check whether the webcam frame returns. If the webcam frame returns then you need to start reading the video frames. If the video frame returns successfully resize the video frame to (width, height) then set it to the frame.
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
if ret_video:
# add image to frame
frame_video = cv2.resize(frame_video, (width, height))
frame[y:y + width, x:x + height] = frame_video
Step #6
Make sure close img variable after the execution.
img.release()
cap.release()
cv2.destroyAllWindows()
Please change img variable to something that makes sense. Like rename the img variable to video_capture and cap to the webcam_capture.
When video stops then webcam stacks. But I want to continue infinitive. and video should start again. But video does not starts from beggining.and webcam freezes
Update
This issue was mentioned in the Playback loop option in OpenCV videos
If you look at the answer, the problem was solved by counting the video frames. When video frames equal to the capture frame count (CAP_PROP_FRAME_COUNT) set to counter and CAP_PROP_FRAME_COUNT to 0.
First initialize the frame counter.
video_frame_counter = 0
and when webcam opens, get the frame. If frame returns, increase the counter by 1.
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
video_frame_counter += 1
If counter equals to the capture class frame count, then initialize both variable to 0.
if video_frame_counter == img.get(cv2.CAP_PROP_FRAME_COUNT):
video_frame_counter = 0
img.set(cv2.CAP_PROP_POS_FRAMES, 0)
Code:
from os.path import sep
import cv2 as cv2
# load the overlay image. size should be smaller than video frame size
# img = cv2.VideoCapture('photos' + sep + 'Baslksz-3.mp4')
video_name = 'photos' + sep + 'Baslksz-3.mp4'
img = cv2.VideoCapture(video_name)
# Get Image dimensions
img.set(cv2.CAP_PROP_FRAME_WIDTH, 150) # float `width`
img.set(cv2.CAP_PROP_FRAME_HEIGHT, 150)
width = 150
height = 150
# Start Capture
cap = cv2.VideoCapture(0)
# cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
# frame_vid = img.read()
# Decide X,Y location of overlay image inside video frame.
# following should be valid:
# * image dimensions must be smaller than frame dimensions
# * x+img_width <= frame_width
# * y+img_height <= frame_height
# otherwise you can resize image as part of your code if required
x = 50
y = 50
video_frame_counter = 0
while cap.isOpened():
# Capture frame-by-frame
ret, frame = cap.read()
if ret:
ret_video, frame_video = img.read()
video_frame_counter += 1
if video_frame_counter == img.get(cv2.CAP_PROP_FRAME_COUNT):
video_frame_counter = 0
img.set(cv2.CAP_PROP_POS_FRAMES, 0)
if ret_video:
# add image to frame
frame_video = cv2.resize(frame_video, (width, height))
frame[y:y + width, x:x + height] = frame_video
'''
tr = 0.3 # transparency between 0-1, show camera if 0
frame = ((1-tr) * frame.astype(np.float) + tr * frame_vid.astype(np.float)).astype(np.uint8)
'''
# Display the resulting frame
cv2.imshow('frame', frame)
# Exit if ESC key is pressed
if cv2.waitKey(1) & 0xFF == 27:
break
img.release()
cap.release()
cv2.destroyAllWindows()

How to solve Opencv VideoWriter issues with global variables

I'mm writing this piece of python to display a stream of video from my webcam while at the same time record the video - which I've got working, however I've grayscaled the video streaming to my screen and time stamped it - but my recorded video is in colour! I've included the code below - I've tried using some global variables but nothing worked - any help, greatly appreciated
import cv2
import numpy as np
import time, datetime
import os
genericfilename = "recording"
filetime = str(time.time())
extension = '.avi'
filename = genericfilename + filetime +extension
frames_per_second = 100
res = '720p'
print("NEW FILE NAME: " + filename)
# Set resolution for the video capture
def change_res(cap, width, height):
cap.set(3, width)
cap.set(4, height)
# Standard Video Dimensions Sizes
STD_DIMENSIONS = {
"480p": (640, 480),
"720p": (1280, 720),
"1080p": (1920, 1080),
"4k": (3840, 2160),
}
# grab resolution dimensions and set video capture to it.
def get_dims(cap, res='1080p'):
width, height = STD_DIMENSIONS["480p"]
if res in STD_DIMENSIONS:
width,height = STD_DIMENSIONS[res]
## change the current caputre device
## to the resulting resolution
change_res(cap, width, height)
return width, height
# Video Encoding, might require additional installs
VIDEO_TYPE = {
'avi': cv2.VideoWriter_fourcc(*'XVID'),
#'mp4': cv2.VideoWriter_fourcc(*'H264'),
'mp4': cv2.VideoWriter_fourcc(*'XVID'),
}
def get_video_type(filename):
filename, ext = os.path.splitext(filename)
if ext in VIDEO_TYPE:
return VIDEO_TYPE[ext]
return VIDEO_TYPE['avi']
capture = cv2.VideoCapture(0)
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
get_dims(capture, res))
while(True):
ret, frame = capture.read()
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
font = cv2.FONT_ITALIC = 1
cv2.putText(grayFrame, str(datetime.datetime.now()), (-330, 460), font, 3,
(200, 200, 200), 2, cv2.LINE_AA)
cv2.imshow('combilift output', grayFrame)
# Press Q on keyboard to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if cv2.waitKey(1) & 0xFF == ord('r'):
print(datetime.datetime.now())
capture.release()
out.release()
cv2.destroyAllWindows()
You save the frame to video, then convert frame to gray.
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
If you want your recorded video to be gray, maybe reverse the order of operations and save grayFrame?
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(grayFrame)
If you want to also save the texts, put the text before writing frame to output.
Lets take a look at ur code
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
.....
while(True):
ret, frame = capture.read()
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
You first save out then convert color
The correct sequence should be
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
.....
while(True):
ret, frame = capture.read()
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(grayFrame)
I don't have data to test. Just in case you experience some issue with channels. You can use opencv merge(grayFrame,grayFrame,grayFrame) to create a normal 3 channel grey scale image and save to video

How can I zoom my webcam in Open CV Python?

I want my webcam to be zoomed in open cv python and I don't know how. Can anyone help me with my problem?
import cv2
video = cv2.VideoCapture(0)
while True:
check, frame = video.read()
cv2.imshow('Video', frame)
key = cv2.waitKey(1)
if key == 27:
break
video.release()
cv2.destroyAllWindows
You can use this solution. It makes the job -> croping + zoom + array up and array down.
import cv2
def show_webcam(mirror=False):
scale=10
cam = cv2.VideoCapture(0)
while True:
ret_val, image = cam.read()
if mirror:
image = cv2.flip(image, 1)
#get the webcam size
height, width, channels = image.shape
#prepare the crop
centerX,centerY=int(height/2),int(width/2)
radiusX,radiusY= int(scale*height/100),int(scale*width/100)
minX,maxX=centerX-radiusX,centerX+radiusX
minY,maxY=centerY-radiusY,centerY+radiusY
cropped = image[minX:maxX, minY:maxY]
resized_cropped = cv2.resize(cropped, (width, height))
cv2.imshow('my webcam', resized_cropped)
if cv2.waitKey(1) == 27:
break # esc to quit
#add + or - 5 % to zoom
if cv2.waitKey(1) == 0:
scale += 5 # +5
if cv2.waitKey(1) == 1:
scale = 5 # +5
cv2.destroyAllWindows()
def main():
show_webcam(mirror=True)
if __name__ == '__main__':
main()
Zooming is simply increasing image size . Just increase image size by converting frame to image using PIL and then resize function.
Sample code
import tkinter
import cv2
from PIL import Image,ImageTk
root = tkinter.Tk()
root.geometry("1000x500+200+0")
w = 1000
h = 630
capture = tkinter.Canvas(root, bd=2, bg="blue", height=h, width=w)
capture.grid(column = 0, row = 0)
video = None
frame = None
img=None
show=None
begin = False
def start_capture(event):
global begin,frame,img,root,show,capture,video
video = cv2.VideoCapture(0)
begin = True
while begin:
check, frame = video.read()
img = Image.fromarray(frame)
w,h = img.size
img = img.resize((w*2,h*2))
show = ImageTk.PhotoImage(img)
capture.create_image(0,0,anchor=tkinter.NW,image=show)
root.update()
def stop_capture(event):
global video,begin
begin = False
video.release()
start = tkinter.Button(root, text='Start')
start.grid(column = 0, row = 2)
start.bind('<Button-1>', start_capture)
stop = tkinter.Button(root, text='Stop')
stop.grid(column = 1, row = 2)
stop.bind('<Button-1>', stop_capture)
root.mainloop()
I am not sure if this is useful now to add this point. (Hope this helps for all the noobs in opencv at least)
I suffered a lot at this: cropped = image[minX:maxX, minY:maxY] Crop was somehow out of the interested area.
After researching a lot, I found out that the problem was with the syntax.
Actually it should have been : cropped = image[minY:maxY , minX:maxX]
because openCV crop syntax should be like this?..
Anyways, thanks to Amara BOUDIB & JDS for the sample codes!

Categories