Home > Net >  convert numpy.ndarray into video
convert numpy.ndarray into video

Time:05-31

In my code i'm looping over frames of a video, and trying to generate another mp4 video.

This is my code:

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)

The output of print(type(my_image)) is numpy.ndarray for each frame. When I ran the code, i got output_video.mp4 file, but weights only 300 kb (it needs to be about 50 mb).

I tried to save each frame as an image, and to see if it will work, and it did. This is the code:

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

CodePudding user response:

I coded this function to solve a similiar problem, you need to save the images singularly into a folder and then you can use frames2video to convert it into a video.

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

For completeness, i post also the viceversa, a function that given a video extract the frames.

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

CodePudding user response:

Ok, I found a solution. I noticed that I had resize function in my code:

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

So I changed

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

to

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

And it works (:

  • Related