【问题标题】:convert numpy.ndarray into video将 numpy.ndarray 转换为视频
【发布时间】:2022-06-27 17:18:54
【问题描述】:

在我的代码中,我正在循环播放视频的帧,并尝试生成另一个 mp4 视频。

这是我的代码:

cap = cv2.VideoCapture(args.video)

frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output_video.mp4', fourcc, fps, (frame_width, frame_height))    

while cap.isOpened():
    ret, img = cap.read()

    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        out.release() 
        break
    #<code>...
    #<code>...
    print(type(my_image))
    out.write(my_image)

print(type(my_image)) 每帧的输出是numpy.ndarray。当我运行代码时,我得到了output_video.mp4 文件,但重量只有 300 kb(它需要大约 50 mb)。

我尝试将每一帧保存为图像,并查看它是否可以工作,确实可以。这是代码:

img = Image.fromarray(my_image, 'RGB')
img.save('frameeeee-%s.png'%i)

【问题讨论】:

    标签: python numpy opencv python-imaging-library numpy-ndarray


    【解决方案1】:

    我编写了这个函数来解决一个类似的问题,你需要将图像单独保存到一个文件夹中,然后你可以使用 frames2video 将其转换为视频。

    def frames2video( path_in = "/content/original_frames" , path_out = "/content/outputvideo", 
                      frame_rate = 30 , video_name="output_video" ):
      """
      Given an input path to a folder that contains a set of frames, this function
      convert them into a video and then save it in the path_out. 
      You need to know the fps of the original video, are 30 by default.
      """
    
      img_path_list = natsorted(os.listdir(path_in))
      assert(len(img_path_list)>0)
    
      img_array = []
      print("[F2V] Frames to video...", end="\n\n")
    
    
      with tqdm(total=len(img_path_list)) as pbar:
    
        for count,filename in enumerate(img_path_list):
          img = cv2.imread(path_in+"/"+filename)
          if(img is None):break
          height, width, layers = img.shape
          img_array.append(img)
          size = (width,height)
          pbar.update()
    
      if os.path.exists(path_out): shutil.rmtree(path_out)
      os.mkdir(path_out)
    
      out = cv2.VideoWriter(path_out+"/"+str(video_name)+'.mp4', cv2.VideoWriter_fourcc(*'DIVX'), frame_rate, size)
    
      for i in range(len(img_array)):
          out.write(img_array[i])
      out.release()
      print("\n[F2V] Video made from "+str(count+1)+" frames", end="\n\n")
    

    为了完整起见,我还发布了反之亦然,一个给定视频提取帧的函数。

    def n_frames(video):
    """
    Given an input video returns the EXACT number of frames(CV2 was not precise)
    """
      success = True
      count = 0
      while success:
        success,image = video.read()
        if success == False: break
        count+=1
      return count
    
    def video2frames( path_in = "/content/video.mp4" , path_out = "/content/original_frames",
                      n_of_frames_to_save = 999999, rotate=True, frames_name = "OrigFrame" ):
        """
        Given a video from path_in saves all the frames inside path_out.
        The number of frames(in case of long videos) can be truncated with
        the n_of_frames_to_save parameter. Rotate is used to save rotated 
        frames by 90 degree. All the frames are named frames_name with an
        index
        """
        blur_threshold = 0
        if os.path.exists(path_out): shutil.rmtree(path_out)
        os.mkdir(path_out)
    
        count = 0
        success = True
        vidcap = cv2.VideoCapture(path_in)
        v2 = cv2.VideoCapture(path_in)
    
        fps = vidcap.get(cv2.CAP_PROP_FPS) 
    
        if(fps>120): 
          print("CAP_PROP_FPS > 120, probabily you are using a webcam. Setting fps manually")
          fps = 25
        
        n_of_frames = n_frames(v2) # #int(video.get(cv2.CAP_PROP_FRAME_COUNT)) is not accurate, https://stackoverflow.com/questions/31472155/python-opencv-cv2-cv-cv-cap-prop-frame-count-get-wrong-numbers
    
        if(n_of_frames_to_save < n_of_frames): n_of_frames = n_of_frames_to_save
    
        print("[V2F] Dividing the video in " + str(n_of_frames) + " frames", end="\n\n")
    
        for count in trange(n_of_frames):
    
          success,image = vidcap.read()   
    
          if not success: break
    
          image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
          if(rotate): image = cv2.rotate(image,cv2.ROTATE_90_CLOCKWISE) 
    
          plt.imsave("%s/%s%d.png" % (path_out,frames_name+"_", count), image)
    
          count+=1
    
        print("\n[V2F] "+str(count)+" frames saved",end="\n\n")
        return fps
    

    【讨论】:

    • 感谢您的回答。你的代码可以工作,但它太复杂了,而且它会降低运行速度,因为你需要从磁盘写入和读取。我能够为我的代码找到解决方案。如果您关心速度和简单性,我建议您尝试做一些类似于我所做的事情。祝你好运!
    • 是的,我需要用这段代码在磁盘上写,但我们的目标是相似的,所以我认为这可能对你的问题有所帮助。另外,这可能对其他人有帮助,所以我决定把它留在这里。无论如何,也祝你好运!
    【解决方案2】:

    好的,我找到了解决方案。我注意到我的代码中有resize 函数:

    my_image = cv2.resize(image_before, (1280, 720))

    所以我改变了

    out = cv2.VideoWriter('output_video.mp4', fourcc, fps, (frame_width, frame_height))    
    

    到

    out = cv2.VideoWriter('outputttttt.mp4', fourcc, fps, (1280, 720))
    

    它有效(:

    【讨论】:

      猜你喜欢
      • 2018-06-07
      • 1970-01-01
      • 2018-11-21
      • 2014-08-11
      • 1970-01-01
      • 2015-07-21
      • 2019-08-31
      • 2017-11-27
      相关资源
      最近更新 更多