Использование warpPerspective () для последовательности точек, заданных HoughCircles (), OpenCV - PullRequest
4 голосов
/ 20 ноября 2011

Я пытаюсь определить положение бильярдных шаров на столе по изображению, сделанному под углом зрения. Я использую метод getPerspectiveTransform (), чтобы найти матрицу преобразования, и я хочу применить его только к тем кругам, которые я обнаружил с помощью HoughCircles. Я пытаюсь перейти от довольно большой трапециевидной формы к меньшей прямоугольной форме. Я не хочу сначала выполнять преобразование на изображении, а затем найти HoughCircles, потому что изображение слишком искажено для того, чтобы рисунки крутились для получения полезных результатов.

Вот мой код:

        CvMat mmat = cvCreateMat(3,3,CV_32FC1);
        double srcX1 = 462;
        double srcX2 = 978;
        double srcX3 = 1440;
        double srcX4 = 0;
        double srcY = 241;
        double srcHeight = 772;

        double dstX = 56.8;
        double dstY = 33.5;
        double dstWidth = 262.4;
        double dstHeight = 447.3;

        CvSeq seq = cvHoughCircles(newGray, circles, CV_HOUGH_GRADIENT, 2.1d, (double)newGray.height()/40, 85d, 65d, 5, 50);

        JavaCV.getPerspectiveTransform(new double[]{srcX1, srcY, srcX2,srcY, srcX3, srcHeight, srcX4, srcHeight}, 
                  new double[]{dstX, dstY, dstWidth, dstY, dstWidth, dstHeight, dstX, dstHeight}, mmat);
        cvWarpPerspective(seq, seq, mmat);


        for(int j=0; j<seq.total(); j++){
            CvPoint3D32f point = new CvPoint3D32f(cvGetSeqElem(seq, j));

            float xyr[] = {point.x(),point.y(),point.z()};
            CvPoint center = new CvPoint(Math.round(xyr[0]), Math.round(xyr[1]));

            int radius = Math.round(xyr[2]);
            cvCircle(gray, center, 3, CvScalar.GREEN, -1, 8, 0);
            cvCircle(gray, center, radius, CvScalar.BLUE, 3, 8, 0);
        }

Проблема в том, что я получаю эту ошибку при использовании метода warpPerspective ():

error: (-215) seq->total > 0 && CV_ELEM_SIZE(seq->flags) == seq->elem_size in function cv::Mat cv::cvarrToMat(const CvArr*, bool, bool, int) 

Также, я думаю, стоит упомянуть, что я использую JavaCV, на случай, если вызовы методов выглядят немного иначе, чем вы привыкли. Спасибо за любую помощь.

1 Ответ

3 голосов
/ 23 ноября 2011

Ответ:

проблема с тем, что вы хотите сделать (помимо очевидного, opencv не позволит вам), заключается в том, что радиус не может быть правильно деформирован. AFAIK Координаты xy довольно легко вычислить x '= ((m00x + m01y + m02) / (m20x + m21y + m22)) y' = ((m10x + m11y + m12) / (m20x + m21y_m22)), когда m матрица преобразования. радиус, который вы можете взломать, преобразовав все точки исходного круга, а затем найдите максимальное расстояние между x'y 'и этими точками (по крайней мере, если радиус в искаженном изображении должен охватывать все эти точки) btw, mIJx = m (i, j) * x (просто чтобы уточнить)

Конечный ответ.


Все, что я пишу, соответствует версии c ++, я никогда не использовал JavaCV, но из того, что я видел, это просто оболочка, которая вызывает нативную библиотеку c ++.

CvSeq - это структура данных sequance, которая ведет себя как связанный список. Утверждение, что ваше приложение сокрушается в

CV_Assert(seq->total > 0 && CV_ELEM_SIZE(seq->flags) == seq->elem_size);

, что означает, что ваш экземпляр seq пуст (total равно количеству элементов в последовательности) или что-то внутренние флаги seq повреждены.

Я бы порекомендовал вам проверить общего члена вашего CvSeq и вызов cvHoughCircles. все это происходит до фактической реализации cvWarpPerspective (это первая строка в реализации, которая конвертирует только ваш CvSeq в cv :: Mat) .. так что это не перекос, а то, что вы делали до этого. в любом случае, чтобы понять, что не так с cvHoughCircles, нам понадобится дополнительная информация о создании newGray и кругов.

вот пример, который я нашел на странице javaCV ( Ссылка )

IplImage gray = cvCreateImage( cvSize( img.width, img.height ), IPL_DEPTH_8U, 1 );
cvCvtColor( img, gray, CV_RGB2GRAY );
// smooth it, otherwise a lot of false circles may be detected
cvSmooth(gray,gray,CV_GAUSSIAN,9,9,2,2);
CvMemStorage circles = CvMemStorage.create();
CvSeq seq = cvHoughCircles(gray, circles.getPointer(), CV_HOUGH_GRADIENT,
                                                2, img.height/4, 100, 100, 0, 0);
for(int i=0; i<seq.total; i++){
        float xyr[] = cvGetSeqElem(seq,i).getFloatArray(0, 3);
        CvPoint center = new CvPoint(Math.round(xyr[0]), Math.round(xyr[1]));

        int radius = Math.round(xyr[2]);
        cvCircle(img, center.byValue(), 3, CvScalar.GREEN, -1, 8, 0);
        cvCircle(img, center.byValue(), radius, CvScalar.BLUE, 3, 8, 0);
}

из того, что я видел в реализации cvHoughCircles, ответ сохраняется в баффе кругов, и в конце они создают из него CvSeq для возврата, поэтому, если вы неправильно распределили бафф кругов, он не будет работать .

EDIT:

, как вы можете видеть, экземпляр CvSeq в случае возврата из cvHoughCircles представляет собой список значений точек, поэтому, вероятно, утверждение не удалось. Вы не можете конвертировать этот CvSeq в cv :: Mat .. потому что он просто не cv :: Mat. чтобы получить только круги, возвращенные из cvHoughCircles в экземпляре cv :: Mat, вам нужно создать новый экземпляр cv :: Mat и затем нарисовать на нем все круги в CvSeq - как видно из приведенного выше примера. чем сработает деформация (у вас будет экземпляр cv :: Mat, и именно этого ожидает функция - cv :: Mat как единственный элемент в CvSeq)

END EDIT

здесь - ссылка на C ++ для CvSeq и если вы хотите возиться с исходным кодом, чем

cvarrToMat находится в matrix.cpp

CV_ELEM_SIZE находится в types_c.h

cvWarpPerspective находится в imgwarp.cpp

cvHoughCircles находится в hough.cpp

Надеюсь, это поможет.

Кстати, ваша следующая ошибка, вероятно, будет: cv :: warpPerspective в C ++ OpencCv утверждает, что dst.data != src.data

таким образом

cvWarpPerspective(seq, seq, mmat);

не сработает, потому что ваш исходный мат и целевой мат ссылаются на одни и те же данные. Не все функции в OpenCV (и обработке изображений в целом) работают in-situ (потому что не существует алгоритма in-situ или потому что он медленнее, чем в другой версии, например, транспонирование n * n мата работать на месте, но n * m, где n! = m будет сложнее сделать на месте и может быть медленнее) Вы не можете предполагать использование матрицы src, поскольку dst будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...