CV_IMPL double cvPseudoInv( CvArr* srcarr, CvArr* dstarr, int flags ) { uchar* buffer = 0; int local_alloc = 0; double condition_number = 0; CV_FUNCNAME( "cvPseudoInv" ); __BEGIN__; CvMat astub, *a = (CvMat*)srcarr; CvMat bstub, *b = (CvMat*)dstarr; CvMat ustub, *u = &ustub; CvMat vstub, *v = &vstub; CvMat tmat; uchar* tw = 0; int type, n, m, nm, mn; int buf_size, pix_size; if( !CV_IS_ARR( a )) CV_CALL( a = cvGetMat( a, &astub )); if( !CV_IS_ARR( b )) CV_CALL( b = cvGetMat( b, &bstub )); if( !CV_ARE_TYPES_EQ( a, b )) CV_ERROR( CV_StsUnmatchedSizes, "" ); n = a->width; m = a->height; nm = MIN( n, m ); mn = MAX( n, m ); if( n != b->height || m != b->width ) CV_ERROR( CV_StsUnmatchedSizes, "" ); type = CV_ARR_TYPE( a->type ); pix_size = icvPixSize[type]; buf_size = nm*2 + mn + m*mn + n*n; if( !(flags & CV_SVD_MODIFY_A) ) buf_size += m*n; buf_size *= pix_size; if( buf_size <= CV_MAX_LOCAL_SIZE ) { buffer = (uchar*)alloca( buf_size ); local_alloc = 1; } else { CV_CALL( buffer = (uchar*)cvAlloc( buf_size )); } if( !(flags & CV_SVD_MODIFY_A) ) { cvInitMatHeader( &tmat, a->height, a->width, type, buffer + buf_size - n*m*pix_size ); cvCopy( a, &tmat ); a = &tmat; } tw = buffer + (nm + mn)*pix_size; cvInitMatHeader( u, m, m, type, tw + nm*pix_size ); cvInitMatHeader( v, n, n, type, u->data.ptr + m*mn*pix_size ); if( type == CV_32FC1 ) { IPPI_CALL( icvSVD_32f( a->data.fl, a->step/sizeof(float), (float*)tw, u->data.fl, u->step/sizeof(float), v->data.fl, v->step/sizeof(float), icvGetMatSize(a), (float*)buffer )); } else if( type == CV_64FC1 ) { IPPI_CALL( icvSVD_64f( a->data.db, a->step/sizeof(double), (double*)tw, u->data.db, u->step/sizeof(double), v->data.db, v->step/sizeof(double), icvGetMatSize(a), (double*)buffer )); } else { CV_ERROR( CV_StsUnsupportedFormat, "" ); } cvT( v, v ); cvGetRow( u, &tmat, 0 ); if( type == CV_32FC1 ) { for( int i = 0; i < nm; i++ ) { double t = ((float*)tw)[i]; tmat.data.ptr = u->data.ptr + i*u->step; t = t > FLT_EPSILON ? 1./t : 0; if( i == mn - 1 ) condition_number = t != 0 ? ((float*)tw)[0]*t : DBL_MAX; cvScale( &tmat, &tmat, t ); } } else { for( int i = 0; i < nm; i++ ) { double t = ((double*)tw)[i]; tmat.data.ptr = u->data.ptr + i*u->step; t = t > DBL_EPSILON ? 1./t : 0; if( i == mn - 1 ) condition_number = t != 0 ? ((double*)tw)[0]*t : DBL_MAX; cvScale( &tmat, &tmat, t ); } } u->height = n; if( n > m ) { cvGetSubArr( u, &tmat, cvRect( 0, m, m, n - m )); cvSetZero( &tmat ); } cvMatMulAdd( v, u, 0, b ); CV_CHECK_NANS( b ); __END__; if( buffer && !local_alloc ) cvFree( (void**)&buffer ); return condition_number; }
CV_IMPL void cvSVD( CvArr* aarr, CvArr* warr, CvArr* uarr, CvArr* varr, int flags ) { uchar* buffer = 0; int local_alloc = 0; CV_FUNCNAME( "cvSVD" ); __BEGIN__; CvMat astub, *a = (CvMat*)aarr; CvMat wstub, *w = (CvMat*)warr; CvMat ustub, *u; CvMat vstub, *v; CvMat tmat; uchar* tw = 0; int type; int a_buf_offset = 0, u_buf_offset = 0, buf_size, pix_size; int temp_u = 0, /* temporary storage for U is needed */ t_svd; /* special case: a->rows < a->cols */ int m, n; int w_rows, w_cols; int u_rows = 0, u_cols = 0; int w_is_mat = 0; if( !CV_IS_MAT( a )) CV_CALL( a = cvGetMat( a, &astub )); if( !CV_IS_MAT( w )) CV_CALL( w = cvGetMat( w, &wstub )); if( !CV_ARE_TYPES_EQ( a, w )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( a->rows >= a->cols ) { m = a->rows; n = a->cols; w_rows = w->rows; w_cols = w->cols; t_svd = 0; } else { CvArr* t; CV_SWAP( uarr, varr, t ); flags = (flags & CV_SVD_U_T ? CV_SVD_V_T : 0)| (flags & CV_SVD_V_T ? CV_SVD_U_T : 0); m = a->cols; n = a->rows; w_rows = w->cols; w_cols = w->rows; t_svd = 1; } u = (CvMat*)uarr; v = (CvMat*)varr; w_is_mat = w_cols > 1 && w_rows > 1; if( !w_is_mat && CV_IS_MAT_CONT(w->type) && w_cols + w_rows - 1 == n ) tw = w->data.ptr; if( u ) { if( !CV_IS_MAT( u )) CV_CALL( u = cvGetMat( u, &ustub )); if( !(flags & CV_SVD_U_T) ) { u_rows = u->rows; u_cols = u->cols; } else { u_rows = u->cols; u_cols = u->rows; } if( !CV_ARE_TYPES_EQ( a, u )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( u_rows != m || (u_cols != m && u_cols != n)) CV_ERROR( CV_StsUnmatchedSizes, !t_svd ? "U matrix has unappropriate size" : "V matrix has unappropriate size" ); temp_u = (u_rows != u_cols && !(flags & CV_SVD_U_T)) || u->data.ptr==a->data.ptr; if( w_is_mat && u_cols != w_rows ) CV_ERROR( CV_StsUnmatchedSizes, !t_svd ? "U and W have incompatible sizes" : "V and W have incompatible sizes" ); } else { u = &ustub; u->data.ptr = 0; u->step = 0; } if( v ) { int v_rows, v_cols; if( !CV_IS_MAT( v )) CV_CALL( v = cvGetMat( v, &vstub )); if( !(flags & CV_SVD_V_T) ) { v_rows = v->rows; v_cols = v->cols; } else { v_rows = v->cols; v_cols = v->rows; } if( !CV_ARE_TYPES_EQ( a, v )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( v_rows != n || v_cols != n ) CV_ERROR( CV_StsUnmatchedSizes, t_svd ? "U matrix has unappropriate size" : "V matrix has unappropriate size" ); if( w_is_mat && w_cols != v_cols ) CV_ERROR( CV_StsUnmatchedSizes, t_svd ? "U and W have incompatible sizes" : "V and W have incompatible sizes" ); } else { v = &vstub; v->data.ptr = 0; v->step = 0; } type = CV_MAT_TYPE( a->type ); pix_size = CV_ELEM_SIZE(type); buf_size = n*2 + m; if( !(flags & CV_SVD_MODIFY_A) ) { a_buf_offset = buf_size; buf_size += a->rows*a->cols; } if( temp_u ) { u_buf_offset = buf_size; buf_size += u->rows*u->cols; } buf_size *= pix_size; if( buf_size <= CV_MAX_LOCAL_SIZE ) { buffer = (uchar*)cvStackAlloc( buf_size ); local_alloc = 1; } else { CV_CALL( buffer = (uchar*)cvAlloc( buf_size )); } if( !(flags & CV_SVD_MODIFY_A) ) { cvInitMatHeader( &tmat, m, n, type, buffer + a_buf_offset*pix_size ); if( !t_svd ) cvCopy( a, &tmat ); else cvT( a, &tmat ); a = &tmat; } if( temp_u ) { cvInitMatHeader( &ustub, u_cols, u_rows, type, buffer + u_buf_offset*pix_size ); u = &ustub; } if( !tw ) tw = buffer + (n + m)*pix_size; if( type == CV_32FC1 ) { icvSVD_32f( a->data.fl, a->step/sizeof(float), a->rows, a->cols, (float*)tw, u->data.fl, u->step/sizeof(float), u_cols, v->data.fl, v->step/sizeof(float), (float*)buffer ); } else if( type == CV_64FC1 ) { icvSVD_64f( a->data.db, a->step/sizeof(double), a->rows, a->cols, (double*)tw, u->data.db, u->step/sizeof(double), u_cols, v->data.db, v->step/sizeof(double), (double*)buffer ); } else { CV_ERROR( CV_StsUnsupportedFormat, "" ); } if( tw != w->data.ptr ) { int shift = w->cols != 1; cvSetZero( w ); if( type == CV_32FC1 ) for( int i = 0; i < n; i++ ) ((float*)(w->data.ptr + i*w->step))[i*shift] = ((float*)tw)[i]; else for( int i = 0; i < n; i++ ) ((double*)(w->data.ptr + i*w->step))[i*shift] = ((double*)tw)[i]; } if( uarr ) { if( !(flags & CV_SVD_U_T)) cvT( u, uarr ); else if( temp_u ) cvCopy( u, uarr ); /*CV_CHECK_NANS( uarr );*/ } if( varr ) { if( !(flags & CV_SVD_V_T)) cvT( v, varr ); /*CV_CHECK_NANS( varr );*/ } CV_CHECK_NANS( w ); __END__; if( buffer && !local_alloc ) cvFree( &buffer ); }
CV_IMPL void cvSVD( CvArr* aarr, CvArr* warr, CvArr* uarr, CvArr* varr, int flags ) { uchar* buffer = 0; int local_alloc = 0; CV_FUNCNAME( "cvSVD" ); __BEGIN__; CvMat astub, *a = (CvMat*)aarr; CvMat wstub, *w = (CvMat*)warr; CvMat ustub, *u = (CvMat*)uarr; CvMat vstub, *v = (CvMat*)varr; CvMat tmat; uchar* tw = 0; int type, nm, mn; int buf_size, pix_size; int t_svd = 0; // special case: a->rows < a->cols if( !CV_IS_ARR( a )) CV_CALL( a = cvGetMat( a, &astub )); if( !CV_IS_ARR( w )) CV_CALL( w = cvGetMat( w, &wstub )); if( !CV_ARE_TYPES_EQ( a, w )) CV_ERROR( CV_StsUnmatchedFormats, "" ); nm = MIN( a->width, a->height ); mn = MAX( a->width, a->height ); if( (w->width == 1 || w->height == 1) && CV_IS_ARR_CONT( w->type ) && w->width*w->height == nm ) { tw = w->data.ptr; } else if( !CV_ARE_SIZES_EQ( w, a )) { CV_ERROR( CV_StsBadSize, "W must be either continuous vector of " "size MIN(A->width,A->height) or matrix of " "the same size as A" ); } if( u ) { if( !CV_IS_ARR( u )) CV_CALL( u = cvGetMat( u, &ustub )); if( !CV_ARE_TYPES_EQ( a, u )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( u->width != u->height || u->height != a->height ) CV_ERROR( CV_StsUnmatchedSizes, "U matrix must be square and have the same " "linear size as number of rows in A" ); if( u->data.ptr == a->data.ptr ) CV_ERROR( CV_StsBadArg, "U can not be equal A" ); } else { u = &ustub; u->data.ptr = 0; u->step = 0; } if( v ) { if( !CV_IS_ARR( v )) CV_CALL( v = cvGetMat( v, &vstub )); if( !CV_ARE_TYPES_EQ( a, v )) CV_ERROR( CV_StsUnmatchedFormats, "" ); if( v->width != v->height || v->width != a->width ) CV_ERROR( CV_StsUnmatchedSizes, "V matrix must be square and have the same " "linear size as number of columns in A" ); if( v->data.ptr == a->data.ptr || v->data.ptr == u->data.ptr ) CV_ERROR( CV_StsBadArg, "V can not be equal U or A" ); } else { v = &vstub; v->data.ptr = 0; v->step = 0; } type = CV_ARR_TYPE( a->type ); pix_size = icvPixSize[type]; buf_size = nm*2 + mn; if( a->rows < a->cols ) { CvMat* t; CV_SWAP( u, v, t ); flags = (flags & CV_SVD_U_T ? CV_SVD_V_T : 0)| (flags & CV_SVD_V_T ? CV_SVD_U_T : 0); t_svd = 1; } if( !(flags & CV_SVD_MODIFY_A) ) buf_size += a->width*a->height; buf_size *= pix_size; if( buf_size <= CV_MAX_LOCAL_SIZE ) { buffer = (uchar*)alloca( buf_size ); local_alloc = 1; } else { CV_CALL( buffer = (uchar*)cvAlloc( buf_size )); } if( !(flags & CV_SVD_MODIFY_A) ) { if( !t_svd ) { cvInitMatHeader( &tmat, a->height, a->width, type, buffer + (nm*2 + mn)*pix_size ); cvCopy( a, &tmat ); } else { cvInitMatHeader( &tmat, a->width, a->height, type, buffer + (nm*2 + mn)*pix_size ); cvT( a, &tmat ); } a = &tmat; } if( !tw ) tw = buffer + (nm + mn)*pix_size; if( type == CV_32FC1 ) { IPPI_CALL( icvSVD_32f( a->data.fl, a->step/sizeof(float), (float*)tw, u->data.fl, u->step/sizeof(float), v->data.fl, v->step/sizeof(float), icvGetMatSize(a), (float*)buffer )); } else if( type == CV_64FC1 ) { IPPI_CALL( icvSVD_64f( a->data.db, a->step/sizeof(double), (double*)tw, u->data.db, u->step/sizeof(double), v->data.db, v->step/sizeof(double), icvGetMatSize(a), (double*)buffer )); } else { CV_ERROR( CV_StsUnsupportedFormat, "" ); } if( tw != w->data.ptr ) { cvSetZero( w ); if( type == CV_32FC1 ) for( int i = 0; i < nm; i++ ) ((float*)(w->data.ptr + i*w->step))[i] = ((float*)tw)[i]; else for( int i = 0; i < nm; i++ ) ((double*)(w->data.ptr + i*w->step))[i] = ((double*)tw)[i]; } if( u->data.ptr ) { if( !(flags & CV_SVD_U_T)) cvT( u, u ); CV_CHECK_NANS( u ); } if( v->data.ptr) { if( !(flags & CV_SVD_V_T)) cvT( v, v ); CV_CHECK_NANS( v ); } CV_CHECK_NANS( w ); __END__; if( buffer && !local_alloc ) cvFree( (void**)&buffer ); }