为了处理手机摄像头的图像,试图用openCv解决问题。尝试了openCv的demo,都是横屏显示,在手机上使用并不方便。
经过一些尝试,对org.opencv.android(v4.1.0)做了少量修改,实现了竖屏显示。
- Manifest
毫无疑问,为了实现竖屏显示,必须设置屏幕方向
android:screenOrientation="portrait"
- CameraBridgeViewBase.CvCameraViewListener2
这是必须在应用程序中实现的接口,包括三个监听器。
private var rgbaMat: Mat? = null
override fun onCameraViewStarted(width: Int, height: Int) {
rgbaMat = Mat(width, height, CvType.CV_8UC4)
}
override fun onCameraViewStopped() {
rgbaMat?.release()
}
override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame?): Mat? {
rgbaMat = inputFrame?.rgba()
Core.rotate(rgbaMat, rgbaMat, Core.ROTATE_90_CLOCKWISE)
return rgbaMat
}
监听器用kotlin实现,在onCameraFrame取得相机帧数据后,顺时针旋转90°,返回到屏幕上。此时预览图像与竖屏一致,但不是全屏。
- CameraBridgeViewBase
看来仅仅在自家APP上动手脚,不能完全解决问题,只好对SDK源代码下手。
// NOTE: On Android 4.1.x the function must be called before SurfaceTexture constructor!
protected void AllocateCache()
{
// mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888);
mCacheBitmap = Bitmap.createBitmap(mFrameHeight, mFrameWidth, Bitmap.Config.ARGB_8888);
}
protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) {
int calcWidth = 0;
int calcHeight = 0;
int maxAllowedWidth = (mMaxWidth != MAX_UNSPECIFIED && mMaxWidth < surfaceWidth)? mMaxWidth : surfaceWidth;
int maxAllowedHeight = (mMaxHeight != MAX_UNSPECIFIED && mMaxHeight < surfaceHeight)? mMaxHeight : surfaceHeight;
for (Object size : supportedSizes) {
int width = accessor.getWidth(size);
int height = accessor.getHeight(size);
// if (width <= maxAllowedWidth && height <= maxAllowedHeight) {
if (height <= maxAllowedWidth && width <= maxAllowedHeight) {
if (width >= calcWidth && height >= calcHeight) {
calcWidth = (int) width;
calcHeight = (int) height;
}
}
}
return new Size(calcWidth, calcHeight);
}
修改处已经标出,但仍然得不到全屏显示。
4. JavaCameraView
原来这里也需要修改。
protected boolean initializeCamera(int width, int height) {
...
// mScale = Math.min(((float)height)/mFrameHeight, ((float)width)/mFrameWidth);
mScale = Math.min(((float)width)/mFrameHeight, ((float)height)/mFrameWidth);
...
}
至此,以org.opencv.android.JavaCameraView为基类的视频View可以得到全竖屏显示。
5. JavaCamera2View
对于以org.opencv.android.JavaCamera2View为基类的View来说,修改有所不同。
@Override
protected boolean connectCamera(int width, int height) {
...
if ((getLayoutParams().width == LayoutParams.MATCH_PARENT) && (getLayoutParams().height == LayoutParams.MATCH_PARENT))
// mScale = Math.min(((float)height)/mFrameHeight, ((float)width)/mFrameWidth);
mScale = Math.min(((float)width)/mFrameHeight, ((float)height)/mFrameWidth);
else
mScale = 0;
...
{
如果不修改这里,图像会显示怪异的颜色。
private class JavaCamera2Frame implements CvCameraViewFrame {
...
@Override
public Mat rgba() {
...
else if (mPreviewFormat == ImageFormat.YUV_420_888) {
assert (mUVFrameData != null);
// Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21);
Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV2BGRA_NV21);
...
{
经过上述修改,虽然能够实现竖屏的全屏显示,但是由于图像数据90°旋转处理的资源占用较多,使得预览帧率下降严重,视频有迟滞现象,最终没有采用这个方案。