Merge pull request #20716 from komakai:fix_ios_macos_put_get

This commit is contained in:
Alexander Alekhin 2021-09-21 15:31:35 +00:00
commit 2558ab3de7
2 changed files with 78 additions and 39 deletions

View File

@ -13,25 +13,28 @@
#import "CvType.h" #import "CvType.h"
#import "CVObjcUtil.h" #import "CVObjcUtil.h"
// return true if we have reached the final index static int idx2Offset(cv::Mat* mat, std::vector<int>& indices) {
static bool incIdx(cv::Mat* mat, std::vector<int>& indices) { int offset = indices[0];
for (int dim = mat->dims-1; dim>=0; dim--) { for (int dim=1; dim < mat->dims; dim++) {
indices[dim] = (indices[dim] + 1) % mat->size[dim]; offset = offset*mat->size[dim] + indices[dim];
if (indices[dim] != 0) { }
return false; return offset;
} }
static void offset2Idx(cv::Mat* mat, size_t offset, std::vector<int>& indices) {
for (int dim=mat->dims-1; dim>=0; dim--) {
indices[dim] = offset % mat->size[dim];
offset = (offset - indices[dim]) / mat->size[dim];
} }
return true;
} }
// returns true if final index was reached // returns true if final index was reached
static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, int inc) { static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, size_t inc) {
for (int index = 0; index < inc; index++) { size_t currentOffset = idx2Offset(mat, indices);
if (incIdx(mat, indices)) { size_t newOffset = currentOffset + inc;
return true; bool reachedEnd = newOffset>=(size_t)mat->total();
} offset2Idx(mat, reachedEnd?0:newOffset, indices);
} return reachedEnd;
return false;
} }
@implementation Mat { @implementation Mat {
@ -724,22 +727,31 @@ template<typename T> int getData(NSArray<NSNumber*>* indices, cv::Mat* mat, int
} }
int arrayAvailable = count; int arrayAvailable = count;
size_t countBytes = count * sizeof(T);
size_t remainingBytes = (size_t)(mat->total() - idx2Offset(mat, tempIndices))*mat->elemSize();
countBytes = (countBytes>remainingBytes)?remainingBytes:countBytes;
int result = (int)countBytes;
int matAvailable = getMatAvailable(mat, tempIndices); int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable); int available = MIN(arrayAvailable, matAvailable);
int result = (int)(available * mat->elemSize() / mat->channels());
if (mat->isContinuous()) { if (mat->isContinuous()) {
memcpy(tBuffer, mat->ptr(tempIndices.data()), available * sizeof(T)); memcpy(tBuffer, mat->ptr(tempIndices.data()), available * sizeof(T));
} else { } else {
int copyOffset = 0; char* buff = (char*)tBuffer;
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); size_t blockSize = mat->size[mat->dims-1] * mat->elemSize();
while (available > 0) { size_t firstPartialBlockSize = (mat->size[mat->dims-1] - tempIndices[mat->dims-1]) * mat->step[mat->dims-1];
memcpy(tBuffer + copyOffset, mat->ptr(tempIndices.data()), copyCount * sizeof(T)); for (int dim=mat->dims-2; dim>=0 && blockSize == mat->step[dim]; dim--) {
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { blockSize *= mat->size[dim];
break; firstPartialBlockSize += (mat->size[dim] - (tempIndices[dim]+1)) * mat->step[dim];
} }
available -= copyCount; size_t copyCount = (countBytes<firstPartialBlockSize)?countBytes:firstPartialBlockSize;
copyOffset += copyCount * sizeof(T); uchar* data = mat->ptr(tempIndices.data());
copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available); while(countBytes>0) {
memcpy(buff, data, copyCount);
updateIdx(mat, tempIndices, copyCount / mat->elemSize());
countBytes -= copyCount;
buff += copyCount;
copyCount = countBytes<blockSize?countBytes:blockSize;
data = mat->ptr(tempIndices.data());
} }
} }
return result; return result;
@ -817,22 +829,31 @@ template<typename T> int putData(NSArray<NSNumber*>* indices, cv::Mat* mat, int
} }
int arrayAvailable = count; int arrayAvailable = count;
size_t countBytes = count * sizeof(T);
size_t remainingBytes = (size_t)(mat->total() - idx2Offset(mat, tempIndices))*mat->elemSize();
countBytes = (countBytes>remainingBytes)?remainingBytes:countBytes;
int result = (int)countBytes;
int matAvailable = getMatAvailable(mat, tempIndices); int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable); int available = MIN(arrayAvailable, matAvailable);
int result = (int)(available * mat->elemSize() / mat->channels());
if (mat->isContinuous()) { if (mat->isContinuous()) {
memcpy(mat->ptr(tempIndices.data()), tBuffer, available * sizeof(T)); memcpy(mat->ptr(tempIndices.data()), tBuffer, available * sizeof(T));
} else { } else {
int copyOffset = 0; char* buff = (char*)tBuffer;
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available); size_t blockSize = mat->size[mat->dims-1] * mat->elemSize();
while (available > 0) { size_t firstPartialBlockSize = (mat->size[mat->dims-1] - tempIndices[mat->dims-1]) * mat->step[mat->dims-1];
memcpy(mat->ptr(tempIndices.data()), tBuffer + copyOffset, copyCount * sizeof(T)); for (int dim=mat->dims-2; dim>=0 && blockSize == mat->step[dim]; dim--) {
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) { blockSize *= mat->size[dim];
break; firstPartialBlockSize += (mat->size[dim] - (tempIndices[dim]+1)) * mat->step[dim];
} }
available -= copyCount; size_t copyCount = (countBytes<firstPartialBlockSize)?countBytes:firstPartialBlockSize;
copyOffset += copyCount * sizeof(T); uchar* data = mat->ptr(tempIndices.data());
copyCount = MIN(mat->size[mat->dims-1] * (int)mat->channels(), available); while(countBytes>0){
memcpy(data, buff, copyCount);
updateIdx(mat, tempIndices, copyCount / mat->elemSize());
countBytes -= copyCount;
buff += copyCount;
copyCount = countBytes<blockSize?countBytes:blockSize;
data = mat->ptr(tempIndices.data());
} }
} }
return result; return result;

View File

@ -431,7 +431,7 @@ class MatTests: OpenCVTestCase {
// whole Mat // whole Mat
var bytesNum = try m.get(row: 1, col: 1, data: &buff) var bytesNum = try m.get(row: 1, col: 1, data: &buff)
XCTAssertEqual(12, bytesNum); XCTAssertEqual(12, bytesNum)
XCTAssert(buff == [110, 111, 120, 121, 130, 131]) XCTAssert(buff == [110, 111, 120, 121, 130, 131])
// sub-Mat // sub-Mat
@ -442,8 +442,26 @@ class MatTests: OpenCVTestCase {
XCTAssert(buff00 == [230, 231, 240, 241]) XCTAssert(buff00 == [230, 231, 240, 241])
var buff11 = [Int16](repeating: 0, count: 4) var buff11 = [Int16](repeating: 0, count: 4)
bytesNum = try sm.get(row: 1, col: 1, data: &buff11) bytesNum = try sm.get(row: 1, col: 1, data: &buff11)
XCTAssertEqual(4, bytesNum); XCTAssertEqual(4, bytesNum)
XCTAssert(buff11 == [340, 341, 0, 0]) XCTAssert(buff11 == [340, 341, 0, 0])
let m2 = Mat(sizes: [5, 6, 8], type: CvType.CV_16S)
let data:[Int16] = (0..<m2.total()).map { Int16($0) }
try m2.put(indices: [0, 0, 0], data: data)
let matNonContinuous = m2.submat(ranges:[Range(start:1, end:4), Range(start:2, end:5), Range(start:3, end:6)])
let matContinuous = matNonContinuous.clone()
var outNonContinuous = [Int16](repeating:0, count: matNonContinuous.total())
try matNonContinuous.get(indices: [0, 0, 0], data: &outNonContinuous)
var outContinuous = [Int16](repeating: 0, count:matNonContinuous.total())
try matContinuous.get(indices: [0, 0, 0], data: &outContinuous)
XCTAssertEqual(outNonContinuous, outContinuous)
let subMat2 = m2.submat(ranges:[Range(start:1, end:4), Range(start:1, end:5), Range(start:0, end:8)])
let subMatClone2 = subMat2.clone()
var outNonContinuous2 = [Int16](repeating:0, count: subMat2.total())
try subMat2.get(indices: [0, 1, 1], data: &outNonContinuous2)
var outContinuous2 = [Int16](repeating:0, count:subMat2.total())
try subMatClone2.get(indices: [0, 1, 1], data: &outContinuous2)
XCTAssertEqual(outNonContinuous2, outContinuous2)
} }
func testGetIntIntUInt16Array() throws { func testGetIntIntUInt16Array() throws {