Круг Хафа не определяет радужную оболочку глаза

Я хочу определить радужные оболочки глаз и их центры, используя алгоритм Hough Circle.

Я использую этот код:

 private void houghCircle()
    {
        Bitmap obtainedBitmap = imagesList.getFirst();
                 /* convert bitmap to mat */
        Mat mat = new Mat(obtainedBitmap.getWidth(),obtainedBitmap.getHeight(),
                CvType.CV_8UC1);
        Mat grayMat = new Mat(obtainedBitmap.getWidth(), obtainedBitmap.getHeight(),
                CvType.CV_8UC1);


        Utils.bitmapToMat(obtainedBitmap, mat);

/* convert to grayscale */
        int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1);

        Imgproc.cvtColor(mat, grayMat, colorChannels);

/* reduce the noise so we avoid false circle detection */
        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;

// min and max radii (set these values as you desire)
        int minRadius = 0, maxRadius = 1000;

// param1 = gradient value used to handle edge detection
// param2 = Accumulator threshold value for the
// cv2.CV_HOUGH_GRADIENT method.
// The smaller the threshold is, the more circles will be
// detected (including false circles).
// The larger the threshold is, the more circles will
// potentially be returned.
        double param1 = 70, param2 = 72;

/* create a Mat object to store the circles detected */
        Mat circles = new Mat(obtainedBitmap.getWidth(), obtainedBitmap.getHeight(), CvType.CV_8UC1);

/* find the circle in the image */
        Imgproc.HoughCircles(grayMat, circles, Imgproc.CV_HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius);

/* get the number of circles detected */
        int numberOfCircles = (circles.rows() == 0) ? 0 : circles.cols();

/* draw the circles found on the image */
        for (int i=0; i<numberOfCircles; i++) {


/* get the circle details, circleCoordinates[0, 1, 2] = (x,y,r)
 * (x,y) are the coordinates of the circle's center
 */
            double[] circleCoordinates = circles.get(0, i);


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

            Point center = new Point(x, y);

            int radius = (int) circleCoordinates[2];

    /* circle's outline */
            Core.circle(mat, center, radius, new Scalar(0,
                    255, 0), 4);

    /* circle's center outline */
            Core.rectangle(mat, new Point(x - 5, y - 5),
                    new Point(x + 5, y + 5),
                    new Scalar(0, 128, 255), -1);
        }

/* convert back to bitmap */
        Utils.matToBitmap(mat, obtainedBitmap);
        MediaStore.Images.Media.insertImage(getContentResolver(),obtainedBitmap, "testgray", "gray" );

    }

Но он не правильно определяет диафрагму на всех изображениях. Особенно, если радужная оболочка имеет темный цвет, например, коричневый. Как я могу исправить этот код, чтобы правильно определить ирисы и их центры?

EDIT: вот несколько примеров изображений (которые я получил из Интернета), которые показывают производительность алгоритма (пожалуйста, не обращайте внимания на ориентиры, представленные красными квадратами):

На этих изображениях алгоритм не обнаруживает все радужки:

введите здесь описание изображения

введите здесь описание изображения

На этом изображении показано, как алгоритм вообще не смог обнаружить радужную оболочку:

введите здесь описание изображения

РЕДАКТИРОВАТЬ 2: Вот код, который использует обнаружение края Canny, но это приводит к сбою приложения:

 private void houghCircle()
    {
        Mat grayMat = new Mat();
        Mat cannyEdges = new Mat();
        Mat circles = new Mat();
        Bitmap obtainedBitmap = imagesList.getFirst();
         /* convert bitmap to mat */
        Mat originalBitmap = new Mat(obtainedBitmap.getWidth(),obtainedBitmap.getHeight(),
                CvType.CV_8UC1);
//Converting the image to grayscale
        Imgproc.cvtColor(originalBitmap,grayMat,Imgproc.COLOR_BGR2GRAY);
        Imgproc.Canny(grayMat, cannyEdges,10, 100);
        Imgproc.HoughCircles(cannyEdges, circles,
                Imgproc.CV_HOUGH_GRADIENT,1, cannyEdges.rows() / 15); //now circles is filled with detected circles.

//, grayMat.rows() / 8);
        Mat houghCircles = new Mat();
        houghCircles.create(cannyEdges.rows(),cannyEdges.cols()
                ,CvType.CV_8UC1);
//Drawing lines on the image
        for(int i = 0 ; i < circles.cols() ; i++)
        {
            double[] parameters = circles.get(0,i);
            double x, y;
            int r;
            x = parameters[0];
            y = parameters[1];
            r = (int)parameters[2];
            Point center = new Point(x, y);
//Drawing circles on an image
            Core.circle(houghCircles,center,r,
                    new Scalar(255,0,0),1);
        }
//Converting Mat back to Bitmap
        Utils.matToBitmap(houghCircles, obtainedBitmap);
        MediaStore.Images.Media.insertImage(getContentResolver(),obtainedBitmap, "testgray", "gray" );

    }

Это ошибка, которую я получаю в журнале

FATAL EXCEPTION: Thread-28685
    CvException [org.opencv.core.CvException: cv::Exception: /hdd2/buildbot/slaves/slave_ardbeg1/50-SDK/opencv/modules/imgproc/src/color.cpp:3739: error: (-215) scn == 3 || scn == 4 in function void cv::cvtColor(cv::InputArray, cv::OutputArray, int, int)
    ]
            at org.opencv.imgproc.Imgproc.cvtColor_1(Native Method)
            at org.opencv.imgproc.Imgproc.cvtColor(Imgproc.java:4598)

Что вызвано этой строкой: Imgproc.cvtColor(originalBitmap,grayMat,Imgproc.COLOR_BGR2GRAY);

Может ли кто-нибудь сказать мне, как эта ошибка может быть решена? Возможно, добавление хитрого обнаружения краев улучшит результаты.


person Dania    schedule 09.02.2016    source источник
comment
Вы должны хотя бы поделиться некоторыми изображениями.   -  person guneykayim    schedule 09.02.2016
comment
@guneykayim спасибо, пожалуйста, проверьте вопрос, который я обновил.   -  person Dania    schedule 09.02.2016
comment
Это просто снимки? Потому что ирисы не соответствуют вашему параметру maxRadius? Меня смущает, что вы нашли что-то с максимальным радиусом 10.   -  person Piglet    schedule 09.02.2016
comment
@Piglet спасибо, извините, но я не понял вашего вопроса относительно изображений, являются ли они реальными или снимками, не могли бы вы уточнить подробнее? Я ввел эти изображения в приложение, и оно дало мне результаты в вопросе. 1-й и 3-й я ввел прямо в приложении, а второй снят с фронтальной камеры устройства. Вы имеете в виду, что maxRadius должен быть 10? В коде установлено значение 10, какое значение подходит для моего случая?   -  person Dania    schedule 09.02.2016
comment
Ваша ошибка связана с тем, что вход в cvtColor уже является одноканальным (CV_8UC1).   -  person mainactual    schedule 09.02.2016
comment
@mainactual Я думаю, это происходит из-за того, что originalBitmap пуст, я исправил его, присвоив ему значение полученного растрового изображения, но все еще не обнаружено irir. Как решить проблему с одним каналом?   -  person Dania    schedule 09.02.2016
comment
Я думаю, вы должны позвонить Utils.bitmapToMat, хотя и не уверены, что это на самом деле. Но если самый верхний фрагмент кода работает, просто позвоните туда Canny, чтобы получить grayMat   -  person mainactual    schedule 09.02.2016
comment
Спасибо, я изменил способ определения серого мата, и я использовал его в canny, но все равно приложение вылетает, прежде чем это сделать, оно выводит некоторые строки, связанные с созданием потоков, и иногда пишет, что поток умер, я запускаю его на фоновый поток, это имеет значение? Есть ли пример кода, который я могу попробовать, поскольку те, что в вопросе, не работают должным образом?   -  person Dania    schedule 09.02.2016
comment
Я не умею писать на Java, но автономная программа лучше всего подходит для отладки сложной и хитрой части. Вы можете использовать Highgui.imread и imwrite для ввода-вывода.   -  person mainactual    schedule 09.02.2016
comment
@mainactual Хорошо, я попробую, спасибо.   -  person Dania    schedule 09.02.2016


Ответы (3)


Круги Хафа лучше работают на четко определенных кругах. Они плохо ладят с такими вещами, как ирис.

После некоторых пороговых значений, морфологических операций или хитрого обнаружения краев методы обнаружения признаков, такие как MSER, работают намного лучше для обнаружения радужной оболочки.

Вот аналогичный вопрос с решением, если вы ищете код.

person Vasanth    schedule 17.03.2016

Поскольку вы хотите обнаружить радужную оболочку с помощью преобразования Хафа (есть и другие), вам лучше изучить детектор границ Кэнни и его параметры. cv::HoughCircles принимает порог Кэнни-гистерезиса в param1. Исследуя только Canny, вы получаете впечатление о хорошем пороговом диапазоне.

Возможно, вместо размытия по Гауссу вы примените лучшее шумоподавление (нелокальные средства, скажем, h=32 и размеры окна 5 и 15), а также попытаетесь гармонизировать контраст изображения, например, используя адаптивное выравнивание гистограммы с ограничением контраста (cv::CLAHE).

Гармонизация заключается в том, чтобы убедиться, что все глаза (светлые и темные) соответствуют одинаковому диапазону интенсивности.

person mainactual    schedule 09.02.2016
comment
Спасибо, я попытался немного прочитать о хитрости, и даже пробовал использовать код, который ее использует, но приложение сразу же вылетает без сообщения об ошибке в журнале, когда я использую код, который содержит хитрость. Я пробовал medianBlur, но это не решило проблему. Что такое гармонизирующие контрасты? И как это может помочь? Не могли бы вы рассказать подробнее? Спасибо. - person Dania; 09.02.2016
comment
Я могу найти исключение, которое вызывает сбой приложения, но я не знаю, как его решить. Я обновил вопрос, пожалуйста, проверьте его. Спасибо. - person Dania; 09.02.2016

Я хотел знать, являются ли эти изображения изображениями, которые вы обработали, или, если вы хотите, сделали снимок экрана вашего мобильного телефона, чтобы загрузить их сюда. Потому что ирисы больше, чем максимальный радиус, который вы установили в своем коде. Поэтому я не понимаю, как вы вообще могли найти ирис. Радужная оболочка на первом изображении имеет радиус более 20. Поэтому вы не сможете их обнаружить. Вы должны установить радиусы в диапазоне радиусов, который вы ожидаете от ваших радужных оболочек.

person Piglet    schedule 09.02.2016
comment
Да, 1-й и 3-й — это снимки, так как мой макет приложения был настроен на вывод входного изображения с обнаруженными радужками. Второй — это изображение, которое приложение сохранило в моей мобильной галерее после обработки входного изображения с фронтальной камеры. Извините, я думаю, что опубликовал модифицированную версию кода в отношении радиуса, поскольку пытался его изменить. Я думаю, что это было 1000. Каково обычное значение радиуса диафрагмы? Я пробовал такие вещи, как 100, но это тоже не сработало. Спасибо. - person Dania; 09.02.2016
comment
Я обновил вопрос, где я добавил код, который также использует хитрое обнаружение, не могли бы вы его проверить, это дает мне исключение. - person Dania; 09.02.2016