1// 2// Mat.m 3// 4// Created by Giles Payne on 2019/10/06. 5// 6 7#import "Mat.h" 8#import "Size2i.h" 9#import "Scalar.h" 10#import "Range.h" 11#import "Rect2i.h" 12#import "Point2i.h" 13#import "CvType.h" 14#import "CVObjcUtil.h" 15 16// return true if we have reached the final index 17static bool incIdx(cv::Mat* mat, std::vector<int>& indices) { 18 for (int dim = mat->dims-1; dim>=0; dim--) { 19 indices[dim] = (indices[dim] + 1) % mat->size[dim]; 20 if (indices[dim] != 0) { 21 return false; 22 } 23 } 24 return true; 25} 26 27// returns true if final index was reached 28static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, int inc) { 29 for (int index = 0; index < inc; index++) { 30 if (incIdx(mat, indices)) { 31 return true; 32 } 33 } 34 return false; 35} 36 37@implementation Mat { 38 NSData* _nsdata; 39} 40 41- (cv::Mat&)nativeRef { 42 return *_nativePtr; 43} 44 45- (instancetype)init { 46 self = [super init]; 47 if (self) { 48 _nativePtr = cv::Ptr<cv::Mat>(new cv::Mat()); 49 } 50 return self; 51} 52 53- (instancetype)initWithNativeMat:(cv::Ptr<cv::Mat>)nativePtr { 54 self = [super init]; 55 if (self) { 56 _nativePtr = nativePtr; 57 } 58 return self; 59} 60 61+ (instancetype)fromNativePtr:(cv::Ptr<cv::Mat>)nativePtr { 62 return [[Mat alloc] initWithNativeMat:nativePtr]; 63} 64 65+ (instancetype)fromNative:(cv::Mat&)nativeRef { 66 return [[Mat alloc] initWithNativeMat:cv::Ptr<cv::Mat>(new cv::Mat(nativeRef))]; 67} 68 69- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type { 70 self = [super init]; 71 if (self) { 72 _nativePtr = new cv::Mat(rows, cols, type); 73 } 74 return self; 75} 76 77- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data { 78 self = [super init]; 79 if (self) { 80 _nativePtr = new cv::Mat(rows, cols, type, (void*)data.bytes); 81 _nsdata = data; // hold onto a reference otherwise this object might be deallocated 82 } 83 return self; 84} 85 86- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data step:(long)step { 87 self = [super init]; 88 if (self) { 89 _nativePtr = new cv::Mat(rows, cols, type, (void*)data.bytes, step); 90 _nsdata = data; // hold onto a reference otherwise this object might be deallocated 91 } 92 return self; 93} 94 95- (instancetype)initWithSize:(Size2i*)size type:(int)type { 96 self = [super init]; 97 if (self) { 98 _nativePtr = new cv::Mat(size.width, size.height, type); 99 } 100 return self; 101} 102 103- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type { 104 self = [super init]; 105 if (self) { 106 std::vector<int> vSizes; 107 for (NSNumber* size in sizes) { 108 vSizes.push_back(size.intValue); 109 } 110 _nativePtr = new cv::Mat((int)sizes.count, vSizes.data(), type); 111 } 112 return self; 113} 114 115- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type scalar:(Scalar*)scalar { 116 self = [super init]; 117 if (self) { 118 cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue); 119 _nativePtr = new cv::Mat(rows, cols, type, scalerTemp); 120 } 121 return self; 122} 123 124- (instancetype)initWithSize:(Size2i*)size type:(int)type scalar:(Scalar *)scalar { 125 self = [super init]; 126 if (self) { 127 cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue); 128 _nativePtr = new cv::Mat(size.width, size.height, type, scalerTemp); 129 } 130 return self; 131} 132 133- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type scalar:(Scalar *)scalar { 134 self = [super init]; 135 if (self) { 136 cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue); 137 std::vector<int> vSizes; 138 for (NSNumber* size in sizes) { 139 vSizes.push_back(size.intValue); 140 } 141 _nativePtr = new cv::Mat((int)sizes.count, vSizes.data(), type, scalerTemp); 142 } 143 return self; 144} 145 146- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange colRange:(Range*)colRange { 147 self = [super init]; 148 if (self) { 149 cv::Range rows(rowRange.start, rowRange.end); 150 cv::Range cols(colRange.start, colRange.end); 151 _nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows, cols); 152 } 153 return self; 154} 155 156- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange { 157 self = [super init]; 158 if (self) { 159 cv::Range rows(rowRange.start, rowRange.end); 160 _nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows); 161 } 162 return self; 163} 164 165- (instancetype)initWithMat:(Mat*)mat ranges:(NSArray<Range*>*)ranges { 166 self = [super init]; 167 if (self) { 168 std::vector<cv::Range> tempRanges; 169 for (Range* range in ranges) { 170 tempRanges.push_back(cv::Range(range.start, range.end)); 171 } 172 _nativePtr = new cv::Mat(mat.nativePtr->operator()(tempRanges)); 173 } 174 return self; 175} 176 177- (instancetype)initWithMat:(Mat*)mat rect:(Rect2i*)roi { 178 self = [super init]; 179 if (self) { 180 cv::Range rows(roi.y, roi.y + roi.height); 181 cv::Range cols(roi.x, roi.x + roi.width); 182 _nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows, cols); 183 } 184 return self; 185} 186 187- (BOOL)isSameMat:(Mat*)mat { 188 return self.nativePtr == mat.nativePtr; 189} 190 191- (Mat*)adjustRoiTop:(int)dtop bottom:(int)dbottom left:(int)dleft right:(int)dright { 192 cv::Mat adjusted = _nativePtr->adjustROI(dtop, dbottom, dleft, dright); 193 return [[Mat alloc] initWithNativeMat:new cv::Mat(adjusted)]; 194} 195 196- (void)assignTo:(Mat*)mat type:(int)type { 197 _nativePtr->assignTo(*(cv::Mat*)mat.nativePtr, type); 198} 199 200- (void)assignTo:(Mat*)mat { 201 _nativePtr->assignTo(*(cv::Mat*)mat.nativePtr); 202} 203 204- (int)channels { 205 return _nativePtr->channels(); 206} 207 208- (int)checkVector:(int)elemChannels depth:(int)depth requireContinuous:(BOOL) requireContinuous { 209 return _nativePtr->checkVector(elemChannels, depth, requireContinuous); 210} 211 212- (int)checkVector:(int)elemChannels depth:(int)depth { 213 return _nativePtr->checkVector(elemChannels, depth); 214} 215 216- (int)checkVector:(int)elemChannels { 217 return _nativePtr->checkVector(elemChannels); 218} 219 220- (Mat*)clone { 221 return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->clone()))]; 222} 223 224- (Mat*)col:(int)x { 225 return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->col(x)))]; 226} 227 228- (Mat*)colRange:(int)start end:(int)end { 229 return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->colRange(start, end)))]; 230} 231 232- (Mat*)colRange:(Range*)range { 233 return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->colRange(range.start, range.end)))]; 234} 235 236- (int)dims { 237 return _nativePtr->dims; 238} 239 240- (int)cols { 241 return _nativePtr->cols; 242} 243 244- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha beta:(double)beta { 245 _nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype, alpha, beta); 246} 247 248- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha { 249 _nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype, alpha); 250} 251 252- (void)convertTo:(Mat*)mat rtype:(int)rtype { 253 _nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype); 254} 255 256- (void)copyTo:(Mat*)mat { 257 _nativePtr->copyTo(*(cv::Mat*)mat->_nativePtr); 258} 259 260- (void)copyTo:(Mat*)mat mask:(Mat*)mask { 261 _nativePtr->copyTo(*(cv::Mat*)mat->_nativePtr, *(cv::Mat*)mask->_nativePtr); 262} 263 264- (void)create:(int)rows cols:(int)cols type:(int)type { 265 _nativePtr->create(rows, cols, type); 266} 267 268- (void)create:(Size2i*)size type:(int)type { 269 cv::Size tempSize(size.width, size.height); 270 _nativePtr->create(tempSize, type); 271} 272 273- (void)createEx:(NSArray<NSNumber*>*)sizes type:(int)type { 274 std::vector<int> tempSizes; 275 for (NSNumber* size in sizes) { 276 tempSizes.push_back(size.intValue); 277 } 278 _nativePtr->create((int)tempSizes.size(), tempSizes.data(), type); 279} 280 281- (void)copySize:(Mat*)mat { 282 _nativePtr->copySize(*(cv::Mat*)mat.nativePtr); 283} 284 285- (Mat*)cross:(Mat*)mat { 286 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->cross(*(cv::Mat*)mat.nativePtr))]; 287} 288 289- (unsigned char*)dataPtr { 290 return _nativePtr->data; 291} 292 293- (int)depth { 294 return _nativePtr->depth(); 295} 296 297- (Mat*)diag:(int)diagonal { 298 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->diag(diagonal))]; 299} 300 301- (Mat*)diag { 302 return [self diag:0]; 303} 304 305+ (Mat*)diag:(Mat*)diagonal { 306 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::diag(*(cv::Mat*)diagonal.nativePtr))]; 307} 308 309- (double)dot:(Mat*)mat { 310 return _nativePtr->dot(*(cv::Mat*)mat.nativePtr); 311} 312 313- (long)elemSize { 314 return _nativePtr->elemSize(); 315} 316 317- (long)elemSize1 { 318 return _nativePtr->elemSize1(); 319} 320 321- (BOOL)empty { 322 return _nativePtr->empty(); 323} 324 325+ (Mat*)eye:(int)rows cols:(int)cols type:(int)type { 326 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::eye(rows, cols, type))]; 327} 328 329+ (Mat*)eye:(Size2i*)size type:(int)type { 330 cv::Size tempSize(size.width, size.height); 331 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::eye(tempSize, type))]; 332} 333 334- (Mat*)inv:(int)method { 335 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->inv(method))]; 336} 337 338- (Mat*)inv { 339 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->inv())]; 340} 341 342- (BOOL)isContinuous { 343 return _nativePtr->isContinuous(); 344} 345 346- (BOOL)isSubmatrix { 347 return _nativePtr->isSubmatrix(); 348} 349 350- (void)locateROI:(Size2i*)wholeSize ofs:(Point2i*)ofs { 351 cv::Size tempWholeSize; 352 cv::Point tempOfs; 353 _nativePtr->locateROI(tempWholeSize, tempOfs); 354 if (wholeSize != nil) { 355 wholeSize.width = tempWholeSize.width; 356 wholeSize.height = tempWholeSize.height; 357 } 358 if (ofs != nil) { 359 ofs.x = tempOfs.x; 360 ofs.y = tempOfs.y; 361 } 362} 363 364- (Mat*)mul:(Mat*)mat scale:(double)scale { 365 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->mul(*(cv::Mat*)mat.nativePtr, scale))]; 366} 367 368- (Mat*)mul:(Mat*)mat { 369 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->mul(*(cv::Mat*)mat.nativePtr))]; 370} 371 372+ (Mat*)ones:(int)rows cols:(int)cols type:(int)type { 373 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones(rows, cols, type))]; 374} 375 376+ (Mat*)ones:(Size2i*)size type:(int)type { 377 cv::Size tempSize(size.width, size.height); 378 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones(tempSize, type))]; 379} 380 381+ (Mat*)onesEx:(NSArray<NSNumber*>*)sizes type:(int)type { 382 std::vector<int> tempSizes; 383 for (NSNumber* size in sizes) { 384 tempSizes.push_back(size.intValue); 385 } 386 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones((int)tempSizes.size(), tempSizes.data(), type))]; 387} 388 389- (void)push_back:(Mat*)mat { 390 _nativePtr->push_back(*(cv::Mat*)mat.nativePtr); 391} 392 393- (Mat*)reshape:(int)channels rows:(int)rows { 394 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels, rows))]; 395} 396 397- (Mat*)reshape:(int)channels { 398 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels))]; 399} 400 401- (Mat*)reshape:(int)channels newshape:(NSArray<NSNumber*>*)newshape { 402 std::vector<int> tempNewshape; 403 for (NSNumber* size in newshape) { 404 tempNewshape.push_back(size.intValue); 405 } 406 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels, tempNewshape))]; 407} 408 409- (Mat*)row:(int)y { 410 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->row(y))]; 411} 412 413- (Mat*)rowRange:(int)start end:(int)end { 414 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->rowRange(start, end))]; 415} 416 417- (Mat*)rowRange:(Range*)range { 418 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->rowRange(range.start, range.end))]; 419} 420 421- (int)rows { 422 return _nativePtr->rows; 423} 424 425- (Mat*)setToScalar:(Scalar*)scalar { 426 cv::Scalar tempScalar(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue); 427 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator=(tempScalar))]; 428} 429 430- (Mat*)setToScalar:(Scalar*)scalar mask:(Mat*)mask { 431 cv::Scalar tempScalar(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue); 432 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(tempScalar, *(cv::Mat*)mask.nativePtr))]; 433} 434 435- (Mat*)setToValue:(Mat*)value mask:(Mat*)mask { 436 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(*(cv::Mat*)value.nativePtr, *(cv::Mat*)mask.nativePtr))]; 437} 438 439- (Mat*)setToValue:(Mat*)value { 440 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(*(cv::Mat*)value.nativePtr))]; 441} 442 443- (Size2i*)size { 444 return [[Size2i alloc] initWithWidth:_nativePtr->size().width height:_nativePtr->size().height]; 445} 446 447- (int)size:(int)dimIndex { 448 return _nativePtr->size[dimIndex]; 449} 450 451- (long)step1:(int)dimIndex { 452 return _nativePtr->step1(dimIndex); 453} 454 455- (long)step1 { 456 return _nativePtr->step1(); 457} 458 459- (Mat*)submat:(int)rowStart rowEnd:(int)rowEnd colStart:(int)colStart colEnd:(int)colEnd { 460 Range* rowRange = [[Range alloc] initWithStart:rowStart end:rowEnd]; 461 Range* colRange = [[Range alloc] initWithStart:colStart end:colEnd]; 462 return [self submat:rowRange colRange:colRange]; 463} 464 465- (Mat*)submat:(Range*)rowRange colRange:(Range*)colRange { 466 cv::Range tempRowRange(rowRange.start, rowRange.end); 467 cv::Range tempColRange(colRange.start, colRange.end); 468 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRowRange, tempColRange))]; 469} 470 471- (Mat*)submat:(NSArray<Range*>*)ranges { 472 std::vector<cv::Range> tempRanges; 473 for (Range* range in ranges) { 474 tempRanges.push_back(cv::Range(range.start, range.end)); 475 } 476 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRanges))]; 477} 478 479- (Mat*)submatRoi:(Rect2i*)roi { 480 cv::Rect tempRoi(roi.x, roi.y, roi.width, roi.height); 481 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRoi))]; 482} 483 484- (Mat*)t { 485 return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->t())]; 486} 487 488- (long)total { 489 return _nativePtr->total(); 490} 491 492- (int)type { 493 return _nativePtr->type(); 494} 495 496+ (Mat*)zeros:(int)rows cols:(int)cols type:(int)type { 497 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros(rows, cols, type))]; 498} 499 500+ (Mat*)zeros:(Size2i*)size type:(int)type { 501 cv::Size tempSize(size.width, size.height); 502 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros(tempSize, type))]; 503} 504 505+ (Mat*)zerosEx:(NSArray<NSNumber*>*)sizes type:(int)type { 506 std::vector<int> tempSizes; 507 for (NSNumber* size in sizes) { 508 tempSizes.push_back(size.intValue); 509 } 510 return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros((int)tempSizes.size(), tempSizes.data(), type))]; 511} 512 513- (NSString*)dimsDescription { 514 if (_nativePtr->dims <= 0) { 515 return @"-1*-1*"; 516 } else { 517 NSMutableString* ret = [NSMutableString string]; 518 for (int index=0; index<_nativePtr->dims; index++) { 519 [ret appendFormat:@"%d*", _nativePtr->size[index]]; 520 } 521 return ret; 522 } 523} 524 525- (NSString*)description { 526 NSString* dimDesc = [self dimsDescription]; 527 return [NSString stringWithFormat:@"Mat [ %@%@, isCont=%s, isSubmat=%s, nativeObj=0x%p, dataAddr=0x%p ]", dimDesc, [CvType typeToString:_nativePtr->type()], _nativePtr->isContinuous()?"YES":"NO", _nativePtr->isSubmatrix()?"YES":"NO", (void*)_nativePtr, (void*)_nativePtr->data]; 528} 529 530- (NSString*)dump { 531 NSMutableString* ret = [NSMutableString string]; 532 cv::Ptr<cv::Formatted> formatted = cv::Formatter::get()->format(*_nativePtr); 533 for(const char* format = formatted->next(); format; format = formatted->next()) { 534 [ret appendFormat:@"%s", format]; 535 } 536 return ret; 537} 538 539template<typename T> void putData(uchar* dataDest, int count, T (^readData)(int)) { 540 T* tDataDest = (T*)dataDest; 541 for (int index = 0; index < count; index++) { 542 tDataDest[index] = readData(index); 543 } 544} 545 546- (void)put:(uchar*)dest data:(NSArray<NSNumber*>*)data offset:(int)offset count:(int)count { 547 int depth = _nativePtr->depth(); 548 if (depth == CV_8U) { 549 putData(dest, count, ^uchar (int index) { return cv::saturate_cast<uchar>(data[offset + index].doubleValue);} ); 550 } else if (depth == CV_8S) { 551 putData(dest, count, ^schar (int index) { return cv::saturate_cast<schar>(data[offset + index].doubleValue);} ); 552 } else if (depth == CV_16U) { 553 putData(dest, count, ^ushort (int index) { return cv::saturate_cast<ushort>(data[offset + index].doubleValue);} ); 554 } else if (depth == CV_16S) { 555 putData(dest, count, ^short (int index) { return cv::saturate_cast<short>(data[offset + index].doubleValue);} ); 556 } else if (depth == CV_32S) { 557 putData(dest, count, ^int32_t (int index) { return cv::saturate_cast<int32_t>(data[offset + index].doubleValue);} ); 558 } else if (depth == CV_32F) { 559 putData(dest, count, ^float (int index) { return cv::saturate_cast<float>(data[offset + index].doubleValue);} ); 560 } else if (depth == CV_64F) { 561 putData(dest, count, ^double (int index) { return data[offset + index].doubleValue;} ); 562 } 563} 564 565- (int)put:(NSArray<NSNumber*>*)indices data:(NSArray<NSNumber*>*)data { 566 cv::Mat* mat = _nativePtr; 567 int type = mat->type(); 568 int rawValueSize = (int)(mat->elemSize() / mat->channels()); 569 if (data == nil || data.count % [CvType channels:type] != 0) { 570 NSException* exception = [NSException 571 exceptionWithName:@"UnsupportedOperationException" 572 reason:[NSString stringWithFormat:@"Provided data element number (%lu) should be multiple of the Mat channels count (%d)", (unsigned long)(data == nil ? 0 : data.count), [CvType channels:type]] 573 userInfo:nil]; 574 @throw exception; 575 } 576 std::vector<int> tempIndices; 577 for (NSNumber* index in indices) { 578 tempIndices.push_back(index.intValue); 579 } 580 for (int index = 0; index < mat->dims; index++) { 581 if (mat->size[index]<=tempIndices[index]) { 582 return 0; // indexes out of range 583 } 584 } 585 586 int arrayAvailable = (int)data.count; 587 int matAvailable = getMatAvailable(mat, tempIndices); 588 int available = MIN(arrayAvailable, matAvailable); 589 int copyOffset = 0; 590 int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); 591 int result = (int)(available * rawValueSize); 592 593 while (available > 0) { 594 [self put:mat->ptr(tempIndices.data()) data:data offset:(int)copyOffset count:copyCount]; 595 if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { 596 break; 597 } 598 available -= copyCount; 599 copyOffset += copyCount; 600 copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available); 601 } 602 return result; 603} 604 605- (int)put:(int)row col:(int)col data:(NSArray<NSNumber*>*)data { 606 NSArray<NSNumber*>* indices = @[[NSNumber numberWithInt:row], [NSNumber numberWithInt:col]]; 607 return [self put:indices data:data]; 608} 609 610template<typename T> void getData(uchar* dataSource, int count, void (^writeData)(int,T)) { 611 T* tDataSource = (T*)dataSource; 612 for (int index = 0; index < count; index++) { 613 writeData(index, tDataSource[index]); 614 } 615} 616 617- (void)get:(uchar*)source data:(NSMutableArray<NSNumber*>*)data offset:(int)offset count:(int)count { 618 int depth = _nativePtr->depth(); 619 if (depth == CV_8U) { 620 getData(source, count, ^void (int index, uchar value) { data[offset + index] = [[NSNumber alloc] initWithUnsignedChar:value]; } ); 621 } else if (depth == CV_8S) { 622 getData(source, count, ^void (int index, char value) { data[offset + index] = [[NSNumber alloc] initWithChar:value]; } ); 623 } else if (depth == CV_16U) { 624 getData(source, count, ^void (int index, ushort value) { data[offset + index] = [[NSNumber alloc] initWithUnsignedShort:value]; } ); 625 } else if (depth == CV_16S) { 626 getData(source, count, ^void (int index, short value) { data[offset + index] = [[NSNumber alloc] initWithShort:value]; } ); 627 } else if (depth == CV_32S) { 628 getData(source, count, ^void (int index, int32_t value) { data[offset + index] = [[NSNumber alloc] initWithInt:value]; } ); 629 } else if (depth == CV_32F) { 630 getData(source, count, ^void (int index, float value) { data[offset + index] = [[NSNumber alloc] initWithFloat:value]; } ); 631 } else if (depth == CV_64F) { 632 getData(source, count, ^void (int index, double value) { data[offset + index] = [[NSNumber alloc] initWithDouble:value]; } ); 633 } 634} 635 636- (int)get:(NSArray<NSNumber*>*)indices data:(NSMutableArray<NSNumber*>*)data { 637 cv::Mat* mat = _nativePtr; 638 int type = mat->type(); 639 if (data == nil || data.count % [CvType channels:type] != 0) { 640 NSException* exception = [NSException 641 exceptionWithName:@"UnsupportedOperationException" 642 reason:[NSString stringWithFormat:@"Provided data element number (%lu) should be multiple of the Mat channels count (%d)", (unsigned long)(data == nil ? 0 : data.count), [CvType channels:type]] 643 userInfo:nil]; 644 @throw exception; 645 } 646 std::vector<int> tempIndices; 647 for (NSNumber* index in indices) { 648 tempIndices.push_back(index.intValue); 649 } 650 for (int index = 0; index < mat->dims; index++) { 651 if (mat->size[index]<=tempIndices[index]) { 652 return 0; // indexes out of range 653 } 654 } 655 656 int arrayAvailable = (int)data.count; 657 int copyOffset = 0; 658 int matAvailable = getMatAvailable(mat, tempIndices); 659 int available = MIN(arrayAvailable, matAvailable); 660 int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); 661 int result = (int)(available * mat->elemSize() / mat->channels()); 662 663 while (available > 0) { 664 [self get:mat->ptr(tempIndices.data()) data:data offset:(int)copyOffset count:copyCount]; 665 if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { 666 break; 667 } 668 available -= copyCount; 669 copyOffset += copyCount; 670 copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available); 671 } 672 return result; 673} 674 675- (int)get:(int)row col:(int)col data:(NSMutableArray<NSNumber*>*)data { 676 NSArray<NSNumber*>* indices = @[[NSNumber numberWithInt:row], [NSNumber numberWithInt:col]]; 677 return [self get:indices data:data]; 678} 679 680- (NSArray<NSNumber*>*)get:(int)row col:(int)col { 681 NSMutableArray<NSNumber*>* result = [NSMutableArray new]; 682 for (int index = 0; index<_nativePtr->channels(); index++) { 683 [result addObject:@0]; 684 } 685 [self get:row col:col data:result]; 686 return result; 687} 688 689- (NSArray<NSNumber*>*)get:(NSArray<NSNumber*>*)indices { 690 NSMutableArray<NSNumber*>* result = [NSMutableArray new]; 691 for (int index = 0; index<_nativePtr->channels(); index++) { 692 [result addObject:@0]; 693 } 694 [self get:indices data:result]; 695 return result; 696} 697 698template<typename T> void getData(uchar* source, void (^writeData)(int,T), int dataOffset, int dataLength) { 699 T* tSource = (T*)source; 700 for (int index = 0; index < dataLength; index++) { 701 writeData(dataOffset+index, tSource[index]); 702 } 703} 704 705int getMatAvailable(cv::Mat* mat, std::vector<int>& indices) { 706 int blockSize = 1; 707 int unavailableCount = 0; 708 for (int index = mat->dims - 1; index >= 0; index--) { 709 unavailableCount += blockSize * indices[index]; 710 blockSize *= mat->size[index]; 711 } 712 return (int)(mat->channels() * (mat->total() - unavailableCount)); 713} 714 715template<typename T> int getData(NSArray<NSNumber*>* indices, cv::Mat* mat, int count, T* tBuffer) { 716 std::vector<int> tempIndices; 717 for (NSNumber* index in indices) { 718 tempIndices.push_back(index.intValue); 719 } 720 for (int index = 0; index < mat->dims; index++) { 721 if (mat->size[index]<=tempIndices[index]) { 722 return 0; // indexes out of range 723 } 724 } 725 726 int arrayAvailable = count; 727 int matAvailable = getMatAvailable(mat, tempIndices); 728 int available = MIN(arrayAvailable, matAvailable); 729 int result = (int)(available * mat->elemSize() / mat->channels()); 730 if (mat->isContinuous()) { 731 memcpy(tBuffer, mat->ptr(tempIndices.data()), available * sizeof(T)); 732 } else { 733 int copyOffset = 0; 734 int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); 735 while (available > 0) { 736 memcpy(tBuffer + copyOffset, mat->ptr(tempIndices.data()), copyCount * sizeof(T)); 737 if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { 738 break; 739 } 740 available -= copyCount; 741 copyOffset += copyCount * sizeof(T); 742 copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available); 743 } 744 } 745 return result; 746} 747 748- (int)get:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(char*)buffer { 749 int depth = _nativePtr->depth(); 750 if (depth != CV_8U && depth != CV_8S) { 751 NSException* exception = [NSException 752 exceptionWithName:@"UnsupportedOperationException" 753 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_8U or CV_8S.", [CvType typeToString:depth]] 754 userInfo:nil]; 755 @throw exception; 756 } 757 return getData(indices, _nativePtr, count, buffer); 758} 759 760- (int)get:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(double*)buffer { 761 int depth = _nativePtr->depth(); 762 if (depth != CV_64F) { 763 NSException* exception = [NSException 764 exceptionWithName:@"UnsupportedOperationException" 765 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_64F.", [CvType typeToString:depth]] 766 userInfo:nil]; 767 @throw exception; 768 } 769 return getData(indices, _nativePtr, count, buffer); 770} 771 772- (int)get:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(float*)buffer { 773 int depth = _nativePtr->depth(); 774 if (depth != CV_32F) { 775 NSException* exception = [NSException 776 exceptionWithName:@"UnsupportedOperationException" 777 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32F.", [CvType typeToString:depth]] 778 userInfo:nil]; 779 @throw exception; 780 } 781 return getData(indices, _nativePtr, count, buffer); 782} 783 784- (int)get:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(int*)buffer { 785 int depth = _nativePtr->depth(); 786 if (depth != CV_32S) { 787 NSException* exception = [NSException 788 exceptionWithName:@"UnsupportedOperationException" 789 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32S.", [CvType typeToString:depth]] 790 userInfo:nil]; 791 @throw exception; 792 } 793 return getData(indices, _nativePtr, count, buffer); 794} 795 796- (int)get:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(short*)buffer { 797 int depth = _nativePtr->depth(); 798 if (depth != CV_16S && depth != CV_16U) { 799 NSException* exception = [NSException 800 exceptionWithName:@"UnsupportedOperationException" 801 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_16S and CV_16U.", [CvType typeToString:depth]] 802 userInfo:nil]; 803 @throw exception; 804 } 805 return getData(indices, _nativePtr, count, buffer); 806} 807 808template<typename T> int putData(NSArray<NSNumber*>* indices, cv::Mat* mat, int count, const T* tBuffer) { 809 std::vector<int> tempIndices; 810 for (NSNumber* index in indices) { 811 tempIndices.push_back(index.intValue); 812 } 813 for (int index = 0; index < mat->dims; index++) { 814 if (mat->size[index]<=tempIndices[index]) { 815 return 0; // indexes out of range 816 } 817 } 818 819 int arrayAvailable = count; 820 int matAvailable = getMatAvailable(mat, tempIndices); 821 int available = MIN(arrayAvailable, matAvailable); 822 int result = (int)(available * mat->elemSize() / mat->channels()); 823 if (mat->isContinuous()) { 824 memcpy(mat->ptr(tempIndices.data()), tBuffer, available * sizeof(T)); 825 } else { 826 int copyOffset = 0; 827 int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); 828 while (available > 0) { 829 memcpy(mat->ptr(tempIndices.data()), tBuffer + copyOffset, copyCount * sizeof(T)); 830 if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { 831 break; 832 } 833 available -= copyCount; 834 copyOffset += copyCount * sizeof(T); 835 copyCount = MIN(mat->size[mat->dims-1] * (int)mat->channels(), available); 836 } 837 } 838 return result; 839} 840 841- (int)put:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(const char*)buffer { 842 int depth = _nativePtr->depth(); 843 if (depth != CV_8U && depth != CV_8S) { 844 NSException* exception = [NSException 845 exceptionWithName:@"UnsupportedOperationException" 846 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_8U or CV_8S.", [CvType typeToString:depth]] 847 userInfo:nil]; 848 @throw exception; 849 } 850 return putData(indices, _nativePtr, count, buffer); 851} 852 853- (int)put:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(const double*)buffer { 854 int depth = _nativePtr->depth(); 855 if (depth != CV_64F) { 856 NSException* exception = [NSException 857 exceptionWithName:@"UnsupportedOperationException" 858 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_64F.", [CvType typeToString:depth]] 859 userInfo:nil]; 860 @throw exception; 861 } 862 return putData(indices, _nativePtr, count, buffer); 863} 864 865- (int)put:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(const float*)buffer { 866 int depth = _nativePtr->depth(); 867 if (depth != CV_32F) { 868 NSException* exception = [NSException 869 exceptionWithName:@"UnsupportedOperationException" 870 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32F.", [CvType typeToString:depth]] 871 userInfo:nil]; 872 @throw exception; 873 } 874 return putData(indices, _nativePtr, count, buffer); 875} 876 877- (int)put:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(const int*)buffer { 878 int depth = _nativePtr->depth(); 879 if (depth != CV_32S) { 880 NSException* exception = [NSException 881 exceptionWithName:@"UnsupportedOperationException" 882 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32S.", [CvType typeToString:depth]] 883 userInfo:nil]; 884 @throw exception; 885 } 886 return putData(indices, _nativePtr, count, buffer); 887} 888 889- (int)put:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(const short*)buffer { 890 int depth = _nativePtr->depth(); 891 if (depth != CV_16S && depth != CV_16U) { 892 NSException* exception = [NSException 893 exceptionWithName:@"UnsupportedOperationException" 894 reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_16S and CV_16U.", [CvType typeToString:depth]] 895 userInfo:nil]; 896 @throw exception; 897 } 898 return putData(indices, _nativePtr, count, buffer); 899} 900 901- (int)height { 902 return [self rows]; 903} 904 905- (int)width { 906 return [self cols]; 907} 908 909@end 910