我想写一个简单的Android OpenCV应用程序,它接受每个相机帧并对帧的像素进行一些计算。我正在使用以下代码。问题是它死得很慢。
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
for(int u = 0; u < frame_width; u++) {
for (int v = 0; v < frame_height; v++) {
double[] current_color = mRgba.get(v, u);
current_color[0] = current_color[0]/2;
mRgba.put(v,u, current_color);
}
}
return mRgba;
或者,如果我使用下面的代码,它运行得非常顺利。
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
Mat imgCanny = new Mat(height,width,CvType.CV_8UC1);
Imgproc.Canny(mRgba,imgCanny,50,150);
return imgCanny;
}
所以我认为缓慢是由访问每个像素引起的。这是我手机中的1024 * 768像素。不幸的是,我需要访问每个像素才能使我的逻辑工作。是否有更快的方式来访问和修改每个像素?
由于
答案 0 :(得分:1)
1)您正在迭代图像的列。您的图像足够大,由于缓存未命中,这将非常慢。列中的每两个连续像素实际上是内存中彼此远离的扫描宽度像素。 通过交换循环的顺序来迭代行。从这个优化开始,你可能会感到惊讶它的速度有多快。
2)不要在循环中使用mRgba.get(u,v)
。我不会在Java中使用openCV,但在C ++中,我会得到一个指向每行开头的指针,并在每一行中按顺序操作像素。在Java中,您可以创建一个行大小的double[]
缓冲区,并使用int get(int row, int col, double[] data)
一次获取整行数据。同样适用于put
函数。我不知道如何用Java访问底层数据缓冲区(即:不复制)。如果你知道怎么做,请告诉我。
3)在您完成1和2后,如果您想要更快地完成并且您可以访问多个内核,则可以并行执行行操作。我无法建议您如何使用Java进行此操作,但也许其他人可以或您可以查看文档。
我对您的结果感兴趣,请尽可能报告。感谢。