| 1 | // This file is part of OpenCV project. |
| 2 | // It is subject to the license terms in the LICENSE file found in the top-level directory |
| 3 | // of this distribution and at http://opencv.org/license.html |
| 4 | |
| 5 | #include "precomp.hpp" |
| 6 | #include "opencv2/core/mat.hpp" |
| 7 | #include "opencv2/core/types_c.h" |
| 8 | |
| 9 | #ifndef OPENCV_EXCLUDE_C_API |
| 10 | // glue |
| 11 | |
| 12 | CvMatND cvMatND(const cv::Mat& m) |
| 13 | { |
| 14 | CvMatND self; |
| 15 | cvInitMatNDHeader(mat: &self, dims: m.dims, sizes: m.size, type: m.type(), data: m.data ); |
| 16 | int i, d = m.dims; |
| 17 | for( i = 0; i < d; i++ ) |
| 18 | self.dim[i].step = (int)m.step[i]; |
| 19 | self.type |= m.flags & cv::Mat::CONTINUOUS_FLAG; |
| 20 | return self; |
| 21 | } |
| 22 | |
| 23 | _IplImage cvIplImage(const cv::Mat& m) |
| 24 | { |
| 25 | _IplImage self; |
| 26 | CV_Assert( m.dims <= 2 ); |
| 27 | cvInitImageHeader(image: &self, size: cvSize(sz: m.size()), depth: cvIplDepth(type: m.flags), channels: m.channels()); |
| 28 | cvSetData(arr: &self, data: m.data, step: (int)m.step[0]); |
| 29 | return self; |
| 30 | } |
| 31 | |
| 32 | namespace cv { |
| 33 | |
| 34 | static Mat cvMatToMat(const CvMat* m, bool copyData) |
| 35 | { |
| 36 | Mat thiz; |
| 37 | |
| 38 | if( !m ) |
| 39 | return thiz; |
| 40 | |
| 41 | if( !copyData ) |
| 42 | { |
| 43 | thiz.flags = Mat::MAGIC_VAL + (m->type & (CV_MAT_TYPE_MASK|CV_MAT_CONT_FLAG)); |
| 44 | thiz.dims = 2; |
| 45 | thiz.rows = m->rows; |
| 46 | thiz.cols = m->cols; |
| 47 | thiz.datastart = thiz.data = m->data.ptr; |
| 48 | size_t esz = CV_ELEM_SIZE(m->type), minstep = thiz.cols*esz, _step = m->step; |
| 49 | if( _step == 0 ) |
| 50 | _step = minstep; |
| 51 | thiz.datalimit = thiz.datastart + _step*thiz.rows; |
| 52 | thiz.dataend = thiz.datalimit - _step + minstep; |
| 53 | thiz.step[0] = _step; thiz.step[1] = esz; |
| 54 | } |
| 55 | else |
| 56 | { |
| 57 | thiz.datastart = thiz.dataend = thiz.data = 0; |
| 58 | Mat(m->rows, m->cols, m->type, m->data.ptr, m->step).copyTo(m: thiz); |
| 59 | } |
| 60 | |
| 61 | return thiz; |
| 62 | } |
| 63 | |
| 64 | static Mat cvMatNDToMat(const CvMatND* m, bool copyData) |
| 65 | { |
| 66 | Mat thiz; |
| 67 | |
| 68 | if( !m ) |
| 69 | return thiz; |
| 70 | thiz.datastart = thiz.data = m->data.ptr; |
| 71 | thiz.flags |= CV_MAT_TYPE(m->type); |
| 72 | int _sizes[CV_MAX_DIM]; |
| 73 | size_t _steps[CV_MAX_DIM]; |
| 74 | |
| 75 | int d = m->dims; |
| 76 | for( int i = 0; i < d; i++ ) |
| 77 | { |
| 78 | _sizes[i] = m->dim[i].size; |
| 79 | _steps[i] = m->dim[i].step; |
| 80 | } |
| 81 | |
| 82 | setSize(m&: thiz, dims: d, sz: _sizes, _steps); |
| 83 | finalizeHdr(m&: thiz); |
| 84 | |
| 85 | if( copyData ) |
| 86 | { |
| 87 | Mat temp(thiz); |
| 88 | thiz.release(); |
| 89 | temp.copyTo(m: thiz); |
| 90 | } |
| 91 | |
| 92 | return thiz; |
| 93 | } |
| 94 | |
| 95 | static Mat iplImageToMat(const IplImage* img, bool copyData) |
| 96 | { |
| 97 | Mat m; |
| 98 | |
| 99 | if( !img ) |
| 100 | return m; |
| 101 | |
| 102 | m.dims = 2; |
| 103 | CV_DbgAssert(CV_IS_IMAGE(img) && img->imageData != 0); |
| 104 | |
| 105 | int imgdepth = IPL2CV_DEPTH(img->depth); |
| 106 | size_t esz; |
| 107 | m.step[0] = img->widthStep; |
| 108 | |
| 109 | if(!img->roi) |
| 110 | { |
| 111 | CV_Assert(img->dataOrder == IPL_DATA_ORDER_PIXEL); |
| 112 | m.flags = Mat::MAGIC_VAL + CV_MAKETYPE(imgdepth, img->nChannels); |
| 113 | m.rows = img->height; |
| 114 | m.cols = img->width; |
| 115 | m.datastart = m.data = (uchar*)img->imageData; |
| 116 | esz = CV_ELEM_SIZE(m.flags); |
| 117 | } |
| 118 | else |
| 119 | { |
| 120 | CV_Assert(img->dataOrder == IPL_DATA_ORDER_PIXEL || img->roi->coi != 0); |
| 121 | bool selectedPlane = img->roi->coi && img->dataOrder == IPL_DATA_ORDER_PLANE; |
| 122 | m.flags = Mat::MAGIC_VAL + CV_MAKETYPE(imgdepth, selectedPlane ? 1 : img->nChannels); |
| 123 | m.rows = img->roi->height; |
| 124 | m.cols = img->roi->width; |
| 125 | esz = CV_ELEM_SIZE(m.flags); |
| 126 | m.datastart = m.data = (uchar*)img->imageData + |
| 127 | (selectedPlane ? (img->roi->coi - 1)*m.step*img->height : 0) + |
| 128 | img->roi->yOffset*m.step[0] + img->roi->xOffset*esz; |
| 129 | } |
| 130 | m.datalimit = m.datastart + m.step.p[0]*m.rows; |
| 131 | m.dataend = m.datastart + m.step.p[0]*(m.rows-1) + esz*m.cols; |
| 132 | m.step[1] = esz; |
| 133 | m.updateContinuityFlag(); |
| 134 | |
| 135 | if( copyData ) |
| 136 | { |
| 137 | Mat m2 = m; |
| 138 | m.release(); |
| 139 | if( !img->roi || !img->roi->coi || |
| 140 | img->dataOrder == IPL_DATA_ORDER_PLANE) |
| 141 | m2.copyTo(m); |
| 142 | else |
| 143 | { |
| 144 | int ch[] = {img->roi->coi - 1, 0}; |
| 145 | m.create(rows: m2.rows, cols: m2.cols, type: m2.type()); |
| 146 | mixChannels(src: &m2, nsrcs: 1, dst: &m, ndsts: 1, fromTo: ch, npairs: 1); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | return m; |
| 151 | } |
| 152 | |
| 153 | Mat cvarrToMat(const CvArr* arr, bool copyData, |
| 154 | bool /*allowND*/, int coiMode, AutoBuffer<double>* abuf ) |
| 155 | { |
| 156 | if( !arr ) |
| 157 | return Mat(); |
| 158 | if( CV_IS_MAT_HDR_Z(arr) ) |
| 159 | return cvMatToMat(m: (const CvMat*)arr, copyData); |
| 160 | if( CV_IS_MATND(arr) ) |
| 161 | return cvMatNDToMat(m: (const CvMatND*)arr, copyData ); |
| 162 | if( CV_IS_IMAGE(arr) ) |
| 163 | { |
| 164 | const IplImage* iplimg = (const IplImage*)arr; |
| 165 | if( coiMode == 0 && iplimg->roi && iplimg->roi->coi > 0 ) |
| 166 | CV_Error(cv::Error::BadCOI, "COI is not supported by the function" ); |
| 167 | return iplImageToMat(img: iplimg, copyData); |
| 168 | } |
| 169 | if( CV_IS_SEQ(arr) ) |
| 170 | { |
| 171 | CvSeq* seq = (CvSeq*)arr; |
| 172 | int total = seq->total, type = CV_MAT_TYPE(seq->flags), esz = seq->elem_size; |
| 173 | if( total == 0 ) |
| 174 | return Mat(); |
| 175 | CV_Assert(total > 0 && CV_ELEM_SIZE(seq->flags) == esz); |
| 176 | if(!copyData && seq->first->next == seq->first) |
| 177 | return Mat(total, 1, type, seq->first->data); |
| 178 | if( abuf ) |
| 179 | { |
| 180 | abuf->allocate(size: ((size_t)total*esz + sizeof(double)-1)/sizeof(double)); |
| 181 | double* bufdata = abuf->data(); |
| 182 | cvCvtSeqToArray(seq, elements: bufdata, CV_WHOLE_SEQ); |
| 183 | return Mat(total, 1, type, bufdata); |
| 184 | } |
| 185 | |
| 186 | Mat buf(total, 1, type); |
| 187 | cvCvtSeqToArray(seq, elements: buf.ptr(), CV_WHOLE_SEQ); |
| 188 | return buf; |
| 189 | } |
| 190 | CV_Error(cv::Error::StsBadArg, "Unknown array type" ); |
| 191 | } |
| 192 | |
| 193 | void (const CvArr* arr, OutputArray _ch, int coi) |
| 194 | { |
| 195 | Mat mat = cvarrToMat(arr, copyData: false, true, coiMode: 1); |
| 196 | _ch.create(dims: mat.dims, size: mat.size, type: mat.depth()); |
| 197 | Mat ch = _ch.getMat(); |
| 198 | if(coi < 0) |
| 199 | { |
| 200 | CV_Assert( CV_IS_IMAGE(arr) ); |
| 201 | coi = cvGetImageCOI(image: (const IplImage*)arr)-1; |
| 202 | } |
| 203 | CV_Assert(0 <= coi && coi < mat.channels()); |
| 204 | int _pairs[] = { coi, 0 }; |
| 205 | mixChannels( src: &mat, nsrcs: 1, dst: &ch, ndsts: 1, fromTo: _pairs, npairs: 1 ); |
| 206 | } |
| 207 | |
| 208 | void insertImageCOI(InputArray _ch, CvArr* arr, int coi) |
| 209 | { |
| 210 | Mat ch = _ch.getMat(), mat = cvarrToMat(arr, copyData: false, true, coiMode: 1); |
| 211 | if(coi < 0) |
| 212 | { |
| 213 | CV_Assert( CV_IS_IMAGE(arr) ); |
| 214 | coi = cvGetImageCOI(image: (const IplImage*)arr)-1; |
| 215 | } |
| 216 | CV_Assert(ch.size == mat.size && ch.depth() == mat.depth() && 0 <= coi && coi < mat.channels()); |
| 217 | int _pairs[] = { 0, coi }; |
| 218 | mixChannels( src: &ch, nsrcs: 1, dst: &mat, ndsts: 1, fromTo: _pairs, npairs: 1 ); |
| 219 | } |
| 220 | |
| 221 | } // cv:: |
| 222 | |
| 223 | // operations |
| 224 | |
| 225 | CV_IMPL void cvSetIdentity( CvArr* arr, CvScalar value ) |
| 226 | { |
| 227 | cv::Mat m = cv::cvarrToMat(arr); |
| 228 | cv::setIdentity(mtx: m, s: value); |
| 229 | } |
| 230 | |
| 231 | |
| 232 | CV_IMPL CvScalar cvTrace( const CvArr* arr ) |
| 233 | { |
| 234 | return cvScalar(s: cv::trace(mtx: cv::cvarrToMat(arr))); |
| 235 | } |
| 236 | |
| 237 | |
| 238 | CV_IMPL void cvTranspose( const CvArr* srcarr, CvArr* dstarr ) |
| 239 | { |
| 240 | cv::Mat src = cv::cvarrToMat(arr: srcarr), dst = cv::cvarrToMat(arr: dstarr); |
| 241 | |
| 242 | CV_Assert( src.rows == dst.cols && src.cols == dst.rows && src.type() == dst.type() ); |
| 243 | transpose( src, dst ); |
| 244 | } |
| 245 | |
| 246 | |
| 247 | CV_IMPL void cvCompleteSymm( CvMat* matrix, int LtoR ) |
| 248 | { |
| 249 | cv::Mat m = cv::cvarrToMat(arr: matrix); |
| 250 | cv::completeSymm( m, lowerToUpper: LtoR != 0 ); |
| 251 | } |
| 252 | |
| 253 | |
| 254 | CV_IMPL void cvCrossProduct( const CvArr* srcAarr, const CvArr* srcBarr, CvArr* dstarr ) |
| 255 | { |
| 256 | cv::Mat srcA = cv::cvarrToMat(arr: srcAarr), dst = cv::cvarrToMat(arr: dstarr); |
| 257 | |
| 258 | CV_Assert( srcA.size() == dst.size() && srcA.type() == dst.type() ); |
| 259 | srcA.cross(m: cv::cvarrToMat(arr: srcBarr)).copyTo(m: dst); |
| 260 | } |
| 261 | |
| 262 | |
| 263 | CV_IMPL void |
| 264 | cvReduce( const CvArr* srcarr, CvArr* dstarr, int dim, int op ) |
| 265 | { |
| 266 | cv::Mat src = cv::cvarrToMat(arr: srcarr), dst = cv::cvarrToMat(arr: dstarr); |
| 267 | |
| 268 | if( dim < 0 ) |
| 269 | dim = src.rows > dst.rows ? 0 : src.cols > dst.cols ? 1 : dst.cols == 1; |
| 270 | |
| 271 | if( dim > 1 ) |
| 272 | CV_Error( cv::Error::StsOutOfRange, "The reduced dimensionality index is out of range" ); |
| 273 | |
| 274 | if( (dim == 0 && (dst.cols != src.cols || dst.rows != 1)) || |
| 275 | (dim == 1 && (dst.rows != src.rows || dst.cols != 1)) ) |
| 276 | CV_Error( cv::Error::StsBadSize, "The output array size is incorrect" ); |
| 277 | |
| 278 | if( src.channels() != dst.channels() ) |
| 279 | CV_Error( cv::Error::StsUnmatchedFormats, "Input and output arrays must have the same number of channels" ); |
| 280 | |
| 281 | cv::reduce(src, dst, dim, rtype: op, dtype: dst.type()); |
| 282 | } |
| 283 | |
| 284 | |
| 285 | CV_IMPL CvArr* |
| 286 | cvRange( CvArr* arr, double start, double end ) |
| 287 | { |
| 288 | CvMat stub, *mat = (CvMat*)arr; |
| 289 | int step; |
| 290 | double val = start; |
| 291 | |
| 292 | if( !CV_IS_MAT(mat) ) |
| 293 | mat = cvGetMat( arr: mat, header: &stub); |
| 294 | |
| 295 | int rows = mat->rows; |
| 296 | int cols = mat->cols; |
| 297 | int type = CV_MAT_TYPE(mat->type); |
| 298 | double delta = (end-start)/(rows*cols); |
| 299 | |
| 300 | if( CV_IS_MAT_CONT(mat->type) ) |
| 301 | { |
| 302 | cols *= rows; |
| 303 | rows = 1; |
| 304 | step = 1; |
| 305 | } |
| 306 | else |
| 307 | step = mat->step / CV_ELEM_SIZE(type); |
| 308 | |
| 309 | if( type == CV_32SC1 ) |
| 310 | { |
| 311 | int* idata = mat->data.i; |
| 312 | int ival = cvRound(value: val), idelta = cvRound(value: delta); |
| 313 | |
| 314 | if( fabs(x: val - ival) < DBL_EPSILON && |
| 315 | fabs(x: delta - idelta) < DBL_EPSILON ) |
| 316 | { |
| 317 | for( int i = 0; i < rows; i++, idata += step ) |
| 318 | for( int j = 0; j < cols; j++, ival += idelta ) |
| 319 | idata[j] = ival; |
| 320 | } |
| 321 | else |
| 322 | { |
| 323 | for( int i = 0; i < rows; i++, idata += step ) |
| 324 | for( int j = 0; j < cols; j++, val += delta ) |
| 325 | idata[j] = cvRound(value: val); |
| 326 | } |
| 327 | } |
| 328 | else if( type == CV_32FC1 ) |
| 329 | { |
| 330 | float* fdata = mat->data.fl; |
| 331 | for( int i = 0; i < rows; i++, fdata += step ) |
| 332 | for( int j = 0; j < cols; j++, val += delta ) |
| 333 | fdata[j] = (float)val; |
| 334 | } |
| 335 | else |
| 336 | CV_Error( cv::Error::StsUnsupportedFormat, "The function only supports 32sC1 and 32fC1 datatypes" ); |
| 337 | |
| 338 | return arr; |
| 339 | } |
| 340 | |
| 341 | |
| 342 | CV_IMPL void |
| 343 | cvSort( const CvArr* _src, CvArr* _dst, CvArr* _idx, int flags ) |
| 344 | { |
| 345 | cv::Mat src = cv::cvarrToMat(arr: _src); |
| 346 | |
| 347 | if( _idx ) |
| 348 | { |
| 349 | cv::Mat idx0 = cv::cvarrToMat(arr: _idx), idx = idx0; |
| 350 | CV_Assert( src.size() == idx.size() && idx.type() == CV_32S && src.data != idx.data ); |
| 351 | cv::sortIdx( src, dst: idx, flags ); |
| 352 | CV_Assert( idx0.data == idx.data ); |
| 353 | } |
| 354 | |
| 355 | if( _dst ) |
| 356 | { |
| 357 | cv::Mat dst0 = cv::cvarrToMat(arr: _dst), dst = dst0; |
| 358 | CV_Assert( src.size() == dst.size() && src.type() == dst.type() ); |
| 359 | cv::sort( src, dst, flags ); |
| 360 | CV_Assert( dst0.data == dst.data ); |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | CV_IMPL int |
| 365 | cvKMeans2( const CvArr* _samples, int cluster_count, CvArr* _labels, |
| 366 | CvTermCriteria termcrit, int attempts, CvRNG*, |
| 367 | int flags, CvArr* _centers, double* _compactness ) |
| 368 | { |
| 369 | cv::Mat data = cv::cvarrToMat(arr: _samples), labels = cv::cvarrToMat(arr: _labels), centers; |
| 370 | if( _centers ) |
| 371 | { |
| 372 | centers = cv::cvarrToMat(arr: _centers); |
| 373 | |
| 374 | centers = centers.reshape(cn: 1); |
| 375 | data = data.reshape(cn: 1); |
| 376 | |
| 377 | CV_Assert( !centers.empty() ); |
| 378 | CV_Assert( centers.rows == cluster_count ); |
| 379 | CV_Assert( centers.cols == data.cols ); |
| 380 | CV_Assert( centers.depth() == data.depth() ); |
| 381 | } |
| 382 | CV_Assert( labels.isContinuous() && labels.type() == CV_32S && |
| 383 | (labels.cols == 1 || labels.rows == 1) && |
| 384 | labels.cols + labels.rows - 1 == data.rows ); |
| 385 | |
| 386 | double compactness = cv::kmeans(data, K: cluster_count, bestLabels: labels, criteria: termcrit, attempts, |
| 387 | flags, centers: _centers ? cv::_OutputArray(centers) : cv::_OutputArray() ); |
| 388 | if( _compactness ) |
| 389 | *_compactness = compactness; |
| 390 | return 1; |
| 391 | } |
| 392 | |
| 393 | #endif // OPENCV_EXCLUDE_C_API |
| 394 | |