OpenCV C++代码到 Java 语言"Production"



我对OpenCV很陌生。我正在努力学习如何将给定的c++ OpenCV代码转换为Java等效代码。

以下"Java翻译"代码的原始代码来自(GitHub)形状检测算法

代码是用Eclipse IDE编写的。作为Android应用程序。代码显示没有错误。我也尝试过围绕它工作,使用不同的方法来转换数据类型,使用列表而不仅仅是矢量,并应用了MatOfPoint的使用……但是它总是在运行时停止响应。

  1. 它总是在运行时停止显示:

不幸的是,ShapeDetection已经停止。

  • 有一个使用MatOfPoint2f的问题,我不清楚它是如何工作的,它是由Java建议的,但后来我需要在ApproxPolyDp函数后将其转换回常规MatOfPoint。
  • 翻译的代码与上面给定链接的代码不100%相同。我想使用相机帧并在REAL TIME检测形状,而不是加载图像然后进行后处理
  • 错误是INSIDE The for loop in onCameraFrame()
  • 我试着寻找解决方案,并逐一应用它们,但都失败了,有些更难以理解,可能是因为我作为一个(相当)新手的身份。
  • 我看到过一个非常类似这个问题的问题,但是没有答案:链接
  • 我希望你能在这个问题上与我分享你的专业知识和时间。这对我来说将是一个很大的帮助,我将能够继续做我的项目,并可能向市场发布应用程序。

    这是MainActivity

        package com.example.shapedetection;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Vector;
    import org.opencv.android.BaseLoaderCallback;
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
    import org.opencv.android.LoaderCallbackInterface;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfPoint;
    import org.opencv.core.MatOfPoint2f;
    import org.opencv.core.Point;
    import org.opencv.core.Rect;
    import org.opencv.core.Scalar;
    import org.opencv.core.Size;
    import org.opencv.imgproc.Imgproc;
    import android.content.pm.ActivityInfo;
    import android.os.Bundle;
    import android.support.v7.app.ActionBarActivity;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.SurfaceView;
    import android.view.Window;
    import android.view.WindowManager;
    public class MainActivity extends ActionBarActivity implements CvCameraViewListener2 {
        private CameraBridgeViewBase cameraView;
        private final String TAG = "ShapeDetection::";
        private List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        //private Vector <Vector <Point> > contours;
        private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
            @Override
            public void onManagerConnected(int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS:
                    {
                        Log.i(TAG, "OpenCV loaded successfully");
                        cameraView.enableView();
                    } break;
                    default:
                    {
                        super.onManagerConnected(status);
                    } break;
                }
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
            setContentView(R.layout.activity_main);
            cameraView = (CameraBridgeViewBase) findViewById(R.id.surface_view);
            cameraView.setVisibility(SurfaceView.VISIBLE);
            cameraView.setCvCameraViewListener(this);
        }
        protected void onResume() {
            super.onResume();
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
        }
        protected void onPause() {
            super.onPause();
            if (cameraView != null)
                cameraView.disableView();
        }
        protected void onDestroy() {
            super.onDestroy();
            if (cameraView != null)
                cameraView.disableView();
        }
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
        @Override
        public void onCameraViewStarted(int width, int height) {        
        }
        @Override
        public void onCameraViewStopped() {     
        }
        @Override
        public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
            Mat cameraFrame = inputFrame.rgba();
            Mat grayFrame = new Mat();
            Imgproc.cvtColor(cameraFrame, grayFrame, Imgproc.COLOR_BGR2GRAY);
            Mat binaryFrame = new Mat();    
            Mat mHierarchy = new Mat();
            Mat retImg = new Mat();
            //Imgproc.Canny(grayFrame, binaryFrame, 80, 90);
            Imgproc.Canny(grayFrame, binaryFrame, 0, 50);
            //Vector <Vector <Point> > contours;
            Imgproc.findContours(binaryFrame.clone(), contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
            //List<MatOfPoint> approx;
            //Vector <Point> approx;
            retImg = cameraFrame.clone();
            //Convert List<MatOfPoint> to an array
            //casted the (Point[]) array
            // Object --> Array of Points
            //Point[] contourArray = (Point[]) contours.toArray();
            MatOfPoint2f approxCurve = new MatOfPoint2f();
            for (int i = 0; i < contours.size(); i++)
            {
                MatOfPoint2f contour2f = new MatOfPoint2f(contours.get(i).toArray());
                double approxDistance = Imgproc.arcLength(contour2f, true) * 0.02;
                // Approximate contour with accuracy proportional
                // to the contour perimeter
                Imgproc.approxPolyDP(contour2f, approxCurve, approxDistance, true);
                //MatOfPoint2f back to MatOfPoint
                MatOfPoint approxCurve2 = new MatOfPoint(approxCurve);
                // Skip small or non-convex objects 
                //contourArray[i]
                if (Math.abs(Imgproc.contourArea(contour2f)) < 100 || !Imgproc.isContourConvex((MatOfPoint) approxCurve2))
                    //continue;
                if (approxCurve2.size().equals(3))
                {
                    setLabel(retImg, "TRI", contours.get(i));    // Triangles
                }
                else if (approxCurve2.size().equals(4) || approxCurve2.size().equals(5) || approxCurve2.size().equals(6))
                {
                    // Number of vertices of polygonal curve
                    //Point[] sizer = approxCurve2.toArray();
                    //int vtc = sizer.length;
                    int vtc;
                    if (approxCurve2.size().equals(4))
                        vtc = 4;
                    else if (approxCurve2.size().equals(5))
                        vtc = 5;
                    else
                        vtc = 6;
                    // Get the cosines of all corners
                    //Converting approxCurve2(MatOfPoint) to Array
                    //This process seems to be one of the reasons to the 
                    //silent error, when I tested it
                    Point[] approxCurveToArray = approxCurve2.toArray();
                    Vector<Double> cos = new Vector<Double>(2);
                    for (int j = 2; j < vtc+1; j++)
                        cos.add(angle(approxCurveToArray[j%vtc], approxCurveToArray[j-2], approxCurveToArray[j-1]));
                    // Sort ascending the cosine values
                    Collections.sort(cos);
                    // Get the lowest and the highest cosine
                    double mincos = cos.firstElement();
                    double maxcos = cos.lastElement();
                    // Use   the degrees obtained above and the number of vertices
                    // to determine the shape of the contour
                    if (vtc == 4 && mincos >= -0.1 && maxcos <= 0.3)
                        setLabel(retImg, "RECT", contours.get(i));
                    else if (vtc == 5 && mincos >= -0.34 && maxcos <= -0.27)
                        setLabel(retImg, "PENTA", contours.get(i));
                    else if (vtc == 6 && mincos >= -0.55 && maxcos <= -0.45)
                        setLabel(retImg, "HEXA", contours.get(i));
                }
                else
                {
                    // Detect and label circles
                    double area = Imgproc.contourArea(contours.get(i));
                    Rect r = Imgproc.boundingRect(contours.get(i));
                    int radius = r.width / 2;
                    if (Math.abs(1 - ((double)r.width / r.height)) <= 0.2 &&
                        Math.abs(1 - (area / (Math.PI * Math.pow(radius, 2)))) <= 0.2)
                        setLabel(retImg, "CIR", contours.get(i));
                }
            } //End of for loop
            ////////////////////////
            //Test Sample
            /*
            Point pt1, pt2;
            pt1 = new Point(200,200);
            pt2 = new Point(500,800);
            org.opencv.core.Core.rectangle(grayFrame, pt1, pt2,new Scalar(255,255,255), -1);
            org.opencv.core.Core.putText(grayFrame, "TEST SAMPLE", pt1, 3, .4, new Scalar(0,0,0), 1);
            return grayFrame;
            */
            return retImg;
        }
        //Helper function to find a cosine of angle between vectors
        public double angle(Point pt1, Point pt2, Point pt0) {
            double dx1 = pt1.x - pt0.x;
            double dy1 = pt1.y - pt0.y;
            double dx2 = pt2.x - pt0.x;
            double dy2 = pt2.y - pt0.y;
            return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
        }
        void setLabel(Mat im, String label, MatOfPoint contour)
        {
            int fontface = 3;
            double scale = 0.4;
            int thickness = 1;
            int[] baseline = {0};
            Point pt;
            Size text = org.opencv.core.Core.getTextSize(label, fontface, scale, thickness, baseline);
                    //getTextSize(label, fontface, scale, thickness, baseline);
            Rect r = Imgproc.boundingRect((MatOfPoint) contours);
            pt = new Point(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));   
            //pt1 = new Point(0, baseline[0]);
            //pt2 = new Point(text.width, -text.height);
            org.opencv.core.Core.rectangle(im, pt /*Point(0, baseline)*/, pt/*Point(text.width, -text.height)*/,new Scalar(255,255,255), thickness - 2);
            //rectangle(im, pt /*Point(0, baseline)*/, pt/*Point(text.width, -text.height)*/,new Scalar(255,255,255), thickness - 2);
            //putText(im, label, pt, fontface, scale, new Scalar(0,0,0), thickness, 8);
            org.opencv.core.Core.putText(im, label, pt, fontface, scale, new Scalar(0,0,0), thickness);
        }
    }
    

    XML非常简单:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.example.shapedetection.MainActivity" >
        <org.opencv.android.JavaCameraView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:visibility="gone"
            android:id="@+id/surface_view" />
    </RelativeLayout>
    

    任何东西都很感激!提前感谢!

    我自己发现了这个错误,它在setLabel()方法内。

    Rect r = Imgproc.boundingRect((MatOfPoint) contours);应为Rect r = Imgproc.boundingRect(contour);参数传递错误

    程序运行,尽管它仍然是错误的,在获得approxCurve2.size().equals()值方面。在这方面,C和Java之间可能存在值的差异。

    未检测到三角形和矩形,所有检测到的轮廓都标记为圆形

    approxCurve2.size()给出宽度x高度,例如三角形为1 x 3。相比之下,对于所有基本形状,approxCurve2.width()返回1,但approxCurve.height()返回顶点的实际数量。

    检测顶点数的方法如下:

        if (approxCurve2.height() == 3)
        {
            setLabel(outMat, "TRI", contours.get(i));    // Triangles
        }
        else if (approxCurve2.height() == 4 || approxCurve2.height() == 5 || approxCurve2.height() == 6)
        {
            // Number of vertices of polygonal curve
            int vertices = approxCurve2.height();
            ......
        }
    

    对于五边形检测,您可能还希望在角度的余弦值中考虑小数四舍五入。

    以下值范围将可靠地检测正五边形。

    if (vertices == 4 && minCosineOfCorners >= -0.1 && maxCosineOfCorners <= 0.3)
        setLabel(outMat, "RECT", contours.get(i));
    else if (vertices == 5 && minCosineOfCorners >= -0.34 && maxCosineOfCorners <= -0.26)
        setLabel(outMat, "PENTA", contours.get(i));
    else if (vertices == 6 && minCosineOfCorners >= -0.55 && maxCosineOfCorners <= -0.45)
        setLabel(outMat, "HEXA", contours.get(i));
    

    最新更新