3

Currently I'm developing an app that will detect colored circles. I'm trying to do this by following this tutorial, where guy detects red circles on image with Python. I've written the same code, just for Java.

                    Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
                            CvType.CV_8UC3);

                    Mat hsv_image = new Mat();
                    Utils.bitmapToMat(bitmap, mat);
                    Imgproc.cvtColor(mat, hsv_image, Imgproc.COLOR_BGR2HSV);

                    Mat lower_red_hue_range = new Mat();
                    Mat upper_red_hue_range = new Mat();

                    Core.inRange(hsv_image, new Scalar(0, 100, 100), new Scalar(10, 255, 255), lower_red_hue_range);
                    Core.inRange(hsv_image, new Scalar(160, 100, 100), new Scalar(179, 255, 255), upper_red_hue_range);
                    Utils.matToBitmap(hsv_image, bitmap);
                mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
                image.setImageBitmap(mutableBitmap);

Image I use is identical to one from tutorial: enter image description here

This is image with applied BGR2HSV: enter image description here

When I execute the code using lower red hue range, it detects the blue circle. When I use upper red hue range it gives me black bmp(doesn't detect anything). How can it be? What am I doing wrong? This is literally copy moved from python to Java. Why's the result different then? Thanks in advance.

1
  • If possible can you please post your code on how you have detected red color in an image using java. Commented Sep 18, 2018 at 5:58

2 Answers 2

3

Your mat is of CvType.CV_8UC1 image, i.e. you are working on a grayscale image. Try with CvType.CV_8UC3

Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC3);

hsv_image should look like this:

enter image description here

How to select a custom range:


You may want to detect a green circle. Well, in HSV, tipically the range is:

H in [0,360]
S,V in [0,100]

However, for CV_8UC3 images, each component H,S,V can be represented by only 256 values at most, since it's stored in 1 byte. So, in OpenCV, the ranges H,S,V for CV_8UC3 are:

H in [0,180] <- halved to fit in the range
S,V in [0,255] <- stretched to fit the range

So to switch from typical range to OpenCV range you need to:

opencv_H = typical_H / 2;
opencv_S = typical_S * 2.55; 
opencv_V = typical_V * 2.55;

So, green colors are around the value of hue of 120. The hue can have a value in the interval [0,360]. However, for Mat3b HSV images, the range for H is in [0,180], i.e. is halved so it can fit in a 8 bit representation with at most 256 possible values. So, you want the H value to be around 120 / 2 = 60, say from 50 to 70. You also set a minimum value for S,V to 100 in order to prevent very dark (almost black) colors.

Mat green_hue_range
inRange(hsv_image, cv::Scalar(50, 100, 100), cv::Scalar(70, 255, 255), green_hue_range);
Sign up to request clarification or add additional context in comments.

7 Comments

Ok. I guess I've figured it out - I converted mat from RGBA to BGR and then used BGR2HSV. Now it displays everything correctly.
@OleksandrFirsov Nice!
Yea, but I don't understand how to define my personal inRange. If I want green circles, for example, what values should I write in Scalar. RGB of wanted color? HSV?
I use this colorizer.org to find my colors. How can you make HSV be (70, 255, 255). If the limit is 100. And also, how can you calculate the range? If using colorizer, how would you find green values there?
I guess, I understand how you do (50, 100, 100). But where do you get 255 for (70, 255, 255)?
|
0

use the following code and pass color to Blob detector and then pass an image to the detector

private Scalar converScalarRgba2HSV(Scalar rgba) {
Mat  pointMatHsv= new Mat();
Mat pointMatRgba = new Mat(1, 1, CvType.CV_8UC3, rgba);
Imgproc.cvtColor(pointMatRgba,pointMatHsv, Imgproc.COLOR_RGB2HSV_FULL, 4);

return new Scalar(pointMatHsv.get(0, 0));}

// Blob Detector

public class ColorBlobDetector {
// Lower and Upper bounds for range checking in HSV color space
private Scalar mLowerBound = new Scalar(0);
private Scalar mUpperBound = new Scalar(0);
// Minimum contour area in percent for contours filtering
private static double mMinContourArea = 0.1;
// Color radius for range checking in HSV color space
private Scalar mColorRadius = new Scalar(25,50,50,0);
private Mat mSpectrum = new Mat();
private List<MatOfPoint> mContours = new ArrayList<MatOfPoint>();

Mat mPyrDownMat = new Mat();
Mat mHsvMat = new Mat();
Mat mMask = new Mat();
Mat mDilatedMask = new Mat();
Mat mHierarchy = new Mat();

public void setColorRadius(Scalar radius) {
    mColorRadius = radius;
}

public void setHsvColor(Scalar hsvColor) {
    double minH = (hsvColor.val[0] >= mColorRadius.val[0]) ? hsvColor.val[0]-mColorRadius.val[0] : 0;
    double maxH = (hsvColor.val[0]+mColorRadius.val[0] <= 255) ? hsvColor.val[0]+mColorRadius.val[0] : 255;

    mLowerBound.val[0] = minH;
    mUpperBound.val[0] = maxH;

    mLowerBound.val[1] = hsvColor.val[1] - mColorRadius.val[1];
    mUpperBound.val[1] = hsvColor.val[1] + mColorRadius.val[1];

    mLowerBound.val[2] = hsvColor.val[2] - mColorRadius.val[2];
    mUpperBound.val[2] = hsvColor.val[2] + mColorRadius.val[2];

    mLowerBound.val[3] = 0;
    mUpperBound.val[3] = 255;

    Mat spectrumHsv = new Mat(1, (int)(maxH-minH), CvType.CV_8UC3);

    for (int j = 0; j < maxH-minH; j++) {
        byte[] tmp = {(byte)(minH+j), (byte)255, (byte)255};
        spectrumHsv.put(0, j, tmp);
    }

    Imgproc.cvtColor(spectrumHsv, mSpectrum, Imgproc.COLOR_HSV2RGB_FULL, 4);
}

public Mat getSpectrum() {
    return mSpectrum;
}

public void setMinContourArea(double area) {
    mMinContourArea = area;
}

public void process(Mat rgbaImage) {
    Imgproc.pyrDown(rgbaImage, mPyrDownMat);
    Imgproc.pyrDown(mPyrDownMat, mPyrDownMat);

    Imgproc.cvtColor(mPyrDownMat, mHsvMat, Imgproc.COLOR_RGB2HSV_FULL);

    Core.inRange(mHsvMat, mLowerBound, mUpperBound, mMask);
    Imgproc.dilate(mMask, mDilatedMask, new Mat());

    List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

    Imgproc.findContours(mDilatedMask, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

    // Find max contour area
    double maxArea = 0;
    Iterator<MatOfPoint> each = contours.iterator();
    while (each.hasNext()) {
        MatOfPoint wrapper = each.next();
        double area = Imgproc.contourArea(wrapper);
        if (area > maxArea)
            maxArea = area;
    }

    // Filter contours by area and resize to fit the original image size
    mContours.clear();
    each = contours.iterator();
    while (each.hasNext()) {
        MatOfPoint contour = each.next();
        if (Imgproc.contourArea(contour) > mMinContourArea*maxArea) {
            Core.multiply(contour, new Scalar(4,4), contour);
            mContours.add(contour);
        }
    }
}

public List<MatOfPoint> getContours() {
    return mContours;
}}

now set detector

public void initDetector() {

    mDetector = new ColorBlobDetector();
    mSpectrum = new Mat();
    mBlobColorRgba = new Scalar(255);
    mBlobColorHsv = new Scalar(255);
    SPECTRUM_SIZE = new org.opencv.core.Size(500, 64);
    CONTOUR_COLOR = new Scalar(0, 255, 0, 255);


    mDetector.setHsvColor(converScalarRgba2HSV(new Scalar(0,255,255,255)));

    Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR_EXACT);

    mIsColorSelected = true;

}

now pass an image to a detector object

 Mat mRgba = new Mat(inputFrame.height(), inputFrame.width(), CvType.CV_8UC4);
    mRgba = inputFrame;

        mDetector.process(mRgba);
        List<MatOfPoint> contours = mDetector.getContours();

        Log.e(TAG, "Contours count: " + contours.size());
       drawContours(mRgba, contours, -1, CONTOUR_COLOR);
       return mRgba;

Happy Codeing !!!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.