在安卓上使用OpenCV旋转VideoCapture

10

当使用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);

但是它不起作用。当我在纵向方向上运行程序(在Android设备上)时-程序不会启动。当我在横向方向上运行程序时-程序可以工作,但是当我旋转设备时,程序可以工作,但显示的图像不会旋转。

2个回答

11

你的问题主要是这个问题的重复,只不过你在寻找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);
    }

注意:

  • 这些示例可能是面向特定方向的,我为横向方向创建了它们。
  • 您不应该为每个视频帧调用这些示例中的代码。其中一些代码只需要运行一次。

当然可以运行。它是人脸识别,但不能直接处理旋转的图像。 - Rui Marques
@gregm 我已经修复了原帖中的几个错别字,并提供了更完整的示例。如果您以前无法使其正常工作,那么您可能无法正确输出生成的图像。这些示例展示了如何输出它(但可以在效率方面进行改进)。 - Rui Marques
@RuiMarques 你好。FeatureDetector现在偏了90度,我该怎么修复? - Jenia Ivanov

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接