【发布时间】:2020-06-09 09:24:57
【问题描述】:
我有一架 Tello ryze 无人机,上面装有摄像头。我正在连接无人机以通过 wifi 接收视频。我的系统是 windows 10,我使用的是 python 2.7。
我正在接收一个 h264 字节码,我使用 Tello 的 libh264 解码器来获取视频的帧,我也显示在我的 UI 中。 我需要做的是将此视频作为文件保存在我的计算机上,但我遇到了问题。我可以使用 opencv 制作快照并将其保存为图像,这不是问题。但是由于某种原因制作视频不起作用。 我在这里阅读了很多帖子,例如this one,但它们对我不起作用。我收到错误或我收到一个非常小的视频文件,无法打开。 我的帧是具有 RGB 值的列表列表,例如:
[[255,200,100][55,200,100][25,20,100]]
这是我的代码以便更好地理解以帮助我
这是 UI 部分(我只是在这里复制所需的代码):
def videoLoop(self):
try:
# start the thread that get GUI image and draw skeleton
time.sleep(0.5)
self.sending_command_thread.start()
while not self.stopEvent.is_set():
system = platform.system()
# read the frame for GUI show
self.frame = self.drone.read()
if self.frame is None or self.frame.size == 0:
continue
# transfer the format from frame to image
image = Image.fromarray(self.frame)
# we found compatibility problem between Tkinter,PIL and Macos,and it will
# sometimes result the very long preriod of the "ImageTk.PhotoImage" function,
# so for Macos,we start a new thread to execute the _updateGUIImage function.
if system == "Windows" or system == "Linux":
self.refreshUI(image)
else:
thread_tmp = threading.Thread(target=self.refreshUI, args=(image,))
thread_tmp.start()
time.sleep(0.03)
except RuntimeError as e:
print("[INFO] caught a RuntimeError")
def refreshUI(self, image):
image = ImageTk.PhotoImage(image)
# if the imagePanel none ,we need to initial it
if self.imagePanel is None:
self.imagePanel = tki.Label(image=image)
self.imagePanel.image = image
self.imagePanel.pack(side="left", fill="both",
expand="yes", padx=10, pady=10)
# otherwise, simply update the imagePanel
else:
self.imagePanel.configure(image=image)
self.imagePanel.image = image
def takeSnapshot(self):
# grab the current timestamp and use it to construct the filename
ts = datetime.datetime.now()
filename = "{}.jpg".format(ts.strftime("%d-%m-%Y_%H-%M-%S"))
p = os.path.sep.join((self.screenShotPath, filename))
# save the file
cv2.imwrite(p, cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR))
print("[INFO] saved {}".format(filename))
您可以在下面找到 Tello 代码(也只有需要的部分):
def read(self):
"""Return the last frame from camera."""
if self.is_freeze:
return self.last_frame
else:
return self.frame
def video_freeze(self, is_freeze=True):
"""Pause video output -- set is_freeze to True"""
self.is_freeze = is_freeze
if is_freeze:
self.last_frame = self.frame
def _receive_video_thread(self):
"""
Listens for video streaming (raw h264) from the Tello.
Runs as a thread, sets self.frame to the most recent frame Tello captured.
"""
packet_data = b''
while True:
try:
res_string, ip = self.socket_video.recvfrom(2048)
packet_data += res_string
# end of frame
if len(res_string) != 1460:
for frame in self._h264_decod(packet_data):
self.frame = frame
packet_data = b''
except socket.error as exc:
print(("Caught exception sock.error : %s" % exc))
def _h264_decod(self, packet_data):
"""
decode raw h264 format data from Tello
:param packet_data: raw h264 data array
:return: a list of decoded frame
"""
res_frame_list = []
frames = self.decoder.decode(packet_data)
for framedata in frames:
(frame, w, h, ls) = framedata
if frame is not None:
# print ('frame size %i bytes, w %i, h %i, linesize %i' % (len(frame), w, h, ls))
frame = np.frombuffer(frame, dtype=np.ubyte, count=len(frame))
frame = (frame.reshape((h, ls // 3, 3)))
frame = frame[:, :w, :]
res_frame_list.append(frame)
return res_frame_list
如果有人能帮我写一个像这样的伪代码这样的方法,你将非常感激:
def saveVideo(self, frame_or_whatever_i_need_here):
out = cv2.VideoWriter('output.avi_or_other_format', -1, 20.0, (640,480))
out.write(frame_or_whatever_i_need_here)
out.release()
编辑 1: 我找到了一个从我的快照中制作视频的选项,这意味着我可以通过线程制作快照,然后将它们保存到视频中。那将是一个选择。问题是,它会占用磁盘中的太多空间。解决方法链接是here
【问题讨论】:
-
我使用的是 python 2.7 为什么? 我收到一个错误然后请分享整个错误消息。
-
@AMC 因为telloryze 的libh264decoder 与python 3 不兼容
-
@nathancy 不,我以前没有,但现在我做到了。在您的代码示例中是否可以使用 ip 和端口而不是链接?如果是这样,那可能是我需要的解决方案
-
@nathancy 在尝试 rtsp_stream_link = '0.0.0.0:11111' 时出现以下错误:(415) cv::VideoWriter::open VIDEOIO(CV_IMAGES): 引发 OpenCV 异常:(-5:Bad参数)CAP_IMAGES:找不到起始编号(在文件名中):函数'cv::icvExtractPattern'中的output.avi