Jam*_*meo 36 android opencv android-camera
我正在尝试使用OpenCV 2.4.3.2创建一个相机应用程序并进行一些opencv处理.我希望它能够有多个UI方向,而不仅仅是Landscape.
问题是,当我将方向更改为纵向时,图像会侧向出现.
我知道我可以在进行图像处理之前旋转输入图像(因此只将方向保留为横向),这很好并且有效,但是没有解决我的其他UI将处于错误方向的问题.
我也尝试使用这段代码来旋转相机90deg,但它似乎没有用.
mCamera.setDisplayOrientation(90);
Run Code Online (Sandbox Code Playgroud)
它要么没有效果,要么有时只会导致预览变黑
有人用OpenCV成功完成了这项工作吗?我的类扩展自JavaCameraView.

我做了一些改进,就是我在OpenCV中旋转了图像,因为它在CameraBridgeViewBase.java类中显示.
在交付和绘制框架方法中:
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
//canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null);
//Change to support portrait view
Matrix matrix = new Matrix();
matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,(canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
matrix.postRotate(90f,(canvas.getWidth()) / 2,(canvas.getHeight()) / 2);
canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
Run Code Online (Sandbox Code Playgroud)
...基本上,这只是像输入图像一样

这样更好,但我显然希望这是全屏.
小智 12
我在尝试实现OpenCV时遇到了同样的问题.我能够通过对deliverAndDrawFrame方法进行以下更改来修复它.
旋转画布对象
Canvas canvas = getHolder().lockCanvas();
// Rotate canvas to 90 degrees
canvas.rotate(90f, canvas.getWidth()/2, canvas.getHeight()/2);
Run Code Online (Sandbox Code Playgroud)在绘制之前调整位图大小以适合整个画布大小
// Resize
Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
// Use bitmap instead of mCacheBitmap
canvas.drawBitmap(bitmap, new Rect(0,0,bitmap.getWidth(), bitmap.getHeight()), new Rect(
(int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2),
(int)((canvas.getHeight() - mScale*bitmap.getHeight()) / 2),
(int)((canvas.getWidth() - mScale*bitmap.getWidth()) / 2 + mScale*bitmap.getWidth()),
(int?((canvas.getHeight() - mScale*bitmap.getHeight()) / 2 + mScale*bitmap.getHeight()
)), null);
// Unlock canvas
getHolder().unlockCanvasAndPost(canvas);
Run Code Online (Sandbox Code Playgroud)小智 10
实际上,你可以只做宽度或高度数学父(全屏).
if (canvas != null) {
Bitmap bitmap = Bitmap.createScaledBitmap(mCacheBitmap, canvas.getHeight(), canvas.getWidth(), true);
canvas.rotate(90,0,0);
float scale = canvas.getWidth() / (float)bitmap.getHeight();
float scale2 = canvas.getHeight() / (float)bitmap.getWidth();
if(scale2 > scale){
scale = scale2;
}
if (scale != 0) {
canvas.scale(scale, scale,0,0);
}
canvas.drawBitmap(bitmap, 0, -bitmap.getHeight(), null);
Run Code Online (Sandbox Code Playgroud)
...
此外,您可以使预览大小大于屏幕.只需修改比例.
我修改了CameraBridgeViewBase.java,如下所示:
protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) {
int calcWidth = 0;
int calcHeight = 0;
if(surfaceHeight > surfaceWidth){
int temp = surfaceHeight;
surfaceHeight = surfaceWidth;
surfaceWidth = temp;
}
Run Code Online (Sandbox Code Playgroud)
在函数"deliverAndDrawFrame"中:
if (mScale != 0) {
if(canvas.getWidth() > canvas.getHeight()) {
canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
(int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
(int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
} else {
canvas.drawBitmap(mCacheBitmap, rotateMe(canvas, mCacheBitmap), null);
}
Run Code Online (Sandbox Code Playgroud)
其中rotateMe的定义如下:
private Matrix rotateMe(Canvas canvas, Bitmap bm) {
// TODO Auto-generated method stub
Matrix mtx=new Matrix();
float scale = (float) canvas.getWidth() / (float) bm.getHeight();
mtx.preTranslate((canvas.getWidth() - bm.getWidth())/2, (canvas.getHeight() - bm.getHeight())/2);
mtx.postRotate(90,canvas.getWidth()/2, canvas.getHeight()/2);
mtx.postScale(scale, scale, canvas.getWidth()/2 , canvas.getHeight()/2 );
return mtx;
}
Run Code Online (Sandbox Code Playgroud)
预览FPS较慢,因为与横向模式相比,计算开销较小.
与其他答案一样,我编写了我个人版本的DeliverAndDrawFrame(我还通过注释通知了我的代码开始和结束的位置):
protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
Mat modified;
if (mListener != null) {
modified = mListener.onCameraFrame(frame);
} else {
modified = frame.rgba();
}
boolean bmpValid = true;
if (modified != null) {
try {
Utils.matToBitmap(modified, mCacheBitmap);
} catch(Exception e) {
Log.e(TAG, "Mat type: " + modified);
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmpValid = false;
}
}
if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
if (BuildConfig.DEBUG) {
Log.d(TAG, "mStretch value: " + mScale);
}
// Start of the fix
Matrix matrix = new Matrix();
matrix.preTranslate( ( canvas.getWidth() - mCacheBitmap.getWidth() ) / 2f, ( canvas.getHeight() - mCacheBitmap.getHeight() ) / 2f );
matrix.postRotate( 90f, ( canvas.getWidth()) / 2f, canvas.getHeight() / 2f );
float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
matrix.postScale(scale, scale, canvas.getWidth() / 2f , canvas.getHeight() / 2f );
canvas.drawBitmap( mCacheBitmap, matrix, null );
// Back to original OpenCV code
if (mFpsMeter != null) {
mFpsMeter.measure();
mFpsMeter.draw(canvas, 20, 30);
}
getHolder().unlockCanvasAndPost(canvas);
}
}
}
Run Code Online (Sandbox Code Playgroud)
预览现在处于纵向模式,如您所见:
小智 5
不幸的是,Opencv4Android不支持肖像相机.但是有一种方法可以克服它.1)编写自定义相机并将其方向设置为纵向.2)注册它的预览回调.3)在onPreviewFrame(byte[]data, Camera camera)创建Mat预览字节时:
Mat mat = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC1);
mat.put(0, 0, data);
Core.transpose(mat, mat);
Core.flip(mat, mat, -1); // rotates Mat to portrait
Run Code Online (Sandbox Code Playgroud)
CvType 取决于相机使用的预览格式.
PS.不要忘记在完成后释放你创建的所有Mat实例.
PPS.最好在单独的线程上管理你的摄像头,以便在进行一些检测时不会超载UI线程.
新的 OpenCV 类似乎CameraBridgeViewBase.java太高级了,并且没有对相机预览的布局提供足够的控制。看看我的示例代码,它基于一些较旧的 OpenCV 示例并使用纯 Android 代码。要使用传入的字节数组onPreviewFrame,put()请将其转换为 Mat 并从 YUV 转换为 RGB:
mYuv = new Mat(previewHeight + previewHeight/2, previewWidth, CvType.CV_8UC1);
mYuv.put(0, 0, mBuffer);
Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGBA, 4);
Run Code Online (Sandbox Code Playgroud)
您也许可以在互联网上找到旧的 OpenCV4Android 示例,尽管它们在几个版本前已被删除。但是,链接的示例代码和上面的代码片段应该足以帮助您入门。
| 归档时间: |
|
| 查看次数: |
30800 次 |
| 最近记录: |