2017-05-27 73 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; 
    }