Проблема использования дистанционного преобразования с новым интерфейсом OpenCV C ++ / Как убедиться, что Mat является двоичной маской? - PullRequest
0 голосов
/ 26 октября 2010

Я портирую свой код для использования нового интерфейса OpenCV C ++. Мне нравится возможность строго вводить все, поэтому выведите все мои изображения и матрицы из класса шаблона:

Mat_<type> var;

Теперь у меня проблемы с использованием функции distanceTransform. Мой код делает что-то вроде этого:

Mat_<float> imgGray;
Mat_<unsigned char> imgBinary;
Mat_<float> imgDistance;

// ... fill imgGray with data ...

threshold(imgGray, imgBinary, 0.25, 255, CV_THRESH_BINARY);
distanceTransform(imgBinary, imgDistance, CV_DIST_L2, CV_DIST_MASK_PRECISE);

distanceTransform завершается ошибкой. Выдает следующую ошибку:

Неподдерживаемый формат или комбинация форматов (исходное изображение должно быть 8uC1, а карта расстояний должна быть 32fC1 (или 8uC1 в случае простого преобразования расстояния L1)) в неизвестной функции, файл ........ \ src \ cv \ cvdistransform.cpp, строка 730

Я понял, что проблема в параметре источника. Он не проходит тест CV_IS_MASK_ARR (src).

Насколько я понимаю, пороговые вызовы создаются на imgBinary для выделения памяти. Так что у меня нет возможности контролировать точный тип (должен быть CV_8UC1) матрицы imgBinary, не так ли? Как я могу убедиться, что imgBinary является правильной двоичной маской, чтобы сделать дистанционное преобразование счастливым?

Спасибо за вашу помощь!

Ура, Роберт

1 Ответ

0 голосов
/ 29 октября 2010

Если вы хотите, вы можете проверить код ниже.Это новая версия DT с OpenCV C ++ API

//#define CV_NO_BACKWARD_COMPATIBILITY

// if you compile the program under Windows and MSVC2008/2005
#if defined WIN32 || defined _MSC_VER
 #pragma warning(disable:4786)
 #pragma warning(disable:4996)

 #define _CRT_SECURE_NO_WARNINGS 
 #define _CRT_SECURE_NO_DEPRECATE
 #define _SCL_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include "cv.h"
#include "cvaux.h"
#include "highgui.h"
#define DEMO_MIXED_API_USE 1

using namespace cv;
using namespace std;

char wndname[] = "Distance transform";
char tbarname[] = "Threshold";
int mask_size = CV_DIST_MASK_5;
int build_voronoi = 0;
int edge_thresh = 100;
int dist_type = CV_DIST_L1;

// The output and temporary images
Mat dist;
Mat dist8u1;
Mat dist8u2;
Mat dist8u;
Mat dist32s;

Mat gray;
Mat edge;
Mat labels;

// threshold trackbar callback
void on_trackbar( int dummy, void *)
{
    static const uchar colors[][3] =
    {
        {0,0,0},
        {255,0,0},
        {255,128,0},
        {255,255,0},
        {0,255,0},
        {0,128,255},
        {0,255,255},
        {0,0,255},
        {255,0,255}
    };

    int msize = mask_size;
    int _dist_type = build_voronoi ? CV_DIST_L2 : dist_type;

    threshold( gray, edge, (double)edge_thresh, (double)edge_thresh, CV_THRESH_BINARY );

    if( build_voronoi )
        msize = CV_DIST_MASK_5;

    if( _dist_type == CV_DIST_L1 )
    {
        distanceTransform( edge, dist, _dist_type, msize );
    }
    else 
    {
        build_voronoi ? distanceTransform( edge, dist, labels, _dist_type, msize ) : distanceTransform( edge, dist, _dist_type, msize ) ;
    }

    if( !build_voronoi )
    {
        // begin "painting" the distance transform result
        dist.convertTo( dist, dist.type(), 5000.0, 0 );             //before--> cvConvertScale( dist, dist, 5000.0, 0 );
        pow( dist, 0.5, dist );                                     //before--> cvPow(dist, dist, 0.5);

        dist.convertTo( dist32s, dist32s.type(), 1.0, 0.5 );        //before--> cvConvertScale( dist, dist32s, 1.0, 0.5 );
        bitwise_and( dist32s, Scalar::all(255), dist32s, Mat() );   //before--> cvAndS( dist32s, ScalarAll(255), dist32s, 0 );
        dist32s.convertTo(dist8u1, dist8u1.type(), 1, 0 );          //before--> cvConvertScale( dist32s, dist8u1, 1, 0 );
        dist32s.convertTo( dist32s, dist32s.type(), -1, 0 );        //before--> cvConvertScale( dist32s, dist32s, -1, 0 );
        add( dist32s, Scalar::all(255), dist32s, Mat() );           //before--> cvAddS( dist32s, cvScalarAll(255), dist32s, 0 );
        dist32s.convertTo( dist8u2, dist8u2.type(), 1, 0 );         //before--> cvConvertScale( dist32s, dist8u2, 1, 0 );

        vector<Mat> Out(3);
        Out[0] = dist8u1;
        Out[1] = dist8u2;
        Out[2] = dist8u2;
        merge( Out, dist8u );           //before--> cvMerge( dist8u1, dist8u2, dist8u2, 0, dist8u );

        // end "painting" the distance transform result
    }
    else
    {
        int i, j;
        for( i = 0; i < labels.rows; i++ )
        {
            int* ll = labels.ptr<int>(i);       //before--> (int*)(labels->imageData + i*labels->widthStep)
            float* dd = dist.ptr<float>(i);     //before--> (float*)(dist->imageData + i*dist->widthStep)
            uchar* d = dist8u.ptr<uchar>(i);    //before--> (uchar*)(dist8u->imageData + i*dist8u->widthStep)

            for( j = 0; j < labels.cols; j++ )
            {
                int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
                int b = cvRound(colors[idx][0]);        // if there is an option to cvRound in the new OpenCV C++ API, tell me please
                int g = cvRound(colors[idx][1]);
                int r = cvRound(colors[idx][2]);
                d[j*3] = saturate_cast<uchar>(b);       //before--> (uchar)b;
                d[j*3+1] = saturate_cast<uchar>(g);     //before--> (uchar)g; 
                d[j*3+2] = saturate_cast<uchar>(r);     //before--> (uchar)r;
            }
        }
    }

    imshow( wndname, dist8u );  //before--> cvShowImage( wndname, dist8u );
}

int main( int argc, char* argv[] )
{
    const char* filename = (argc == 2 ? argv[1] : "Debug/stuff.jpg");//lena.jpg

    gray = imread( filename, 0 );   // -1 loads image full(3 channels + alpha) , 0 only in grayscale

    if( gray.empty() )
        return -1;

    cout << "Hot keys: \n"
         << "\tESC - quit the program\n"
         << "\tC - use C/Inf metric\n"
         << "\tL1 - use L1 metric\n"
         << "\tL2 - use L2 metric\n"
         << "\t3 - use 3x3 mask\n"
         << "\t5 - use 5x5 mask\n"
         << "\t0 - use precise distance transform\n"
         << "\tv - switch Voronoi diagram mode on/off\n"
         << "\tSPACE - loop through all the modes\n" << endl;

    dist = Mat( gray.size(), CV_32FC1 );    //dist = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32F, 1 );
    dist8u1 = gray.clone();                 //dist8u1 = cvCloneImage( gray );
    dist8u2 = gray.clone();                 //dist8u2 = cvCloneImage( gray );
    dist8u = Mat( gray.size(), CV_8UC3 );   //dist8u = cvCreateImage( cvGetSize(gray), IPL_DEPTH_8U, 3 );
    dist32s = Mat( gray.size(), CV_32SC1 ); //dist32s = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );
    edge = gray.clone();                    //edge = cvCloneImage( gray );
    labels = Mat( gray.size(), CV_32SC1 );  //labels = cvCreateImage( cvGetSize(gray), IPL_DEPTH_32S, 1 );

    namedWindow( wndname, 1 );

    createTrackbar( tbarname, wndname, &edge_thresh, 255, on_trackbar );

    for(;;)
    {
        int c;

        // Call to update the view
        on_trackbar(0, 0);

        c = waitKey(0);

        if( (char)c == 27 )
            break;

        if( (char)c == 'c' || (char)c == 'C' )
            dist_type = CV_DIST_C;
        else if( (char)c == '1' )
            dist_type = CV_DIST_L1;
        else if( (char)c == '2' )
            dist_type = CV_DIST_L2;
        else if( (char)c == '3' )
            mask_size = CV_DIST_MASK_3;
        else if( (char)c == '5' )
            mask_size = CV_DIST_MASK_5;
        else if( (char)c == '0' )
            mask_size = CV_DIST_MASK_PRECISE;
        else if( (char)c == 'v' )
            build_voronoi ^= 1;
        else if( (char)c == ' ' )
        {
            if( build_voronoi )
            {
                build_voronoi = 0;
                mask_size = CV_DIST_MASK_3;
                dist_type = CV_DIST_C;
            }
            else if( dist_type == CV_DIST_C )
                dist_type = CV_DIST_L1;
            else if( dist_type == CV_DIST_L1 )
                dist_type = CV_DIST_L2;
            else if( mask_size == CV_DIST_MASK_3 )
                mask_size = CV_DIST_MASK_5;
            else if( mask_size == CV_DIST_MASK_5 )
                mask_size = CV_DIST_MASK_PRECISE;
            else if( mask_size == CV_DIST_MASK_PRECISE )
                build_voronoi = 1;
        }
    }

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