首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OpenCV C++代码到Java语言“简单形状检测应用程序”

OpenCV C++代码到Java语言“简单形状检测应用程序”
EN

Stack Overflow用户
提问于 2015-09-16 06:41:24
回答 2查看 1K关注 0票数 0

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

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

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

发行

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

不幸的是,ShapeDetection已经停止了。

  1. MatOfPoint2f的使用有一个问题,我不清楚它是如何工作的,它是由Java建议的,但在MatOfPoint函数之后,我需要将它转换回常规的ApproxPolyDp函数。
  2. 正在翻译的代码与上面给定链接中的代码不完全相同。我想使用相机帧,并在实时上检测形状,而不是加载图像,然后再进行后处理。
  3. 错误是 for loop中的onCameraFrame()
  4. 我试着找出解决方案,然后一个接一个地应用,但都失败了,有些很难理解,可能是因为我是个新手。
  5. 我见过一个类似于这个问题的问题,但没有答案:链接

我希望你能在这个问题上和我分享你的专业知识和时间。这将是一个很大的帮助,我将能够继续做我的项目,并可能发布一个应用程序的市场。

这里是MainActivity

代码语言:javascript
复制
    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非常简单:

代码语言:javascript
复制
<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>

任何事情都是值得感激的!提前感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-09-16 10:01:26

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

Rect r = Imgproc.boundingRect((MatOfPoint) contours);应该是Rect r = Imgproc.boundingRect(contour);,参数传递是错误的。

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

没有检测到三角形和矩形,所有检测到的轮廓都被标记为圆圈。

票数 0
EN

Stack Overflow用户

发布于 2015-11-28 19:21:25

gives ()给出宽度x高度,例如1x3表示三角形。相反,为所有基本形状返回1,而approxCurve.height()返回实际顶点数。

以下将用于检测顶点计数:

代码语言:javascript
复制
    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();
        ......
    }

对于五角大楼检测,您也可能想要考虑十进制四舍五入的余弦值的角度。

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

代码语言:javascript
复制
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));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32601396

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档