如何解决Camerax ImageCapture 传递给 Chaquopy 太慢
我用 Chaquopy 制作了 Camerax 应用程序:
- ImageCapture 用例捕获图像(jpg)
- 将其转换为位图
- 将位图转换为字符串
- 将字符串传递给 Python
- Python OpenCV 获取图像分辨率并将其返回给 Android(如字符串)
- 在 Textview 上显示
应用程序正在运行,但问题是:
- 应用速度太慢:15-20 秒(字符串转换?)
- 它显示错误的分辨率(分辨率在 ImageCapture 配置中设置)
- 如何加速我的应用程序?
- 除了base64字符串之外,还有其他方法可以将图像传递给python吗??
Android CameraAtivity 代码:
'''
public class CameraActivity extends AppCompatActivity {
private PreviewView previewView;
private ImageCapture imageCapture;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private TextView textView;
private Button button;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
previewView = findViewById(R.id.previewView);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
textView = findViewById(R.id.length);
button = findViewById(R.id.button);
cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindImageAnalysis(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
},ContextCompat.getMainExecutor(this));
}
private void bindImageAnalysis(@NonNull ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
preview.setSurfaceProvider(previewView.createSurfaceProvider());
Executor cameraexecutor = ContextCompat.getMainExecutor(this);
ImageCapture imageCapture = new ImageCapture.Builder().setTargetResolution(new Size(1200,1600)).build();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
imageCapture.takePicture(cameraexecutor,new ImageCapture.OnImageCapturedCallback() {
@Override
public void onCaptureSuccess(@NonNull ImageProxy image){
ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[byteBuffer.capacity()];
byteBuffer.get(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,bytes.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG,100,baos);
byte[] imageBytes = baos.toByteArray();
String imgString = Base64.encodeToString(imageBytes,Base64.DEFAULT);
PyObject obj = pythonn(imgString);
textView.setText(obj.toString());
}
@Override
public void onError(@NonNull ImageCaptureException error) {
error.printStackTrace();
}
});
}
});
cameraProvider.bindToLifecycle((LifecycleOwner)this,cameraSelector,imageCapture,preview);
}
private PyObject pythonn(String imgString) {
if(!Python.isStarted())
Python.start(new AndroidPlatform(this ));
Python py = Python.getInstance();
final PyObject pyobj = py.getModule("shape");
PyObject obj = pyobj.callAttr("main",imgString);
return obj;
}
}
'''
Python 代码;
import cv2
import numpy as np
import base64
def main(imgString):
decoded_data = base64.b64decode(imgString)
np_data = np.fromstring(decoded_data,np.uint8)
img = cv2.imdecode(np_data,cv2.IMREAD_UNCHANGED)
if img.shape[0] > img.shape[1]:
img = cv2.transpose(img)
return str(str(img.shape[0]) + "_" + str(img.shape[1]))
所有代码都在 Github 上: https://github.com/kintipu/Camerax_ImageCapture_Chaquopy_OpenCV_ImageResolution/tree/master
2021 年 3 月 29 日更新。: 我会尝试使用 bytearray,就像 mhsmith 建议的那样。 与此同时,我尝试了另一件事:
-
捕获图片并保存为jpg
-
然后直接从python读取图片 应用程序可以在模拟器上运行,但不能在真手机上运行 安卓代码: '''
公共类 CameraActivity 扩展 AppCompatActivity { 私人预览视图预览视图; 私有 ImageCapture imageCapture; 私人 ListenableFuture cameraProviderFuture; 私有文本视图文本视图; 私人按钮按钮; 私有上下文上下文;
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); previewView = findViewById(R.id.previewView); cameraProviderFuture = ProcessCameraProvider.getInstance(this); textView = findViewById(R.id.length); button = findViewById(R.id.button); cameraProviderFuture.addListener(new Runnable() { @Override public void run() { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); bindImageAnalysis(cameraProvider); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } } },ContextCompat.getMainExecutor(this)); } private void bindImageAnalysis(@NonNull ProcessCameraProvider cameraProvider) { Preview preview = new Preview.Builder().build(); CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK).build(); preview.setSurfaceProvider(previewView.createSurfaceProvider()); Executor cameraexecutor = ContextCompat.getMainExecutor(this); ImageCapture imageCapture = new ImageCapture.Builder().setTargetResolution(new Size(1200,1600)).build(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { File file = new File(getBatchDirectoryName(),"photo"+ ".jpg"); ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build(); imageCapture.takePicture(outputFileOptions,cameraexecutor,new ImageCapture.OnImageSavedCallback () { @Override public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) { new Handler().post(new Runnable() { @Override public void run() { Toast.makeText(CameraActivity.this,"Image Saved successfully" + file.getAbsolutePath(),Toast.LENGTH_LONG).show(); PyObject obj = pythonn(); textView.setText(obj.toString()); } }); } @Override public void onError(@NonNull ImageCaptureException error) { error.printStackTrace(); } }); } }); cameraProvider.bindToLifecycle((LifecycleOwner)this,preview); } public String getBatchDirectoryName() { String app_folder_path = ""; app_folder_path = Environment.getExternalStorageDirectory().toString() + "/images"; File dir = new File(app_folder_path); if (!dir.exists() && !dir.mkdirs()) { } return app_folder_path; } private PyObject pythonn() { if(!Python.isStarted()) Python.start(new AndroidPlatform(this )); Python py = Python.getInstance(); final PyObject pyobj = py.getModule("shape"); PyObject obj = pyobj.callAttr("main"); return obj; }
}
'''
Python 代码:
'''
import cv2
import numpy as np
from android.os import Environment
path = str(str(Environment.getExternalStorageDirectory()) + "/images" + "/photo.jpg")
def main():
img = cv2.imread(path)
return str(str(img.shape[0]) + "_" + str(img.shape[1]))
'''
2021 年 4 月 4 日更新:
我通过一些修改使它更快:
- 将像字节数组这样的图像传递给 python(而不是字符串和 base64 转换) - 根据 Malcom Smith 的建议
- 位图压缩设置为 JPEG(而不是 PNG)
- Python 从 Create 开始
安卓代码; '''
public class CameraActivity extends AppCompatActivity {
private PreviewView previewView;
private ImageCapture imageCapture;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private TextView textView;
private Button button;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
previewView = findViewById(R.id.previewView);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
textView = findViewById(R.id.length);
button = findViewById(R.id.button);
if(!Python.isStarted())
Python.start(new AndroidPlatform(this ));
cameraProviderFuture.addListener(new Runnable() {
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindImageAnalysis(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
},bytes.length);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,baos);
byte[] imageBytes = baos.toByteArray();
// String length = String.valueOf((imgString.length()));
// textView.setText(length);
PyObject obj = pythonn(imageBytes);
textView.setText(obj.toString());
}
@Override
public void onError(@NonNull ImageCaptureException error) {
error.printStackTrace();
}
});
}
});
cameraProvider.bindToLifecycle((LifecycleOwner)this,preview);
}
private PyObject pythonn(byte[] imageBytes) {
Python py = Python.getInstance();
final PyObject pyobj = py.getModule("shape");
PyObject obj = pyobj.callAttr("main",imageBytes);
return obj;
}
}
蟒蛇: '''
import cv2
import numpy as np
def main(imageBytes):
np_data = np.asarray(imageBytes,np.uint8)
img = cv2.imdecode(np_data,cv2.IMREAD_UNCHANGED)
if img.shape[0] > img.shape[1]:
img = cv2.transpose(img)
img = cv2.resize(img,(1600,1200))
return str(str(img.shape[0]) + "_" + str(img.shape[1]))
解决方法
不需要使用 base64,您可以发送 PNG 编码的 byte[]
数组,它会在 Python 中作为字节对象接收。我不确定这个对象是否会被 cv2.imdecode
直接接受,但它肯定会被 np.array
或 np.frombuffer
接受。 (不推荐将二进制数据传递给 np.fromstring
,正如其 documentation page 解释的那样。)
如果您不确定是哪一行代码导致了延迟,您可以在各行之间添加 Log
调用(或 Python 中的 print
调用),然后检查 {{1}} 中的时间戳{3}}。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。