VideoCapture() to read multiple videos and frame r

2019-07-31 12:21发布

问题:

According to the answer from this article which refer to the way to combine single image into a 4 side. From there, I want to change from using only single video to use 4 videos as an input.

This is my code which used single video as an input

import cv2
import numpy as np


def make4side(image, scale=0.5):

   # image = cv2.imread(image)
   h = int((scale*image.shape[0])) #height
   w = int((scale*image.shape[1])) #width
   image = cv2.resize(image, (w,h ), interpolation = cv2.INTER_AREA) #shrink image to half

   output = np.zeros((w+h+h , w + h + h, 3), dtype="uint8")

   # top 
   output[0:h, h:h+w] = image 
   # left >> rotate 90
   output[h:h+w, 0:h] = np.rot90(image,1) 
   # right >> rotate 270
   output[h:h + w, h + w:h +w +h] = np.rot90(image,3)  
   # bottom >> rotate 180
   output[h+w:h+w+h, h:h+w] = np.rot90(image,2) 

   return output
   #cv2.imwrite('test.jpg', output)

def process(video):
   cap = cv2.VideoCapture(video)
   fourcc = cv2.VideoWriter_fourcc(*'XVID')
   holo = None
   ret = False
   while(not ret):
    ret, frame = cap.read()
    if ret:
        frame = cv2.resize(frame, (640, 480), interpolation = cv2.INTER_AREA)
        holo = make4side(frame)
   out = cv2.VideoWriter('hologram640x480.avi',fourcc, 23.98, (holo.shape[0],holo.shape[1]))
   total_frames = cap.get(cv2.CAP_PROP_FRAME_COUNT)
   count = 0
   print("Processing %d frames"%(total_frames))
   while(True):
       # Capture frame-by-frame
       ret, frame = cap.read()
       if ret:
           frame = cv2.resize(frame, (640, 480), interpolation = cv2.INTER_AREA)
           holo = make4side(frame)
           out.write(holo)
           count += 1
           print("Total:%d of %d"%(count,total_frames))
       if(count>=total_frames-1):
           break

   cap.release()
   out.release()
   return

process('g.mov')

the result is like this.

In this code, the overall frame's height and width are based only on the input which is the single video which I concern on this too since I use 4 videos and of course the frame resolution are not the same (but all are landscape). Variables h and w in the function make4side() are the main part that help positioning each of the small frame. So for this case, what should the big frame (variable output) resolution be?

I have to read 4 videos and write it into one so, how can I use VideoCapture object to do it for this purpose

To make my question clear, I want to have a single video that consist of 4 input videos, each of them are going to be placed at each of the position (top, bottom, left and right). I have a problem with the big frame resolution which I don't know what to use if I have 4 videos instead of one. Another problem is about the VideoCapture object. How can I read frames of all videos at the same time or any other way to do this?

Thank you

Edit: top side

left side

back side

right side

These are not the real frames I will be used but just a simple idea what I am going to use for my video. Another thing, input files may not have the same resolution. How can I use many videocapture objects to read each of them and place it on each side of the big frame to write a single video

回答1:

So everything depends on what you want to do, so it will come on what type of images you will be processing. First of all, you can always have 4 instances of the VideoCapture class, and each of them loads a new video, something like:

videoTop = cv2.VideoCapture(videoTopFileName)
videoLeft = cv2.VideoCapture(videoLeftFileName)
videoRight = cv2.VideoCapture(videoRightFileName)
videoBottom = cv2.VideoCapture(videoBottomFileName)

readCorrect = True
while( readCorrect ):
  readCorrect , topFrame = videoTop.read()
  ret, leftFrame = videoLeft.read()
  readCorrect = readCorrect and ret
  ret, rightFrame = videoRight.read()
  readCorrect  = readCorrect and ret
  ret, bottomFrame = videoBottom.read()
  readCorrect = readCorrect and ret
  if readCorrect :
     holo = make4side(topFrame, leftFrame, rightFrame, bottomFrame )

You can in this loop already save your image in the VideoWriter.

Now it comes the tricky part, your images are not of equal size... you can do something like:

import cv2
import numpy as np

# load images, in your case frames from videos
top = cv2.imread("D:\\testing\\1.jpg")
left = cv2.imread("D:\\testing\\2.jpg")
bottom = cv2.imread("D:\\testing\\3.jpg")
right = cv2.imread("D:\\testing\\4.jpg")

targetSize = (200,200)

h = targetSize[1] #height
w = targetSize[0] #width

top = cv2.resize(top,  targetSize )
left = cv2.resize(left,  targetSize )
bottom = cv2.resize(bottom,  targetSize )
right = cv2.resize(right,  targetSize )

output = np.zeros((w+h+h , w + h + h, 3), dtype="uint8")

# top
output[0:h, h:h+w] = top
# left >> rotate 90
output[h:h+w, 0:h] = np.rot90(left,1)
# right >> rotate 270
output[h:h + w, h + w:h +w +h] = np.rot90(bottom,3)
# bottom >> rotate 180
output[h+w:h+w+h, h:h+w] = np.rot90(right,2)

cv2.imshow("frame", output )
cv2.waitKey(0)import cv2
import numpy as np

# load images, in your case frames from videos
top = cv2.imread("D:\\testing\\1.jpg")
left = cv2.imread("D:\\testing\\2.jpg")
bottom = cv2.imread("D:\\testing\\3.jpg")
right = cv2.imread("D:\\testing\\4.jpg")

targetSize = (200,200)

h = targetSize[1] #height
w = targetSize[0] #width

top = cv2.resize(top,  targetSize )
left = cv2.resize(left,  targetSize )
bottom = cv2.resize(bottom,  targetSize )
right = cv2.resize(right,  targetSize )

output = np.zeros((w+h+h , w + h + h, 3), dtype="uint8")

# top
output[0:h, h:h+w] = top
# left >> rotate 90
output[h:h+w, 0:h] = np.rot90(left,1)
# right >> rotate 270
output[h:h + w, h + w:h +w +h] = np.rot90(bottom,3)
# bottom >> rotate 180
output[h+w:h+w+h, h:h+w] = np.rot90(right,2)

cv2.imshow("frame", output )
cv2.waitKey(0)

But this generates a "bad" image like this one:

To make it not distorted, you should find the aspect ratio and try to resize them something similar. In case that the aspect ratio is different, then you will have to pad the images. This is the part that depends on your task, you can crop the image or pad it.

But basically that is what should be done. I hope this helps you.


Update:

Just to clarify the loop part:

  readCorrect , topFrame = videoTop.read()
  ret, leftFrame = videoLeft.read()
  readCorrect = readCorrect and ret

In the first line I assigned to the readCorrect variable the boolean return from read. Then in the next image I assigned to ret and do a logic and with the previous result. This way you know if all of them are true, or if ANY is false.

I also corrected something in the loop that had a mistake (I put while not readCorrect and it should be without the not).

One more thing before the loop you should create the VideoWriter object, you can always get the sizes of each video before reading with the get with the argument CV_CAP_PROP_FRAME_WIDTH and CV_CAP_PROP_FRAME_HEIGHT, like videoTop.get(CV_CAP_PROP_FRAME_WIDTH).

And then inside the loop, specifically inside the if after getting the image you can write it to.