【问题标题】:Detection of red circle-alike | openCV | Java红色圆圈的检测|开放简历 |爪哇
【发布时间】:2017-05-27 16:32:32
【问题描述】:

我正在编写一个程序,该程序需要从这张图片中检测红色圆圈。

我尝试过精明的边缘检测并找到轮廓,但没有一个找到这个红色的“圆圈”。我还尝试将其转换为 hsv 并通过颜色检测它,但我无法确定这种颜色的良好范围,也许背景颜色会混淆它?

我在最后一次尝试中放了一段代码..

Mat image = new Mat();
image = Imgcodecs.imread("image.jpg");
Mat hsvImage = new Mat();
Mat grayscaleImage = new Mat();
Mat binaryImage = new Mat();
Imgproc.blur(image, image, new Size(1, 1));  
Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);           
Imgproc.cvtColor(image, grayscaleImage, Imgproc.COLOR_BGR2GRAY);            
Imgproc.equalizeHist(grayscaleImage, grayscaleImage);
Imgproc.Canny(grayscaleImage, grayscaleImage, 50, 150, 3,false);

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(grayscaleImage.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);


        for (int id=0;id<contours.size();id++){
            MatOfPoint2f mop2f = new MatOfPoint2f();
            contours.get(id).convertTo(mop2f,CvType.CV_32F);
            RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
            if (rectangle.boundingRect().width>80)
            Imgproc.drawContours(image,contours,id,new Scalar(0,255,0));

        }

【问题讨论】:

  • 这是您的原始输入图像吗?还是您手动标记了那些红色圆圈以突出显示?
  • 我手动做了一些改变——那些圆圈没有链接,所以我改变了几个像素来关闭这个区域以改进算法。你认为是 findcontours 和 canny 算法没有找到这些的问题吗?
  • 但我认为那些红色的“圆圈”是之前在原始图像上绘制的。
  • 我的意思是,您的原始图像是否有那些红色圆圈/半圆形?
  • 我认为没有

标签: java opencv geometry detection color-detection


【解决方案1】:

如果您想处理该标记图像,您可能确实需要检测颜色。通常这是在 HSV 颜色空间中完成的。

这里是一些用于检测“红色”颜色的 C++ 代码。结果还不足以使用 findContours,但可能经过一些膨胀。也许您可以将代码转换为 Java。

如果要检测不同的颜色,请将行 redMask = thresholdHue(hsv, 0, 20, 50, 50); 更改为 mask = thresholdHue(hsv, yourWantedHueColorValue, 20, 50, 50);`

// for example to shift a circluar hue-channel
cv::Mat shiftChannel(cv::Mat H, int shift, int maxVal = 180)
{
    // CV_8UC1 only!
    cv::Mat shiftedH = H.clone();
    //int shift = 25; // in openCV hue values go from 0 to 180 (so have to be doubled to get to 0 .. 360) because of byte range from 0 to 255
    for (int j = 0; j < shiftedH.rows; ++j)
    for (int i = 0; i < shiftedH.cols; ++i)
    {
        shiftedH.at<unsigned char>(j, i) = (shiftedH.at<unsigned char>(j, i) + shift) % maxVal;
    }

    return shiftedH;
}

cv::Mat thresholdHue(cv::Mat hsvImage, int hueVal, int range = 30, int minSat = 50, int minValue = 50)
{
    // hsvImage must be CV_8UC3 HSV image.
    // hue val and range are in openCV's hue range (0 .. 180)
    // range shouldnt be bigger than 90, because that's max (all colors), after shifting the hue channel.

    // this function will
    //    1. shift the hue channel, so that even colors near the border (red color!) will be detectable with same code.
    //    2. threshold the hue channel around the value 90 +/- range

    cv::Mat mask; // return-value

    std::vector<cv::Mat> channels;
    cv::split(hsvImage, channels);

    int targetHueVal = 180 / 2; // we'll shift the hue-space so that the target val will always be 90 afterwards, no matter which hue value was chosen. This can be important if 
    int shift = targetHueVal - hueVal;
    if (shift < 0) shift += 180;

    cv::Mat shiftedHue = shiftChannel(channels[0], shift, 180);

    // merge the channels back to hsv image
    std::vector<cv::Mat> newChannels;
    newChannels.push_back(shiftedHue);
    newChannels.push_back(channels[1]);
    newChannels.push_back(channels[2]);
    cv::Mat shiftedHSV;
    cv::merge(newChannels, shiftedHSV);

    // threshold
    cv::inRange(shiftedHSV, cv::Vec3b(targetHueVal - range, minSat, minValue), cv::Vec3b(targetHueVal + range, 255, 255), mask);

    return mask;
}


int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/redCircleLikeContours.jpg");


    cv::Mat redMask; 

    cv::Mat hsv;
    cv::cvtColor(input, hsv, CV_BGR2HSV);

    redMask = thresholdHue(hsv, 0, 20, 50, 50);

    cv::imshow("red", redMask);

    cv::imshow("input", input);
    cv::imwrite("C:/StackOverflow/Output/redCircleLikeContoursMask.png", redMask);

    cv::waitKey(0);
    return 0;
}

结果如下:

【讨论】:

  • 非常感谢,非常感谢您的帮助,我将尝试转换您的代码,并让您知道其中的内容:)
  • 我已经将它转换为 java 添加了一些膨胀和 findcontours,结果对我来说已经足够好了。非常感谢!
  • 很高兴听到,如果您愿意,请将您的最终 Java 代码添加到问题中:)
  • 我认为这个任务会更容易解决,如果(手绘?)标记没有绘制成半透明的并且可能每个标记颜色都有一个图像(因为有时它们重叠)。
【解决方案2】:

如果有人想看,这是我的代码:)

public static void main (String args[]){

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);               

        Mat image = new Mat();
        image = Imgcodecs.imread("imageorg.jpg");

        if ( image == null) System.out.println("Image is fine");
        else System.out.println("Wrong path to image");


        Mat hsvImage = new Mat();
        Imgproc.blur(image, image, new Size(3,3));  
        Imgproc.cvtColor(image, hsvImage, Imgproc.COLOR_BGR2HSV);           

        Mat redMask = new Mat();
        redMask = thresholdHue(hsvImage,0,20,50,50);

        Mat kernel = new Mat();
        kernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(2,2));        

        Mat dilateMat = new Mat();
        Imgproc.dilate(redMask, dilateMat, kernel);                         

        Imgcodecs.imwrite("redCircleLikeContours.png", redMask);                


        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Imgproc.findContours(dilateMat.clone(), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);           


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

        for (int id=0;id<contours.size();id++){                     
            MatOfPoint2f mop2f = new MatOfPoint2f();
            contours.get(id).convertTo(mop2f,CvType.CV_32F);
            RotatedRect rectangle = Imgproc.minAreaRect(mop2f);
            if (rectangle.boundingRect().height<10){
                removedContoursList.add(contours.get(id));
                System.out.println("removing: "+rectangle.boundingRect());
                contours.remove(id);
                id--;
            }
        }

    }


    public static Mat thresholdHue(Mat hsvImage, int hueVal, int range, int minSat, int minValue)
    {   
        Mat mask = new Mat(); 

        List<Mat> channels = new ArrayList<Mat>();
        Core.split(hsvImage, channels);

        int targetHueVal = 180 / 2; 
        int shift = targetHueVal - hueVal;
        if (shift < 0) shift += 180;

        Mat shiftedHue = shiftChannel(channels.get(0), shift, 180);


        List<Mat> newChannels = new ArrayList<Mat>();

        newChannels.add(shiftedHue);
        newChannels.add(channels.get(1));
        newChannels.add(channels.get(2));
        Mat shiftedHSV = new Mat();
        Core.merge(newChannels, shiftedHSV);


        Core.inRange(shiftedHSV, new Scalar(targetHueVal - range, minSat, minValue), new Scalar(targetHueVal + range, 255, 255), mask);

        return mask;
    }


    private static Mat shiftChannel(Mat H, int shift, int maxVal)
    {

        Mat shiftedH = H.clone();
        for (int j = 0; j < shiftedH.rows(); ++j)
        for (int i = 0; i < shiftedH.cols(); ++i)
        {
            shiftedH.put(j, i,(shiftedH.get(j,i)[0] + shift) % maxVal);
        }

        return shiftedH;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 2022-06-29
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多