2017-05-27 72 views
1

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

enter image description here

我已经试过Canny边缘检测和发现的轮廓,但他们没有找到这个红色的“圈子”。我也尝试将其转换为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)); 

     } 
+1

这是你的原始输入图像吗?或者您已手动标记这些红色圆圈以突出显示? – ZdaR

+0

我手动做了一些修改 - 那些圆圈没有链接,所以我改变了几个像素来关闭这个区域来改进算法。你认为这是为什么findcontours和canny算法没有找到那些问题? – Fleczer

+0

但我也认为那些红色的“圆圈”是早先在原始图像上画的。 – Fleczer

回答

3

如果你想的过程,有水印的图像,你真的可能要检测的颜色。通常这是在HSV色彩空间中完成的。

这里是一些C++代码来检测“红色”的颜色。结果还不足以使用findContours,但也许在一些扩展之后。也许你可以将代码转换为Java。

如果要检测不同的颜色,改变线redMask = thresholdHue(hsv, 0, 20, 50, 50);掩盖= 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; 
} 

这里的结果:

enter image description here

+0

非常感谢,非常感谢您的帮助我会尽力转换您的代码,我会让你知道这是什么:) – Fleczer

+1

我已经将它转换为java添加了一些扩展和findcontours和结果对我来说已经足够了。非常感谢! – Fleczer

+0

很高兴听到,添加您的最终Java代码的问题,如果你喜欢:) – Micka

1

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

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