安卓OpenCV颜色检测

3

我目前正在开发一款能够检测彩色圆形的应用程序。我正在尝试按照这个教程(使用Python检测图像中的红色圆圈)来完成,该教程中的作者通过Python检测图像中的红色圆圈。我已经编写了相同的代码,只不过是用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);

我使用的图片与教程中的一样: enter image description here 这是应用BGR2HSV后的图片: enter image description here 当我使用较低的红色色调范围时,它会检测到蓝色圆圈。当我使用较高的红色色调范围时,它会给我黑色bmp(没有检测到任何东西)。这怎么可能?我做错了什么?这个代码是从Python移植到Java的,为什么结果不同呢? 提前感谢您的帮助。

如果可能的话,您能否发布一下您使用Java检测图像中红色的代码? - Pranesh Sahu
2个回答

3

您的matCvType.CV_8UC1图像,即您正在处理灰度图像。请尝试使用CvType.CV_8UC3

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

hsv_image 应该长这样:

enter image description here

如何选择自定义范围:


你可能想要检测一个绿色的圆圈。 在HSV中,通常的范围是:

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

然而,对于CV_8UC3图像,每个分量H、S、V最多可以用256个值来表示,因为它们储存在1个字节中。因此,在OpenCV中,CV_8UC3的H、S、V范围如下:

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

如果要从典型范围切换到OpenCV范围,您需要:

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

所以,绿色的色调值约为120。 色调值可以在区间[0,360]内取值。 然而,对于Mat3b HSV图像,H的范围在[0,180]内,即将其减半,以便它适合8位表示,最多具有256个可能值。 因此,您希望H值约为120/2=60,大约从50到70。 您还设置了S、V的最小值为100,以防止非常暗(几乎黑色)的颜色。
Mat green_hue_range
inRange(hsv_image, cv::Scalar(50, 100, 100), cv::Scalar(70, 255, 255), green_hue_range);

1
好的,我想我已经弄清楚了 - 我将 mat 从 RGBA 转换为 BGR,然后使用 BGR2HSV。现在它正确地显示了一切。 - Oleksandr Firsov
@OleksandrFirsov 很好! - Miki
我使用http://colorizer.org/来查找我的颜色。如果限制为100,如何使HSV为(70,255,255)?另外,如何计算范围?如果使用colorizer,您将如何查找绿色值? - Oleksandr Firsov
我猜我明白你是如何得到 (50, 100, 100) 的。但是你从哪里得到 (70, 255, 255) 中的 255 呢? - Oleksandr Firsov
现在我明白了。谢谢! - Oleksandr Firsov
显示剩余2条评论

0
使用以下代码,将颜色传递给Blob检测器,然后将图像传递给检测器。
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 检测器

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;
}}

现在设置探测器

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;

}

现在将图像传递给检测器对象

 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;

编程愉快!!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接