【问题标题】:How to detect bullet holes on the target using Android Opencv如何使用 Android Opencv 检测目标上的弹孔
【发布时间】:2017-03-29 04:48:53
【问题描述】:

我在一个项目中工作,我必须扫描目标并识别目标中的孔,并且必须根据击球得分。我不知道如何识别目标中的孔的确切代码。我导入了opencv库并通过了一个程序,如果我触摸它就会识别相应的颜色。现在我陷入了编码部分。这是给我的目标表的屏幕截图。

任何人都可以帮助我如何进一步进行。提前致谢。

【问题讨论】:

标签: android opencv image-processing image-recognition


【解决方案1】:

做你想做的你应该:

1) find white areas with max brightness;
2) find bounding contours of areas with max brightness (from p.1);
3) find bounding boxes for contours from p.2;
4) count bounding boxes.

还要考虑一些特殊情况,例如图像中的“双”孔。

要在 Android 上实现该步骤,最简单的方法是使用 OpenCV。如何将它添加到您的项目中很好地描述了here(您应该做一些工作:从here 下载 SDK 并正确添加它)。然后你应该看看一些关于在 Android 中使用 OpenCV 的教程,例如,official。而且,您可以使用这样的代码(您的图像添加到演示项目的drawable 文件夹为target.png):

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();

    private ImageView mImageView;
    private Button mProcessButton;

    private Mat mSourceImageMat;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = (ImageView) findViewById(R.id.target_image_view);
        mProcessButton = (Button) findViewById(R.id.process_button);
        mProcessButton.setVisibility(View.INVISIBLE);

        mProcessButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                processImage();
            }
        });
    }

    private void processImage() {
        try {
            mSourceImageMat = Utils.loadResource(this, R.drawable.target);
            Bitmap bm = Bitmap.createBitmap(mSourceImageMat.cols(), mSourceImageMat.rows(),Bitmap.Config.ARGB_8888);

            final Mat mat = new Mat();
            final List<Mat> channels = new ArrayList<>(3);

            mSourceImageMat.copyTo(mat);

            // split image channels: 0-H, 1-S, 2-V
            Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGB2HSV);
            Core.split(mat, channels);
            final Mat frameV = channels.get(2);

            // find white areas with max brightness
            Imgproc.threshold(frameV, frameV, 245, 255, Imgproc.THRESH_BINARY);

            // find contours
            List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Imgproc.findContours(frameV, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

            // find average contour area for "twin" hole detection
            double averageArea = 0;
            int contoursCount = 0;
            Iterator<MatOfPoint> each = contours.iterator();
            while (each.hasNext()) {
                averageArea += Imgproc.contourArea(each.next());
                contoursCount++;
            }
            if (contoursCount != 0) {
                averageArea /= contoursCount;
            }

            int holesCount = 0;
            each = contours.iterator();
            while (each.hasNext()) {
                MatOfPoint contour = each.next();

                MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray());
                RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints);
                Point rect_points[] = new Point[4];

                boundingRect.points(rect_points);
                for(int i=0; i<4; ++i){
                    Imgproc.line(mSourceImageMat, rect_points[i], rect_points[(i+1)%4], new Scalar(255,0,0), 2);
                }
                holesCount++;

                Imgproc.putText(mSourceImageMat, Integer.toString(holesCount), new Point(boundingRect.center.x + 20, boundingRect.center.y),
                        Core.FONT_HERSHEY_PLAIN, 1.5 ,new  Scalar(255, 0, 0));

                // case of "twin" hole (like 9 & 10) on image
                if (Imgproc.contourArea(contour) > 1.3f * averageArea) {
                    holesCount++;
                    Imgproc.putText(mSourceImageMat, ", " + Integer.toString(holesCount), new Point(boundingRect.center.x + 40, boundingRect.center.y),
                            Core.FONT_HERSHEY_PLAIN, 1.5 ,new  Scalar(255, 0, 0));
                }

            }

            // convert to bitmap:
            Utils.matToBitmap(mSourceImageMat, bm);
            mImageView.setImageBitmap(bm);

            // release
            frameV.release();
            mat.release();

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mOpenCVLoaderCallback);
    }

    private BaseLoaderCallback mOpenCVLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS: {
                    Log.i(TAG, "OpenCV loaded successfully");
                    mProcessButton.setVisibility(View.VISIBLE);
                } break;
                default: {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };
}

如果你按FIND HOLES Button 你会得到这样的结果

对于其他图像,您应该调整 245, 255 中的值

Imgproc.threshold(frameV, frameV, 245, 255, Imgproc.THRESH_BINARY);

行。

更新:MainActivity 布局 (activity_main.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    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=".MainActivity">

    <ImageView
        android:id="@+id/target_image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        app:srcCompat="@drawable/target"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/process_button"/>

    <Button
        android:id="@+id/process_button"
        android:text="Find holes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"/>

</RelativeLayout>

【讨论】:

  • 非常感谢@Andriy Omelchenko。你的程序就像一个魅力。我只是按照您的步骤操作,效果很好。你真的很有帮助。我只是一个新手,开始我的运营商作为一名 android 开发人员。这是我的第一个图像处理项目。所以我对此一无所知。我仍然有许多里程碑要完成。无论如何,非常感谢您的指导。你太有帮助了。我希望我能从你那里学到更多东西,先生。谢谢先生。
  • 不客气! (你也可以投票赞成答案;))
  • 你好@Andriy Omelchenko,我需要你的另一个帮助。我希望你能在这方面帮助我。您的示例适用于存储在可绘制文件夹中的单个图像。所以假设如果我想捕捉图像并识别孔意味着我应该怎么做?你能帮我编码部分吗?现在我想捕捉图像,当我单击“查找孔”按钮时,我应该能够识别这些孔。有没有办法做到这一点?请我希望你能帮我解决这个问题。谢谢。
  • 最简单的方法 - 通过意图从 Camera 获取图片,如 barmaley 所描述的 here。并且您可以通过这种方式获得bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, mImageUri); 然后只需将mSourceImageMat = Utils.loadResource(this, R.drawable.target); 替换为Utils.bitmapToMat(bitmap, mSourceImageMat);
猜你喜欢
  • 2016-01-24
  • 2021-06-28
  • 2017-05-19
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 2018-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多