opencv python接收绝对视频URI路径,但无法访问/读取视频文件

w9apscun  于 2023-08-06  发布在  Python
关注(0)|答案(1)|浏览(103)

我正在开发一个程序,它从Android存储中获取视频并将其转换为uint8数组。
为此,我获取视频URI路径并将其传递给一个python脚本,该脚本执行帧处理,将帧转换为uint8矩阵元素。我用的是最新版本的chaquopy。
我能够获得视频的绝对和相对URI路径(可以由用户选择)并将其传递给python函数。
然而,Python函数似乎无法访问视频和处理帧。
有谁知道我该怎么解决这个问题吗?
\主活动

public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_PICK_VIDEO = 101;
    private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 101;
    private static final String TAG = "APP_TAG";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Start the process of picking a video from the gallery
        if (checkPermission()) {
            pickVideo();
        }
    }

    private void pickVideo() {
        // Start the video picker activity
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, "video/*");
        startActivityForResult(intent, REQUEST_PICK_VIDEO);
        intent.setType("video/*");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_PICK_VIDEO && resultCode == RESULT_OK && data != null) {
            Uri videoUri = data.getData();
            Log.d(TAG,"Not real URI is: "+ videoUri);

            // Pass the selected video Uri to the VideoProcessor
            VideoProcessor.processVideo(this, videoUri);

            // Access the processed frames as a list of byte arrays
            List<byte[]> processedFrames = VideoProcessor.getProcessedFrames();

            // Check if the list is not null and not empty
            if (processedFrames != null && !processedFrames.isEmpty()) {
                Log.d("VideoProcessor", "Number of processed frames: " + processedFrames.size());
            } else {
                // Handle the case when the processedFrames list is empty or null
                Log.e("VideoProcessor", "No processed frames available.");
                Toast.makeText(this, "No processed frames available.", Toast.LENGTH_SHORT).show();
            }
        } else {
            // Handling for canceled or failed video picking
            Toast.makeText(this, "Video picking canceled or failed.", Toast.LENGTH_SHORT).show();
        }
    }

    // Check for READ_EXTERNAL_STORAGE permission and request it if necessary
    private boolean checkPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
            return false;
        }
        return true;
    }

}

字符串
\ VideoProcessor类

public class VideoProcessor {

    private static final String TAG = "APP_TAG";
    private static List<byte[]> processedFrames;

    public VideoProcessor() {
        processedFrames = new ArrayList<>();
    }

    public static void processVideo(Context context, Uri videoUri) {
        Python py = Python.getInstance();
        if (!Python.isStarted()) {
            Python.start(new AndroidPlatform(context));
        }

        // Convert videoUri to a String representation of the file path
        String videoPath = getRealPathFromUri(context, videoUri);
        Log.d(TAG, "Real URI path is:" + videoPath);

        PyObject videoProcessingModule = py.getModule("script");

        // Call the process_video function in the Python script and pass the video file path as a parameter
        PyObject processedData = videoProcessingModule.callAttr("process_video", videoPath);

        // Get the processed data as a 2D NumPy array (assuming video_processing.py returns a 2D array)
        PyObject[] processedFramesArray = processedData.toJava(PyObject[].class);

        // Convert PyObject[] to List<byte[]>
        for (PyObject frame : processedFramesArray) {
            processedFrames.add(frame.toJava(byte[].class));
        }
    }

    public static List<byte[]> getProcessedFrames() {
        return processedFrames;
    }

    // get the real file path from a content Uri
    private static String getRealPathFromUri(Context context, Uri contentUri) {
        String realPath = null;
        String[] projection = {MediaStore.MediaColumns.DATA};

        try (Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                realPath = cursor.getString(column_index);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return realPath;
    }
}


\ Python脚本

import cv2
import numpy as np
import os

def process_video(video_path):
    print("Received video path:", video_path)

    # Check if the file exists
    if not os.path.exists(video_path):
        print("Error: Video file does not exist.")
        return []

    # Check if the file is readable
    if not os.access(video_path, os.R_OK):
        print("Error: Video file is not readable.")
        return []

    cap = cv2.VideoCapture(video_path)

    frames = []
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        # Process the frame (example: convert it to grayscale)
        processed_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        frames.append(processed_frame)

    cap.release()

    print("Number of processed frames:", len(frames))

    # Return the frames as a list of 1D byte arrays
    return [frame.tobytes() for frame in frames]


\选择视频后输出

2023-08-02 17:26:07.587  3729-3729  python.stdout           com.example.a07312023                I  Received video path: /storage/emulated/0/Pictures/MyCameraApp/VID_20230416_204625.mp4
2023-08-02 17:26:07.587  3729-3729  python.stdout           com.example.a07312023                I  Error: Video file is not readable.
2023-08-02 17:26:07.590  3729-3729  VideoProcessor          com.example.a07312023                E  No processed frames available.

mgdq6dx1

mgdq6dx11#

因为它给出了绝对路径作为输出。
您不能保证这一点,因为有许多对ACTION_PICK的有效响应,其中代码将失败。而且,即使您最终得到了文件系统路径,您也可能无法通过文件系统API读取内容。
我必须首先将视频作为InputStream传递,然后将其发送给python吗?
如果有人用枪逼着你使用Python,你可能需要在Java代码中使用ContentResolveropenInputStream来获取InputStream,使用该流将内容复制到你控制的某个文件中,然后在Python代码中使用该文件。如果您的Python环境碰巧能够直接使用InputStream,那么可能会有更好的性能。

相关问题