我正在开发一个程序,它从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.
型
1条答案
按热度按时间mgdq6dx11#
因为它给出了绝对路径作为输出。
您不能保证这一点,因为有许多对
ACTION_PICK
的有效响应,其中代码将失败。而且,即使您最终得到了文件系统路径,您也可能无法通过文件系统API读取内容。我必须首先将视频作为InputStream传递,然后将其发送给python吗?
如果有人用枪逼着你使用Python,你可能需要在Java代码中使用
ContentResolver
和openInputStream
来获取InputStream
,使用该流将内容复制到你控制的某个文件中,然后在Python代码中使用该文件。如果您的Python环境碰巧能够直接使用InputStream
,那么可能会有更好的性能。