【问题标题】:openCV video saving in pythonpython中的openCV视频保存
【发布时间】:2015-06-01 18:14:04
【问题描述】:

我正在尝试保存视频,但无法正常工作。 我按照 openCV 文档中的说明进行操作。

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)


        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break
cap.release()

out.release()

cv2.destroyAllWindows()

怎么了?

【问题讨论】:

  • 它在我的电脑上运行良好。事实上,接受的答案不起作用
  • 确保你要写入的目录存在,否则会静默失败。
  • 在我的系统上,只有“DIVX”有效,而 opencv 文档示例中给出的编码,即“M”、“J”、“P”、“G”,只是默默地不写入文件.我希望有一种方法可以验证编解码器,以便我的代码在编解码器可用性方面更安全地移植。

标签: python opencv


【解决方案1】:

试试这个。它对我有用(Windows 10)。

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
#fourcc = cv2.cv.CV_FOURCC(*'DIVX')
#out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
out = cv2.VideoWriter('output.avi', -1, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        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()

【讨论】:

  • 这对我不起作用。仅创建一个空视频文件(大小为 5.6 kB)。
  • 无法生成视频的请更改fourcc参数
  • 它没有创建 output.avi 文件
  • 问题中的代码 sn-p 工作得很好
  • 确实问题中的代码 sn-p 工作正常,但这个答案没有。它依赖于操作系统吗?我在 ubuntu 上。
【解决方案2】:

就我而言,我发现 Writer 的大小必须与相机或文件的帧大小相匹配。这样我就先阅读了帧大小,然后将其应用于写入器设置,如下所示。

(grabbed, frame) = camera.read()
fshape = frame.shape
fheight = fshape[0]
fwidth = fshape[1]
print fwidth , fheight
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (fwidth,fheight))

【讨论】:

  • 相机未定义,相机是什么?
  • @nycynik 如果您直接使用相机而不是保存的视频
  • 这是唯一对我有用的解决方案。要么 OpenCV 发生了变化,要么其他人似乎都有 640x480 的网络摄像头。
【解决方案3】:

https://github.com/ContinuumIO/anaconda-issues/issues/223 的 jveitchmichaelis 提供了详尽的答案。在这里我复制了他的答案:

OpenCV 中的文档说(隐藏)你只能写 使用 OpenCV3 转至 avi。不管这是不是真的,我无法做到 确定,但我无法写入其他任何内容。

然而,OpenCV 主要是一个计算机视觉库,而不是视频流、编解码器和编写器。因此,开发商试图保持 这部分尽可能简单。由于这个用于视频的 OpenCV 容器仅支持 avi 扩展,它的第一个版本。

发件人:http://docs.opencv.org/3.1.0/d7/d9e/tutorial_video_write.html

我的设置:我使用 MSVC 2015 从源代码构建了 OpenCV 3,包括 ffmpeg。我还从以下位置下载并安装了 XVID 和 openh264 Cisco,我添加到我的 PATH 中。我正在运行 Anaconda Python 3。我也 下载了最新版本的 ffmpeg 并将 bin 文件夹添加到我的 路径,尽管这不应该有所作为,因为它已经融入 OpenCV。

我在 Win 10 64 位中运行。

这段代码似乎在我的电脑上运行良好。它将生成一个视频 包含随机静态:

writer = cv2.VideoWriter("output.avi",
cv2.VideoWriter_fourcc(*"MJPG"), 30,(640,480))

for frame in range(1000):
    writer.write(np.random.randint(0, 255, (480,640,3)).astype('uint8'))

writer.release()

我通过反复试验学到的一些东西:

  • 只能使用“.avi”,它只是一个容器,编解码器很重要。
  • 在指定帧大小时要小心。在构造函数中,您需要将帧大小作为 (column, row) 传递,例如640x480。然而 您传入的数组被索引为(行,列)。见上文 例如它是如何切换的?

  • 如果您的输入图像与 VideoWriter 的大小不同,它将失败(通常是静默)

  • 仅传入 8 位图像,如果必须手动转换数组 (.astype('uint8'))
  • 事实上,没关系,只是总是投射。即使您使用 cv2.imread 加载图像,您也需要转换为 uint8...
  • 如果您不传入 3 通道、8 位图像,MJPG 将失败。至少我得到了一个断言失败。
  • XVID 还需要 3 通道图像,但如果您不这样做,则会静默失败。
  • H264 似乎适合单通道图像
  • 如果您需要原始输出,例如机器视觉相机,您可以使用“DIB”。 'RAW' 或空编解码器有时会起作用。奇怪的是,如果我使用 DIB,我收到一个 ffmpeg 错误,但视频保存得很好。如果我使用RAW, 没有错误,但 Windows 视频播放器不会打开它。全部是 在 VLC 中很好。

最后,我认为关键是 OpenCV 并非旨在 一个视频捕捉库——它甚至不支持声音。视频作家 很有用,但 99% 的情况下你最好把所有的钱都存起来 图像放入文件夹并使用 ffmpeg 将它们变成有用的 视频。

【讨论】:

  • "(column, row) e.g. 640x480. 但是你传入的数组被索引为 (row, column)" 我因此失去了 1 天的工作。谢谢!
【解决方案4】:

您需要像这样获取捕获的确切大小:

import cv2

cap = cv2.VideoCapture(0)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5)
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5)
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('your_video.avi', fourcc, 20.0, size)

while(True):
    _, frame = cap.read()
    cv2.imshow('Recording...', frame)
    out.write(frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

【讨论】:

  • 谢谢它对我有用!但你能告诉我为什么我们需要“精确”尺寸吗?
  • @Mayan 原始视频帧宽度和高度意义上的精确尺寸。
  • 这在窗口 10,python 3.7 上对我有用
  • + 0.5有什么意义?
【解决方案5】:

请确保设置正确的宽度和高度。你可以像下面这样设置它

cv2.VideoWriter('output.avi', fourcc, 20.0, (int(cap.get(3)), int(cap.get(4))))

【讨论】:

    【解决方案6】:

    我也遇到了同样的问题,但是当我使用 'MJPG' 而不是 'XVID'

    时它起作用了

    我用过

    fourcc = cv2.VideoWriter_fourcc(*'MJPG')
    

    而不是

    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    

    【讨论】:

      【解决方案7】:

      这是一个仅在 MacOS 中测试过的答案,但它可能也适用于 Linux 和 Windows。

      import numpy as np
      import cv2
      
      cap = cv2.VideoCapture(0)
      
      # Get the Default resolutions
      frame_width = int(cap.get(3))
      frame_height = int(cap.get(4))
      
      # Define the codec and filename.
      out = cv2.VideoWriter('output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))
      
      while(cap.isOpened()):
          ret, frame = cap.read()
          if ret==True:
      
              # write the  frame
              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()
      
      

      【讨论】:

      • 这确实有效,但我的输入视频文件为 83MB,但我最终得到了 接近 1GB 大小的 output.avi您能否解释一下为什么会发生这种情况以及如何解决这个问题? 另外,为什么我需要使用相同的heightwidth
      【解决方案8】:

      我遇到了同样的问题,然后我尝试了这个:

      frame = cv2.flip(frame,180) 
      

      而不是

      frame= cv2.flip(frame,0) 
      

      它正在工作。

      【讨论】:

      • 如果您不想翻转图像,只需删除该行,它不是必需的。
      【解决方案9】:

      我没有像上面的答案那样遇到编解码器问题或尺寸问题。相反,我的问题是因为我的输出帧是灰度的。

      我必须使用参数 isColor=False 创建一个 VideoWriter

      out = cv2.VideoWriter(output_path,
                            cv2.VideoWriter_fourcc(*'mp4v'),
                            30,
                            (INPUT_VIDEO_WIDTH,INPUT_VIDEO_HEIGHT),
                            isColor=False
                            )
      

      API Docs 中,它错误地表示该标志目前仅在 Windows 上受支持。我在 Ubuntu 20.04 上进行了测试,使用 opencv-python==4.2.0.34,它最终正确写入文件。

      【讨论】:

        【解决方案10】:

        这个答案涵盖了变量的含义,重要的是,输入帧和视频大小的输出大小应相同。

        import cv2
        
        save_name = "output.mp4"
        fps = 10
        width = 600
        height = 480
        output_size = (width, height)
        out = cv2.VideoWriter(save_name,cv2.VideoWriter_fourcc('M','J','P','G'), fps , output_size )
        
        cap = cv2.VideoCapture(0) # 0 for webcam or you can put in videopath
        while(True):
            _, frame = cap.read()
            cv2.imshow('Video Frame', frame)
            out.write(cv2.resize(frame, output_size ))
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        cap.release()
        out.release()
        cv2.destroyAllWindows()
        

        【讨论】:

          【解决方案11】:

          Nuru 答案确实有效,唯一的事情是在if ret==True: 循环下删除这一行frame = cv2.flip(frame,0),它将输出视频文件而不翻转

          【讨论】:

            【解决方案12】:

            举个例子:

            fourcc = cv2.VideoWriter_fourcc(*'MJPG')
            out_corner = cv2.VideoWriter('img_corner_1.avi',fourcc, 20.0, (640, 480))
            

            在那个地方,必须将 X,Y 定义为宽度和高度

            但是,当您创建图像(例如空白图像)时,您必须将 Y,X 定义为高度和宽度:

                img_corner = np.zeros((480, 640, 3), np.uint8)
            

            【讨论】:

              【解决方案13】:

              正如@ปรีดา ตั้งนภากร所说:Writer的大小必须与相机或文件的框架相匹配。

              您可以使用此类代码检查您的相机是否为(640、480):

              print(int(cap.get(3)), int(cap.get(4)))
              

              对于我自己,我发现我的相机是 (1280, 720) 并用 (1280, 720) 替换 (640, 480)。然后它可以保存视频。

              【讨论】:

              • 你想参考谁?对我来说,它表示您将 @ปรีดา ตั้งนภากร 归功于此线程中的任何人。
              • ปรีดา ตั้งนภากร 是回答这个问题的人之一。您可以在此线程/页面中找到/搜索他。或许还是找官方解释比较好。
              • 啊无视,你是对的。出于某种原因,我根本没有看到他的答案。
              • 对于好奇的人,那些波浪形的东西(泰语)发音为“Prida Tangnaphakorn”! :P
              【解决方案14】:
              import cv2
              
              cap = cv2.VideoCapture(0)
              
              fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
              frame_width = int(cap.get(3))
              frame_height = int(cap.get(4))
              
              out = cv2.VideoWriter('output.mp4', fourcc, 20,(frame_width,frame_height),True )
              print(int(cap.get(3)))
              print(int(cap.get(4)))
              while(cap.isOpened()):
                  ret,frame = cap.read()
                  if ret == True:
                      print(frame.shape)
                      out.write(frame)
                      cv2.imshow('Frame', frame)
                      if cv2.waitKey(1) & 0xFF == ord('q'):
                          break
                  else:
                      break
              cap.release()
              out.release()`enter code here`
              
              cv2.destroyAllWindows()
              

              这可以正常工作,但视频尺寸相对较小的问题意味着没有捕获任何内容。因此,请确保视频的高度和宽度与您要录制的图像相同。如果您在捕获视频后使用某些操作,则必须确认大小(之前和之后)。 希望它能节省一些时间

              【讨论】:

                【解决方案15】:

                我想写一个灰度图像,但没有任何效果,我必须在 VideoWriter 中添加一个 0

                out = cv2.VideoWriter(outfilename, fourcc, fps, (width, height), 0)

                【讨论】:

                  【解决方案16】:

                  我有点晚了,但是VidGear Python 库的WriteGear API 使用Hardware Encoders support 自动将 OpenCV 帧实时流水线化到任何平台上的 FFmpeg 中同时提供相同的 opencv-python 语法。这是一个基本的python示例:

                  # import libraries
                  from vidgear.gears import WriteGear
                  import cv2
                  
                  output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg tweak parameters for writer
                  
                  stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device
                  
                  writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4' 
                  
                  # infinite loop
                  while True:
                      
                      (grabbed, frame) = stream.read()
                      # read frames
                  
                      # check if frame empty
                      if not is grabbed:
                          #if True break the infinite loop
                          break
                      
                  
                      # {do something with frame here}
                      gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
                  
                      # write a modified frame to writer
                      writer.write(gray) 
                         
                      # Show output window
                      cv2.imshow("Output Frame", frame)
                  
                      key = cv2.waitKey(1) & 0xFF
                      # check for 'q' key-press
                      if key == ord("q"):
                          #if 'q' key-pressed break out
                          break
                  
                  cv2.destroyAllWindows()
                  # close output window
                  
                  stream.release()
                  # safely close video stream
                  writer.close()
                  # safely close writer
                  

                  来源:https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/#using-compression-mode-with-opencv

                  您可以查看VidGear Docs 了解更多高级应用程序和功能。

                  【讨论】:

                    猜你喜欢
                    • 2023-01-19
                    • 2020-07-09
                    • 2019-12-04
                    • 1970-01-01
                    • 2021-01-02
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-09-14
                    • 2020-09-24
                    相关资源
                    最近更新 更多