Сохраните видеовход h264 с камеры дрона в виде видеофайла на компьютер - PullRequest
0 голосов
/ 25 февраля 2020

У меня есть дрон телло ризы, у которого есть камера на борту. Я подключаюсь к дрону, чтобы получить видео по Wi-Fi. Моя система windows 10, и я использую python 2.7.

Я получаю байт-код h264, и я использую декодер libh264 от tello, чтобы получить кадры видео, которые я также отображаю в моем интерфейсе. Что мне нужно сделать, это сохранить это видео в виде файла на моем компьютере, и у меня есть проблемы с этим. Я могу сделать снимок с помощью opencv и сохранить его как изображение, это не проблема. Но по какой-то причине создание видео не работает. Я читаю много постов здесь, как этот , но они не работают для меня. Я получаю либо ошибку, либо получаю очень маленький видеофайл, который не открывается. Мои кадры - это список списка со значениями RGB, такими как:

[[255,200,100][55,200,100][25,20,100]]

Вот мой код для лучшего понимания, чтобы помочь мне

Это часть пользовательского интерфейса (я просто скопирую здесь только необходимый код):

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

Ниже вы можете найти код Телло (только необходимую часть):

    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: я нашел вариант сделать видео из моих снимков, это означает, что я могу сделать снимок поверх потока, а затем сохранить его в видео. Это было бы вариантом. Проблема в том, что он будет занимать слишком много места на диске. Обходная ссылка здесь

1 Ответ

0 голосов
/ 26 февраля 2020

Я нашел решение, поэтому я опубликую его здесь, если кому-то понадобится то же самое. Я использовал следующий блог и изменил код для своей работы, вы можете найти пост здесь

self.frame = None
self.frame_array = []

 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()
            self.frame_array.append(self.frame)

            if self.frame is None or self.frame.size == 0:
                continue

                # transfer the format from frame to image
            image = Image.fromarray(self.frame)


            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 convert_frames_to_video(self, pathOut, fps):

    size = (self.videoWidth, self.videoHeight)
    out = cv2.VideoWriter(pathOut, cv2.VideoWriter_fourcc(*'DIVX'), fps, size)

    for i in range(len(self.frame_array)):
        # writing to a image array
        out.write(self.frame_array[i])
    out.release()

 def onClose(self):

    print("[INFO] closing...")
    self.convert_frames_to_video('video.avi', 25.0)
    self.stopEvent.set()
    del self.drone
    self.root.quit()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...