VideoCapture()读取多个视频和帧分辨率问题

时间:2018-09-11 14:54:37

标签: python opencv video-processing

根据此article的答案,该答案指的是将单个图像合并为4面的方式。从那里,我想从仅使用单个视频改为使用4个视频作为输入。

这是我的代码,它使用单个视频作为输入

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

结果是这样的。

4 sided video from single video

在此代码中,整个帧的高度和宽度仅基于输入,这也是我关注的单个视频,因为我使用了4个视频,当然帧分辨率也不相同(但所有分辨率都是横向的) )。函数make4side()中的变量h和w是帮助定位每个小框架的主要部分。那么对于这种情况,大帧(可变输出)分辨率应该是什么?

我必须阅读4个视频并将其写入一个视频,因此,如何使用VideoCapture对象来实现此目的

为使我的问题更清楚,我希望有一个包含4个输入视频的视频,每个输入视频都将放置在每个位置(顶部,底部,左侧和右侧)。我对大帧分辨率有问题,如果我有4个视频而不是一个,我不知道该怎么用。另一个问题与VideoCapture对象有关。如何同时或以其他任何方式读取所有视频的帧?

谢谢

编辑: top 顶部

left 左侧

back 背面

right 右侧

这些不是我将要使用的真实帧,而仅仅是一个简单的想法,我将在视频中使用什么。另一件事,输入文件的分辨率可能不同。如何使用许多视频捕获对象读取每个对象并将其放置在大框架的每一侧以编写单个视频

1 个答案:

答案 0 :(得分:1)

因此,一切取决于您要执行的操作,因此这取决于您要处理的图像类型。首先,您始终可以拥有4个VideoCapture类的实例,并且每个实例都加载一个新视频,例如:

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 )

您可以在此循环中将图像保存在VideoWriter中。

现在这是棘手的部分,您的图像大小不相等...您可以执行以下操作:

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)

但这会生成一个像这样的“坏”图像:

enter image description here

为使其不失真,应找到长宽比并尝试将其调整为类似尺寸。如果宽高比不同,则必须填充图像。这是取决于您的任务的部分,您可以裁剪图像或将其填充。

但是基本上那是应该做的。希望对您有帮助。


更新

仅需澄清循环部分:

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

在我分配给readCorrect变量的第一行中,从read返回的布尔值。然后在下一个图像中,我分配给ret并对上一个结果进行逻辑and。通过这种方式,您可以知道它们是否全部为真,或者ANY是否为假。

我还纠正了循环中有错误的某些内容(我在未读取时正确放置了它,应该没有它)。

在循环之前,您还应该创建VideoWriter对象,在使用带有参数CV_CAP_PROP_FRAME_WIDTHCV_CAP_PROP_FRAME_HEIGHT的{​​{3}}进行读取之前,始终可以获取每个视频的大小,例如videoTop.get(CV_CAP_PROP_FRAME_WIDTH)

然后在循环中,特别是在获取图像后可以将其写入的if内部。