2015-07-05 27 views
6

Obecnie pracuję nad aplikacją, która wykrywa kręgi ze zdjęć. Udało mi się napisać kod do tego, ale albo robi fałszywe negatywy, albo fałszywe alarmy, jeśli odbiorę telefon trochę z ekranu komputera. Jak mogę poprawić wynik? Mam na myśli, że istnieje wiele aplikacji wykrywających małe i niejasne kręgi.Android OpenCV Poprawianie jakości wykrywania

[Aktualizacja]

mam błahy z wartościami w GaussianBlur i HoughCircles. Zmiana Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2); na Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 9, 9); i podwójne poprawić wynik, ale nie wystarczy.

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

      Utils.bitmapToMat(bitmap, mat); 

      int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY 
        : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1); 

      Imgproc.cvtColor(mat, grayMat, colorChannels); 


      Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2); 

      // accumulator value 
      double dp = 1.2d; 
      // minimum distance between the center coordinates of detected circles in pixels 
      double minDist = 100; 


      int minRadius = 0, maxRadius = 0; 

      double param1 = 70, param2 = 72; 


      Mat circles = new Mat(bitmap.getWidth(), 
        bitmap.getHeight(), CvType.CV_8UC1); 


      Imgproc.HoughCircles(grayMat, circles, 
        Imgproc.CV_HOUGH_GRADIENT, dp, minDist, param1, 
        param2, minRadius, maxRadius); 


      int numberOfCircles = 9; 

      if (numberOfCircles > circles.cols()){ 
       numberOfCircles = circles.cols(); 
      } 


      for (int i=0; i<numberOfCircles; i++) { 



       double[] circleCoordinates = circles.get(0, i); 



       if(circleCoordinates == null){ 
       break; 
       } 



       int x = (int) circleCoordinates[0], y = (int) circleCoordinates[1]; 

       Point center = new Point(x, y); 
       android.graphics.Point centerC = new android.graphics.Point(x, y); 

       int radius = (int) circleCoordinates[2]; 



       Core.circle(mat, center, radius, new Scalar(0, 
         255, 0), 4); 


       Core.rectangle(mat, new Point(x - 5, y - 5), 
         new Point(x + 5, y + 5), 
         new Scalar(0, 128, 255), -1); 

Z góry dziękuję.

Teraz używam tych punktów w kształcie litery A, aby przetestować kod, ale chcę wykryć nawet mniejsze kręgi na zdjęciu. enter image description here

+0

Czy próbowałeś różnych zestawów parametrów dla param1 i param2? –

+0

Nie. Nie. Jak myślisz, jak powinienem spróbować je zmienić? Zwiększyć parametr 2? –

+0

Moim pierwszym domysłem byłoby zmniejszenie param2. Będziesz miał kilka fałszywych trafień, ale zakładam, że łatwiej jest radzić sobie z fałszywymi pozytywami niż fałszywie negatywnymi. Po drugie, spróbuj zmniejszyć parametr param1. Zwiększa to czułość detektora krawędzi Canny'ego, co może być miłe, gdy chcesz wykryć kręgi, które nie wyróżniają się w tle. –

Odpowiedz

0

Myślę, że jeśli chcesz wykryć tylko białe kółka, musisz zaimplementować wykrywanie koloru. Nie tylko znacznie poprawi jakość wykrywania, ale usunie wiele fałszywych alarmów i negatywów. Używanie wykrywania koloru jest całkiem proste, ponieważ jest już obecne w OpenCV. Do tego użyj funkcji Core.inRange. Możesz znaleźć więcej informacji na ten temat here. Ale prawdopodobnie najlepszą rzeczą dla Ciebie byłoby skorzystanie z samouczka: this. Został napisany w języku Python, ale jest zrozumiały i musisz zmienić tylko kilka linii, aby działał na Androida. Mam nadzieję, że to pomaga :)

+0

Hej, dzięki za szczegółową odpowiedź! Jeśli spojrzysz na komentarze, zobaczysz, że wymyśliłem to samo rozwiązanie tego pytania. Westchnienie, gdybyś tylko odpowiedział kilka dni wcześniej ... –

+0

Czy to oznacza, że ​​nie dostanę nagrody? T-T –

+0

Nie, wydaje mi się, że nadal zasługujesz na to. Dzięki jeszcze raz. –

0

ogólnie wytwarzania param1 i param2 mniejszą rozluźni próg rozpoznawania koła, więc nie będzie bardziej fałszywe pozytywy [wykrywania koła w przypadku braku] oraz mniejszą liczbę wyników fałszywie negatywne [niewykrycie koło którym jest jeden].

Param2 ustawia próg wykrywania okręgu. Jeśli liczba jest mniejsza, zostanie wykrytych więcej kręgów.

Param1 ustawia próg czułości dla detektora krawędzi Canny. Jeśli liczba jest mniejsza, bardziej prawdopodobne jest wykrycie słabszych kółek niż w przypadku większej liczby.

Podobnie jak w przypadku każdego widzenia w komputerze lub uczenia maszynowego, jeśli nie działa niezawodnie i nie wiesz dlaczego, spróbuj zmienić niektóre parametry. :-D

Katastrofa, gdy jest mniej niż dziewięć okręgów, pochodzi z kodowania z liczbą kręgów do dziewięciu. Kiedy jest mniej niż dziewięć okręgów, program próbuje uzyskać dostęp poza granice macierzy Mat.

Nie mam systemu do testowania OpenCV w tej chwili, ale mogę napisać trochę kodu. Moim jedynym zastrzeżeniem jest to, że możesz potrzebować circles.rows zamiast circles.cols. Edycja: także, kręgi są puste, jeśli ma 0 wpisów.

int numberOfCircles = 9; 
if (circles == null) numberOfCircles = 0; 
else if (numberOfCircles > circles.cols) numberOfCircles = circles.cols; 

for (int i=0; i<numberOfCircles; i++) { 
    double[] circleCoordinates = circles.get(0, i); 
    ... 
+0

Ten kod pomógł. Częściowo. Teraz aplikacja nie zawiesza się, jeśli mam od 1 do x kręgów. Jeśli liczba wynosi 0 - crash. –

+0

Co to jest komunikat o błędzie? –

+0

Spójrz na pytanie –

0

Spróbuj tego.

Mat input = new Mat(); 
    Mat rgb = new Mat(); 
    Mat output = new Mat(); 
    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentImagePath, bitOpts); 
    input = Utils.bitmapToMat(bitmap); 
    FeatureDetector fast = FeatureDetector.create(FeatureDetector.FAST); 
    List<KeyPoint> keypoints = new ArrayList<KeyPoint>(); 
    fast.detect(input, keypoints); 
    Imgproc.cvtColor(input, rgb, Imgproc.COLOR_RGBA2RGB); 
    Features2d.drawKeypoints(rgb, keypoints, rgb); 
    Imgproc.cvtColor(rgb, output, Imgproc.COLOR_RGB2RGBA); 
    Utils.matToBitmap(output, bitmap); 
    //SHOW IMAGE 
    mImageView.setImageBitmap(bitmap); 
    input.release(); 
    rgb.release(); 
    output.release(); 
+0

Dziękuję za odpowiedź, ale myślę, że mam to - zaimplementowałem wykrywanie koloru. –

+0

@OleksandrFirsov Więc w czym problem? –

+1

Mam go rozwiązać –