当我试图在Android-NDK上使用getPerspectiveTransform来转换透视图时,断言失败了

时间:2013-03-28 13:28:48

标签: android opencv android-ndk computer-vision

所以我试图在ndk上使用opencv检测android上的方形对象,并将其裁剪为2D图形,我检测到正方形的点,但是当我尝试使用getPerspectiveTRansform(src,dst)时,我得到了这个错误消息:

OpenCV Error: Assertion failed (src.checkVector(2, CV_32F) == 4 && dst.checkVector(2, CV_32F)  == 4) in cv::Mat cv::getPerspectiveTransform(cv::InputArray, cv::InputArray), file /home/reports/ci/slave/50-SDK/opencv/modules/imgproc/src/imgwarp.cpp, line 3607

这是我在android中的活动:

package org.opencv.samples.tutorial1;

import java.io.ByteArrayOutputStream;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvException;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class Tutorial1Activity extends Activity implements
        CvCameraViewListener2 {
    private static final String TAG = "OCVSample::Activity";

    private Mat mRgba;
    private Mat mGrayMat;
    private Mat imageTaken;

    private CameraBridgeViewBase mOpenCvCameraView;
    private boolean mIsJavaCamera = true;
    private MenuItem mItemSwitchCamera = null;

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV loaded successfully");

                System.loadLibrary("native_sample");

                mOpenCvCameraView.enableView();
            }
                break;
            default: {
                super.onManagerConnected(status);
            }
                break;
            }
        }
    };

    public Tutorial1Activity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.tutorial1_surface_view);

        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);

        mOpenCvCameraView.setCvCameraViewListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this,
                mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.i(TAG, "called onCreateOptionsMenu");
        // mItemSwitchCamera = menu.add("Toggle Native/Java camera");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        String toastMesage = new String();
        Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);

        if (item == mItemSwitchCamera) {
            mOpenCvCameraView.setVisibility(SurfaceView.GONE);
            mIsJavaCamera = !mIsJavaCamera;

            if (mIsJavaCamera) {
                mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);
                toastMesage = "Java Camera";
            } else {
                mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_native_surface_view);
                toastMesage = "Native Camera";
            }

            mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
            mOpenCvCameraView.setCvCameraViewListener(this);
            mOpenCvCameraView.enableView();

            mOpenCvCameraView.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    takePicture();
                }
            });

            Toast toast = Toast.makeText(this, toastMesage, Toast.LENGTH_LONG);
            toast.show();
        }

        return true;
    }

    public void takePicture() {

        if (imageTaken != null) {

            Bitmap resultBitmap = null;

            try {
                // Imgproc.cvtColor(imageTaken, imageTaken,
                // Imgproc.COLOR_BGR2GRAY);
                // Imgproc.cvtColor(imageTaken, imageTaken,
                // Imgproc.COLOR_GRAY2RGBA, 4);

                /*
                 * Mat test =
                 * Imgproc.getPerspectiveTransform(ImageSrc,ImageDst);
                 * Imgproc.warpPerspective(ImageSrc, ImageDst, test,
                 * ImageDst.size());
                 */

                resultBitmap = Bitmap.createBitmap(imageTaken.cols(),
                        imageTaken.rows(), Bitmap.Config.ARGB_8888);
                //
                Utils.matToBitmap(imageTaken, resultBitmap);

                byte[] sendData = codec(resultBitmap,
                        Bitmap.CompressFormat.JPEG, 50);

                Intent i = new Intent(getApplicationContext(),
                        ShowImageActivity.class);
                i.putExtra("data", sendData);
                startActivity(i);

            } catch (CvException e) {
                // TODO: handle exception
                e.printStackTrace();
            }

        }

    }

    private byte[] codec(Bitmap src, Bitmap.CompressFormat format, int quality) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        src.compress(format, quality, os);

        byte[] array = os.toByteArray();
        System.out.println(array.length);

//      return BitmapFactory.decodeByteArray(array, 0, array.length);
        return array;

    }

    public void onCameraViewStarted(int width, int height) {
        mRgba = new Mat();
        mGrayMat = new Mat();
        imageTaken = new Mat();
    }

    public void onCameraViewStopped() {
        mRgba.release();
        mGrayMat.release();
        imageTaken.release();
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

        /*long start = System.currentTimeMillis();

        Size originalSize = inputFrame.rgba().size();

        Imgproc.resize(inputFrame.rgba(), mRgba, new Size(800, 480));

        */
//      FindSquares(inputFrame.rgba().getNativeObjAddr(), 1);
        // imageTaken = inputFrame.clone();

//      System.out.println(inputFrame.rgba().type());

        findSquare(inputFrame.rgba().getNativeObjAddr(), imageTaken.getNativeObjAddr(),  1);

        // if (mDraw == 1) {
        /*Imgproc.resize(mRgba, inputFrame.rgba(), originalSize);
        // }

        long end = System.currentTimeMillis();
        Log.d("Frame time", "" + (end - start) + " ms");
*/
        return inputFrame.rgba();

    }

    public native void FindFeatures(long matAddrGr, long matAddrRgba);

    public native int FindSquares(long matAddrRgba, int draw);

    public native void findSquare(long matAddrRgba, long matAddrDescriptor, int draw);
}

这是我的jni代码:

JNIEXPORT jint JNICALL Java_com_gconsent_opencv_MainActivity_findSquare(JNIEnv*,
        jobject, jlong addrRgba, jlong addrDescriptor, jlong addrSrc, jlong addrDst, jint draw){

    Mat& image = *(Mat*) addrRgba;

    Mat& imageCropped = *(Mat*) addrDescriptor;

    Mat& imageSrc = *(Mat*) addrSrc;
    Mat& imageDst = *(Mat*) addrDst;


    Mat newSrc = image.clone();
    imageCropped = image.clone();
    Mat testImage = image.clone();

    // blur will enhance edge detection
    Mat blurred(testImage);
    medianBlur(testImage, blurred, 9);

    Mat gray0(blurred.size(), CV_8U), gray;
    vector < vector<Point> > contours;

    // find squares in every color plane of the image
    for (int c = 0; c < 3; c++) {
        int ch[] = { c, 0 };
        mixChannels(&blurred, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        const int threshold_level = 2;
        for (int l = 0; l < threshold_level; l++) {
            // Use Canny instead of zero threshold level!
            // Canny helps to catch squares with gradient shading
            if (l == 0) {
                Canny(gray0, gray, 10, 20, 3); //

                // Dilate helps to remove potential holes between edge segments
                dilate(gray, gray, Mat(), Point(-1, -1));
            } else {
                gray = gray0 >= (l + 1) * 255 / threshold_level;
            }

            // Find contours and store them in a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            // Test contours
            vector < Point > approx;
            for (size_t i = 0; i < contours.size(); i++) {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx,
                        arcLength(Mat(contours[i]), true) * 0.02, true);

                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000
                        && isContourConvex(Mat(approx))) {
                    double maxCosine = 0;

                    for (int j = 2; j < 5; j++) {
                        double cosine = fabs(
                                angle(approx[j % 4], approx[j - 2],
                                        approx[j - 1]));
                        maxCosine = MAX(maxCosine, cosine);
                    }

                    if (maxCosine < 0.3) {

                        line(image, approx[0], approx[1],
                                Scalar(0, 255, 0, 255), 2, 4, 0);
                        line(image, approx[1], approx[2],
                                Scalar(0, 255, 0, 255), 2, 4, 0);
                        line(image, approx[2], approx[3],
                                Scalar(0, 255, 0, 255), 2, 4, 0);
                        line(image, approx[3], approx[0],
                                Scalar(0, 255, 0, 255), 2, 4, 0);



                        vector<Point2f> src(4);

//                      src.push_back(approx[0]);
//                      src.push_back(approx[1]);
//                      src.push_back(approx[2]);
//                      src.push_back(approx[3]);


                        src[0] = approx[0];
                        src[1] = approx[1];
                        src[2] = approx[2];
                        src[3] = approx[3];

                        cv::Mat quad = cv::Mat::zeros(300, 220, CV_8U);

                        // transformed quadrangle
                        vector < Point2f > quad_pts(4);

//                      Point2f quad_pts[4];

                        quad_pts.push_back(Point(0, 0));
                        quad_pts.push_back(Point(quad.cols, 0));
                        quad_pts.push_back(Point(quad.cols, quad.rows));
                        quad_pts.push_back(Point(0, quad.rows));

//                      quad_pts[0] = Point(0, 0);
//                      quad_pts[1] = Point(quad.cols, 0);
//                      quad_pts[2] = Point(quad.cols, quad.rows);
//                      quad_pts[3] = Point(0, quad.rows);

                        imageSrc = Mat(src);
                        imageDst = Mat(quad_pts);


                        Mat transmtx = getPerspectiveTransform(src, quad_pts);
                        warpPerspective(src, quad, transmtx, quad.size());

                        imageCropped = quad.clone();

                    }
                }
            }
        }

    }

//  imageCropped = getPolygon(newSrc);

    return 1;

}

1 个答案:

答案 0 :(得分:4)

将输入cv::Mat类型更改为CV_32FC2。 另请查看this