-3

I am working in a project where I have to scan the target and recognize the holes in the target and have to score according to the shots. I am not aware of the exact code how to recognize the holes in the target. I imported the opencv library and gone through a program where if I touch it will recognize the corresponding color. Now I am stuck in the coding part. Here is the screenshot of the target sheet that is given to me.

enter image description here

Could anyone please help me how to proceed further. Thanks in advance.

Saeed Zhiany
  • 2,051
  • 9
  • 30
  • 41
SomeshShuffle
  • 21
  • 1
  • 5
  • I could find the same problem in another question but it was using in python. http://stackoverflow.com/questions/33321303/how-to-detect-bullet-holes-on-the-target-using-python – SomeshShuffle Nov 15 '16 at 10:43

1 Answers1

2

To do what You want You should:

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.

and also take into account some special cases, like "twin" holes in your image.

To implement that steps on Android easiest way is to use OpenCV. How to add it to your project well described here (You should do some work to do to it: download SDK from here and add it correctly). Then You should take a look at some tutorial about using OpenCV in Android, for example, official. And than, You can use code like this (your image added to drawable folder of demo project as 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;
            }
        }
    };
}

And if You press FIND HOLES Button You get result like this

result

For other images You should adjust 245, 255 values in

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

line.

Update: MainActivity layout (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>
Community
  • 1
  • 1
Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
  • Thanks a lot @Andriy Omelchenko. Your program works like a charm. I just followed your steps and it works great. Really you are so helpful. I am just a fresher started my carrier as an android developer. This is my first project on Image processing. So I do not have any idea about it. Still I have many milestones to complete. Any way thanks a lot for your guidance. You are so helpful. I wish I could learn more things from you sir. Thank you sir. – SomeshShuffle Nov 17 '16 at 11:20
  • You are welcome! (and also You can upvote the answer ;) ) – Andrii Omelchenko Nov 17 '16 at 11:44
  • Hello @Andriy Omelchenko, I need another help from you. I hope you can help me in this. Your example works for single image that is stored in a drawable folder. So suppose if I want to capture an image and recognize the holes means what should I do? Could you please help me with the coding part. Now I want to capture an image and when I click the "Find holes" button I should be able to recognize the holes. Is there a way to do it? Please I hope you can help me fix the issue. Thank you. – SomeshShuffle Nov 21 '16 at 12:40
  • Easiest way - get picture from `Camera` via intent, like described [here](http://stackoverflow.com/a/6449092) by [barmaley](http://stackoverflow.com/users/472270/barmaley). And You can get `bitmap` with picture this way `bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, mImageUri);` Then just replace `mSourceImageMat = Utils.loadResource(this, R.drawable.target);` with `Utils.bitmapToMat(bitmap, mSourceImageMat);`. – Andrii Omelchenko Nov 21 '16 at 13:45