在 Android 上的 OpenCV 中旋转 VideoCapture

Posted

技术标签:

【中文标题】在 Android 上的 OpenCV 中旋转 VideoCapture【英文标题】:Rotate VideoCapture in OpenCV on Android 【发布时间】:2012-10-08 14:59:12 【问题描述】:

在 OpenCV 上使用 VideoCapture 类时如何旋转相机? (android 上的人脸检测示例)。 我正在旋转画布:

if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)

    Matrix matrix = new Matrix();
    matrix.preTranslate(
    (canvas.getWidth() - bmp.getWidth()) / 2,
    (canvas.getHeight() - bmp.getHeight()) / 2);
    matrix.postRotate(270f, (canvas.getWidth()) / 2,
    (canvas.getHeight()) / 2);
    canvas.drawBitmap(bmp, matrix, null);

但来自相机的图像不旋转:人脸检测不起作用。

相机从以下接收流:

protected Bitmap processFrame(VideoCapture capture) 

    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);

    capture.retrieve(mGray,
    Highgui.CV_CAP_ANDROID_GREY_FRAME);

更新 我做了以下事情:

@Override
    protected Bitmap processFrame(VideoCapture capture) 

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) 
        Core.flip(mRgba.t(), mRgba, 0);
    

    else 
    
    capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
    capture.retrieve(mDetect_thread.mGray,
            Highgui.CV_CAP_ANDROID_GREY_FRAME);

但是不工作。当我以 portret 方向(在 android 设备上)运行程序时 - 程序不启动当我以横向方向运行 rogram 时 - 程序工作,但是当我旋转设备时,程序工作,但显示的图像不旋转

【问题讨论】:

【参考方案1】:

您的问题主要是duplicate of this,只是您正在寻找Android版本。它非常相似,但在这里,可以通过转置然后翻转图像来获得 90º 旋转:

# rotate 90º counter-clockwise
Core.flip(mRgba.t(), mRgba, 0); //mRgba.t() is the transpose

# rotate 90º clockwise
Core.flip(mRgba.t(), mRgba, 1);

对于其他轮换,您可以使用warpAffine:

Point center = new Point(x,y);
double angle = 90;
double scale = 1.0;

Mat mapMatrix = Imgproc.getRotationMatrix2D(center, angle, scale);
Imgproc.warpAffine(srcMat, dstMat, mapMatrix, Imgproc.INTER_LINEAR);

编辑 - 更完整的示例如下:

    /** 
     * Image is first resized-to-fit the dst Mat and then rotated. 
     * mRgba is the source image, mIntermediateMat should have the same type.
     */
    private void rotationTutorial()
        double ratio =  mRgba.height() / (double) mRgba.width();

        int rotatedHeight = mRgba.height();     
        int rotatedWidth  = (int) Math.round(mRgba.height() * ratio);

        Imgproc.resize(mRgba, mIntermediateMat, new Size(rotatedHeight, rotatedWidth));

        Core.flip(mIntermediateMat.t(), mIntermediateMat, 0);

        Mat ROI = mRgba.submat(0, mIntermediateMat.rows(), 0, mIntermediateMat.cols());

        mIntermediateMat.copyTo(ROI);       
    


    /** 
     * Image is rotated - cropped-to-fit dst Mat.
     * 
     */
    private void rotationAffineTutorial()
        // assuming source image's with and height are a pair value:
        int centerX = Math.round(mRgba.width()/2);
        int centerY = Math.round(mRgba.height()/2);

        Point center = new Point(centerY,centerX);
        double angle = 90;
        double scale = 1.0;

        double ratio =  mRgba.height() / (double) mRgba.width();

        int rotatedHeight = (int) Math.round(mRgba.height());       
        int rotatedWidth  = (int) Math.round(mRgba.height() * ratio);

        Mat mapMatrix = Imgproc.getRotationMatrix2D(center, angle, scale);

        Size rotatedSize = new Size(rotatedWidth, rotatedHeight);
        mIntermediateMat = new Mat(rotatedSize, mRgba.type());

        Imgproc.warpAffine(mRgba, mIntermediateMat, mapMatrix, mIntermediateMat.size(), Imgproc.INTER_LINEAR);

        Mat ROI = mRgba.submat(0, mIntermediateMat.rows(), 0, mIntermediateMat.cols());

        mIntermediateMat.copyTo(ROI);
    

注意:

这些示例可能是特定方向的,我将它们用于横向。 您不应为每个视频帧调用这些示例中的代码。有些代码应该只运行一次。

【讨论】:

当然可以。人脸识别无法通过旋转图像开箱即用。 @gregm 我已经修复了原始帖子的一些错别字,并提供了一些更完整的示例。如果您之前没有设法让它工作,您可能无法正确输出结果图像。这些示例展示了如何输出它(但可以提高效率)。 @RuiMarques 你好。 FeatureDetector 现在偏离了 90 度。我该如何解决?【参考方案2】:

如果您只需要进行 90、180 或 270 度旋转(这似乎是您的情况),您最好使用更快的 Core.flip()。 下面是一个为你做的方法:

public static Mat rotate(Mat src, double angle)

    Mat dst = new Mat();
    if(angle == 180 || angle == -180) 
        Core.flip(src, dst, -1);
     else if(angle == 90 || angle == -270) 
        Core.flip(src.t(), dst, 1);
     else if(angle == 270 || angle == -90) 
        Core.flip(src.t(), dst, 0);
    

    return dst;

【讨论】:

以上是关于在 Android 上的 OpenCV 中旋转 VideoCapture的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 中将 OpenCV 旋转和平移矢量与 OpenGL ES 一起使用?

android opencv - 每次旋转是不是有可能捕捉到对 3D 对象的不同点击?

将相机预览旋转到人像 Android OpenCV 相机和 Xamarin

为旋转图像构建正样本以在 OpenCV 中进行级联训练

为旋转图像构建正样本以在 OpenCV 中进行级联训练

裁剪和旋转图片 OpenCV