Exemplo n.º 1
0
static void
icxLogicSM( const void* srcarr, CxScalar* scalar, void* dstarr,
            const void* maskarr, CxArithmUniMaskFunc2D func )
{
    CX_FUNCNAME( "icxLogicSM" );
    
    __BEGIN__;

    double buf[12];
    int coi1 = 0, coi2 = 0;
    CxMat  srcstub, *src = (CxMat*)srcarr;
    CxMat  dststub, *dst = (CxMat*)dstarr;
    CxMat  maskstub, *mask = (CxMat*)maskarr;
    int pix_size, type;
    int dst_step, mask_step;
    CxSize size;

    if( !CX_IS_MAT(src))
        CX_CALL( src = cxGetMat( src, &srcstub, &coi1 ));

    if( !CX_IS_MAT(dst))
        CX_CALL( dst = cxGetMat( dst, &dststub ));

    if( coi1 != 0 || coi2 != 0 )
        CX_ERROR( CX_BadCOI, "" );

    CX_CALL( mask = cxGetMat( mask, &maskstub ));

    if( !CX_IS_MASK_ARR(mask) )
        CX_ERROR_FROM_CODE( CX_StsBadMask );

    if( !CX_ARE_SIZES_EQ( mask, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    if( src->data.ptr != dst->data.ptr )
    {
        CX_CALL( cxCopy( src, dst, mask ));
    }

    size = cxGetMatSize( dst );
    dst_step = dst->step;
    mask_step = mask->step;

    if( CX_IS_MAT_CONT( mask->type & dst->type ))
    {
        size.width *= size.height;
        dst_step = mask_step = CX_STUB_STEP;
        size.height = 1;
    }

    type = CX_MAT_TYPE( src->type );
    pix_size = icxPixSize[type];
    
    CX_CALL( cxScalarToRawData( scalar, buf, type, 0 ));
    IPPI_CALL( func( dst->data.ptr, dst_step, mask->data.ptr,
                     mask_step, size, buf, pix_size ));

    __END__;
}
Exemplo n.º 2
0
CX_IMPL  void
cxMinMaxLoc( const void* img, double* minVal, double* maxVal,
             CxPoint* minLoc, CxPoint* maxLoc, const void* mask )
{
    static CxFuncTable minmax_tab, minmaxcoi_tab;
    static CxFuncTable minmaxmask_tab, minmaxmaskcoi_tab;
    static int inittab = 0;

    CX_FUNCNAME("cxMinMaxLoc");

    __BEGIN__;

    int type, depth, cn, coi = 0;
    int mat_step, mask_step = 0;
    CxSize size;
    CxMat stub, maskstub, *mat = (CxMat*)img, *matmask = (CxMat*)mask;

    if( !inittab )
    {
        icxInitMinMaxIndxC1RTable( &minmax_tab );
        icxInitMinMaxIndxCnCRTable( &minmaxcoi_tab );
        icxInitMinMaxIndxC1MRTable( &minmaxmask_tab );
        icxInitMinMaxIndxCnCMRTable( &minmaxmaskcoi_tab );
        inittab = 1;
    }
    
    CX_CALL( mat = cxGetMat( mat, &stub, &coi ));

    type = CX_MAT_TYPE( mat->type );
    depth = CX_MAT_DEPTH( type );
    cn = CX_MAT_CN( type );
    size = cxGetMatSize( mat );

    if( cn > 1 && coi == 0 )
        CX_ERROR( CX_StsBadArg, "" );
    
    mat_step = mat->step;

    if( !mask )
    {
        if( size.height == 1 )
            mat_step = CX_STUB_STEP;

        if( CX_MAT_CN(type) == 1 || coi == 0 )
        {
            CxFunc2D_1A4P func = (CxFunc2D_1A4P)(minmax_tab.fn_2d[depth]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, size,
                             minVal, maxVal, minLoc, maxLoc ));
        }
        else
        {
            CxFunc2DnC_1A4P func = (CxFunc2DnC_1A4P)(minmaxcoi_tab.fn_2d[depth]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, size, cn, coi,
                             minVal, maxVal, minLoc, maxLoc ));
        }
    }
    else
    {
        CX_CALL( matmask = cxGetMat( matmask, &maskstub ));

        if( !CX_IS_MASK_ARR( matmask ))
            CX_ERROR( CX_StsBadMask, "" );

        if( !CX_ARE_SIZES_EQ( mat, matmask ))
            CX_ERROR( CX_StsUnmatchedSizes, "" );

        mask_step = matmask->step;

        if( size.height == 1 )
            mat_step = mask_step = CX_STUB_STEP;

        if( CX_MAT_CN(type) == 1 || coi == 0 )
        {
            CxFunc2D_2A4P func = (CxFunc2D_2A4P)(minmaxmask_tab.fn_2d[depth]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, matmask->data.ptr,
                             mask_step, size,
                             minVal, maxVal, minLoc, maxLoc ));
        }
        else
        {
            CxFunc2DnC_2A4P func = (CxFunc2DnC_2A4P)(minmaxmaskcoi_tab.fn_2d[depth]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step,
                             matmask->data.ptr, mask_step, size, cn, coi,
                             minVal, maxVal, minLoc, maxLoc ));
        }
    }

    if( depth < CX_32S || depth == CX_32F )
    {
        if( minVal )
            *minVal = *(float*)minVal;

        if( maxVal )
            *maxVal = *(float*)maxVal;
    }

    __END__;
}
Exemplo n.º 3
0
CX_IMPL void
icxLogicM( const void* srcimg1, const void* srcimg2,
           void* dstarr, const void* maskarr,
           CxArithmBinMaskFunc2D func )
{
    CX_FUNCNAME( "icxLogicM" );
    
    __BEGIN__;

    int  coi1 = 0, coi2 = 0, coi3 = 0;
    CxMat  srcstub1, *src1 = (CxMat*)srcimg1;
    CxMat  srcstub2, *src2 = (CxMat*)srcimg2;
    CxMat  dststub, *dst = (CxMat*)dstarr;
    CxMat  maskstub, *mask = (CxMat*)maskarr;
    int src_step, dst_step, mask_step; 
    int pix_size;
    CxSize size;

    CX_CALL( src1 = cxGetMat( src1, &srcstub1, &coi1 ));
    CX_CALL( src2 = cxGetMat( src2, &srcstub2, &coi2 ));
    CX_CALL( dst = cxGetMat( dst, &dststub, &coi3 ));
    CX_CALL( mask = cxGetMat( mask, &maskstub ));

    if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
        CX_ERROR( CX_BadCOI, "" );

    if( !CX_IS_MASK_ARR(mask) )
        CX_ERROR_FROM_CODE( CX_StsBadMask );

    if( !CX_ARE_SIZES_EQ( mask, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    if( !CX_ARE_SIZES_EQ( src1, src2 ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    size = cxGetMatSize( src1 );
    pix_size = icxPixSize[CX_MAT_TYPE(src1->type)];
        
    if( src2->data.ptr != dst->data.ptr )
    {
        if( src1->data.ptr != dst->data.ptr )
        {
            CX_CALL( cxCopy( src2, dst, mask ));
        }
        else
            src1 = src2;
    }
    
    if( !CX_ARE_TYPES_EQ( src1, dst ))
        CX_ERROR_FROM_CODE( CX_StsUnmatchedFormats );

    if( !CX_ARE_SIZES_EQ( src1, dst ))
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    src_step = src1->step;
    dst_step = dst->step;
    mask_step = mask->step;
    
    if( CX_IS_MAT_CONT( src1->type & dst->type & mask->type ))
    {
        size.width *= size.height;
        src_step = dst_step = mask_step = CX_STUB_STEP;
        size.height = 1;
    }

    IPPI_CALL( func( src1->data.ptr, src_step, mask->data.ptr, mask_step,
                     dst->data.ptr, dst_step, size, pix_size ));

    __END__;
}
Exemplo n.º 4
0
static void
icxLogic( const void* srcimg1, const void* srcimg2,
          void* dstarr, CxFunc2D_3A fn_2d )
{
    CX_FUNCNAME( "icxLogic" );
    
    __BEGIN__;

    int coi1 = 0, coi2 = 0, coi3 = 0;
    int is_nd = 0;
    CxMat  srcstub1, *src1 = (CxMat*)srcimg1;
    CxMat  srcstub2, *src2 = (CxMat*)srcimg2;
    CxMat  dststub,  *dst = (CxMat*)dstarr;
    int src1_step, src2_step, dst_step;
    CxSize size;

    if( !CX_IS_MAT(src1))
    {
        if( CX_IS_MATND(src1) )
            is_nd = 1;
        else
            CX_CALL( src1 = cxGetMat( src1, &srcstub1, &coi1 ));
    }

    if( !CX_IS_MAT(src2))
    {
        if( CX_IS_MATND(src2) )
            is_nd = 1;
        else
            CX_CALL( src2 = cxGetMat( src2, &srcstub2, &coi2 ));
    }

    if( !CX_IS_MAT(dst))
    {
        if( CX_IS_MATND(dst) )
            is_nd = 1;
        else
            CX_CALL( dst = cxGetMat( dst, &dststub, &coi3 ));
    }

    if( is_nd )
    {
        CxArr* arrs[] = { src1, src2, dst };
        CxMatND stubs[3];
        CxNArrayIterator iterator;
        int type;

        CX_CALL( cxInitNArrayIterator( 3, arrs, 0, stubs, &iterator ));

        type = CX_MAT_TYPE(iterator.hdr[0]->type);
        iterator.size.width *= icxPixSize[type];

        do
        {
            IPPI_CALL( fn_2d( iterator.ptr[0], CX_STUB_STEP,
                              iterator.ptr[1], CX_STUB_STEP,
                              iterator.ptr[2], CX_STUB_STEP,
                              iterator.size ));
        }
        while( cxNextNArraySlice( &iterator ));
        EXIT;
    }

    if( coi1 != 0 || coi2 != 0 || coi3 != 0 )
        CX_ERROR_FROM_CODE( CX_BadCOI );

    if( !CX_ARE_TYPES_EQ( src1, src2 ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedFormats );

    if( !CX_ARE_SIZES_EQ( src1, src2 ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    size = cxGetMatSize( src1 );
        
    if( !CX_ARE_TYPES_EQ( src1, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedFormats );
    
    if( !CX_ARE_SIZES_EQ( src1, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    src1_step = src1->step;
    src2_step = src2->step;
    dst_step = dst->step;

    if( CX_IS_MAT_CONT( src1->type & src2->type & dst->type ))
    {
        size.width *= size.height;
        src1_step = src2_step = dst_step = CX_STUB_STEP;
        size.height = 1;
    }

    size.width *= icxPixSize[CX_MAT_TYPE(src1->type)];

    IPPI_CALL( fn_2d( src1->data.ptr, src1_step, src2->data.ptr, src2_step,
                      dst->data.ptr, dst_step, size ));

    __END__;
}
Exemplo n.º 5
0
static void
icxLogicS( const void* srcarr, CxScalar* scalar,
           void* dstarr, CxFunc2D_2A1P1I fn_2d )
{
    CX_FUNCNAME( "icxLogicS" );
    
    __BEGIN__;

    CxMat srcstub, *src = (CxMat*)srcarr;
    CxMat dststub, *dst = (CxMat*)dstarr;
    
    int coi1 = 0, coi2 = 0;
    int is_nd = 0;
    int pix_size, type;
    double buf[12];
    CxSize size;
    int src_step, dst_step;

    if( !CX_IS_MAT(src))
    {
        if( CX_IS_MATND(src) )
            is_nd = 1;
        else
            CX_CALL( src = cxGetMat( src, &srcstub, &coi1 ));
    }

    if( !CX_IS_MAT(dst))
    {
        if( CX_IS_MATND(dst) )
            is_nd = 1;
        else
            CX_CALL( dst = cxGetMat( dst, &dststub, &coi2 ));
    }

    if( is_nd )
    {
        CxArr* arrs[] = { src, dst };
        CxMatND stubs[2];
        CxNArrayIterator iterator;

        CX_CALL( cxInitNArrayIterator( 2, arrs, 0, stubs, &iterator ));

        type = CX_MAT_TYPE(iterator.hdr[0]->type);
        iterator.size.width *= icxPixSize[type];
        pix_size = icxPixSize[type & CX_MAT_DEPTH_MASK];

        CX_CALL( cxScalarToRawData( scalar, buf, type, 1 ));

        do
        {
            IPPI_CALL( fn_2d( iterator.ptr[0], CX_STUB_STEP,
                              iterator.ptr[1], CX_STUB_STEP,
                              iterator.size, buf, pix_size ));
        }
        while( cxNextNArraySlice( &iterator ));
        EXIT;
    }

    if( coi1 != 0 || coi2 != 0 )
        CX_ERROR( CX_BadCOI, "" );

    if( !CX_ARE_TYPES_EQ( src, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedFormats );

    if( !CX_ARE_SIZES_EQ( src, dst ) )
        CX_ERROR_FROM_CODE( CX_StsUnmatchedSizes );

    size = cxGetMatSize( src );
    src_step = src->step;
    dst_step = dst->step;

    if( CX_IS_MAT_CONT( src->type & dst->type ))
    {
        size.width *= size.height;
        src_step = dst_step = CX_STUB_STEP;
        size.height = 1;
    }

    type = CX_MAT_TYPE( src->type );
    size.width *= icxPixSize[type];
    pix_size = icxPixSize[type & CX_MAT_DEPTH_MASK];

    CX_CALL( cxScalarToRawData( scalar, buf, type, 1 ));

    IPPI_CALL( fn_2d( src->data.ptr, src_step, dst->data.ptr, dst_step,
                      size, buf, pix_size ));

    __END__;
}
Exemplo n.º 6
0
CX_IMPL  void
cxAvgSdv( const void* img, CxScalar* _mean, CxScalar* _sdv, const void* mask )
{
    CxScalar mean = {{0,0,0,0}};
    CxScalar sdv = {{0,0,0,0}};

    static CxBigFuncTable meansdv_tab;
    static CxFuncTable meansdvcoi_tab;
    static CxBigFuncTable meansdvmask_tab;
    static CxFuncTable meansdvmaskcoi_tab;
    static int inittab = 0;

    CX_FUNCNAME("cxMean_StdDev");

    __BEGIN__;

    int type, coi = 0;
    int mat_step, mask_step = 0;
    CxSize size;
    CxMat stub, maskstub, *mat = (CxMat*)img, *matmask = (CxMat*)mask;

    if( !inittab )
    {
        icxInitMean_StdDevRTable( &meansdv_tab );
        icxInitMean_StdDevCnCRTable( &meansdvcoi_tab );
        icxInitMean_StdDevMRTable( &meansdvmask_tab );
        icxInitMean_StdDevCnCMRTable( &meansdvmaskcoi_tab );
        inittab = 1;
    }
    
    CX_CALL( mat = cxGetMat( mat, &stub, &coi ));

    type = CX_MAT_TYPE( mat->type );
    size = cxGetMatSize( mat );
    
    mat_step = mat->step;

    if( !mask )
    {
        if( CX_IS_MAT_CONT( mat->type ))
        {
            size.width *= size.height;
            size.height = 1;
            mat_step = CX_STUB_STEP;
        }

        if( CX_MAT_CN(type) == 1 || coi == 0 )
        {
            CxFunc2D_1A2P func = (CxFunc2D_1A2P)(meansdv_tab.fn_2d[type]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, size, mean.val, sdv.val ));
        }
        else
        {
            CxFunc2DnC_1A2P func = (CxFunc2DnC_1A2P)
                (meansdvcoi_tab.fn_2d[CX_MAT_DEPTH(type)]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, size,
                             CX_MAT_CN(type), coi, mean.val, sdv.val ));
        }
    }
    else
    {
        CX_CALL( matmask = cxGetMat( matmask, &maskstub ));

        mask_step = matmask->step;

        if( !CX_IS_MASK_ARR( matmask ))
            CX_ERROR( CX_StsBadMask, "" );

        if( !CX_ARE_SIZES_EQ( mat, matmask ))
            CX_ERROR( CX_StsUnmatchedSizes, "" );

        if( CX_IS_MAT_CONT( mat->type & matmask->type ))
        {
            size.width *= size.height;
            size.height = 1;
            mat_step = mask_step = CX_STUB_STEP;
        }

        if( CX_MAT_CN(type) == 1 || coi == 0 )
        {
            CxFunc2D_2A2P func = (CxFunc2D_2A2P)(meansdvmask_tab.fn_2d[type]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step, matmask->data.ptr,
                             mask_step, size, mean.val, sdv.val ));
        }
        else
        {
            CxFunc2DnC_2A2P func = (CxFunc2DnC_2A2P)
                (meansdvmaskcoi_tab.fn_2d[CX_MAT_DEPTH(type)]);

            if( !func )
                CX_ERROR( CX_StsBadArg, cxUnsupportedFormat );

            IPPI_CALL( func( mat->data.ptr, mat_step,
                             matmask->data.ptr, mask_step,
                             size, CX_MAT_CN(type), coi, mean.val, sdv.val ));
        }
    }

    __END__;

    if( _mean )
        *_mean = mean;

    if( _sdv )
        *_sdv = sdv;
}
Exemplo n.º 7
0
CX_IMPL void
cxKMeans2( const CxArr* samples_arr, int cluster_count,
           CxArr* labels_arr, CxTermCriteria termcrit )
{
    CxMat* centers = 0;
    CxMat* old_centers = 0;
    CxMat* counters = 0;
    
    CX_FUNCNAME( "cxKMeans2" );

    __BEGIN__;

    CxMat samples_stub, *samples = (CxMat*)samples_arr;
    CxMat cluster_idx_stub, *labels = (CxMat*)labels_arr;
    CxMat* temp = 0;
    CxRandState rng;
    int i, k, sample_count, dims;
    int ids_delta, iter;
    double max_dist;
    int pix_size;

    if( !CX_IS_MAT( samples ))
        CX_CALL( samples = cxGetMat( samples, &samples_stub ));
    
    if( !CX_IS_MAT( labels ))
        CX_CALL( labels = cxGetMat( labels, &cluster_idx_stub ));

    if( cluster_count < 1 )
        CX_ERROR( CX_StsOutOfRange, "Number of clusters should be positive" );

    if( CX_MAT_DEPTH(samples->type) != CX_32F || CX_MAT_TYPE(labels->type) != CX_32SC1 )
        CX_ERROR( CX_StsUnsupportedFormat,
        "samples should be floating-point matrix, cluster_idx - integer vector" );

    pix_size = CX_ELEM_SIZE(samples->type);

    if( labels->rows != 1 && labels->cols != 1 || labels->rows + labels->cols - 1 != samples->rows )
        CX_ERROR( CX_StsUnmatchedSizes,
        "cluster_idx should be 1D vector of the same number of elements as samples' number of rows" ); 

    switch( termcrit.type )
    {
    case CX_TERMCRIT_EPS:
        if( termcrit.epsilon < 0 )
            termcrit.epsilon = 0;
        termcrit.maxIter = 100;
        break;
    case CX_TERMCRIT_ITER:
        if( termcrit.maxIter < 1 )
            termcrit.maxIter = 1;
        termcrit.epsilon = 1e-6;
        break;
    case CX_TERMCRIT_EPS|CX_TERMCRIT_ITER:
        if( termcrit.epsilon < 0 )
            termcrit.epsilon = 0;
        if( termcrit.maxIter < 1 )
            termcrit.maxIter = 1;
        break;
    default:
        CX_ERROR( CX_StsBadArg, "Invalid termination criteria" );
    }

    termcrit.epsilon *= termcrit.epsilon;

    sample_count = samples->rows;

    if( cluster_count > sample_count )
        cluster_count = sample_count;

    dims = samples->cols*CX_MAT_CN(samples->type);
    ids_delta = labels->step ? labels->step/(int)sizeof(int) : 1;

    cxRandInit( &rng, 0, 1, -1, CX_RAND_UNI );

    CX_CALL( centers = cxCreateMat( cluster_count, dims, CX_64FC1 ));
    CX_CALL( old_centers = cxCreateMat( cluster_count, dims, CX_64FC1 ));
    // samples_count >= cluster_count, <samples_count>
    // elements are used during initialization
#if 0    
    CX_CALL( counters = cxCreateMat( 1, sample_count, CX_32SC1 ));
    cxZero( counters );

    // init centers
    for( i = 0; i < cluster_count; i++ )
    {
        int j, idx;
        double* c = (double*)(centers->data.ptr + i*centers->step);
        float* s;
        do
            idx = cxRandNext( &rng ) % cluster_count;
        while( counters->data.i[idx] != 0 );
        counters->data.i[idx] = 1;

        s = (float*)(samples->data.ptr + idx*samples->step);
        for( j = 0; j < samples->cols; j++ )
            c[j] = s[j];
    }

    counters->cols = cluster_count;
#else
    CX_CALL( counters = cxCreateMat( 1, cluster_count, CX_32SC1 ));

    // init centers
    for( i = 0, k = 0; i < sample_count; i++ )
    {
        labels->data.i[i] = k;
        k = k < cluster_count-1 ? k+1 : 0;
    }
#endif

    counters->cols = cluster_count; // cut down counters
    max_dist = termcrit.epsilon*2;

    for( iter = 0; iter < termcrit.maxIter; iter++ )
    {
        int i, j, k;

        // computer centers
        cxZero( centers );
        cxZero( counters );

        for( i = 0; i < sample_count; i++ )
        {
            float* s = (float*)(samples->data.ptr + i*samples->step);
            int k = labels->data.i[i*ids_delta];
            double* c = (double*)(centers->data.ptr + k*centers->step);
            j = 0;
            for( ; j <= dims - 4; j += 4 )
            {
                double t0 = c[j] + s[j];
                double t1 = c[j+1] + s[j+1];

                c[j] = t0;
                c[j+1] = t1;

                t0 = c[j+2] + s[j+2];
                t1 = c[j+3] + s[j+3];

                c[j+2] = t0;
                c[j+3] = t1;
            }
            for( ; j < dims; j++ )
                c[j] += s[j];
            counters->data.i[k]++;
        }

        if( iter > 0 )
            max_dist = 0;

        for( k = 0; k < cluster_count; k++ )
        {
            double* c = (double*)(centers->data.ptr + k*centers->step);
            if( counters->data.i[k] != 0 )
            {
                double scale = 1./counters->data.i[k];
                for( j = 0; j < dims; j++ )
                    c[j] *= scale;
            }
            else
            {
                int i = cxRandNext( &rng ) % sample_count;
                float* s = (float*)(samples->data.ptr + i*samples->step);
                for( j = 0; j < dims; j++ )
                    c[j] = s[j];
            }
            
            if( iter > 0 )
            {
                double dist = 0;
                double* c_o = (double*)(old_centers->data.ptr + k*old_centers->step);
                for( j = 0; j < dims; j++ )
                {
                    double t = c[j] - c_o[j];
                    dist += t*t;
                }
                if( max_dist < dist )
                    max_dist = dist;
            }
        }

        // assign labels
        for( i = 0; i < sample_count; i++ )
        {
            float* s = (float*)(samples->data.ptr + i*samples->step);
            int k_best = 0;
            double min_dist = DBL_MAX;

            for( k = 0; k < cluster_count; k++ )
            {
                double* c = (double*)(centers->data.ptr + k*centers->step);
                double dist = 0;
                
                j = 0;
                for( ; j <= dims - 4; j += 4 )
                {
                    double t0 = c[j] - s[j];
                    double t1 = c[j+1] - s[j+1];
                    dist += t0*t0 + t1*t1;
                    t0 = c[j+2] - s[j+2];
                    t1 = c[j+3] - s[j+3];
                    dist += t0*t0 + t1*t1;
                }

                for( ; j < dims; j++ )
                {
                    double t = c[j] - s[j];
                    dist += t*t;
                }
                
                if( min_dist > dist )
                {
                    min_dist = dist;
                    k_best = k;
                }
            }

            labels->data.i[i*ids_delta] = k_best;
        }

        if( max_dist < termcrit.epsilon )
            break;

        CX_SWAP( centers, old_centers, temp );
    }

    __END__;

    cxReleaseMat( &centers );
    cxReleaseMat( &old_centers );
    cxReleaseMat( &counters );
}