python 如何使用 opencv 从 sftp 位置读取视频文件

How to read video file from sftp location using opencv in python

我在使用 opencv 库从 sftp 位置读取文件时遇到问题。你能告诉我如何从 sftp 位置或 sftp 文件对象读取文件吗?如果你能告诉我直接读取大文件到 opencv lib 那就太好了。

import paramiko
import cv2
import numpy as np

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("IPADDRESS", port=22, username='USERNAME', password='PASSWORD')
t = client.get_transport()
sftp = paramiko.SFTPClient.from_transport(t)
sftp.chdir("/home/bizviz/devanshu_copy")

obj = sftp.open("SampleVideo_1280x720_1mb.mp4")

cap = cv2.VideoCapture.open(obj)

while True:
    _,frame = cap.read()
    print(frame)
    cv2.imshow('res', frame)
    key = cv2.waitKey(1)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()

仅使用 Paramiko,您需要将文件复制到本地文件系统,然后将该本地文件用于 cv2。

cv2 不接受这种传递文件的方法。

当然,python 拥有适用于所有内容的库,所以我认为使用 fs.sshfs, which is an extension on pyfilesystem2 来包含 SFTP 应该可以解决问题。 请注意,这实际上与 opencv-python 不兼容。


编辑 1:

docs here 您可以看到可以将文件传递给 VideoCapture.Open() 的方式。

编辑代码以在本地复制文件,然后将本地文件传递给 openCV 工作正常。

sftp.get('file.mp4', 'file.mp4')
sftp.close() # Also, close the sftp connection

cap = cv2.VideoCapture.open('file.mp4')

EDIT2:

因此,使用 ssfhs works. Best way would be to mount the SFTP on the OS level using the tested methods for this. Below is sample python code to do everything in python, but note that this assumes ssfhs can connect correctly to the SFTP host from commandline. I'm not explaining that part here as there are excellent different tutorials 将 SFTP 文件系统挂载到本地文件系统。

请注意,这仅包含一些基本的错误检查,因此我建议您确保捕捉到任何可能弹出的错误。这是概念证明。

import cv2
import os
import subprocess


g_remoteuser = 'USERNAME'
g_remotepassword = 'PASSWORD'
g_remotehost = 'HOSTIP'
g_remotepath = '/home/{remoteuser}/files'.format(remoteuser=g_remoteuser)
g_localuser = 'LOCAL_MACHINE_LINUX_USERNAME'
g_localmntpath = '/home/{localuser}/mnt/remotehost/'.format(localuser=g_localuser)
g_filename = 'file.mp4'


def check_if_path_exists(path):
    # check if the path exists, create the path if it doesn't
    if not os.path.exists(path):
        os.makedirs(path)


def mount(remoteuser, remotehost, remotepath, remotepassword, localmntpath):
    check_if_path_exists(localmntpath)
    if not check_if_mounted(localmntpath):
        subprocess.call([
            '''echo "{remotepassword}" | sshfs {remoteuser}@{remotehost}:{remotepath} {localmntpath} \
             -o password_stdin -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o auto_unmount -o allow_other'''.format(
                remoteuser=remoteuser,
                remotehost=remotehost,
                remotepath=remotepath,
                localmntpath=localmntpath,
                remotepassword=remotepassword
            )], shell=True)


def unmount(path):
    try:
        subprocess.call(['sudo umount -l {path}'.format(path=path)], shell=True)
    except Exception as e:
        print(e)


def check_if_mounted(path):
    # check if there's actually files. Hacky way to check if the remote host is already mounted.
    # will of course fail if there's no files in the remotehost
    from os import walk
    f = []
    for (dirpath, dirnames, filenames) in walk(path):
        f.extend(filenames)
        f.extend(dirnames)
        if dirnames or filenames or f:
            return True
        break
    return False


if check_if_mounted(g_localmntpath):
    unmount(g_localmntpath)

mount(g_remoteuser, g_remotehost, g_remotepath, g_remotepassword, g_localmntpath)


cap = cv2.VideoCapture()
cap.open(g_localmntpath + g_filename)


while True:
    _, frame = cap.read()
    print(frame)
    cv2.imshow('res', frame)
    key = cv2.waitKey(1)
    if key == 27:
        break

cap.release()
cv2.destroyAllWindows()
unmount(g_localmntpath)