Merge pull request #17165 from komakai:objc-binding

Objc binding

* Initial work on Objective-C wrapper

* Objective-C generator script; update manually generated wrappers

* Add Mat tests

* Core Tests

* Imgproc wrapper generation and tests

* Fixes for Imgcodecs wrapper

* Miscellaneous fixes. Swift build support

* Objective-C wrapper build/install

* Add Swift wrappers for videoio/objdetect/feature2d

* Framework build;iOS support

* Fix toArray functions;Use enum types whenever possible

* Use enum types where possible;prepare test build

* Update test

* Add test runner scripts for iOS and macOS

* Add test scripts and samples

* Build fixes

* Fix build (cmake 3.17.x compatibility)

* Fix warnings

* Fix enum name conflicting handling

* Add support for document generation with Jazzy

* Swift/Native fast accessor functions

* Add Objective-C wrapper for calib3d, dnn, ml, photo and video modules

* Remove IntOut/FloatOut/DoubleOut classes

* Fix iOS default test platform value

* Fix samples

* Revert default framework name to opencv2

* Add converter util functions

* Fix failing test

* Fix whitespace

* Add handling for deprecated methods;fix warnings;define __OPENCV_BUILD

* Suppress cmake warnings

* Reduce severity of "jazzy not found" log message

* Fix incorrect #include of compatibility header in ios.h

* Use explicit returns in subscript/get implementation

* Reduce minimum required cmake version to 3.15 for Objective-C/Swift binding
pull/17503/head
Giles Payne 5 years ago committed by GitHub
parent f30b5995b6
commit 02385472b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 7
      CMakeLists.txt
  3. 5
      cmake/OpenCVGenConfig.cmake
  4. 1
      cmake/OpenCVModule.cmake
  5. 2
      modules/calib3d/CMakeLists.txt
  6. 5
      modules/calib3d/misc/objc/gen_dict.json
  7. 465
      modules/calib3d/misc/objc/test/Calib3dTest.swift
  8. 2
      modules/core/CMakeLists.txt
  9. 16
      modules/core/misc/objc/common/ArrayUtil.h
  10. 15
      modules/core/misc/objc/common/ArrayUtil.mm
  11. 88
      modules/core/misc/objc/common/ByteVector.h
  12. 76
      modules/core/misc/objc/common/ByteVector.mm
  13. 53
      modules/core/misc/objc/common/ByteVectorExt.swift
  14. 85
      modules/core/misc/objc/common/CVObjcUtil.h
  15. 98
      modules/core/misc/objc/common/Converters.h
  16. 205
      modules/core/misc/objc/common/Converters.mm
  17. 67
      modules/core/misc/objc/common/CvType.h
  18. 105
      modules/core/misc/objc/common/CvType.mm
  19. 90
      modules/core/misc/objc/common/CvTypeExt.swift
  20. 82
      modules/core/misc/objc/common/DMatch.h
  21. 107
      modules/core/misc/objc/common/DMatch.mm
  22. 93
      modules/core/misc/objc/common/Double2.h
  23. 75
      modules/core/misc/objc/common/Double2.mm
  24. 94
      modules/core/misc/objc/common/Double3.h
  25. 85
      modules/core/misc/objc/common/Double3.mm
  26. 88
      modules/core/misc/objc/common/DoubleVector.h
  27. 76
      modules/core/misc/objc/common/DoubleVector.mm
  28. 53
      modules/core/misc/objc/common/DoubleVectorExt.swift
  29. 99
      modules/core/misc/objc/common/Float4.h
  30. 95
      modules/core/misc/objc/common/Float4.mm
  31. 112
      modules/core/misc/objc/common/Float6.h
  32. 115
      modules/core/misc/objc/common/Float6.mm
  33. 88
      modules/core/misc/objc/common/FloatVector.h
  34. 76
      modules/core/misc/objc/common/FloatVector.mm
  35. 53
      modules/core/misc/objc/common/FloatVectorExt.swift
  36. 99
      modules/core/misc/objc/common/Int4.h
  37. 95
      modules/core/misc/objc/common/Int4.mm
  38. 88
      modules/core/misc/objc/common/IntVector.h
  39. 76
      modules/core/misc/objc/common/IntVector.mm
  40. 53
      modules/core/misc/objc/common/IntVectorExt.swift
  41. 98
      modules/core/misc/objc/common/KeyPoint.h
  42. 95
      modules/core/misc/objc/common/KeyPoint.mm
  43. 157
      modules/core/misc/objc/common/Mat.h
  44. 913
      modules/core/misc/objc/common/Mat.mm
  45. 244
      modules/core/misc/objc/common/MatExt.swift
  46. 62
      modules/core/misc/objc/common/MatOfByte.h
  47. 69
      modules/core/misc/objc/common/MatOfByte.mm
  48. 64
      modules/core/misc/objc/common/MatOfDMatch.h
  49. 83
      modules/core/misc/objc/common/MatOfDMatch.mm
  50. 63
      modules/core/misc/objc/common/MatOfDouble.h
  51. 69
      modules/core/misc/objc/common/MatOfDouble.mm
  52. 60
      modules/core/misc/objc/common/MatOfFloat.h
  53. 69
      modules/core/misc/objc/common/MatOfFloat.mm
  54. 62
      modules/core/misc/objc/common/MatOfFloat4.h
  55. 69
      modules/core/misc/objc/common/MatOfFloat4.mm
  56. 62
      modules/core/misc/objc/common/MatOfFloat6.h
  57. 69
      modules/core/misc/objc/common/MatOfFloat6.mm
  58. 62
      modules/core/misc/objc/common/MatOfInt.h
  59. 69
      modules/core/misc/objc/common/MatOfInt.mm
  60. 62
      modules/core/misc/objc/common/MatOfInt4.h
  61. 69
      modules/core/misc/objc/common/MatOfInt4.mm
  62. 64
      modules/core/misc/objc/common/MatOfKeyPoint.h
  63. 87
      modules/core/misc/objc/common/MatOfKeyPoint.mm
  64. 64
      modules/core/misc/objc/common/MatOfPoint2f.h
  65. 81
      modules/core/misc/objc/common/MatOfPoint2f.mm
  66. 65
      modules/core/misc/objc/common/MatOfPoint2i.h
  67. 81
      modules/core/misc/objc/common/MatOfPoint2i.mm
  68. 64
      modules/core/misc/objc/common/MatOfPoint3.h
  69. 82
      modules/core/misc/objc/common/MatOfPoint3.mm
  70. 64
      modules/core/misc/objc/common/MatOfPoint3f.h
  71. 82
      modules/core/misc/objc/common/MatOfPoint3f.mm
  72. 65
      modules/core/misc/objc/common/MatOfRect2d.h
  73. 88
      modules/core/misc/objc/common/MatOfRect2d.mm
  74. 65
      modules/core/misc/objc/common/MatOfRect2i.h
  75. 83
      modules/core/misc/objc/common/MatOfRect2i.mm
  76. 64
      modules/core/misc/objc/common/MatOfRotatedRect.h
  77. 87
      modules/core/misc/objc/common/MatOfRotatedRect.mm
  78. 38
      modules/core/misc/objc/common/MinMaxLocResult.h
  79. 27
      modules/core/misc/objc/common/MinMaxLocResult.mm
  80. 87
      modules/core/misc/objc/common/Point2d.h
  81. 107
      modules/core/misc/objc/common/Point2d.mm
  82. 87
      modules/core/misc/objc/common/Point2f.h
  83. 105
      modules/core/misc/objc/common/Point2f.mm
  84. 88
      modules/core/misc/objc/common/Point2i.h
  85. 105
      modules/core/misc/objc/common/Point2i.mm
  86. 84
      modules/core/misc/objc/common/Point3d.h
  87. 114
      modules/core/misc/objc/common/Point3d.mm
  88. 85
      modules/core/misc/objc/common/Point3f.h
  89. 111
      modules/core/misc/objc/common/Point3f.mm
  90. 84
      modules/core/misc/objc/common/Point3i.h
  91. 111
      modules/core/misc/objc/common/Point3i.mm
  92. 93
      modules/core/misc/objc/common/Range.h
  93. 86
      modules/core/misc/objc/common/Range.m
  94. 111
      modules/core/misc/objc/common/Rect2d.h
  95. 155
      modules/core/misc/objc/common/Rect2d.mm
  96. 111
      modules/core/misc/objc/common/Rect2f.h
  97. 151
      modules/core/misc/objc/common/Rect2f.mm
  98. 112
      modules/core/misc/objc/common/Rect2i.h
  99. 150
      modules/core/misc/objc/common/Rect2i.mm
  100. 86
      modules/core/misc/objc/common/RotatedRect.h
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -24,3 +24,4 @@ bin/
build
node_modules
CMakeSettings.json
xcuserdata/

@ -452,6 +452,7 @@ OCV_OPTION(BUILD_FAT_JAVA_LIB "Create Java wrapper exporting all functions
OCV_OPTION(BUILD_ANDROID_SERVICE "Build OpenCV Manager for Google Play" OFF IF ANDROID )
OCV_OPTION(BUILD_CUDA_STUBS "Build CUDA modules stubs when no CUDA SDK" OFF IF (NOT APPLE_FRAMEWORK) )
OCV_OPTION(BUILD_JAVA "Enable Java support" (ANDROID OR NOT CMAKE_CROSSCOMPILING) IF (ANDROID OR (NOT APPLE_FRAMEWORK AND NOT WINRT)) )
OCV_OPTION(BUILD_OBJC "Enable Objective-C support" ON IF APPLE_FRAMEWORK )
# OpenCV installation options
# ===================================================
@ -1595,6 +1596,12 @@ if(BUILD_JAVA)
status(" Java tests:" BUILD_TESTS AND opencv_test_java_BINARY_DIR THEN YES ELSE NO)
endif()
# ========================== Objective-C =======================
if(BUILD_OBJC)
status("")
status(" Objective-C wrappers:" HAVE_opencv_objc THEN YES ELSE NO)
endif()
ocv_cmake_hook(STATUS_DUMP_EXTRA)
# ========================== auxiliary ==========================

@ -30,6 +30,11 @@ if(BUILD_FAT_JAVA_LIB AND HAVE_opencv_java)
list(APPEND OPENCV_MODULES_CONFIGCMAKE opencv_java)
endif()
if(BUILD_OBJC AND HAVE_opencv_objc)
list(APPEND OPENCV_MODULES_CONFIGCMAKE opencv_objc)
endif()
# -------------------------------------------------------------------------------------------
# Part 1/3: ${BIN_DIR}/OpenCVConfig.cmake -> For use *without* "make install"
# -------------------------------------------------------------------------------------------

@ -788,6 +788,7 @@ macro(ocv_glob_module_sources)
if (APPLE)
file(GLOB_RECURSE lib_srcs_apple
"${CMAKE_CURRENT_LIST_DIR}/src/*.mm"
"${CMAKE_CURRENT_LIST_DIR}/src/*.swift"
)
list(APPEND lib_srcs ${lib_srcs_apple})
endif()

@ -7,5 +7,5 @@ if(DEBUG_opencv_calib3d)
list(APPEND debug_modules opencv_highgui)
endif()
ocv_define_module(calib3d opencv_imgproc opencv_features2d opencv_flann ${debug_modules}
WRAP java python js
WRAP java objc python js
)

@ -0,0 +1,5 @@
{
"func_arg_fix" : {
"findCirclesGrid" : { "blobDetector" : {"defval" : "cv::SimpleBlobDetector::create()"} }
}
}

@ -0,0 +1,465 @@
//
// Calib3dTest.swift
//
// Created by Giles Payne on 2020/05/26.
//
import XCTest
import OpenCV
class Calib3dTest: OpenCVTestCase {
var size = Size()
override func setUp() {
super.setUp()
size = Size(width: 3, height: 3)
}
override func tearDown() {
super.tearDown()
}
func testComposeRTMatMatMatMatMatMat() throws {
let rvec1 = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try rvec1.put(row: 0, col: 0, data: [0.5302828, 0.19925919, 0.40105945] as [Float])
let tvec1 = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try tvec1.put(row: 0, col: 0, data: [0.81438506, 0.43713298, 0.2487897] as [Float])
let rvec2 = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try rvec2.put(row: 0, col: 0, data: [0.77310503, 0.76209372, 0.30779448] as [Float])
let tvec2 = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try tvec2.put(row: 0, col: 0, data: [0.70243168, 0.4784472, 0.79219002] as [Float])
let rvec3 = Mat()
let tvec3 = Mat()
let outRvec = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try outRvec.put(row: 0, col: 0, data: [1.418641, 0.88665926, 0.56020796])
let outTvec = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
try outTvec.put(row: 0, col: 0, data: [1.4560841, 1.0680628, 0.81598103])
Calib3d.composeRT(rvec1: rvec1, tvec1: tvec1, rvec2: rvec2, tvec2: tvec2, rvec3: rvec3, tvec3: tvec3)
try assertMatEqual(outRvec, rvec3, OpenCVTestCase.EPS)
try assertMatEqual(outTvec, tvec3, OpenCVTestCase.EPS)
}
func testFilterSpecklesMatDoubleIntDouble() throws {
gray_16s_1024.copy(to: dst)
let center = Point(x: gray_16s_1024.rows() / 2, y: gray_16s_1024.cols() / 2)
Imgproc.circle(img: dst, center: center, radius: 1, color: Scalar.all(4096))
try assertMatNotEqual(gray_16s_1024, dst)
Calib3d.filterSpeckles(img: dst, newVal: 1024.0, maxSpeckleSize: 100, maxDiff: 0.0)
try assertMatEqual(gray_16s_1024, dst)
}
func testFindChessboardCornersMatSizeMat() {
let patternSize = Size(width: 9, height: 6)
let corners = MatOfPoint2f()
Calib3d.findChessboardCorners(image: grayChess, patternSize: patternSize, corners: corners)
XCTAssertFalse(corners.empty())
}
func testFindChessboardCornersMatSizeMatInt() {
let patternSize = Size(width: 9, height: 6)
let corners = MatOfPoint2f()
Calib3d.findChessboardCorners(image: grayChess, patternSize: patternSize, corners: corners, flags: Calib3d.CALIB_CB_ADAPTIVE_THRESH + Calib3d.CALIB_CB_NORMALIZE_IMAGE + Calib3d.CALIB_CB_FAST_CHECK)
XCTAssertFalse(corners.empty())
}
func testFind4QuadCornerSubpix() {
let patternSize = Size(width: 9, height: 6)
let corners = MatOfPoint2f()
let region_size = Size(width: 5, height: 5)
Calib3d.findChessboardCorners(image: grayChess, patternSize: patternSize, corners: corners)
Calib3d.find4QuadCornerSubpix(img: grayChess, corners: corners, region_size: region_size)
XCTAssertFalse(corners.empty())
}
func testFindCirclesGridMatSizeMat() {
let size = 300
let img = Mat(rows:Int32(size), cols:Int32(size), type:CvType.CV_8U)
img.setTo(scalar: Scalar(255))
let centers = Mat()
XCTAssertFalse(Calib3d.findCirclesGrid(image: img, patternSize: Size(width: 5, height: 5), centers: centers))
for i in 0..<5 {
for j in 0..<5 {
let x = Int32(size * (2 * i + 1) / 10)
let y = Int32(size * (2 * j + 1) / 10)
let pt = Point(x: x, y: y)
Imgproc.circle(img: img, center: pt, radius: 10, color: Scalar(0), thickness: -1)
}
}
XCTAssert(Calib3d.findCirclesGrid(image: img, patternSize:Size(width:5, height:5), centers:centers))
XCTAssertEqual(25, centers.rows())
XCTAssertEqual(1, centers.cols())
XCTAssertEqual(CvType.CV_32FC2, centers.type())
}
func testFindCirclesGridMatSizeMatInt() {
let size:Int32 = 300
let img = Mat(rows:size, cols: size, type: CvType.CV_8U)
img.setTo(scalar: Scalar(255))
let centers = Mat()
XCTAssertFalse(Calib3d.findCirclesGrid(image: img, patternSize: Size(width: 3, height: 5), centers: centers, flags: Calib3d.CALIB_CB_CLUSTERING | Calib3d.CALIB_CB_ASYMMETRIC_GRID))
let step = size * 2 / 15
let offsetx = size / 6
let offsety = (size - 4 * step) / 2
for i:Int32 in 0...2 {
for j:Int32 in 0...4 {
let pt = Point(x: offsetx + (2 * i + j % 2) * step, y: offsety + step * j)
Imgproc.circle(img: img, center: pt, radius: 10, color: Scalar(0), thickness: -1)
}
}
XCTAssert(Calib3d.findCirclesGrid(image: img, patternSize: Size(width: 3, height: 5), centers: centers, flags: Calib3d.CALIB_CB_CLUSTERING | Calib3d.CALIB_CB_ASYMMETRIC_GRID))
XCTAssertEqual(15, centers.rows())
XCTAssertEqual(1, centers.cols())
XCTAssertEqual(CvType.CV_32FC2, centers.type())
}
func testFindHomographyListOfPointListOfPoint() throws {
let NUM:Int32 = 20
let originalPoints = MatOfPoint2f()
originalPoints.alloc(NUM)
let transformedPoints = MatOfPoint2f()
transformedPoints.alloc(NUM)
for i:Int32 in 0..<NUM {
let x:Float = Float.random(in: -50...50)
let y:Float = Float.random(in: -50...50)
try originalPoints.put(row:i, col:0, data:[x, y])
try transformedPoints.put(row:i, col:0, data:[y, x])
}
let hmg = Calib3d.findHomography(srcPoints: originalPoints, dstPoints: transformedPoints)
truth = Mat(rows: 3, cols: 3, type: CvType.CV_64F)
try truth!.put(row:0, col:0, data:[0, 1, 0, 1, 0, 0, 0, 0, 1] as [Double])
try assertMatEqual(truth!, hmg, OpenCVTestCase.EPS)
}
func testReprojectImageTo3DMatMatMat() throws {
let transformMatrix = Mat(rows: 4, cols: 4, type: CvType.CV_64F)
try transformMatrix.put(row:0, col:0, data:[0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] as [Double])
let disparity = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_32F)
var disp = [Float].init(repeating: 0.0, count: Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize))
for i in 0..<Int(OpenCVTestCase.matSize) {
for j in 0..<Int(OpenCVTestCase.matSize) {
disp[i * Int(OpenCVTestCase.matSize) + j] = Float(i - j)
}
}
try disparity.put(row:0, col:0, data:disp)
let _3dPoints = Mat()
Calib3d.reprojectImageTo3D(disparity: disparity, _3dImage: _3dPoints, Q: transformMatrix)
XCTAssertEqual(CvType.CV_32FC3, _3dPoints.type())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.rows())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.cols())
truth = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_32FC3)
var _truth = [Float](repeating: 0.0, count: Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize * 3))
for i:Int in 0..<Int(OpenCVTestCase.matSize) {
for j:Int in 0..<Int(OpenCVTestCase.matSize) {
let start:Int = (i * Int(OpenCVTestCase.matSize) + j) * 3
_truth[start + 0] = Float(i)
_truth[start + 1] = Float(j)
_truth[start + 2] = Float(i - j)
}
}
try truth!.put(row: 0, col: 0, data: _truth)
try assertMatEqual(truth!, _3dPoints, OpenCVTestCase.EPS)
}
func testReprojectImageTo3DMatMatMatBoolean() throws {
let transformMatrix = Mat(rows: 4, cols: 4, type: CvType.CV_64F)
try transformMatrix.put(row: 0, col: 0, data: [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] as [Double])
let disparity = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_32F)
var disp = [Float](repeating: 0.0, count: Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize))
for i in 0..<Int(OpenCVTestCase.matSize) {
for j in 0..<Int(OpenCVTestCase.matSize) {
disp[i * Int(OpenCVTestCase.matSize) + j] = Float(i - j)
}
}
disp[0] = -.greatestFiniteMagnitude
try disparity.put(row: 0, col: 0, data: disp)
let _3dPoints = Mat()
Calib3d.reprojectImageTo3D(disparity: disparity, _3dImage: _3dPoints, Q: transformMatrix, handleMissingValues: true)
XCTAssertEqual(CvType.CV_32FC3, _3dPoints.type())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.rows())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.cols())
truth = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_32FC3)
var _truth = [Float](repeating: 0.0, count:Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize * 3))
for i in 0..<Int(OpenCVTestCase.matSize) {
for j in 0..<Int(OpenCVTestCase.matSize) {
_truth[(i * Int(OpenCVTestCase.matSize) + j) * 3 + 0] = Float(i)
_truth[(i * Int(OpenCVTestCase.matSize) + j) * 3 + 1] = Float(j)
_truth[(i * Int(OpenCVTestCase.matSize) + j) * 3 + 2] = Float(i - j)
}
}
_truth[2] = 10000
try truth!.put(row: 0, col: 0, data: _truth)
try assertMatEqual(truth!, _3dPoints, OpenCVTestCase.EPS)
}
func testReprojectImageTo3DMatMatMatBooleanInt() throws {
let transformMatrix = Mat(rows: 4, cols: 4, type: CvType.CV_64F)
try transformMatrix.put(row: 0, col: 0, data: [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] as [Double])
let disparity = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_32F)
var disp = [Float](repeating: 0.0, count: Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize))
for i in 0..<Int(OpenCVTestCase.matSize) {
for j in 0..<Int(OpenCVTestCase.matSize) {
disp[i * Int(OpenCVTestCase.matSize) + j] = Float(i - j)
}
}
try disparity.put(row:0, col:0, data:disp)
let _3dPoints = Mat()
Calib3d.reprojectImageTo3D(disparity: disparity, _3dImage: _3dPoints, Q: transformMatrix, handleMissingValues: false, ddepth: CvType.CV_16S)
XCTAssertEqual(CvType.CV_16SC3, _3dPoints.type())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.rows())
XCTAssertEqual(OpenCVTestCase.matSize, _3dPoints.cols())
truth = Mat(rows: OpenCVTestCase.matSize, cols: OpenCVTestCase.matSize, type: CvType.CV_16SC3)
var _truth = [Int16](repeating: 0, count: Int(OpenCVTestCase.matSize * OpenCVTestCase.matSize * 3))
for i in 0..<Int(OpenCVTestCase.matSize) {
for j in 0..<Int(OpenCVTestCase.matSize) {
let start = (i * Int(OpenCVTestCase.matSize) + j) * 3
_truth[start + 0] = Int16(i)
_truth[start + 1] = Int16(j)
_truth[start + 2] = Int16(i - j)
}
}
try truth!.put(row: 0, col: 0, data: _truth)
try assertMatEqual(truth!, _3dPoints, OpenCVTestCase.EPS)
}
func testRodriguesMatMat() throws {
let r = Mat(rows: 3, cols: 1, type: CvType.CV_32F)
let R = Mat(rows: 3, cols: 3, type: CvType.CV_32F)
try r.put(row:0, col:0, data:[.pi, 0, 0] as [Float])
Calib3d.Rodrigues(src: r, dst: R)
truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F)
try truth!.put(row:0, col:0, data:[1, 0, 0, 0, -1, 0, 0, 0, -1] as [Float])
try assertMatEqual(truth!, R, OpenCVTestCase.EPS)
let r2 = Mat()
Calib3d.Rodrigues(src: R, dst: r2)
try assertMatEqual(r, r2, OpenCVTestCase.EPS)
}
func testSolvePnPListOfPoint3ListOfPointMatMatMatMat() throws {
let intrinsics = Mat.eye(rows: 3, cols: 3, type: CvType.CV_64F)
try intrinsics.put(row: 0, col: 0, data: [400] as [Double])
try intrinsics.put(row: 1, col: 1, data: [400] as [Double])
try intrinsics.put(row: 0, col: 2, data: [640 / 2] as [Double])
try intrinsics.put(row: 1, col: 2, data: [480 / 2] as [Double])
let minPnpPointsNum: Int32 = 4
let points3d = MatOfPoint3f()
points3d.alloc(minPnpPointsNum)
let points2d = MatOfPoint2f()
points2d.alloc(minPnpPointsNum)
for i in 0..<minPnpPointsNum {
let x = Float.random(in: -50...50)
let y = Float.random(in: -50...50)
try points2d.put(row: i, col: 0, data: [x, y]) //add(Point(x, y))
try points3d.put(row: i, col: 0, data: [0, y, x]) // add(Point3(0, y, x))
}
let rvec = Mat()
let tvec = Mat()
Calib3d.solvePnP(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvec: rvec, tvec: tvec)
let truth_rvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F)
try truth_rvec.put(row: 0, col: 0, data: [0, .pi / 2, 0] as [Double])
let truth_tvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F)
try truth_tvec.put(row: 0, col: 0, data: [-320, -240, 400] as [Double])
try assertMatEqual(truth_rvec, rvec, OpenCVTestCase.EPS)
try assertMatEqual(truth_tvec, tvec, OpenCVTestCase.EPS)
}
func testComputeCorrespondEpilines() throws {
let fundamental = Mat(rows: 3, cols: 3, type: CvType.CV_64F)
try fundamental.put(row: 0, col: 0, data: [0, -0.577, 0.288, 0.577, 0, 0.288, -0.288, -0.288, 0])
let left = MatOfPoint2f()
left.alloc(1)
try left.put(row: 0, col: 0, data: [2, 3] as [Float]) //add(Point(x, y))
let lines = Mat()
let truth = Mat(rows: 1, cols: 1, type: CvType.CV_32FC3)
try truth.put(row: 0, col: 0, data: [-0.70735186, 0.70686162, -0.70588124])
Calib3d.computeCorrespondEpilines(points: left, whichImage: 1, F: fundamental, lines: lines)
try assertMatEqual(truth, lines, OpenCVTestCase.EPS)
}
func testConstants()
{
// calib3d.hpp: some constants have conflict with constants from 'fisheye' namespace
XCTAssertEqual(1, Calib3d.CALIB_USE_INTRINSIC_GUESS)
XCTAssertEqual(2, Calib3d.CALIB_FIX_ASPECT_RATIO)
XCTAssertEqual(4, Calib3d.CALIB_FIX_PRINCIPAL_POINT)
XCTAssertEqual(8, Calib3d.CALIB_ZERO_TANGENT_DIST)
XCTAssertEqual(16, Calib3d.CALIB_FIX_FOCAL_LENGTH)
XCTAssertEqual(32, Calib3d.CALIB_FIX_K1)
XCTAssertEqual(64, Calib3d.CALIB_FIX_K2)
XCTAssertEqual(128, Calib3d.CALIB_FIX_K3)
XCTAssertEqual(0x0800, Calib3d.CALIB_FIX_K4)
XCTAssertEqual(0x1000, Calib3d.CALIB_FIX_K5)
XCTAssertEqual(0x2000, Calib3d.CALIB_FIX_K6)
XCTAssertEqual(0x4000, Calib3d.CALIB_RATIONAL_MODEL)
XCTAssertEqual(0x8000, Calib3d.CALIB_THIN_PRISM_MODEL)
XCTAssertEqual(0x10000, Calib3d.CALIB_FIX_S1_S2_S3_S4)
XCTAssertEqual(0x40000, Calib3d.CALIB_TILTED_MODEL)
XCTAssertEqual(0x80000, Calib3d.CALIB_FIX_TAUX_TAUY)
XCTAssertEqual(0x100000, Calib3d.CALIB_USE_QR)
XCTAssertEqual(0x200000, Calib3d.CALIB_FIX_TANGENT_DIST)
XCTAssertEqual(0x100, Calib3d.CALIB_FIX_INTRINSIC)
XCTAssertEqual(0x200, Calib3d.CALIB_SAME_FOCAL_LENGTH)
XCTAssertEqual(0x400, Calib3d.CALIB_ZERO_DISPARITY)
XCTAssertEqual((1 << 17), Calib3d.CALIB_USE_LU)
XCTAssertEqual((1 << 22), Calib3d.CALIB_USE_EXTRINSIC_GUESS)
}
func testSolvePnPGeneric_regression_16040() throws {
let intrinsics = Mat.eye(rows: 3, cols: 3, type: CvType.CV_64F)
try intrinsics.put(row: 0, col: 0, data: [400] as [Double])
try intrinsics.put(row: 1, col: 1, data: [400] as [Double])
try intrinsics.put(row: 0, col: 2, data: [640 / 2] as [Double])
try intrinsics.put(row: 1, col: 2, data: [480 / 2] as [Double])
let minPnpPointsNum: Int32 = 4
let points3d = MatOfPoint3f()
points3d.alloc(minPnpPointsNum)
let points2d = MatOfPoint2f()
points2d.alloc(minPnpPointsNum)
for i in 0..<minPnpPointsNum {
let x = Float.random(in: -50...50)
let y = Float.random(in: -50...50)
try points2d.put(row: i, col: 0, data: [x, y]) //add(Point(x, y))
try points3d.put(row: i, col: 0, data: [0, y, x]) // add(Point3(0, y, x))
}
let rvecs = NSMutableArray()
let tvecs = NSMutableArray()
let rvec = Mat()
let tvec = Mat()
let reprojectionError = Mat(rows: 2, cols: 1, type: CvType.CV_64FC1)
Calib3d.solvePnPGeneric(objectPoints: points3d, imagePoints: points2d, cameraMatrix: intrinsics, distCoeffs: MatOfDouble(), rvecs: rvecs, tvecs: tvecs, useExtrinsicGuess: false, flags: .SOLVEPNP_IPPE, rvec: rvec, tvec: tvec, reprojectionError: reprojectionError)
let truth_rvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F)
try truth_rvec.put(row: 0, col: 0, data: [0, .pi / 2, 0] as [Double])
let truth_tvec = Mat(rows: 3, cols: 1, type: CvType.CV_64F)
try truth_tvec.put(row: 0, col: 0, data: [-320, -240, 400] as [Double])
try assertMatEqual(truth_rvec, rvecs[0] as! Mat, 10 * OpenCVTestCase.EPS)
try assertMatEqual(truth_tvec, tvecs[0] as! Mat, 1000 * OpenCVTestCase.EPS)
}
func testGetDefaultNewCameraMatrixMat() {
let mtx = Calib3d.getDefaultNewCameraMatrix(cameraMatrix: gray0)
XCTAssertFalse(mtx.empty())
XCTAssertEqual(0, Core.countNonZero(src: mtx))
}
func testGetDefaultNewCameraMatrixMatSizeBoolean() {
let mtx = Calib3d.getDefaultNewCameraMatrix(cameraMatrix: gray0, imgsize: size, centerPrincipalPoint: true)
XCTAssertFalse(mtx.empty())
XCTAssertFalse(0 == Core.countNonZero(src: mtx))
// TODO_: write better test
}
func testUndistortMatMatMatMat() throws {
let src = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(3))
let cameraMatrix = Mat(rows: 3, cols: 3, type: CvType.CV_32F)
try cameraMatrix.put(row: 0, col: 0, data: [1, 0, 1] as [Float])
try cameraMatrix.put(row: 1, col: 0, data: [0, 1, 2] as [Float])
try cameraMatrix.put(row: 2, col: 0, data: [0, 0, 1] as [Float])
let distCoeffs = Mat(rows: 1, cols: 4, type: CvType.CV_32F)
try distCoeffs.put(row: 0, col: 0, data: [1, 3, 2, 4] as [Float])
Calib3d.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs)
truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F)
try truth!.put(row: 0, col: 0, data: [0, 0, 0] as [Float])
try truth!.put(row: 1, col: 0, data: [0, 0, 0] as [Float])
try truth!.put(row: 2, col: 0, data: [0, 3, 0] as [Float])
try assertMatEqual(truth!, dst, OpenCVTestCase.EPS)
}
func testUndistortMatMatMatMatMat() throws {
let src = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(3))
let cameraMatrix = Mat(rows: 3, cols: 3, type: CvType.CV_32F)
try cameraMatrix.put(row: 0, col: 0, data: [1, 0, 1] as [Float])
try cameraMatrix.put(row: 1, col: 0, data: [0, 1, 2] as [Float])
try cameraMatrix.put(row: 2, col: 0, data: [0, 0, 1] as [Float])
let distCoeffs = Mat(rows: 1, cols: 4, type: CvType.CV_32F)
try distCoeffs.put(row: 0, col: 0, data: [2, 1, 4, 5] as [Float])
let newCameraMatrix = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(1))
Calib3d.undistort(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs, newCameraMatrix: newCameraMatrix)
truth = Mat(rows: 3, cols: 3, type: CvType.CV_32F, scalar: Scalar(3))
try assertMatEqual(truth!, dst, OpenCVTestCase.EPS)
}
//undistortPoints(List<Point> src, List<Point> dst, Mat cameraMatrix, Mat distCoeffs)
func testUndistortPointsListOfPointListOfPointMatMat() {
let src = MatOfPoint2f(array: [Point2f(x: 1, y: 2), Point2f(x: 3, y: 4), Point2f(x: -1, y: -1)])
let dst = MatOfPoint2f()
let cameraMatrix = Mat.eye(rows: 3, cols: 3, type: CvType.CV_64FC1)
let distCoeffs = Mat(rows: 8, cols: 1, type: CvType.CV_64FC1, scalar: Scalar(0))
Calib3d.undistortPoints(src: src, dst: dst, cameraMatrix: cameraMatrix, distCoeffs: distCoeffs)
XCTAssertEqual(src.toArray(), dst.toArray())
}
}

@ -19,7 +19,7 @@ ocv_add_dispatched_file_force_all(test_intrin512 TEST AVX512_SKX)
ocv_add_module(core
OPTIONAL opencv_cudev
WRAP java python js)
WRAP java objc python js)
set(extra_libs "")

@ -0,0 +1,16 @@
//
// ArrayUtil.h
//
// Created by Giles Payne on 2020/02/09.
//
#pragma once
#import <Foundation/Foundation.h>
/**
* Utility function to create and populate an NSMutableArray with a specific size
* @param size Size of array to create
* @param val Value with which to initialize array elements
*/
NSMutableArray* createArrayWithSize(int size, NSObject* val);

@ -0,0 +1,15 @@
//
// ArrayUtil.mm
//
// Created by Giles Payne on 2020/02/09.
//
#import "ArrayUtil.h"
NSMutableArray* createArrayWithSize(int size, NSObject* val) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
for (int i = 0; i < size; i++){
[array addObject:val];
}
return array;
}

@ -0,0 +1,88 @@
//
// ByteVector.h
//
// Created by Giles Payne on 2020/01/04.
//
#pragma once
#import <Foundation/Foundation.h>
#ifdef __cplusplus
#import <vector>
#endif
NS_ASSUME_NONNULL_BEGIN
/**
* Utility class to wrap a `std::vector<char>`
*/
@interface ByteVector : NSObject
#pragma mark - Constructors
/**
* Create ByteVector and initialize with the contents of an NSData object
* @param data NSData containing raw byte array
*/
-(instancetype)initWithData:(NSData*)data;
/**
* Create ByteVector and initialize with the contents of another ByteVector object
* @param src ByteVector containing data to copy
*/
-(instancetype)initWithVector:(ByteVector*)src;
#ifdef __OBJC__
/**
* Create ByteVector from raw C array
* @param array The raw C array
* @elements elements The number of elements in the array
*/
-(instancetype)initWithNativeArray:(char*)array elements:(NSInteger)elements;
#endif
#ifdef __cplusplus
/**
* Create ByteVector from std::vector<char>
* @param src The std::vector<char> object to wrap
*/
-(instancetype)initWithStdVector:(std::vector<char>&)src;
+(instancetype)fromNative:(std::vector<char>&)src;
#endif
#pragma mark - Properties
/**
* Length of the vector
*/
@property(readonly) NSInteger length;
#ifdef __OBJC__
/**
* Raw C array
*/
@property(readonly) char* nativeArray;
#endif
#ifdef __cplusplus
/**
* The wrapped std::vector<char> object
*/
@property(readonly) std::vector<char>& nativeRef;
#endif
/**
* NSData object containing the raw byte data
*/
@property(readonly) NSData* data;
#pragma mark - Accessor method
/**
* Return array element
* @param index Index of the array element to return
*/
-(char)get:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,76 @@
//
// ByteVector.m
//
// Created by Giles Payne on 2020/01/04.
//
#import "ByteVector.h"
#import <vector>
@implementation ByteVector {
std::vector<char> v;
}
-(instancetype)initWithData:(NSData*)data {
self = [super init];
if (self) {
if (data.length % sizeof(char) != 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Invalid data length" userInfo:nil];
}
v.insert(v.begin(), (char*)data.bytes, (char*)data.bytes + data.length/sizeof(char));
}
return self;
}
-(instancetype)initWithVector:(ByteVector*)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.nativeRef.begin(), src.nativeRef.end());
}
return self;
}
-(NSInteger)length {
return v.size();
}
-(char*)nativeArray {
return (char*)v.data();
}
-(instancetype)initWithNativeArray:(char*)array elements:(NSInteger)elements {
self = [super init];
if (self) {
v.insert(v.begin(), array, array + elements);
}
return self;
}
- (std::vector<char>&)nativeRef {
return v;
}
-(instancetype)initWithStdVector:(std::vector<char>&)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.begin(), src.end());
}
return self;
}
+(instancetype)fromNative:(std::vector<char>&)src {
return [[ByteVector alloc] initWithStdVector:src];
}
-(char)get:(NSInteger)index {
if (index < 0 || index >= (long)v.size()) {
@throw [NSException exceptionWithName:NSRangeException reason:@"Invalid data length" userInfo:nil];
}
return v[index];
}
-(NSData*)data {
return [NSData dataWithBytesNoCopy:v.data() length:(v.size() * sizeof(char)) freeWhenDone:NO];
}
@end

@ -0,0 +1,53 @@
//
// ByteVectorExt.swift
//
// Created by Giles Payne on 2020/01/04.
//
import Foundation
public extension ByteVector {
convenience init(_ array:[Int8]) {
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(data:data);
}
subscript(index: Int) -> Int8 {
get {
return self.get(index)
}
}
var array: [Int8] {
get {
var ret = Array<Int8>(repeating: 0, count: data.count/MemoryLayout<Int8>.stride)
_ = ret.withUnsafeMutableBytes { data.copyBytes(to: $0) }
return ret
}
}
}
extension ByteVector : Sequence {
public typealias Iterator = ByteVectorIterator
public func makeIterator() -> ByteVectorIterator {
return ByteVectorIterator(self)
}
}
public struct ByteVectorIterator: IteratorProtocol {
public typealias Element = Int8
let byteVector: ByteVector
var pos = 0
init(_ byteVector: ByteVector) {
self.byteVector = byteVector
}
mutating public func next() -> Int8? {
guard pos >= 0 && pos < byteVector.length
else { return nil }
pos += 1
return byteVector.get(pos - 1)
}
}

@ -0,0 +1,85 @@
//
// CVObjcUtil.h
//
// Created by Giles Payne on 2020/01/02.
//
#pragma once
typedef union { double d; int64_t l; } V64;
typedef union { float f; int32_t i; } V32;
#define DOUBLE_TO_BITS(x) ((V64){ .d = x }).l
#define FLOAT_TO_BITS(x) ((V32){ .f = x }).i
#ifdef __cplusplus
#import <vector>
#define MAKE_PTR(t) (*((cv::Ptr<t>*)self.nativePtr))
template <typename CV, typename OBJC> std::vector<CV> objc2cv(NSArray<OBJC*>* _Nonnull array, CV& (* _Nonnull converter)(OBJC* _Nonnull)) {
std::vector<CV> ret;
for (OBJC* obj in array) {
ret.push_back(converter(obj));
}
return ret;
}
#define OBJC2CV(CV_CLASS, OBJC_CLASS, v, a) \
std::vector<CV_CLASS> v = objc2cv<CV_CLASS, OBJC_CLASS>(a, [](OBJC_CLASS* objc) -> CV_CLASS& { return objc.nativeRef; })
#define OBJC2CV_CUSTOM(CV_CLASS, OBJC_CLASS, v, a, CONV) \
std::vector<CV_CLASS> v; \
for (OBJC_CLASS* obj in a) { \
CV_CLASS tmp = CONV(obj); \
v.push_back(tmp); \
}
template <typename CV, typename OBJC> void cv2objc(std::vector<CV>& vector, NSMutableArray<OBJC*>* _Nonnull array, OBJC* _Nonnull (* _Nonnull converter)(CV&)) {
[array removeAllObjects];
for (size_t index = 0; index < vector.size(); index++) {
[array addObject:converter(vector[index])];
}
}
#define CV2OBJC(CV_CLASS, OBJC_CLASS, v, a) \
cv2objc<CV_CLASS, OBJC_CLASS>(v, a, [](CV_CLASS& cv) -> OBJC_CLASS* { return [OBJC_CLASS fromNative:cv]; })
#define CV2OBJC_CUSTOM(CV_CLASS, OBJC_CLASS, v, a, UNCONV) \
[a removeAllObjects]; \
for (size_t index = 0; index < v.size(); index++) { \
OBJC_CLASS *tmp = UNCONV(v[index]); \
[a addObject:tmp]; \
}
template <typename CV, typename OBJC> std::vector<std::vector<CV>> objc2cv2(NSArray<NSArray<OBJC*>*>* _Nonnull array, CV& (* _Nonnull converter)(OBJC* _Nonnull)) {
std::vector<std::vector<CV>> ret;
for (NSArray<OBJC*>* innerArray in array) {
std::vector<CV> innerVector;
for (OBJC* obj in innerArray) {
innerVector.push_back(converter(obj));
}
ret.push_back(innerVector);
}
return ret;
}
#define OBJC2CV2(CV_CLASS, OBJC_CLASS, v, a) \
std::vector<std::vector<CV_CLASS>> v = objc2cv2<CV_CLASS, OBJC_CLASS>(a, [](OBJC_CLASS* objc) -> CV_CLASS& { return objc.nativeRef; })
template <typename CV, typename OBJC> void cv2objc2(std::vector<std::vector<CV>>& vector, NSMutableArray<NSMutableArray<OBJC*>*>* _Nonnull array, OBJC* _Nonnull (* _Nonnull converter)(CV&)) {
[array removeAllObjects];
for (size_t index = 0; index < vector.size(); index++) {
std::vector<CV>& innerVector = vector[index];
NSMutableArray<OBJC*>* innerArray = [NSMutableArray arrayWithCapacity:innerVector.size()];
for (size_t index2 = 0; index2 < innerVector.size(); index2++) {
[innerArray addObject:converter(innerVector[index2])];
}
[array addObject:innerArray];
}
}
#define CV2OBJC2(CV_CLASS, OBJC_CLASS, v, a) \
cv2objc2<CV_CLASS, OBJC_CLASS>(v, a, [](CV_CLASS& cv) -> OBJC_CLASS* { return [OBJC_CLASS fromNative:cv]; })
#endif

@ -0,0 +1,98 @@
//
// Converters.h
//
// Created by Giles Payne on 2020/03/03.
//
#pragma once
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif
#import <Foundation/Foundation.h>
#import "Mat.h"
#import "CvType.h"
#import "Point2i.h"
#import "Point2f.h"
#import "Point2d.h"
#import "Point3i.h"
#import "Point3f.h"
#import "Point3d.h"
#import "Rect2i.h"
#import "Rect2d.h"
#import "KeyPoint.h"
#import "DMatch.h"
#import "RotatedRect.h"
NS_ASSUME_NONNULL_BEGIN
@interface Converters : NSObject
+ (Mat*)vector_Point_to_Mat:(NSArray<Point2i*>*)pts NS_SWIFT_NAME(vector_Point_to_Mat(_:));
+ (NSArray<Point2i*>*)Mat_to_vector_Point:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point(_:));
+ (Mat*)vector_Point2f_to_Mat:(NSArray<Point2f*>*)pts NS_SWIFT_NAME(vector_Point2f_to_Mat(_:));
+ (NSArray<Point2f*>*)Mat_to_vector_Point2f:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point2f(_:));
+ (Mat*)vector_Point2d_to_Mat:(NSArray<Point2d*>*)pts NS_SWIFT_NAME(vector_Point2d_to_Mat(_:));
+ (NSArray<Point2f*>*)Mat_to_vector_Point2d:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point2d(_:));
+ (Mat*)vector_Point3i_to_Mat:(NSArray<Point3i*>*)pts NS_SWIFT_NAME(vector_Point3i_to_Mat(_:));
+ (NSArray<Point3i*>*)Mat_to_vector_Point3i:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point3i(_:));
+ (Mat*)vector_Point3f_to_Mat:(NSArray<Point3f*>*)pts NS_SWIFT_NAME(vector_Point3f_to_Mat(_:));
+ (NSArray<Point3f*>*)Mat_to_vector_Point3f:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point3f(_:));
+ (Mat*)vector_Point3d_to_Mat:(NSArray<Point3d*>*)pts NS_SWIFT_NAME(vector_Point3d_to_Mat(_:));
+ (NSArray<Point3d*>*)Mat_to_vector_Point3d:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Point3d(_:));
+ (Mat*)vector_float_to_Mat:(NSArray<NSNumber*>*)fs NS_SWIFT_NAME(vector_float_to_Mat(_:));
+ (NSArray<NSNumber*>*)Mat_to_vector_float:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_float(_:));
+ (Mat*)vector_uchar_to_Mat:(NSArray<NSNumber*>*)us NS_SWIFT_NAME(vector_uchar_to_Mat(_:));
+ (NSArray<NSNumber*>*)Mat_to_vector_uchar:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_uchar(_:));
+ (Mat*)vector_char_to_Mat:(NSArray<NSNumber*>*)cs NS_SWIFT_NAME(vector_char_to_Mat(_:));
+ (NSArray<NSNumber*>*)Mat_to_vector_char:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_char(_:));
+ (Mat*)vector_int_to_Mat:(NSArray<NSNumber*>*)is NS_SWIFT_NAME(vector_int_to_Mat(_:));
+ (NSArray<NSNumber*>*)Mat_to_vector_int:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_int(_:));
+ (Mat*)vector_Rect_to_Mat:(NSArray<Rect2i*>*)rs NS_SWIFT_NAME(vector_Rect_to_Mat(_:));
+ (NSArray<Rect2i*>*)Mat_to_vector_Rect:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Rect(_:));
+ (Mat*)vector_Rect2d_to_Mat:(NSArray<Rect2d*>*)rs NS_SWIFT_NAME(vector_Rect2d_to_Mat(_:));
+ (NSArray<Rect2d*>*)Mat_to_vector_Rect2d:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_Rect2d(_:));
+ (Mat*)vector_KeyPoint_to_Mat:(NSArray<KeyPoint*>*)kps NS_SWIFT_NAME(vector_KeyPoint_to_Mat(_:));
+ (NSArray<KeyPoint*>*)Mat_to_vector_KeyPoint:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_KeyPoint(_:));
+ (Mat*)vector_double_to_Mat:(NSArray<NSNumber*>*)ds NS_SWIFT_NAME(vector_double_to_Mat(_:));
+ (NSArray<NSNumber*>*)Mat_to_vector_double:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_double(_:));
+ (Mat*)vector_DMatch_to_Mat:(NSArray<DMatch*>*)matches NS_SWIFT_NAME(vector_DMatch_to_Mat(_:));
+ (NSArray<DMatch*>*)Mat_to_vector_DMatch:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_DMatch(_:));
+ (Mat*)vector_RotatedRect_to_Mat:(NSArray<RotatedRect*>*)rs NS_SWIFT_NAME(vector_RotatedRect_to_Mat(_:));
+ (NSArray<RotatedRect*>*)Mat_to_vector_RotatedRect:(Mat*)mat NS_SWIFT_NAME(Mat_to_vector_RotatedRect(_:));
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,205 @@
//
// Converters.mm
//
// Created by Giles Payne on 31/05/2020.
//
#import "Converters.h"
#import "ArrayUtil.h"
#import "MatOfPoint2i.h"
#import "MatOfPoint2f.h"
#import "MatOfPoint3.h"
#import "MatOfPoint3f.h"
#import "MatOfFloat.h"
#import "MatOfByte.h"
#import "MatOfInt.h"
#import "MatOfDouble.h"
#import "MatOfRect2i.h"
#import "MatOfRect2d.h"
#import "MatOfKeyPoint.h"
#import "MatOfDMatch.h"
#import "MatOfRotatedRect.h"
@implementation Converters
+ (Mat*)vector_Point_to_Mat:(NSArray<Point2i*>*)pts {
return [[MatOfPoint2i alloc] initWithArray:pts];
}
+ (NSArray<Point2i*>*)Mat_to_vector_Point:(Mat*)mat {
return [[[MatOfPoint2i alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Point2f_to_Mat:(NSArray<Point2f*>*)pts {
return [[MatOfPoint2f alloc] initWithArray:pts];
}
+ (NSArray<Point2f*>*)Mat_to_vector_Point2f:(Mat*)mat {
return [[[MatOfPoint2f alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Point2d_to_Mat:(NSArray<Point2d*>*)pts {
Mat* res = [[Mat alloc] initWithRows:(int)pts.count cols:1 type:CV_64FC2];
NSMutableArray<NSNumber*>* buff = [NSMutableArray arrayWithCapacity:pts.count*2];
for (Point2d* pt in pts) {
[buff addObject:[NSNumber numberWithDouble:pt.x]];
[buff addObject:[NSNumber numberWithDouble:pt.y]];
}
[res put:0 col:0 data:buff];
return res;
}
+ (NSArray<Point2d*>*)Mat_to_vector_Point2d:(Mat*)mat {
if (mat.cols != 1 || mat.type != CV_64FC2) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid Mat. Mat must be of type CV_64FC2 and have 1 column."]
userInfo:nil];
@throw exception;
}
NSMutableArray<Point2d*>* ret = [NSMutableArray new];
NSMutableArray<NSNumber*>* buff = createArrayWithSize(mat.rows*2, [NSNumber numberWithInt:0]);
[mat get:0 col:0 data:buff];
for (int i = 0; i < mat.rows; i++) {
[ret addObject:[[Point2d alloc] initWithX:buff[i * 2].doubleValue y:buff[i * 2 + 1].doubleValue]];
}
return ret;
}
+ (Mat*)vector_Point3i_to_Mat:(NSArray<Point3i*>*)pts {
return [[MatOfPoint3 alloc] initWithArray:pts];
}
+ (NSArray<Point3i*>*)Mat_to_vector_Point3i:(Mat*)mat {
return [[[MatOfPoint3 alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Point3f_to_Mat:(NSArray<Point3f*>*)pts {
return [[MatOfPoint3f alloc] initWithArray:pts];
}
+ (NSArray<Point3f*>*)Mat_to_vector_Point3f:(Mat*)mat {
return [[[MatOfPoint3f alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Point3d_to_Mat:(NSArray<Point3d*>*)pts {
Mat* res = [[Mat alloc] initWithRows:(int)pts.count cols:1 type:CV_64FC3];
NSMutableArray<NSNumber*>* buff = [NSMutableArray arrayWithCapacity:pts.count*3];
for (Point3d* pt in pts) {
[buff addObject:[NSNumber numberWithDouble:pt.x]];
[buff addObject:[NSNumber numberWithDouble:pt.y]];
[buff addObject:[NSNumber numberWithDouble:pt.z]];
}
[res put:0 col:0 data:buff];
return res;
}
+ (NSArray<Point3d*>*)Mat_to_vector_Point3d:(Mat*)mat {
if (mat.cols != 1 || mat.type != CV_64FC3) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid Mat. Mat must be of type CV_64FC3 and have 1 column."]
userInfo:nil];
@throw exception;
}
NSMutableArray<Point3d*>* ret = [NSMutableArray new];
NSMutableArray<NSNumber*>* buff = createArrayWithSize(mat.rows*3, [NSNumber numberWithInt:0]);
[mat get:0 col:0 data:buff];
for (int i = 0; i < mat.rows; i++) {
[ret addObject:[[Point3d alloc] initWithX:buff[i * 3].doubleValue y:buff[i * 3 + 1].doubleValue z:buff[i * 3 + 2].doubleValue]];
}
return ret;
}
+ (Mat*)vector_float_to_Mat:(NSArray<NSNumber*>*)fs {
return [[MatOfFloat alloc] initWithArray:fs];
}
+ (NSArray<NSNumber*>*)Mat_to_vector_float:(Mat*)mat {
return [[[MatOfFloat alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_uchar_to_Mat:(NSArray<NSNumber*>*)us {
return [[MatOfByte alloc] initWithArray:us];
}
+ (NSArray<NSNumber*>*)Mat_to_vector_uchar:(Mat*)mat {
return [[[MatOfByte alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_char_to_Mat:(NSArray<NSNumber*>*)cs {
Mat* res = [[Mat alloc] initWithRows:(int)cs.count cols:1 type:CV_8S];
[res put:0 col:0 data:cs];
return res;
}
+ (NSArray<NSNumber*>*)Mat_to_vector_char:(Mat*)mat {
if (mat.cols != 1 || mat.type != CV_8S) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid Mat. Mat must be of type CV_8S and have 1 column."]
userInfo:nil];
@throw exception;
}
NSMutableArray<NSNumber*>* ret = createArrayWithSize(mat.rows, @0);
[mat get:0 col:0 data:ret];
return ret;
}
+ (Mat*)vector_int_to_Mat:(NSArray<NSNumber*>*)is {
return [[MatOfInt alloc] initWithArray:is];
}
+ (NSArray<NSNumber*>*)Mat_to_vector_int:(Mat*)mat {
return [[[MatOfInt alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Rect_to_Mat:(NSArray<Rect2i*>*)rs {
return [[MatOfRect2i alloc] initWithArray:rs];
}
+ (NSArray<Rect2i*>*)Mat_to_vector_Rect:(Mat*)mat {
return [[[MatOfRect2i alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_Rect2d_to_Mat:(NSArray<Rect2d*>*)rs {
return [[MatOfRect2d alloc] initWithArray:rs];
}
+ (NSArray<Rect2d*>*)Mat_to_vector_Rect2d:(Mat*)mat {
return [[[MatOfRect2d alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_KeyPoint_to_Mat:(NSArray<KeyPoint*>*)kps {
return [[MatOfKeyPoint alloc] initWithArray:kps];
}
+ (NSArray<KeyPoint*>*)Mat_to_vector_KeyPoint:(Mat*)mat {
return [[[MatOfKeyPoint alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_double_to_Mat:(NSArray<NSNumber*>*)ds {
return [[MatOfDouble alloc] initWithArray:ds];
}
+ (NSArray<NSNumber*>*)Mat_to_vector_double:(Mat*)mat {
return [[[MatOfDouble alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_DMatch_to_Mat:(NSArray<DMatch*>*)matches {
return [[MatOfDMatch alloc] initWithArray:matches];
}
+ (NSArray<DMatch*>*)Mat_to_vector_DMatch:(Mat*)mat {
return [[[MatOfDMatch alloc] initWithMat:mat] toArray];
}
+ (Mat*)vector_RotatedRect_to_Mat:(NSArray<RotatedRect*>*)rs {
return [[MatOfRotatedRect alloc] initWithArray:rs];
}
+ (NSArray<RotatedRect*>*)Mat_to_vector_RotatedRect:(Mat*)mat {
return [[[MatOfRotatedRect alloc] initWithMat:mat] toArray];
}
@end

@ -0,0 +1,67 @@
//
// CvType.h
//
// Created by Giles Payne on 2019/10/13.
//
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Utility functions for handling CvType values
*/
@interface CvType : NSObject
#pragma mark - Type Utility functions
/**
* Create CvType value from depth and channel values
* @param depth Depth value. One of CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F or CV_64F
* @param channels Number of channels (from 1 to (CV_CN_MAX - 1))
*/
+ (int)makeType:(int)depth channels:(int)channels;
/**
* Get number of channels for type
* @param type Type value
*/
+ (int)channels:(int)type;
/**
* Get depth for type
* @param type Type value
*/
+ (int)depth:(int)type;
/**
* Get raw type size in bytes for type
* @param type Type value
*/
+ (int)rawTypeSize:(int)type;
/**
* Returns true if the raw type is an integer type (if depth is CV_8U, CV_8S, CV_16U, CV_16S or CV_32S)
* @param type Type value
*/
+ (BOOL)isInteger:(int)type;
/**
* Get element size in bytes for type
* @param type Type value
*/
+ (int)ELEM_SIZE:(int)type NS_SWIFT_NAME(elemSize(_:));
/**
* Get the string name for type
* @param type Type value
*/
+ (NSString*)typeToString:(int)type;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,105 @@
//
// CvType.m
//
// Created by Giles Payne on 2019/10/13.
//
#import "CvType.h"
@implementation CvType
+ (int)makeType:(int)depth channels:(int)channels {
if (channels <= 0 || channels >= CV_CN_MAX) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Channels count should be 1..%d", CV_CN_MAX - 1]
userInfo:nil];
@throw exception;
}
if (depth < 0 || depth >= CV_DEPTH_MAX) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Data type depth should be 0..%d", CV_DEPTH_MAX - 1]
userInfo:nil];
@throw exception;
}
return (depth & (CV_DEPTH_MAX - 1)) + ((channels - 1) << CV_CN_SHIFT);
}
+ (int)channels:(int)type {
return (type >> CV_CN_SHIFT) + 1;
}
+ (int)depth:(int)type {
return type & (CV_DEPTH_MAX - 1);
}
+ (BOOL)isInteger:(int)type {
return [CvType depth:type] < CV_32F;
}
+ (int)typeSizeBits:(int)type {
int depth = [CvType depth:type];
switch (depth) {
case CV_8U:
case CV_8S:
return 8;
case CV_16U:
case CV_16S:
case CV_16F:
return 16;
case CV_32S:
case CV_32F:
return 32;
case CV_64F:
return 64;
default:
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Unsupported CvType value: %d", type]
userInfo:nil];
@throw exception;
}
}
+ (int)rawTypeSize:(int)type {
return [CvType typeSizeBits:type] >> 3;
}
+ (char)typeMnenomic:(int)type {
int depth = [CvType depth:type];
switch (depth) {
case CV_8U:
case CV_16U:
return 'U';
case CV_8S:
case CV_16S:
case CV_32S:
return 'S';
case CV_16F:
case CV_32F:
case CV_64F:
return 'F';
default:
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Unsupported CvType value: %d", type]
userInfo:nil];
@throw exception;
}
}
+ (int)ELEM_SIZE:(int)type {
int typeSizeBytes = [CvType rawTypeSize:type];
return typeSizeBytes * [CvType channels:type];
}
+ (NSString*)typeToString:(int)type {
int typeSizeBits = [CvType typeSizeBits:type];
char typeMnenomic = [CvType typeMnenomic:type];
int channels = [CvType channels:type];
NSString* channelsSuffix = [NSString stringWithFormat:(channels <= 4)?@"%d":@"(%d)", channels];
return [NSString stringWithFormat:@"CV_%d%cC%@", typeSizeBits, typeMnenomic, channelsSuffix];
}
@end

@ -0,0 +1,90 @@
//
// CvTypeExt.swift
//
// Created by Giles Payne on 2020/01/19.
//
import Foundation
public extension CvType {
static let CV_8U: Int32 = 0
static let CV_8S: Int32 = 1
static let CV_16U: Int32 = 2
static let CV_16S: Int32 = 3
static let CV_32S: Int32 = 4
static let CV_32F: Int32 = 5
static let CV_64F: Int32 = 6
static let CV_16F: Int32 = 7
static let CV_8UC1: Int32 = CV_8UC(1)
static let CV_8UC2: Int32 = CV_8UC(2)
static let CV_8UC3: Int32 = CV_8UC(3)
static let CV_8UC4: Int32 = CV_8UC(4)
static let CV_8SC1: Int32 = CV_8SC(1)
static let CV_8SC2: Int32 = CV_8SC(2)
static let CV_8SC3: Int32 = CV_8SC(3)
static let CV_8SC4: Int32 = CV_8SC(4)
static let CV_16UC1: Int32 = CV_16UC(1)
static let CV_16UC2: Int32 = CV_16UC(2)
static let CV_16UC3: Int32 = CV_16UC(3)
static let CV_16UC4: Int32 = CV_16UC(4)
static let CV_16SC1: Int32 = CV_16SC(1)
static let CV_16SC2: Int32 = CV_16SC(2)
static let CV_16SC3: Int32 = CV_16SC(3)
static let CV_16SC4: Int32 = CV_16SC(4)
static let CV_32SC1: Int32 = CV_32SC(1)
static let CV_32SC2: Int32 = CV_32SC(2)
static let CV_32SC3: Int32 = CV_32SC(3)
static let CV_32SC4: Int32 = CV_32SC(4)
static let CV_32FC1: Int32 = CV_32FC(1)
static let CV_32FC2: Int32 = CV_32FC(2)
static let CV_32FC3: Int32 = CV_32FC(3)
static let CV_32FC4: Int32 = CV_32FC(4)
static let CV_64FC1: Int32 = CV_64FC(1)
static let CV_64FC2: Int32 = CV_64FC(2)
static let CV_64FC3: Int32 = CV_64FC(3)
static let CV_64FC4: Int32 = CV_64FC(4)
static let CV_16FC1: Int32 = CV_16FC(1)
static let CV_16FC2: Int32 = CV_16FC(2)
static let CV_16FC3: Int32 = CV_16FC(3)
static let CV_16FC4: Int32 = CV_16FC(4)
static let CV_CN_MAX = 512
static let CV_CN_SHIFT = 3
static let CV_DEPTH_MAX = 1 << CV_CN_SHIFT
static func CV_8UC(_ channels:Int32) -> Int32 {
return make(CV_8U, channels: channels)
}
static func CV_8SC(_ channels:Int32) -> Int32 {
return make(CV_8S, channels: channels)
}
static func CV_16UC(_ channels:Int32) -> Int32 {
return make(CV_16U, channels: channels)
}
static func CV_16SC(_ channels:Int32) -> Int32 {
return make(CV_16S, channels: channels)
}
static func CV_32SC(_ channels:Int32) -> Int32 {
return make(CV_32S, channels: channels)
}
static func CV_32FC(_ channels:Int32) -> Int32 {
return make(CV_32F, channels: channels)
}
static func CV_64FC(_ channels:Int32) -> Int32 {
return make(CV_64F, channels: channels)
}
static func CV_16FC(_ channels:Int32) -> Int32 {
return make(CV_16F, channels: channels)
}
}

@ -0,0 +1,82 @@
//
// DMatch.h
//
// Created by Giles Payne on 2019/12/25.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Structure for matching: query descriptor index, train descriptor index, train
* image index and distance between descriptors.
*/
@interface DMatch : NSObject
/**
* Query descriptor index.
*/
@property int queryIdx;
/**
* Train descriptor index.
*/
@property int trainIdx;
/**
* Train image index.
*/
@property int imgIdx;
/**
* Distance
*/
@property float distance;
#ifdef __cplusplus
@property(readonly) cv::DMatch& nativeRef;
#endif
- (instancetype)init;
- (instancetype)initWithQueryIdx:(int)queryIdx trainIdx:(int)trainIdx distance:(float)distance;
- (instancetype)initWithQueryIdx:(int)queryIdx trainIdx:(int)trainIdx imgIdx:(int)imgIdx distance:(float)distance;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::DMatch&)dMatch;
#endif
/**
* Distance comparison
* @param it DMatch object to compare
*/
- (BOOL)lessThan:(DMatch*)it;
/**
* Clone object
*/
- (DMatch*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,107 @@
//
// DMatch.m
//
// Created by Giles Payne on 2019/12/25.
//
#import "DMatch.h"
#import "CVObjcUtil.h"
@implementation DMatch {
cv::DMatch native;
}
- (int)queryIdx {
return native.queryIdx;
}
- (void)setQueryIdx:(int)queryIdx {
native.queryIdx = queryIdx;
}
- (int)trainIdx {
return native.trainIdx;
}
- (void)setTrainIdx:(int)trainIdx {
native.trainIdx = trainIdx;
}
- (int)imgIdx {
return native.imgIdx;
}
- (void)setImgIdx:(int)imgIdx {
native.imgIdx = imgIdx;
}
- (float)distance {
return native.distance;
}
- (void)setDistance:(float)distance {
native.distance = distance;
}
- (cv::DMatch&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithQueryIdx:-1 trainIdx:-1 distance:FLT_MAX];
}
- (instancetype)initWithQueryIdx:(int)queryIdx trainIdx:(int)trainIdx distance:(float)distance {
return [self initWithQueryIdx:queryIdx trainIdx:trainIdx imgIdx:-1 distance:distance];
}
- (instancetype)initWithQueryIdx:(int)queryIdx trainIdx:(int)trainIdx imgIdx:(int)imgIdx distance:(float)distance {
self = [super init];
if (self != nil) {
self.queryIdx = queryIdx;
self.trainIdx = trainIdx;
self.imgIdx = imgIdx;
self.distance = distance;
}
return self;
}
+ (instancetype)fromNative:(cv::DMatch&)dMatch {
return [[DMatch alloc] initWithQueryIdx:dMatch.queryIdx trainIdx:dMatch.trainIdx imgIdx:dMatch.imgIdx distance:dMatch.distance];
}
- (BOOL)lessThan:(DMatch*)it {
return self.distance < it.distance;
}
- (DMatch*)clone {
return [[DMatch alloc] initWithQueryIdx:self.queryIdx trainIdx:self.trainIdx imgIdx:self.imgIdx distance:self.distance];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[DMatch class]]) {
return NO;
} else {
DMatch* dMatch = (DMatch*)other;
return self.queryIdx == dMatch.queryIdx && self.trainIdx == dMatch.trainIdx && self.imgIdx == dMatch.imgIdx && self.distance == dMatch.distance;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.queryIdx;
result = prime * result + self.trainIdx;
result = prime * result + self.imgIdx;
result = prime * result + FLOAT_TO_BITS(self.distance);
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"DMatch { queryIdx: %d, trainIdx: %d, imgIdx: %d, distance: %f}", self.queryIdx, self.trainIdx, self.imgIdx, self.distance];
}
@end

@ -0,0 +1,93 @@
//
// Double2.h
//
// Created by Giles Payne on 2020/05/22.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Mat;
NS_ASSUME_NONNULL_BEGIN
/**
* Simple wrapper for a vector of two `double`
*/
@interface Double2 : NSObject
#pragma mark - Properties
/**
* First vector element
*/
@property double v0;
/**
* Second vector element
*/
@property double v1;
/**
* Third vector element
*/
@property double v2;
#ifdef __cplusplus
/**
* The wrapped vector
*/
@property(readonly) cv::Vec2d& nativeRef;
#endif
#pragma mark - Constructors
/**
* Create zero-initialize vecior
*/
-(instancetype)init;
/**
* Create vector with specified element values
* @param v0 First element
* @param v1 Second element
*/
-(instancetype)initWithV0:(double)v0 v1:(double)v1;
/**
* Create vector with specified element values
* @param vals array of element values
*/
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::Vec2d&)vec2d;
#endif
/**
* Update vector with specified element values
* @param vals array of element values
*/
-(void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
/**
* Get vector as an array
*/
-(NSArray<NSNumber*>*)get;
#pragma mark - Common Methods
/**
* Compare for equality
* @param other Object to compare
*/
-(BOOL)isEqual:(nullable id)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,75 @@
//
// Double2.mm
//
// Created by Giles Payne on 2020/05/22.
//
#import "Double2.h"
#import "Mat.h"
@implementation Double2 {
cv::Vec2d native;
}
-(double)v0 {
return native[0];
}
-(void)setV0:(double)v {
native[0] = v;
}
-(double)v1 {
return native[1];
}
-(void)setV1:(double)v {
native[1] = v;
}
-(instancetype)init {
return [self initWithV0:0 v1:0];
}
-(instancetype)initWithV0:(double)v0 v1:(double)v1 {
self = [super init];
if (self) {
self.v0 = v0;
self.v1 = v1;
}
return self;
}
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+(instancetype)fromNative:(cv::Vec2d&)vec2d {
return [[Double2 alloc] initWithV0:vec2d[0] v1:vec2d[1]];
}
-(void)set:(NSArray<NSNumber*>*)vals {
self.v0 = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0;
self.v1 = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0;
}
-(NSArray<NSNumber*>*)get {
return @[[NSNumber numberWithFloat:native[0]], [NSNumber numberWithFloat:native[1]]];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Double2 class]]) {
return NO;
} else {
Double2* d2 = (Double2*)other;
return self.v0 == d2.v0 && self.v1 == d2.v1;
}
}
@end

@ -0,0 +1,94 @@
//
// Double3.h
//
// Created by Giles Payne on 2020/05/22.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Mat;
NS_ASSUME_NONNULL_BEGIN
/**
* Simple wrapper for a vector of three `double`
*/
@interface Double3 : NSObject
#pragma mark - Properties
/**
* First vector element
*/
@property double v0;
/**
* Second vector element
*/
@property double v1;
/**
* Third vector element
*/
@property double v2;
#ifdef __cplusplus
/**
* The wrapped vector
*/
@property(readonly) cv::Vec3d& nativeRef;
#endif
#pragma mark - Constructors
/**
* Create zero-initialize vecior
*/
-(instancetype)init;
/**
* Create vector with specified element values
* @param v0 First element
* @param v1 Second element
* @param v2 Third element
*/
-(instancetype)initWithV0:(double)v0 v1:(double)v1 v2:(double)v2;
/**
* Create vector with specified element values
* @param vals array of element values
*/
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::Vec3d&)vec3d;
#endif
/**
* Update vector with specified element values
* @param vals array of element values
*/
-(void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
/**
* Get vector as an array
*/
-(NSArray<NSNumber*>*)get;
#pragma mark - Common Methods
/**
* Compare for equality
* @param other Object to compare
*/
-(BOOL)isEqual:(nullable id)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,85 @@
//
// Double3.mm
//
// Created by Giles Payne on 2020/05/22.
//
#import "Double3.h"
#import "Mat.h"
@implementation Double3 {
cv::Vec3d native;
}
-(double)v0 {
return native[0];
}
-(void)setV0:(double)v {
native[0] = v;
}
-(double)v1 {
return native[1];
}
-(void)setV1:(double)v {
native[1] = v;
}
-(double)v2 {
return native[2];
}
-(void)setV2:(double)v {
native[2] = v;
}
-(instancetype)init {
return [self initWithV0:0 v1:0 v2:0];
}
-(instancetype)initWithV0:(double)v0 v1:(double)v1 v2:(double)v2 {
self = [super init];
if (self) {
self.v0 = v0;
self.v1 = v1;
self.v2 = v2;
}
return self;
}
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+(instancetype)fromNative:(cv::Vec3d&)vec3d {
return [[Double3 alloc] initWithV0:vec3d[0] v1:vec3d[1] v2:vec3d[2]];
}
-(void)set:(NSArray<NSNumber*>*)vals {
self.v0 = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0;
self.v1 = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0;
self.v2 = (vals != nil && vals.count > 2) ? vals[2].doubleValue : 0;
}
-(NSArray<NSNumber*>*)get {
return @[[NSNumber numberWithFloat:native[0]], [NSNumber numberWithFloat:native[1]], [NSNumber numberWithFloat:native[2]]];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Double3 class]]) {
return NO;
} else {
Double3* d3 = (Double3*)other;
return self.v0 == d3.v0 && self.v1 == d3.v1 && self.v2 == d3.v2;
}
}
@end

@ -0,0 +1,88 @@
//
// DoubleVector.h
//
// Created by Giles Payne on 2020/01/04.
//
#pragma once
#import <Foundation/Foundation.h>
#ifdef __cplusplus
#import <vector>
#endif
NS_ASSUME_NONNULL_BEGIN
/**
* Utility class to wrap a `std::vector<double>`
*/
@interface DoubleVector : NSObject
#pragma mark - Constructors
/**
* Create DoubleVector and initialize with the contents of an NSData object
* @param data NSData containing raw double array
*/
-(instancetype)initWithData:(NSData*)data;
/**
* Create DoubleVector and initialize with the contents of another DoubleVector object
* @param src DoubleVector containing data to copy
*/
-(instancetype)initWithVector:(DoubleVector*)src;
#ifdef __OBJC__
/**
* Create DoubleVector from raw C array
* @param array The raw C array
* @elements elements The number of elements in the array
*/
-(instancetype)initWithNativeArray:(double*)array elements:(int)elements;
#endif
#ifdef __cplusplus
/**
* Create DoubleVector from std::vector<double>
* @param src The std::vector<double> object to wrap
*/
-(instancetype)initWithStdVector:(std::vector<double>&)src;
+(instancetype)fromNative:(std::vector<double>&)src;
#endif
#pragma mark - Properties
/**
* Length of the vector
*/
@property(readonly) size_t length;
#ifdef __OBJC__
/**
* Raw C array
*/
@property(readonly) double* nativeArray;
#endif
#ifdef __cplusplus
/**
* The wrapped std::vector<double> object
*/
@property(readonly) std::vector<double>& nativeRef;
#endif
/**
* NSData object containing the raw double data
*/
@property(readonly) NSData* data;
#pragma mark - Accessor method
/**
* Return array element
* @param index Index of the array element to return
*/
-(double)get:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,76 @@
//
// DoubleVector.m
//
// Created by Giles Payne on 2020/01/04.
//
#import "DoubleVector.h"
#import <vector>
@implementation DoubleVector {
std::vector<double> v;
}
-(instancetype)initWithData:(NSData*)data {
self = [super init];
if (self) {
if (data.length % sizeof(double) != 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Invalid data length" userInfo:nil];
}
v.insert(v.begin(), (double*)data.bytes, (double*)data.bytes + data.length/sizeof(double));
}
return self;
}
-(instancetype)initWithVector:(DoubleVector*)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.nativeRef.begin(), src.nativeRef.end());
}
return self;
}
-(size_t)length {
return v.size();
}
-(double*)nativeArray {
return (double*)v.data();
}
-(instancetype)initWithNativeArray:(double*)array elements:(int)elements {
self = [super init];
if (self) {
v.insert(v.begin(), array, array + elements);
}
return self;
}
- (std::vector<double>&)nativeRef {
return v;
}
-(instancetype)initWithStdVector:(std::vector<double>&)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.begin(), src.end());
}
return self;
}
+(instancetype)fromNative:(std::vector<double>&)src {
return [[DoubleVector alloc] initWithStdVector:src];
}
-(double)get:(NSInteger)index {
if (index < 0 || index >= (long)v.size()) {
@throw [NSException exceptionWithName:NSRangeException reason:@"Invalid data length" userInfo:nil];
}
return v[index];
}
-(NSData*)data {
return [NSData dataWithBytesNoCopy:v.data() length:(v.size() * sizeof(double)) freeWhenDone:NO];
}
@end

@ -0,0 +1,53 @@
//
// DoubleVectorExt.swift
//
// Created by Giles Payne on 2020/01/04.
//
import Foundation
public extension DoubleVector {
convenience init(_ array:[Double]) {
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(data:data);
}
subscript(index: Int) -> Double {
get {
return self.get(index)
}
}
var array: [Double] {
get {
var ret = Array<Double>(repeating: 0, count: data.count/MemoryLayout<Double>.stride)
_ = ret.withUnsafeMutableBytes { data.copyBytes(to: $0) }
return ret
}
}
}
extension DoubleVector : Sequence {
public typealias Iterator = DoubleVectorIterator
public func makeIterator() -> DoubleVectorIterator {
return DoubleVectorIterator(self)
}
}
public struct DoubleVectorIterator: IteratorProtocol {
public typealias Element = Double
let doubleVector: DoubleVector
var pos = 0
init(_ doubleVector: DoubleVector) {
self.doubleVector = doubleVector
}
mutating public func next() -> Double? {
guard pos >= 0 && pos < doubleVector.length
else { return nil }
pos += 1
return doubleVector.get(pos - 1)
}
}

@ -0,0 +1,99 @@
//
// Float4.h
//
// Created by Giles Payne on 2020/02/05.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class Mat;
/**
* Simple wrapper for a vector of four `float`
*/
@interface Float4 : NSObject
#pragma mark - Properties
/**
* First vector element
*/
@property float v0;
/**
* Second vector element
*/
@property float v1;
/**
* Third vector element
*/
@property float v2;
/**
* Fourth vector element
*/
@property float v3;
#ifdef __cplusplus
/**
* The wrapped vector
*/
@property(readonly) cv::Vec4f& nativeRef;
#endif
#pragma mark - Constructors
/**
* Create zero-initialize vecior
*/
-(instancetype)init;
/**
* Create vector with specified element values
* @param v0 First element
* @param v1 Second element
* @param v2 Third element
* @param v3 Fourth element
*/
-(instancetype)initWithV0:(float)v0 v1:(float)v1 v2:(float)v2 v3:(float)v3;
/**
* Create vector with specified element values
* @param vals array of element values
*/
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::Vec4f&)vec4f;
#endif
/**
* Update vector with specified element values
* @param vals array of element values
*/
-(void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
/**
* Get vector as an array
*/
-(NSArray<NSNumber*>*)get;
#pragma mark - Common Methods
/**
* Compare for equality
* @param other Object to compare
*/
-(BOOL)isEqual:(nullable id)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,95 @@
//
// Float4.mm
//
// Created by Giles Payne on 2020/02/05.
//
#import "Float4.h"
#import "Mat.h"
@implementation Float4 {
cv::Vec4f native;
}
-(float)v0 {
return native[0];
}
-(void)setV0:(float)v {
native[0] = v;
}
-(float)v1 {
return native[1];
}
-(void)setV1:(float)v {
native[1] = v;
}
-(float)v2 {
return native[2];
}
-(void)setV2:(float)v {
native[2] = v;
}
-(float)v3 {
return native[3];
}
-(void)setV3:(float)v {
native[3] = v;
}
-(instancetype)init {
return [self initWithV0:0.0 v1:0.0 v2:0.0 v3:0.0];
}
-(instancetype)initWithV0:(float)v0 v1:(float)v1 v2:(float)v2 v3:(float)v3 {
self = [super init];
if (self) {
self.v0 = v0;
self.v1 = v1;
self.v2 = v2;
self.v3 = v3;
}
return self;
}
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+(instancetype)fromNative:(cv::Vec4f&)vec4f {
return [[Float4 alloc] initWithV0:vec4f[0] v1:vec4f[1] v2:vec4f[2] v3:vec4f[3]];
}
-(void)set:(NSArray<NSNumber*>*)vals {
self.v0 = (vals != nil && vals.count > 0) ? vals[0].floatValue : 0;
self.v1 = (vals != nil && vals.count > 1) ? vals[1].floatValue : 0;
self.v2 = (vals != nil && vals.count > 2) ? vals[2].floatValue : 0;
self.v3 = (vals != nil && vals.count > 3) ? vals[3].floatValue : 0;
}
-(NSArray<NSNumber*>*)get {
return @[[NSNumber numberWithFloat:native[0]], [NSNumber numberWithFloat:native[1]], [NSNumber numberWithFloat:native[2]], [NSNumber numberWithFloat:native[3]]];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Float4 class]]) {
return NO;
} else {
Float4* point = (Float4*)other;
return self.v0 == point.v0 && self.v1 == point.v1 && self.v2 == point.v2 && self.v3 == point.v3;
}
}
@end

@ -0,0 +1,112 @@
//
// Float6.h
//
// Created by Giles Payne on 2020/02/05.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Mat;
NS_ASSUME_NONNULL_BEGIN
/**
* Simple wrapper for a vector of six `float`
*/
@interface Float6 : NSObject
#pragma mark - Properties
/**
* First vector element
*/
@property float v0;
/**
* Second vector element
*/
@property float v1;
/**
* Third vector element
*/
@property float v2;
/**
* Fourth vector element
*/
@property float v3;
/**
* Fifth vector element
*/
@property float v4;
/**
* Sixth vector element
*/
@property float v5;
#ifdef __cplusplus
/**
* The wrapped vector
*/
@property(readonly) cv::Vec6f& nativeRef;
#endif
#pragma mark - Constructors
/**
* Create zero-initialize vecior
*/
-(instancetype)init;
/**
* Create vector with specified element values
* @param v0 First element
* @param v1 Second element
* @param v2 Third element
* @param v3 Fourth element
* @param v4 Fifth element
* @param v5 Sixth element
*/
-(instancetype)initWithV0:(float)v0 v1:(float)v1 v2:(float)v2 v3:(float)v3 v4:(float)v4 v5:(float)v5;
/**
* Create vector with specified element values
* @param vals array of element values
*/
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::Vec6f&)vec6f;
#endif
/**
* Update vector with specified element values
* @param vals array of element values
*/
-(void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
/**
* Get vector as an array
*/
-(NSArray<NSNumber*>*)get;
#pragma mark - Common Methods
/**
* Compare for equality
* @param other Object to compare
*/
-(BOOL)isEqual:(nullable id)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,115 @@
//
// Float6.mm
//
// Created by Giles Payne on 2020/02/05.
//
#import "Float6.h"
#import "Mat.h"
@implementation Float6 {
cv::Vec6f native;
}
-(float)v0 {
return native[0];
}
-(void)setV0:(float)v {
native[0] = v;
}
-(float)v1 {
return native[1];
}
-(void)setV1:(float)v {
native[1] = v;
}
-(float)v2 {
return native[2];
}
-(void)setV2:(float)v {
native[2] = v;
}
-(float)v3 {
return native[3];
}
-(void)setV3:(float)v {
native[3] = v;
}
-(float)v4 {
return native[4];
}
-(void)setV4:(float)v {
native[4] = v;
}
-(float)v5 {
return native[5];
}
-(void)setV5:(float)v {
native[5] = v;
}
-(instancetype)init {
return [self initWithV0:0.0 v1:0.0 v2:0.0 v3:0.0 v4:0.0 v5:0.0];
}
-(instancetype)initWithV0:(float)v0 v1:(float)v1 v2:(float)v2 v3:(float)v3 v4:(float)v4 v5:(float)v5 {
self = [super init];
if (self) {
self.v0 = v0;
self.v1 = v1;
self.v2 = v2;
self.v3 = v3;
self.v4 = v4;
self.v5 = v5;
}
return self;
}
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+(instancetype)fromNative:(cv::Vec6f&)vec6f {
return [[Float6 alloc] initWithV0:vec6f[0] v1:vec6f[1] v2:vec6f[2] v3:vec6f[3] v4:vec6f[4] v5:vec6f[5]];
}
-(void)set:(NSArray<NSNumber*>*)vals {
self.v0 = (vals != nil && vals.count > 0) ? vals[0].floatValue : 0.0;
self.v1 = (vals != nil && vals.count > 1) ? vals[1].floatValue : 0.0;
self.v2 = (vals != nil && vals.count > 2) ? vals[2].floatValue : 0.0;
self.v3 = (vals != nil && vals.count > 3) ? vals[3].floatValue : 0.0;
self.v4 = (vals != nil && vals.count > 4) ? vals[4].floatValue : 0.0;
self.v5 = (vals != nil && vals.count > 5) ? vals[5].floatValue : 0.0;
}
-(NSArray<NSNumber*>*)get {
return @[[NSNumber numberWithFloat:native[0]], [NSNumber numberWithFloat:native[1]], [NSNumber numberWithFloat:native[2]], [NSNumber numberWithFloat:native[3]]];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Float6 class]]) {
return NO;
} else {
Float6* point = (Float6*)other;
return self.v0 == point.v0 && self.v1 == point.v1 && self.v2 == point.v2 && self.v3 == point.v3 && self.v4 == point.v4 && self.v5 == point.v5;
}
}
@end

@ -0,0 +1,88 @@
//
// FloatVector.h
//
// Created by Giles Payne on 2020/01/04.
//
#pragma once
#import <Foundation/Foundation.h>
#ifdef __cplusplus
#import <vector>
#endif
NS_ASSUME_NONNULL_BEGIN
/**
* Utility class to wrap a `std::vector<float>`
*/
@interface FloatVector : NSObject
#pragma mark - Constructors
/**
* Create FloatVector and initialize with the contents of an NSData object
* @param data NSData containing raw float array
*/
-(instancetype)initWithData:(NSData*)data;
/**
* Create FloatVector and initialize with the contents of another FloatVector object
* @param src FloatVector containing data to copy
*/
-(instancetype)initWithVector:(FloatVector*)src;
#ifdef __OBJC__
/**
* Create FloatVector from raw C array
* @param array The raw C array
* @elements elements The number of elements in the array
*/
-(instancetype)initWithNativeArray:(float*)array elements:(NSInteger)elements;
#endif
#ifdef __cplusplus
/**
* Create FloatVector from std::vector<float>
* @param src The std::vector<float> object to wrap
*/
-(instancetype)initWithStdVector:(std::vector<float>&)src;
+(instancetype)fromNative:(std::vector<float>&)src;
#endif
#pragma mark - Properties
/**
* Length of the vector
*/
@property(readonly) NSInteger length;
#ifdef __OBJC__
/**
* Raw C array
*/
@property(readonly) float* nativeArray;
#endif
#ifdef __cplusplus
/**
* The wrapped std::vector<float> object
*/
@property(readonly) std::vector<float>& nativeRef;
#endif
/**
* NSData object containing the raw float data
*/
@property(readonly) NSData* data;
#pragma mark - Accessor method
/**
* Return array element
* @param index Index of the array element to return
*/
-(float)get:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,76 @@
//
// FloatVector.m
//
// Created by Giles Payne on 2020/01/04.
//
#import "FloatVector.h"
#import <vector>
@implementation FloatVector {
std::vector<float> v;
}
-(instancetype)initWithData:(NSData*)data {
self = [super init];
if (self) {
if (data.length % sizeof(float) != 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Invalid data length" userInfo:nil];
}
v.insert(v.begin(), (float*)data.bytes, (float*)data.bytes + data.length/sizeof(float));
}
return self;
}
-(instancetype)initWithVector:(FloatVector *)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.nativeRef.begin(), src.nativeRef.end());
}
return self;
}
-(NSInteger)length {
return v.size();
}
-(float*)nativeArray {
return (float*)v.data();
}
-(instancetype)initWithNativeArray:(float*)array elements:(NSInteger)elements {
self = [super init];
if (self) {
v.insert(v.begin(), array, array + elements);
}
return self;
}
- (std::vector<float>&)nativeRef {
return v;
}
-(instancetype)initWithStdVector:(std::vector<float>&)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.begin(), src.end());
}
return self;
}
+(instancetype)fromNative:(std::vector<float>&)src {
return [[FloatVector alloc] initWithStdVector:src];
}
-(float)get:(NSInteger)index {
if (index < 0 || index >= (long)v.size()) {
@throw [NSException exceptionWithName:NSRangeException reason:@"Invalid data length" userInfo:nil];
}
return v[index];
}
-(NSData*)data {
return [NSData dataWithBytesNoCopy:v.data() length:(v.size() * sizeof(float)) freeWhenDone:NO];
}
@end

@ -0,0 +1,53 @@
//
// FloatVectorExt.swift
//
// Created by Giles Payne on 2020/01/04.
//
import Foundation
public extension FloatVector {
convenience init(_ array:[Float]) {
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(data:data);
}
subscript(index: Int) -> Float {
get {
return self.get(index)
}
}
var array: [Float] {
get {
var ret = Array<Float>(repeating: 0, count: data.count/MemoryLayout<Float>.stride)
_ = ret.withUnsafeMutableBytes { data.copyBytes(to: $0) }
return ret
}
}
}
extension FloatVector : Sequence {
public typealias Iterator = FloatVectorIterator
public func makeIterator() -> FloatVectorIterator {
return FloatVectorIterator(self)
}
}
public struct FloatVectorIterator: IteratorProtocol {
public typealias Element = Float
let floatVector: FloatVector
var pos = 0
init(_ floatVector: FloatVector) {
self.floatVector = floatVector
}
mutating public func next() -> Float? {
guard pos >= 0 && pos < floatVector.length
else { return nil }
pos += 1
return floatVector.get(pos - 1)
}
}

@ -0,0 +1,99 @@
//
// Int4.h
//
// Created by Giles Payne on 2020/02/05.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Mat;
NS_ASSUME_NONNULL_BEGIN
/**
* Simple wrapper for a vector of four `int`
*/
@interface Int4 : NSObject
#pragma mark - Properties
/**
* First vector element
*/
@property int v0;
/**
* Second vector element
*/
@property int v1;
/**
* Third vector element
*/
@property int v2;
/**
* Fourth vector element
*/
@property int v3;
#ifdef __cplusplus
/**
* The wrapped vector
*/
@property(readonly) cv::Vec4i& nativeRef;
#endif
#pragma mark - Constructors
/**
* Create zero-initialize vecior
*/
-(instancetype)init;
/**
* Create vector with specified element values
* @param v0 First element
* @param v1 Second element
* @param v2 Third element
* @param v3 Fourth element
*/
-(instancetype)initWithV0:(int)v0 v1:(int)v1 v2:(int)v2 v3:(int)v3;
/**
* Create vector with specified element values
* @param vals array of element values
*/
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+(instancetype)fromNative:(cv::Vec4i&)vec4i;
#endif
/**
* Update vector with specified element values
* @param vals array of element values
*/
-(void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
/**
* Get vector as an array
*/
-(NSArray<NSNumber*>*)get;
#pragma mark - Common Methods
/**
* Compare for equality
* @param other Object to compare
*/
-(BOOL)isEqual:(nullable id)other;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,95 @@
//
// Int4.mm
//
// Created by Giles Payne on 2020/02/05.
//
#import "Int4.h"
#import "Mat.h"
@implementation Int4 {
cv::Vec4i native;
}
-(int)v0 {
return native[0];
}
-(void)setV0:(int)v {
native[0] = v;
}
-(int)v1 {
return native[1];
}
-(void)setV1:(int)v {
native[1] = v;
}
-(int)v2 {
return native[2];
}
-(void)setV2:(int)v {
native[2] = v;
}
-(int)v3 {
return native[3];
}
-(void)setV3:(int)v {
native[3] = v;
}
-(instancetype)init {
return [self initWithV0:0 v1:0 v2:0 v3:0];
}
-(instancetype)initWithV0:(int)v0 v1:(int)v1 v2:(int)v2 v3:(int)v3 {
self = [super init];
if (self) {
self.v0 = v0;
self.v1 = v1;
self.v2 = v2;
self.v3 = v3;
}
return self;
}
-(instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+(instancetype)fromNative:(cv::Vec4i&)vec4i {
return [[Int4 alloc] initWithV0:vec4i[0] v1:vec4i[1] v2:vec4i[2] v3:vec4i[3]];
}
-(void)set:(NSArray<NSNumber*>*)vals {
self.v0 = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.v1 = (vals != nil && vals.count > 1) ? vals[1].intValue : 0;
self.v2 = (vals != nil && vals.count > 2) ? vals[2].intValue : 0;
self.v3 = (vals != nil && vals.count > 3) ? vals[3].intValue : 0;
}
-(NSArray<NSNumber*>*)get {
return @[[NSNumber numberWithFloat:native[0]], [NSNumber numberWithFloat:native[1]], [NSNumber numberWithFloat:native[2]], [NSNumber numberWithFloat:native[3]]];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Int4 class]]) {
return NO;
} else {
Int4* point = (Int4*)other;
return self.v0 == point.v0 && self.v1 == point.v1 && self.v2 == point.v2 && self.v3 == point.v3;
}
}
@end

@ -0,0 +1,88 @@
//
// IntVector.h
//
// Created by Giles Payne on 2020/01/04.
//
#pragma once
#import <Foundation/Foundation.h>
#ifdef __cplusplus
#import <vector>
#endif
NS_ASSUME_NONNULL_BEGIN
/**
* Utility class to wrap a `std::vector<int>`
*/
@interface IntVector : NSObject
#pragma mark - Constructors
/**
* Create IntVector and initialize with the contents of an NSData object
* @param data NSData containing raw int array
*/
-(instancetype)initWithData:(NSData*)data;
/**
* Create IntVector and initialize with the contents of another IntVector object
* @param src IntVector containing data to copy
*/
-(instancetype)initWithVector:(IntVector*)src;
#ifdef __OBJC__
/**
* Create IntVector from raw C array
* @param array The raw C array
* @elements elements The number of elements in the array
*/
-(instancetype)initWithNativeArray:(int*)array elements:(NSInteger)elements;
#endif
#ifdef __cplusplus
/**
* Create IntVector from std::vector<int>
* @param src The std::vector<int> object to wrap
*/
-(instancetype)initWithStdVector:(std::vector<int>&)src;
+(instancetype)fromNative:(std::vector<int>&)src;
#endif
#pragma mark - Properties
/**
* Length of the vector
*/
@property(readonly) NSInteger length;
#ifdef __OBJC__
/**
* Raw C array
*/
@property(readonly) int* nativeArray;
#endif
#ifdef __cplusplus
/**
* The wrapped std::vector<int> object
*/
@property(readonly) std::vector<int>& nativeRef;
#endif
/**
* NSData object containing the raw int data
*/
@property(readonly) NSData* data;
#pragma mark - Accessor method
/**
* Return array element
* @param index Index of the array element to return
*/
-(int)get:(NSInteger)index;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,76 @@
//
// IntVector.m
//
// Created by Giles Payne on 2020/01/04.
//
#import "IntVector.h"
#import <vector>
@implementation IntVector {
std::vector<int> v;
}
-(instancetype)initWithData:(NSData*)data {
self = [super init];
if (self) {
if (data.length % sizeof(int) != 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Invalid data length" userInfo:nil];
}
v.insert(v.begin(), (int*)data.bytes, (int*)data.bytes + data.length/sizeof(int));
}
return self;
}
-(instancetype)initWithVector:(IntVector*)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.nativeRef.begin(), src.nativeRef.end());
}
return self;
}
-(NSInteger)length {
return v.size();
}
-(int*)nativeArray {
return (int*)v.data();
}
-(instancetype)initWithNativeArray:(int*)array elements:(NSInteger)elements {
self = [super init];
if (self) {
v.insert(v.begin(), array, array + elements);
}
return self;
}
- (std::vector<int>&)nativeRef {
return v;
}
-(instancetype)initWithStdVector:(std::vector<int>&)src {
self = [super init];
if (self) {
v.insert(v.begin(), src.begin(), src.end());
}
return self;
}
+(instancetype)fromNative:(std::vector<int>&)src {
return [[IntVector alloc] initWithStdVector:src];
}
-(int)get:(NSInteger)index {
if (index < 0 || index >= (long)v.size()) {
@throw [NSException exceptionWithName:NSRangeException reason:@"Invalid data length" userInfo:nil];
}
return v[index];
}
-(NSData*)data {
return [NSData dataWithBytesNoCopy:v.data() length:(v.size() * sizeof(int)) freeWhenDone:NO];
}
@end

@ -0,0 +1,53 @@
//
// IntVectorExt.swift
//
// Created by Giles Payne on 2020/01/04.
//
import Foundation
public extension IntVector {
convenience init(_ array:[Int32]) {
let data = array.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(data:data);
}
subscript(index: Int) -> Int32 {
get {
return self.get(index)
}
}
var array: [Int32] {
get {
var ret = Array<Int32>(repeating: 0, count: data.count/MemoryLayout<Int32>.stride)
_ = ret.withUnsafeMutableBytes { data.copyBytes(to: $0) }
return ret
}
}
}
extension IntVector : Sequence {
public typealias Iterator = IntVectorIterator
public func makeIterator() -> IntVectorIterator {
return IntVectorIterator(self)
}
}
public struct IntVectorIterator: IteratorProtocol {
public typealias Element = Int32
let intVector: IntVector
var pos = 0
init(_ intVector: IntVector) {
self.intVector = intVector
}
mutating public func next() -> Int32? {
guard pos >= 0 && pos < intVector.length
else { return nil }
pos += 1
return intVector.get(pos - 1)
}
}

@ -0,0 +1,98 @@
//
// KeyPoint.h
//
// Created by Giles Payne on 2019/10/08.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Point2f;
NS_ASSUME_NONNULL_BEGIN
/**
* Object representing a point feature found by one of many available keypoint detectors, such as Harris corner detector, FAST, StarDetector, SURF, SIFT etc.
*/
@interface KeyPoint : NSObject
#pragma mark - Properties
/**
* Coordinates of the keypoint.
*/
@property Point2f* pt;
/**
* Diameter of the useful keypoint adjacent area.
*/
@property float size;
/**
* Computed orientation of the keypoint (-1 if not applicable).
*/
@property float angle;
/**
* The response, by which the strongest keypoints have been selected. Can
* be used for further sorting or subsampling.
*/
@property float response;
/**
* Octave (pyramid layer), from which the keypoint has been extracted.
*/
@property int octave;
/**
* Object ID, that can be used to cluster keypoints by an object they
* belong to.
*/
@property int classId;
#ifdef __cplusplus
@property(readonly) cv::KeyPoint& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response octave:(int)octave classId:(int)classId;
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response octave:(int)octave;
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response;
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle;
- (instancetype)initWithX:(float)x y:(float)y size:(float)size;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::KeyPoint&)keyPoint;
#endif
#pragma mark - Common Methods
/**
* Clone object
*/
- (KeyPoint*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,95 @@
//
// KeyPoint.m
//
// Created by Giles Payne on 2019/12/25.
//
#import "KeyPoint.h"
#import "Point2f.h"
#import "CVObjcUtil.h"
@implementation KeyPoint {
cv::KeyPoint native;
}
- (cv::KeyPoint&)nativeRef {
native.pt.x = self.pt.x;
native.pt.y = self.pt.y;
native.size = self.size;
native.angle = self.angle;
native.response = self.response;
native.octave = self.octave;
native.class_id = self.classId;
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0 size:0];
}
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response octave:(int)octave classId:(int)classId {
self = [super init];
if (self != nil) {
self.pt = [[Point2f alloc] initWithX:x y:y];
self.size = size;
self.angle = angle;
self.response = response;
self.octave = octave;
self.classId = classId;
}
return self;
}
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response octave:(int)octave {
return [self initWithX:x y:y size:size angle:angle response:response octave:octave classId:-1];
}
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle response:(float)response {
return [self initWithX:x y:y size:size angle:angle response:response octave:0];
}
- (instancetype)initWithX:(float)x y:(float)y size:(float)size angle:(float)angle {
return [self initWithX:x y:y size:size angle:angle response:0];
}
- (instancetype)initWithX:(float)x y:(float)y size:(float)size {
return [self initWithX:x y:y size:size angle:-1];
}
+ (instancetype)fromNative:(cv::KeyPoint&)keyPoint {
return [[KeyPoint alloc] initWithX:keyPoint.pt.x y:keyPoint.pt.y size:keyPoint.size angle:keyPoint.angle response:keyPoint.response octave:keyPoint.octave classId:keyPoint.class_id];
}
- (KeyPoint*)clone {
return [[KeyPoint alloc] initWithX:self.pt.x y:self.pt.y size:self.size angle:self.angle response:self.response octave:self.octave classId:self.classId];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[KeyPoint class]]) {
return NO;
} else {
KeyPoint* keyPoint = (KeyPoint*)other;
return [self.pt isEqual:keyPoint.pt] && self.size == keyPoint.size && self.angle == keyPoint.angle && self.response == keyPoint.response && self.octave == keyPoint.octave && self.classId == keyPoint.classId;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + FLOAT_TO_BITS(self.pt.x);
result = prime * result + FLOAT_TO_BITS(self.pt.y);
result = prime * result + FLOAT_TO_BITS(self.size);
result = prime * result + FLOAT_TO_BITS(self.angle);
result = prime * result + FLOAT_TO_BITS(self.response);
result = prime * result + self.octave;
result = prime * result + self.classId;
return result;
}
- (NSString*)description {
return [NSString stringWithFormat:@"KeyPoint { pt: %@, size: %f, angle: %f, response: %f, octave: %d, classId: %d}", self.pt.description, self.size, self.angle, self.response, self.octave, self.classId];
}
@end

@ -0,0 +1,157 @@
//
// Mat.h
//
// Created by Giles Payne on 2019/10/06.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Size2i;
@class Scalar;
@class Range;
@class Rect2i;
@class Point2i;
NS_ASSUME_NONNULL_BEGIN
/**
* The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array.
*/
@interface Mat : NSObject
#ifdef __cplusplus
@property(readonly) cv::Mat* nativePtr;
@property(readonly) cv::Mat& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (void)dealloc;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
+ (instancetype)fromNativePtr:(cv::Mat*)nativePtr;
+ (instancetype)fromNative:(cv::Mat&)nativeRef;
#endif
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type;
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data;
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data step:(long)step;
- (instancetype)initWithSize:(Size2i*)size type:(int)type;
- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type;
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type scalar:(Scalar*)scalar;
- (instancetype)initWithSize:(Size2i*)size type:(int)type scalar:(Scalar*)scalar;
- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type scalar:(Scalar*)scalar;
- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange colRange:(Range*)colRange;
- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange;
- (instancetype)initWithMat:(Mat*)mat ranges:(NSArray<Range*>*)ranges;
- (instancetype)initWithMat:(Mat*)mat rect:(Rect2i*)roi;
#pragma mark - Mat operations
- (Mat*)adjustRoiTop:(int)dtop bottom:(int)dbottom left:(int)dleft right:(int)dright NS_SWIFT_NAME(adjustRoi(top:bottom:left:right:));
- (void)assignTo:(Mat*)mat type:(int)type;
- (void)assignTo:(Mat*)mat;
- (BOOL)isSameMat:(Mat*)mat;
- (int)channels;
- (int)checkVector:(int)elemChannels depth:(int)depth requireContinuous:(BOOL) requireContinuous NS_SWIFT_NAME(checkVector(elemChannels:depth:requireContinuous:));
- (int)checkVector:(int)elemChannels depth:(int)depth NS_SWIFT_NAME(checkVector(elemChannels:depth:));
- (int)checkVector:(int)elemChannels NS_SWIFT_NAME(checkVector(elemChannels:));
- (Mat*)clone;
- (Mat*)col:(int)x;
- (Mat*)colRange:(int)start end:(int)end NS_SWIFT_NAME(colRange(start:end:));
- (Mat*)colRange:(Range*)range;
- (int)dims;
- (int)cols;
- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha beta:(double)beta;
- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha;
- (void)convertTo:(Mat*)mat rtype:(int)rtype;
- (void)copyTo:(Mat*)mat;
- (void)copyTo:(Mat*)mat mask:(Mat*)mask;
- (void)create:(int)rows cols:(int)cols type:(int)type NS_SWIFT_NAME(create(rows:cols:type:));
- (void)create:(Size2i*)size type:(int)type NS_SWIFT_NAME(create(size:type:));
- (void)createEx:(NSArray<NSNumber*>*)sizes type:(int)type NS_SWIFT_NAME(create(sizes:type:));
- (void)copySize:(Mat*)mat;
- (Mat*)cross:(Mat*)mat;
- (int)depth;
- (Mat*)diag:(int)diagonal;
- (Mat*)diag;
+ (Mat*)diag:(Mat*)diagonal;
- (double)dot:(Mat*)mat;
- (long)elemSize;
- (long)elemSize1;
- (BOOL)empty;
+ (Mat*)eye:(int)rows cols:(int)cols type:(int)type NS_SWIFT_NAME(eye(rows:cols:type:));
+ (Mat*)eye:(Size2i*)size type:(int)type NS_SWIFT_NAME(eye(size:type:));
- (Mat*)inv:(int)method;
- (Mat*)inv;
- (BOOL)isContinuous;
- (BOOL)isSubmatrix;
- (void)locateROI:(Size2i*)wholeSize ofs:(Point2i*)offset NS_SWIFT_NAME(locateROI(wholeSize:offset:));
- (Mat*)mul:(Mat*)mat scale:(double)scale;
- (Mat*)mul:(Mat*)mat;
+ (Mat*)ones:(int)rows cols:(int)cols type:(int)type NS_SWIFT_NAME(ones(rows:cols:type:));
+ (Mat*)ones:(Size2i*)size type:(int)type NS_SWIFT_NAME(ones(size:type:));
+ (Mat*)onesEx:(NSArray<NSNumber*>*)sizes type:(int)type NS_SWIFT_NAME(ones(sizes:type:));
- (void)push_back:(Mat*)mat;
- (Mat*)reshape:(int)channels rows:(int)rows NS_SWIFT_NAME(reshape(channels:rows:));
- (Mat*)reshape:(int)channels NS_SWIFT_NAME(reshape(channels:));
- (Mat*)reshape:(int)channels newshape:(NSArray<NSNumber*>*)newshape NS_SWIFT_NAME(reshape(channels:newshape:));
- (Mat*)row:(int)y;
- (Mat*)rowRange:(int)start end:(int)end NS_SWIFT_NAME(rowRange(start:end:));
- (Mat*)rowRange:(Range*)range;
- (int)rows;
- (Mat*)setToScalar:(Scalar*)scalar NS_SWIFT_NAME(setTo(scalar:));
- (Mat*)setToScalar:(Scalar*)scalar mask:(Mat*)mask NS_SWIFT_NAME(setTo(scalar:mask:));
- (Mat*)setToValue:(Mat*)value mask:(Mat*)mask NS_SWIFT_NAME(setTo(value:mask:));
- (Mat*)setToValue:(Mat*)value NS_SWIFT_NAME(setTo(value:));
- (Size2i*)size;
- (int)size:(int)dim;
- (long)step1:(int)dim;
- (long)step1;
- (Mat*)submat:(int)rowStart rowEnd:(int)rowEnd colStart:(int)colStart colEnd:(int)colEnd NS_SWIFT_NAME(submat(rowStart:rowEnd:colStart:colEnd:));
- (Mat*)submat:(Range*)rowRange colRange:(Range*)colRange NS_SWIFT_NAME(submat(rowRange:colRange:));
- (Mat*)submat:(NSArray<Range*>*)ranges NS_SWIFT_NAME(submat(ranges:));
- (Mat*)submatRoi:(Rect2i*)roi NS_SWIFT_NAME(submat(roi:));
- (Mat*)t;
- (long)total;
- (int)type;
+ (Mat*)zeros:(int)rows cols:(int)cols type:(int)type;
+ (Mat*)zeros:(Size2i*)size type:(int)type;
+ (Mat*)zerosEx:(NSArray<NSNumber*>*)sizes type:(int)type NS_SWIFT_NAME(zeros(sizes:type:));
- (NSString*)description;
- (NSString*)dump;
- (int)height;
- (int)width;
#pragma mark - Accessors
- (int)put:(int)row col:(int)col data:(NSArray<NSNumber*>*)data NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices data:(NSArray<NSNumber*>*)data NS_REFINED_FOR_SWIFT;
- (int)get:(int)row col:(int)col data:(NSMutableArray<NSNumber*>*)data NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices data:(NSMutableArray<NSNumber*>*)data NS_REFINED_FOR_SWIFT;
- (NSArray<NSNumber*>*)get:(int)row col:(int)col NS_REFINED_FOR_SWIFT;
- (NSArray<NSNumber*>*)get:(NSArray<NSNumber*>*)indices NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(char*)buffer NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(double*)buffer NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(float*)buffer NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(int*)buffer NS_REFINED_FOR_SWIFT;
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(short*)buffer NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(const char*)buffer NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(const double*)buffer NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(const float*)buffer NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(const int*)buffer NS_REFINED_FOR_SWIFT;
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(const short*)buffer NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,913 @@
//
// Mat.m
//
// Created by Giles Payne on 2019/10/06.
//
#import "Mat.h"
#import "Size2i.h"
#import "Scalar.h"
#import "Range.h"
#import "Rect2i.h"
#import "Point2i.h"
#import "CvType.h"
#import "CVObjcUtil.h"
// return true if we have reached the final index
static bool incIdx(cv::Mat* mat, std::vector<int>& indices) {
for (int dim = mat->dims-1; dim>=0; dim--) {
indices[dim] = (indices[dim] + 1) % mat->size[dim];
if (indices[dim] != 0) {
return false;
}
}
return true;
}
// returns true if final index was reached
static bool updateIdx(cv::Mat* mat, std::vector<int>& indices, int inc) {
for (int index = 0; index < inc; index++) {
if (incIdx(mat, indices)) {
return true;
}
}
return false;
}
@implementation Mat {
NSData* _nsdata;
}
- (cv::Mat&)nativeRef {
return *(cv::Mat*)_nativePtr;
}
- (instancetype)init {
self = [super init];
if (self) {
_nativePtr = new cv::Mat();
}
return self;
}
- (void)dealloc {
if (_nativePtr != NULL) {
_nativePtr->release();
delete _nativePtr;
}
_nsdata = NULL;
}
- (instancetype)initWithNativeMat:(cv::Mat*)nativePtr {
self = [super init];
if (self) {
_nativePtr = new cv::Mat(*nativePtr);
}
return self;
}
+ (instancetype)fromNativePtr:(cv::Mat*)nativePtr {
return [[Mat alloc] initWithNativeMat:nativePtr];
}
+ (instancetype)fromNative:(cv::Mat&)nativeRef {
return [[Mat alloc] initWithNativeMat:&nativeRef];
}
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type {
self = [super init];
if (self) {
_nativePtr = new cv::Mat(rows, cols, type);
}
return self;
}
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data {
self = [super init];
if (self) {
_nativePtr = new cv::Mat(rows, cols, type, (void*)data.bytes);
_nsdata = data; // hold onto a reference otherwise this object might be deallocated
}
return self;
}
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type data:(NSData*)data step:(long)step {
self = [super init];
if (self) {
_nativePtr = new cv::Mat(rows, cols, type, (void*)data.bytes, step);
_nsdata = data; // hold onto a reference otherwise this object might be deallocated
}
return self;
}
- (instancetype)initWithSize:(Size2i*)size type:(int)type {
self = [super init];
if (self) {
_nativePtr = new cv::Mat(size.width, size.height, type);
}
return self;
}
- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type {
self = [super init];
if (self) {
std::vector<int> vSizes;
for (NSNumber* size in sizes) {
vSizes.push_back(size.intValue);
}
_nativePtr = new cv::Mat((int)sizes.count, vSizes.data(), type);
}
return self;
}
- (instancetype)initWithRows:(int)rows cols:(int)cols type:(int)type scalar:(Scalar*)scalar {
self = [super init];
if (self) {
cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue);
_nativePtr = new cv::Mat(rows, cols, type, scalerTemp);
}
return self;
}
- (instancetype)initWithSize:(Size2i*)size type:(int)type scalar:(Scalar *)scalar {
self = [super init];
if (self) {
cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue);
_nativePtr = new cv::Mat(size.width, size.height, type, scalerTemp);
}
return self;
}
- (instancetype)initWithSizes:(NSArray<NSNumber*>*)sizes type:(int)type scalar:(Scalar *)scalar {
self = [super init];
if (self) {
cv::Scalar scalerTemp(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue);
std::vector<int> vSizes;
for (NSNumber* size in sizes) {
vSizes.push_back(size.intValue);
}
_nativePtr = new cv::Mat((int)sizes.count, vSizes.data(), type, scalerTemp);
}
return self;
}
- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange colRange:(Range*)colRange {
self = [super init];
if (self) {
cv::Range rows(rowRange.start, rowRange.end);
cv::Range cols(colRange.start, colRange.end);
_nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows, cols);
}
return self;
}
- (instancetype)initWithMat:(Mat*)mat rowRange:(Range*)rowRange {
self = [super init];
if (self) {
cv::Range rows(rowRange.start, rowRange.end);
_nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows);
}
return self;
}
- (instancetype)initWithMat:(Mat*)mat ranges:(NSArray<Range*>*)ranges {
self = [super init];
if (self) {
std::vector<cv::Range> tempRanges;
for (Range* range in ranges) {
tempRanges.push_back(cv::Range(range.start, range.end));
}
_nativePtr = new cv::Mat(mat.nativePtr->operator()(tempRanges));
}
return self;
}
- (instancetype)initWithMat:(Mat*)mat rect:(Rect2i*)roi {
self = [super init];
if (self) {
cv::Range rows(roi.y, roi.y + roi.height);
cv::Range cols(roi.x, roi.x + roi.width);
_nativePtr = new cv::Mat(*(cv::Mat*)mat.nativePtr, rows, cols);
}
return self;
}
- (BOOL)isSameMat:(Mat*)mat {
return self.nativePtr == mat.nativePtr;
}
- (Mat*)adjustRoiTop:(int)dtop bottom:(int)dbottom left:(int)dleft right:(int)dright {
cv::Mat adjusted = _nativePtr->adjustROI(dtop, dbottom, dleft, dright);
return [[Mat alloc] initWithNativeMat:new cv::Mat(adjusted)];
}
- (void)assignTo:(Mat*)mat type:(int)type {
_nativePtr->assignTo(*(cv::Mat*)mat.nativePtr, type);
}
- (void)assignTo:(Mat*)mat {
_nativePtr->assignTo(*(cv::Mat*)mat.nativePtr);
}
- (int)channels {
return _nativePtr->channels();
}
- (int)checkVector:(int)elemChannels depth:(int)depth requireContinuous:(BOOL) requireContinuous {
return _nativePtr->checkVector(elemChannels, depth, requireContinuous);
}
- (int)checkVector:(int)elemChannels depth:(int)depth {
return _nativePtr->checkVector(elemChannels, depth);
}
- (int)checkVector:(int)elemChannels {
return _nativePtr->checkVector(elemChannels);
}
- (Mat*)clone {
return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->clone()))];
}
- (Mat*)col:(int)x {
return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->col(x)))];
}
- (Mat*)colRange:(int)start end:(int)end {
return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->colRange(start, end)))];
}
- (Mat*)colRange:(Range*)range {
return [[Mat alloc] initWithNativeMat:(new cv::Mat(_nativePtr->colRange(range.start, range.end)))];
}
- (int)dims {
return _nativePtr->dims;
}
- (int)cols {
return _nativePtr->cols;
}
- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha beta:(double)beta {
_nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype, alpha, beta);
}
- (void)convertTo:(Mat*)mat rtype:(int)rtype alpha:(double)alpha {
_nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype, alpha);
}
- (void)convertTo:(Mat*)mat rtype:(int)rtype {
_nativePtr->convertTo(*(cv::Mat*)mat->_nativePtr, rtype);
}
- (void)copyTo:(Mat*)mat {
_nativePtr->copyTo(*(cv::Mat*)mat->_nativePtr);
}
- (void)copyTo:(Mat*)mat mask:(Mat*)mask {
_nativePtr->copyTo(*(cv::Mat*)mat->_nativePtr, *(cv::Mat*)mask->_nativePtr);
}
- (void)create:(int)rows cols:(int)cols type:(int)type {
_nativePtr->create(rows, cols, type);
}
- (void)create:(Size2i*)size type:(int)type {
cv::Size tempSize(size.width, size.height);
_nativePtr->create(tempSize, type);
}
- (void)createEx:(NSArray<NSNumber*>*)sizes type:(int)type {
std::vector<int> tempSizes;
for (NSNumber* size in sizes) {
tempSizes.push_back(size.intValue);
}
_nativePtr->create((int)tempSizes.size(), tempSizes.data(), type);
}
- (void)copySize:(Mat*)mat {
_nativePtr->copySize(*(cv::Mat*)mat.nativePtr);
}
- (Mat*)cross:(Mat*)mat {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->cross(*(cv::Mat*)mat.nativePtr))];
}
- (int)depth {
return _nativePtr->depth();
}
- (Mat*)diag:(int)diagonal {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->diag(diagonal))];
}
- (Mat*)diag {
return [self diag:0];
}
+ (Mat*)diag:(Mat*)diagonal {
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::diag(*(cv::Mat*)diagonal.nativePtr))];
}
- (double)dot:(Mat*)mat {
return _nativePtr->dot(*(cv::Mat*)mat.nativePtr);
}
- (long)elemSize {
return _nativePtr->elemSize();
}
- (long)elemSize1 {
return _nativePtr->elemSize1();
}
- (BOOL)empty {
return _nativePtr->empty();
}
+ (Mat*)eye:(int)rows cols:(int)cols type:(int)type {
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::eye(rows, cols, type))];
}
+ (Mat*)eye:(Size2i*)size type:(int)type {
cv::Size tempSize(size.width, size.height);
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::eye(tempSize, type))];
}
- (Mat*)inv:(int)method {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->inv(method))];
}
- (Mat*)inv {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->inv())];
}
- (BOOL)isContinuous {
return _nativePtr->isContinuous();
}
- (BOOL)isSubmatrix {
return _nativePtr->isSubmatrix();
}
- (void)locateROI:(Size2i*)wholeSize ofs:(Point2i*)ofs {
cv::Size tempWholeSize;
cv::Point tempOfs;
_nativePtr->locateROI(tempWholeSize, tempOfs);
if (wholeSize != nil) {
wholeSize.width = tempWholeSize.width;
wholeSize.height = tempWholeSize.height;
}
if (ofs != nil) {
ofs.x = tempOfs.x;
ofs.y = tempOfs.y;
}
}
- (Mat*)mul:(Mat*)mat scale:(double)scale {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->mul(*(cv::Mat*)mat.nativePtr, scale))];
}
- (Mat*)mul:(Mat*)mat {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->mul(*(cv::Mat*)mat.nativePtr))];
}
+ (Mat*)ones:(int)rows cols:(int)cols type:(int)type {
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones(rows, cols, type))];
}
+ (Mat*)ones:(Size2i*)size type:(int)type {
cv::Size tempSize(size.width, size.height);
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones(tempSize, type))];
}
+ (Mat*)onesEx:(NSArray<NSNumber*>*)sizes type:(int)type {
std::vector<int> tempSizes;
for (NSNumber* size in sizes) {
tempSizes.push_back(size.intValue);
}
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::ones((int)tempSizes.size(), tempSizes.data(), type))];
}
- (void)push_back:(Mat*)mat {
_nativePtr->push_back(*(cv::Mat*)mat.nativePtr);
}
- (Mat*)reshape:(int)channels rows:(int)rows {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels, rows))];
}
- (Mat*)reshape:(int)channels {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels))];
}
- (Mat*)reshape:(int)channels newshape:(NSArray<NSNumber*>*)newshape {
std::vector<int> tempNewshape;
for (NSNumber* size in newshape) {
tempNewshape.push_back(size.intValue);
}
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->reshape(channels, tempNewshape))];
}
- (Mat*)row:(int)y {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->row(y))];
}
- (Mat*)rowRange:(int)start end:(int)end {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->rowRange(start, end))];
}
- (Mat*)rowRange:(Range*)range {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->rowRange(range.start, range.end))];
}
- (int)rows {
return _nativePtr->rows;
}
- (Mat*)setToScalar:(Scalar*)scalar {
cv::Scalar tempScalar(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue);
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator=(tempScalar))];
}
- (Mat*)setToScalar:(Scalar*)scalar mask:(Mat*)mask {
cv::Scalar tempScalar(scalar.val[0].doubleValue, scalar.val[1].doubleValue, scalar.val[2].doubleValue, scalar.val[3].doubleValue);
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(tempScalar, *(cv::Mat*)mask.nativePtr))];
}
- (Mat*)setToValue:(Mat*)value mask:(Mat*)mask {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(*(cv::Mat*)value.nativePtr, *(cv::Mat*)mask.nativePtr))];
}
- (Mat*)setToValue:(Mat*)value {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->setTo(*(cv::Mat*)value.nativePtr))];
}
- (Size2i*)size {
return [[Size2i alloc] initWithWidth:_nativePtr->size().width height:_nativePtr->size().height];
}
- (int)size:(int)dimIndex {
return _nativePtr->size[dimIndex];
}
- (long)step1:(int)dimIndex {
return _nativePtr->step1(dimIndex);
}
- (long)step1 {
return _nativePtr->step1();
}
- (Mat*)submat:(int)rowStart rowEnd:(int)rowEnd colStart:(int)colStart colEnd:(int)colEnd {
Range* rowRange = [[Range alloc] initWithStart:rowStart end:rowEnd];
Range* colRange = [[Range alloc] initWithStart:colStart end:colEnd];
return [self submat:rowRange colRange:colRange];
}
- (Mat*)submat:(Range*)rowRange colRange:(Range*)colRange {
cv::Range tempRowRange(rowRange.start, rowRange.end);
cv::Range tempColRange(colRange.start, colRange.end);
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRowRange, tempColRange))];
}
- (Mat*)submat:(NSArray<Range*>*)ranges {
std::vector<cv::Range> tempRanges;
for (Range* range in ranges) {
tempRanges.push_back(cv::Range(range.start, range.end));
}
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRanges))];
}
- (Mat*)submatRoi:(Rect2i*)roi {
cv::Rect tempRoi(roi.x, roi.y, roi.width, roi.height);
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->operator()(tempRoi))];
}
- (Mat*)t {
return [[Mat alloc] initWithNativeMat:new cv::Mat(_nativePtr->t())];
}
- (long)total {
return _nativePtr->total();
}
- (int)type {
return _nativePtr->type();
}
+ (Mat*)zeros:(int)rows cols:(int)cols type:(int)type {
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros(rows, cols, type))];
}
+ (Mat*)zeros:(Size2i*)size type:(int)type {
cv::Size tempSize(size.width, size.height);
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros(tempSize, type))];
}
+ (Mat*)zerosEx:(NSArray<NSNumber*>*)sizes type:(int)type {
std::vector<int> tempSizes;
for (NSNumber* size in sizes) {
tempSizes.push_back(size.intValue);
}
return [[Mat alloc] initWithNativeMat:new cv::Mat(cv::Mat::zeros((int)tempSizes.size(), tempSizes.data(), type))];
}
- (NSString*)dimsDescription {
if (_nativePtr->dims <= 0) {
return @"-1*-1*";
} else {
NSMutableString* ret = [NSMutableString string];
for (int index=0; index<_nativePtr->dims; index++) {
[ret appendFormat:@"%d*", _nativePtr->size[index]];
}
return ret;
}
}
- (NSString*)description {
NSString* dimDesc = [self dimsDescription];
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];
}
- (NSString*)dump {
NSMutableString* ret = [NSMutableString string];
cv::Ptr<cv::Formatted> formatted = cv::Formatter::get()->format(*_nativePtr);
for(const char* format = formatted->next(); format; format = formatted->next()) {
[ret appendFormat:@"%s", format];
}
return ret;
}
template<typename T> void putData(uchar* dataDest, int count, T (^readData)(int)) {
T* tDataDest = (T*)dataDest;
for (int index = 0; index < count; index++) {
tDataDest[index] = readData(index);
}
}
- (void)put:(uchar*)dest data:(NSArray<NSNumber*>*)data offset:(int)offset count:(int)count {
int depth = _nativePtr->depth();
if (depth == CV_8U) {
putData(dest, count, ^uchar (int index) { return cv::saturate_cast<uchar>(data[offset + index].doubleValue);} );
} else if (depth == CV_8S) {
putData(dest, count, ^char (int index) { return cv::saturate_cast<char>(data[offset + index].doubleValue);} );
} else if (depth == CV_16U) {
putData(dest, count, ^ushort (int index) { return cv::saturate_cast<ushort>(data[offset + index].doubleValue);} );
} else if (depth == CV_16S) {
putData(dest, count, ^short (int index) { return cv::saturate_cast<short>(data[offset + index].doubleValue);} );
} else if (depth == CV_32S) {
putData(dest, count, ^int32_t (int index) { return cv::saturate_cast<int32_t>(data[offset + index].doubleValue);} );
} else if (depth == CV_32F) {
putData(dest, count, ^float (int index) { return cv::saturate_cast<float>(data[offset + index].doubleValue);} );
} else if (depth == CV_64F) {
putData(dest, count, ^double (int index) { return data[offset + index].doubleValue;} );
}
}
- (int)put:(NSArray<NSNumber*>*)indices data:(NSArray<NSNumber*>*)data {
cv::Mat* mat = _nativePtr;
int type = mat->type();
int rawValueSize = (int)(mat->elemSize() / mat->channels());
if (data == nil || data.count % [CvType channels:type] != 0) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
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]]
userInfo:nil];
@throw exception;
}
std::vector<int> tempIndices;
for (NSNumber* index in indices) {
tempIndices.push_back(index.intValue);
}
for (int index = 0; index < mat->dims; index++) {
if (mat->size[index]<=tempIndices[index]) {
return 0; // indexes out of range
}
}
int arrayAvailable = (int)data.count;
int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable);
int copyOffset = 0;
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available);
int result = (int)(available * rawValueSize);
while (available > 0) {
[self put:mat->ptr(tempIndices.data()) data:data offset:(int)copyOffset count:copyCount];
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) {
break;
}
available -= copyCount;
copyOffset += copyCount;
copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available);
}
return result;
}
- (int)put:(int)row col:(int)col data:(NSArray<NSNumber*>*)data {
NSArray<NSNumber*>* indices = @[[NSNumber numberWithInt:row], [NSNumber numberWithInt:col]];
return [self put:indices data:data];
}
template<typename T> void getData(uchar* dataSource, int count, void (^writeData)(int,T)) {
T* tDataSource = (T*)dataSource;
for (int index = 0; index < count; index++) {
writeData(index, tDataSource[index]);
}
}
- (void)get:(uchar*)source data:(NSMutableArray<NSNumber*>*)data offset:(int)offset count:(int)count {
int depth = _nativePtr->depth();
if (depth == CV_8U) {
getData(source, count, ^void (int index, uchar value) { data[offset + index] = [[NSNumber alloc] initWithUnsignedChar:value]; } );
} else if (depth == CV_8S) {
getData(source, count, ^void (int index, char value) { data[offset + index] = [[NSNumber alloc] initWithChar:value]; } );
} else if (depth == CV_16U) {
getData(source, count, ^void (int index, ushort value) { data[offset + index] = [[NSNumber alloc] initWithUnsignedShort:value]; } );
} else if (depth == CV_16S) {
getData(source, count, ^void (int index, short value) { data[offset + index] = [[NSNumber alloc] initWithShort:value]; } );
} else if (depth == CV_32S) {
getData(source, count, ^void (int index, int32_t value) { data[offset + index] = [[NSNumber alloc] initWithInt:value]; } );
} else if (depth == CV_32F) {
getData(source, count, ^void (int index, float value) { data[offset + index] = [[NSNumber alloc] initWithFloat:value]; } );
} else if (depth == CV_64F) {
getData(source, count, ^void (int index, double value) { data[offset + index] = [[NSNumber alloc] initWithDouble:value]; } );
}
}
- (int)get:(NSArray<NSNumber*>*)indices data:(NSMutableArray<NSNumber*>*)data {
cv::Mat* mat = _nativePtr;
int type = mat->type();
if (data == nil || data.count % [CvType channels:type] != 0) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
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]]
userInfo:nil];
@throw exception;
}
std::vector<int> tempIndices;
for (NSNumber* index in indices) {
tempIndices.push_back(index.intValue);
}
for (int index = 0; index < mat->dims; index++) {
if (mat->size[index]<=tempIndices[index]) {
return 0; // indexes out of range
}
}
int arrayAvailable = (int)data.count;
int copyOffset = 0;
int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable);
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available);
int result = (int)(available * mat->elemSize() / mat->channels());
while (available > 0) {
[self get:mat->ptr(tempIndices.data()) data:data offset:(int)copyOffset count:copyCount];
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) {
break;
}
available -= copyCount;
copyOffset += copyCount;
copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available);
}
return result;
}
- (int)get:(int)row col:(int)col data:(NSMutableArray<NSNumber*>*)data {
NSArray<NSNumber*>* indices = @[[NSNumber numberWithInt:row], [NSNumber numberWithInt:col]];
return [self get:indices data:data];
}
- (NSArray<NSNumber*>*)get:(int)row col:(int)col {
NSMutableArray<NSNumber*>* result = [NSMutableArray new];
for (int index = 0; index<_nativePtr->channels(); index++) {
[result addObject:@0];
}
[self get:row col:col data:result];
return result;
}
- (NSArray<NSNumber*>*)get:(NSArray<NSNumber*>*)indices {
NSMutableArray<NSNumber*>* result = [NSMutableArray new];
for (int index = 0; index<_nativePtr->channels(); index++) {
[result addObject:@0];
}
[self get:indices data:result];
return result;
}
template<typename T> void getData(uchar* source, void (^writeData)(int,T), int dataOffset, int dataLength) {
T* tSource = (T*)source;
for (int index = 0; index < dataLength; index++) {
writeData(dataOffset+index, tSource[index]);
}
}
int getMatAvailable(cv::Mat* mat, std::vector<int>& indices) {
int blockSize = 1;
int unavailableCount = 0;
for (int index = mat->dims - 1; index >= 0; index--) {
unavailableCount += blockSize * indices[index];
blockSize *= mat->size[index];
}
return (int)(mat->channels() * (mat->total() - unavailableCount));
}
template<typename T> int getData(NSArray<NSNumber*>* indices, cv::Mat* mat, int count, T* tBuffer) {
std::vector<int> tempIndices;
for (NSNumber* index in indices) {
tempIndices.push_back(index.intValue);
}
for (int index = 0; index < mat->dims; index++) {
if (mat->size[index]<=tempIndices[index]) {
return 0; // indexes out of range
}
}
int arrayAvailable = count;
int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable);
int result = (int)(available * mat->elemSize() / mat->channels());
if (mat->isContinuous()) {
memcpy(tBuffer, mat->ptr(tempIndices.data()), available * sizeof(T));
} else {
int copyOffset = 0;
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available);
while (available > 0) {
memcpy(tBuffer + copyOffset, mat->ptr(tempIndices.data()), copyCount * sizeof(T));
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) {
break;
}
available -= copyCount;
copyOffset += copyCount * sizeof(T);
copyCount = MIN(mat->size[mat->dims-1] * mat->channels(), available);
}
}
return result;
}
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(char*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_8U && depth != CV_8S) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_8U or CV_8S.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return getData(indices, _nativePtr, count, buffer);
}
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(double*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_64F) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_64F.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return getData(indices, _nativePtr, count, buffer);
}
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(float*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_32F) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32F.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return getData(indices, _nativePtr, count, buffer);
}
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(int*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_32S) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32S.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return getData(indices, _nativePtr, count, buffer);
}
- (int)get:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(short*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_16S && depth != CV_16U) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_16S and CV_16U.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return getData(indices, _nativePtr, count, buffer);
}
template<typename T> int putData(NSArray<NSNumber*>* indices, cv::Mat* mat, int count, const T* tBuffer) {
std::vector<int> tempIndices;
for (NSNumber* index in indices) {
tempIndices.push_back(index.intValue);
}
for (int index = 0; index < mat->dims; index++) {
if (mat->size[index]<=tempIndices[index]) {
return 0; // indexes out of range
}
}
int arrayAvailable = count;
int matAvailable = getMatAvailable(mat, tempIndices);
int available = MIN(arrayAvailable, matAvailable);
int result = (int)(available * mat->elemSize() / mat->channels());
if (mat->isContinuous()) {
memcpy(mat->ptr(tempIndices.data()), tBuffer, available * sizeof(T));
} else {
int copyOffset = 0;
int copyCount = MIN((mat->size[mat->dims - 1] - tempIndices[mat->dims - 1]) * mat->channels(), available);
while (available > 0) {
memcpy(mat->ptr(tempIndices.data()), tBuffer + copyOffset, copyCount * sizeof(T));
if (updateIdx(mat, tempIndices, copyCount / mat->channels())) {
break;
}
available -= copyCount;
copyOffset += copyCount * sizeof(T);
copyCount = MIN(mat->size[mat->dims-1] * (int)mat->channels(), available);
}
}
return result;
}
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count byteBuffer:(const char*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_8U && depth != CV_8S) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_8U or CV_8S.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return putData(indices, _nativePtr, count, buffer);
}
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count doubleBuffer:(const double*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_64F) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_64F.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return putData(indices, _nativePtr, count, buffer);
}
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count floatBuffer:(const float*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_32F) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32F.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return putData(indices, _nativePtr, count, buffer);
}
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count intBuffer:(const int*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_32S) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depth for this call is CV_32S.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return putData(indices, _nativePtr, count, buffer);
}
- (int)put:(NSArray<NSNumber*>*)indices count:(int)count shortBuffer:(const short*)buffer {
int depth = _nativePtr->depth();
if (depth != CV_16S && depth != CV_16U) {
NSException* exception = [NSException
exceptionWithName:@"UnsupportedOperationException"
reason:[NSString stringWithFormat:@"Invalid depth (%@). Valid depths for this call are CV_16S and CV_16U.", [CvType typeToString:depth]]
userInfo:nil];
@throw exception;
}
return putData(indices, _nativePtr, count, buffer);
}
- (int)height {
return [self rows];
}
- (int)width {
return [self cols];
}
@end

@ -0,0 +1,244 @@
//
// MatExt.swift
//
// Created by Giles Payne on 2020/01/19.
//
import Foundation
let OpenCVErrorDomain = "OpenCVErrorDomain"
enum OpenCVError : Int {
case IncompatibleDataType = 10001
case IncompatibleBufferSize
}
func throwIncompatibleDataType(typeName: String) throws {
throw NSError(
domain: OpenCVErrorDomain,
code: OpenCVError.IncompatibleDataType.rawValue,
userInfo: [
NSLocalizedDescriptionKey: "Incompatible Mat type \(typeName)"
]
)
}
func throwIncompatibleBufferSize(count: Int, channels: Int32) throws {
throw NSError(
domain: OpenCVErrorDomain,
code: OpenCVError.IncompatibleBufferSize.rawValue,
userInfo: [
NSLocalizedDescriptionKey: "Provided data element number \(count) should be multiple of the Mat channels count \(channels)"
]
)
}
public extension Mat {
convenience init(rows:Int32, cols:Int32, type:Int32, data:[Int8]) {
let dataObject = data.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(rows: rows, cols: cols, type: type, data: dataObject)
}
convenience init(rows:Int32, cols:Int32, type:Int32, data:[Int8], step:Int) {
let dataObject = data.withUnsafeBufferPointer { Data(buffer: $0) }
self.init(rows: rows, cols: cols, type: type, data: dataObject, step:step)
}
@discardableResult func get(indices:[Int32], data:inout [Int8]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_8U && depth() != CvType.CV_8S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeMutableBufferPointer { body in
return __get(indices as [NSNumber], count: count, byteBuffer: body.baseAddress!)
}
}
@discardableResult func get(indices:[Int32], data:inout [Double]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_64F {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeMutableBufferPointer { body in
return __get(indices as [NSNumber], count: count, doubleBuffer: body.baseAddress!)
}
}
@discardableResult func get(indices:[Int32], data:inout [Float]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_32F {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeMutableBufferPointer { body in
return __get(indices as [NSNumber], count: count, floatBuffer: body.baseAddress!)
}
}
@discardableResult func get(indices:[Int32], data:inout [Int32]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_32S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeMutableBufferPointer { body in
return __get(indices as [NSNumber], count: count, intBuffer: body.baseAddress!)
}
}
@discardableResult func get(indices:[Int32], data:inout [Int16]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_16U && depth() != CvType.CV_16S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeMutableBufferPointer { body in
return __get(indices as [NSNumber], count: count, shortBuffer: body.baseAddress!)
}
}
@discardableResult func get(row: Int32, col: Int32, data:inout [Int8]) throws -> Int32 {
return try get(indices: [row, col], data: &data)
}
@discardableResult func get(row: Int32, col: Int32, data:inout [Double]) throws -> Int32 {
return try get(indices: [row, col], data: &data)
}
@discardableResult func get(row: Int32, col: Int32, data:inout [Float]) throws -> Int32 {
return try get(indices: [row, col], data: &data)
}
@discardableResult func get(row: Int32, col: Int32, data:inout [Int32]) throws -> Int32 {
return try get(indices: [row, col], data: &data)
}
@discardableResult func get(row: Int32, col: Int32, data:inout [Int16]) throws -> Int32 {
return try get(indices: [row, col], data: &data)
}
@discardableResult func put(indices:[Int32], data:[Int8]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_8U && depth() != CvType.CV_8S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: count, byteBuffer: body.baseAddress!)
}
}
@discardableResult func put(indices:[Int32], data:[Int8], offset: Int, length: Int32) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_8U && depth() != CvType.CV_8S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: length, byteBuffer: body.baseAddress! + offset)
}
}
// unlike other put:indices:data functions this one (with [Double]) should convert input values to correct type
@discardableResult func put(indices:[Int32], data:[Double]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
}
if depth() == CvType.CV_64F {
let count = Int32(data.count)
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: count, doubleBuffer: body.baseAddress!)
}
} else {
return __put(indices as [NSNumber], data: data as [NSNumber])
}
}
@discardableResult func put(indices:[Int32], data:[Float]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_32F {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: count, floatBuffer: body.baseAddress!)
}
}
@discardableResult func put(indices:[Int32], data:[Int32]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_32S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: count, intBuffer: body.baseAddress!)
}
}
@discardableResult func put(indices:[Int32], data:[Int16]) throws -> Int32 {
let channels = CvType.channels(Int32(type()))
if Int32(data.count) % channels != 0 {
try throwIncompatibleBufferSize(count: data.count, channels: channels)
} else if depth() != CvType.CV_16U && depth() != CvType.CV_16S {
try throwIncompatibleDataType(typeName: CvType.type(toString: type()))
}
let count = Int32(data.count)
return data.withUnsafeBufferPointer { body in
return __put(indices as [NSNumber], count: count, shortBuffer: body.baseAddress!)
}
}
@discardableResult func put(row: Int32, col: Int32, data:[Int8]) throws -> Int32 {
return try put(indices: [row, col], data: data)
}
@discardableResult func put(row: Int32, col: Int32, data: [Int8], offset: Int, length: Int32) throws -> Int32 {
return try put(indices: [row, col], data: data, offset: offset, length: length)
}
@discardableResult func put(row: Int32, col: Int32, data: [Double]) throws -> Int32 {
return try put(indices: [row, col], data: data)
}
@discardableResult func put(row: Int32, col: Int32, data: [Float]) throws -> Int32 {
return try put(indices: [row, col], data: data)
}
@discardableResult func put(row: Int32, col: Int32, data: [Int32]) throws -> Int32 {
return try put(indices: [row, col], data: data)
}
@discardableResult func put(row: Int32, col: Int32, data: [Int16]) throws -> Int32 {
return try put(indices: [row, col], data: data)
}
@discardableResult func get(row: Int32, col: Int32) -> [Double] {
return get(indices: [row, col])
}
@discardableResult func get(indices: [Int32]) -> [Double] {
return __get(indices as [NSNumber]) as! [Double]
}
}

@ -0,0 +1,62 @@
//
// MatOfByte.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of bytes
*/
@interface MatOfByte : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfByte from Mat object
* @param mat Mat object from which to create MatOfByte
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfByte from array
* @param array Array from which to create MatOfByte
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfByte.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfByte.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfByte
static const int _depth = CV_8U;
static const int _channels = 1;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = createArrayWithSize(length, @0.0);
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfDMatch.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class DMatch;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of DMatch objects
*/
@interface MatOfDMatch : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfDMatch from Mat object
* @param mat Mat object from which to create MatOfDMatch
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfDMatch from array
* @param array Array from which to create MatOfDMatch
*/
- (instancetype)initWithArray:(NSArray<DMatch*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<DMatch*>*)array;
/**
* Output Mat elements as an array of DMatch objects
*/
- (NSArray<DMatch*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,83 @@
//
// MatOfDMatch.m
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfDMatch.h"
#import "Range.h"
#import "DMatch.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfDMatch
static const int _depth = CV_32F;
static const int _channels = 4;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<DMatch*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<DMatch*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithFloat:array[index].queryIdx];
data[_channels * index + 1] = [NSNumber numberWithFloat:array[index].trainIdx];
data[_channels * index + 2] = [NSNumber numberWithFloat:array[index].imgIdx];
data[_channels * index + 3] = [NSNumber numberWithFloat:array[index].distance];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<DMatch*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<DMatch*>* ret = createArrayWithSize(length, [DMatch new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[DMatch alloc] initWithQueryIdx:data[index * _channels].intValue trainIdx:data[index * _channels + 1].intValue imgIdx:data[index * _channels + 2].intValue distance:data[index * _channels + 3].floatValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,63 @@
//
// MatOfDouble.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of doubles
*/
@interface MatOfDouble : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfDouble from Mat object
* @param mat Mat object from which to create MatOfDouble
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfDouble from array
* @param array Array from which to create MatOfDouble
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfDouble.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfDouble.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfDouble
static const int _depth = CV_64F;
static const int _channels = 1;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = createArrayWithSize(length, @0.0);
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,60 @@
//
// MatOfFloat.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of floats
*/
@interface MatOfFloat : Mat
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfFloat from Mat object
* @param mat Mat object from which to create MatOfFloat
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfFloat from array
* @param array Array from which to create MatOfFloat
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfFloat.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfFloat.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfFloat
static const int _depth = CV_32F;
static const int _channels = 1;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = createArrayWithSize(length, @0.0);
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,62 @@
//
// MatOfFloat4.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of vectors of four floats
*/
@interface MatOfFloat4 : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfFloat4 from Mat object
* @param mat Mat object from which to create MatOfFloat4
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfFloat4 from array
* @param array Array from which to create MatOfFloat4
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfFloat4.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfFloat4.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfFloat4
static const int _depth = CV_32F;
static const int _channels = 4;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:length];
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,62 @@
//
// MatOfFloat6.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of vectors of six floats
*/
@interface MatOfFloat6 : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfFloat6 from Mat object
* @param mat Mat object from which to create MatOfFloat6
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfFloat6 from array
* @param array Array from which to create MatOfFloat6
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfFloat6.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfFloat6.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfFloat6
static const int _depth = CV_32F;
static const int _channels = 6;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:length];
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,62 @@
//
// MatOfInt.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of ints
*/
@interface MatOfInt : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfInt from Mat object
* @param mat Mat object from which to create MatOfInt
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfInt from array
* @param array Array from which to create MatOfInt
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfInt.mm
//
// Created by Giles Payne on 2019/12/26.
//
#import "MatOfInt.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfInt
static const int _depth = CV_32S;
static const int _channels = 1;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = createArrayWithSize(length, @0.0);
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,62 @@
//
// MatOfInt4.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of vectors of four ints
*/
@interface MatOfInt4 : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfInt4 from Mat object
* @param mat Mat object from which to create MatOfInt4
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfInt4 from array
* @param array Array from which to create MatOfInt4
*/
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<NSNumber*>*)array;
/**
* Output Mat elements as an array
*/
- (NSArray<NSNumber*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,69 @@
//
// MatOfInt4.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfInt4.h"
#import "Range.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfInt4
static const int _depth = CV_32S;
static const int _channels = 4;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<NSNumber*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<NSNumber*>*)array {
[self alloc:(int)array.count / _channels];
[self put:0 col:0 data:array];
}
- (NSArray<NSNumber*>*)toArray {
int length = [self length];
NSMutableArray<NSNumber*>* data = createArrayWithSize(length, @0.0);
[self get:0 col:0 data:data];
return data;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfKeyPoint.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class KeyPoint;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of KeyPoint objects
*/
@interface MatOfKeyPoint : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfKeyPoint from Mat object
* @param mat Mat object from which to create MatOfKeyPoint
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfKeyPoint from array
* @param array Array from which to create MatOfKeyPoint
*/
- (instancetype)initWithArray:(NSArray<KeyPoint*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<KeyPoint*>*)array;
/**
* Output Mat elements as an array of KeyPoint objects
*/
- (NSArray<KeyPoint*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,87 @@
//
// MatOfKeyPoint.m
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfKeyPoint.h"
#import "Range.h"
#import "Point2f.h"
#import "KeyPoint.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfKeyPoint
static const int _depth = CV_32F;
static const int _channels = 7;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<KeyPoint*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<KeyPoint*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithFloat:array[index].pt.x];
data[_channels * index + 1] = [NSNumber numberWithFloat:array[index].pt.y];
data[_channels * index + 2] = [NSNumber numberWithFloat:array[index].size];
data[_channels * index + 3] = [NSNumber numberWithFloat:array[index].angle];
data[_channels * index + 4] = [NSNumber numberWithFloat:array[index].response];
data[_channels * index + 5] = [NSNumber numberWithFloat:array[index].octave];
data[_channels * index + 6] = [NSNumber numberWithFloat:array[index].classId];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<KeyPoint*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<KeyPoint*>* ret = createArrayWithSize(length, [KeyPoint new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[KeyPoint alloc] initWithX:data[index * _channels].floatValue y:data[index * _channels + 1].floatValue size:data[index * _channels + 2].floatValue angle:data[index * _channels + 3].floatValue response:data[index * _channels + 4].floatValue octave:data[index * _channels + 5].intValue classId:data[index * _channels + 6].intValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfPoint2f.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
NS_ASSUME_NONNULL_BEGIN
@class Point2f;
/**
* Mat representation of an array of Point2f objects
*/
@interface MatOfPoint2f : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfPoint2f from Mat object
* @param mat Mat object from which to create MatOfPoint2f
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfPoint2f from array
* @param array Array from which to create MatOfPoint2f
*/
- (instancetype)initWithArray:(NSArray<Point2f*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Point2f*>*)array;
/**
* Output Mat elements as an array of Point2f objects
*/
- (NSArray<Point2f*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,81 @@
//
// MatOfPoint2f.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfPoint2f.h"
#import "Range.h"
#import "Point2f.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfPoint2f
static const int _depth = CV_32F;
static const int _channels = 2;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Point2f*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Point2f*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithFloat:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithFloat:array[index].y];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Point2f*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Point2f*>* ret = createArrayWithSize(length, [Point2f new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Point2f alloc] initWithX:data[index * _channels].floatValue y:data[index * _channels + 1].floatValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,65 @@
//
// MatOfPoint2i.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class Point2i;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of Point objects
*/
NS_SWIFT_NAME(MatOfPoint)
@interface MatOfPoint2i : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfPoint from Mat object
* @param mat Mat object from which to create MatOfPoint
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfPoint from array
* @param array Array from which to create MatOfPoint
*/
- (instancetype)initWithArray:(NSArray<Point2i*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Point2i*>*)array;
/**
* Output Mat elements as an array of Point objects
*/
- (NSArray<Point2i*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,81 @@
//
// MatOfPoint2i.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfPoint2i.h"
#import "Range.h"
#import "Point2i.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfPoint2i
static const int _depth = CV_32S;
static const int _channels = 2;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Point2i*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Point2i*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithInt:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithInt:array[index].y];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Point2i*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Point2i*>* ret = createArrayWithSize(length, [Point2i new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Point2i alloc] initWithX:data[index * _channels].intValue y:data[index * _channels + 1].intValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfPoint3.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class Point3i;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of Point3i objects
*/
@interface MatOfPoint3 : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfPoint3 from Mat object
* @param mat Mat object from which to create MatOfPoint3
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfPoint3 from array
* @param array Array from which to create MatOfPoint3
*/
- (instancetype)initWithArray:(NSArray<Point3i*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Point3i*>*)array;
/**
* Output Mat elements as an array of Point3i objects
*/
- (NSArray<Point3i*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,82 @@
//
// MatOfPoint3.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfPoint3.h"
#import "Range.h"
#import "Point3i.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfPoint3
static const int _depth = CV_32S;
static const int _channels = 3;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Point3i*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Point3i*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithInt:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithInt:array[index].y];
data[_channels * index + 2] = [NSNumber numberWithInt:array[index].z];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Point3i*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Point3i*>* ret = createArrayWithSize(length, [Point3i new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Point3i alloc] initWithX:data[index * _channels].intValue y:data[index * _channels + 1].intValue z:data[index * _channels + 2].intValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfPoint3f.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class Point3f;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of Point3f objects
*/
@interface MatOfPoint3f : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfPoint3f from Mat object
* @param mat Mat object from which to create MatOfPoint3f
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfPoint3f from array
* @param array Array from which to create MatOfPoint3f
*/
- (instancetype)initWithArray:(NSArray<Point3f*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Point3f*>*)array;
/**
* Output Mat elements as an array of Point3f objects
*/
- (NSArray<Point3f*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,82 @@
//
// MatOfPoint3f.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfPoint3f.h"
#import "Range.h"
#import "Point3f.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfPoint3f
static const int _depth = CV_32F;
static const int _channels = 3;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Point3f*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Point3f*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithFloat:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithFloat:array[index].y];
data[_channels * index + 2] = [NSNumber numberWithFloat:array[index].z];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Point3f*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Point3f*>* ret = createArrayWithSize(length, [Point3f new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Point3f alloc] initWithX:data[index * _channels].floatValue y:data[index * _channels + 1].floatValue z:data[index * _channels + 2].floatValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,65 @@
//
// MatOfRect2d.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class Rect2d;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of Rect2d objects
*/
@interface MatOfRect2d : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
+ (instancetype)fromNative:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfRect2d from Mat object
* @param mat Mat object from which to create MatOfRect2d
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfRect2d from array
* @param array Array from which to create MatOfRect2d
*/
- (instancetype)initWithArray:(NSArray<Rect2d*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Rect2d*>*)array;
/**
* Output Mat elements as an array of Rect2d objects
*/
- (NSArray<Rect2d*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,88 @@
//
// MatOfRect2d.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfRect2d.h"
#import "Range.h"
#import "Rect2d.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfRect2d
static const int _depth = CV_64F;
static const int _channels = 4;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
+ (instancetype)fromNative:(cv::Mat*)nativeMat {
return [[MatOfRect2d alloc] initWithNativeMat:nativeMat];
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Rect2d*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Rect2d*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithDouble:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithDouble:array[index].y];
data[_channels * index + 2] = [NSNumber numberWithDouble:array[index].width];
data[_channels * index + 3] = [NSNumber numberWithDouble:array[index].height];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Rect2d*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Rect2d*>* ret = createArrayWithSize(length, [Rect2d new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Rect2d alloc] initWithX:data[index * _channels].doubleValue y:data[index * _channels + 1].doubleValue width:data[index * _channels + 2].doubleValue height:data[index * _channels + 3].doubleValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,65 @@
//
// MatOfRect2i.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class Rect2i;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of Rect objects
*/
NS_SWIFT_NAME(MatOfRect)
@interface MatOfRect2i : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfRect from Mat object
* @param mat Mat object from which to create MatOfRect
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfRect from array
* @param array Array from which to create MatOfRect
*/
- (instancetype)initWithArray:(NSArray<Rect2i*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<Rect2i*>*)array;
/**
* Output Mat elements as an array of Rect objects
*/
- (NSArray<Rect2i*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,83 @@
//
// MatOfRect2i.m
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfRect2i.h"
#import "Range.h"
#import "Rect2i.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfRect2i
static const int _depth = CV_32S;
static const int _channels = 4;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<Rect2i*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<Rect2i*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithInt:array[index].x];
data[_channels * index + 1] = [NSNumber numberWithInt:array[index].y];
data[_channels * index + 2] = [NSNumber numberWithInt:array[index].width];
data[_channels * index + 3] = [NSNumber numberWithInt:array[index].height];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<Rect2i*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<Rect2i*>* ret = createArrayWithSize(length, [Rect2i new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[Rect2i alloc] initWithX:data[index * _channels].intValue y:data[index * _channels + 1].intValue width:data[index * _channels + 2].intValue height:data[index * _channels + 3].intValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,64 @@
//
// MatOfRotatedRect.h
//
// Created by Giles Payne on 2019/12/27.
//
#pragma once
#import "Mat.h"
@class RotatedRect;
NS_ASSUME_NONNULL_BEGIN
/**
* Mat representation of an array of RotatedRect objects
*/
@interface MatOfRotatedRect : Mat
#pragma mark - Constructors
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat;
#endif
/**
* Create MatOfRotatedRect from Mat object
* @param mat Mat object from which to create MatOfRotatedRect
*/
- (instancetype)initWithMat:(Mat*)mat;
/**
* Create MatOfRotatedRect from array
* @param array Array from which to create MatOfRotatedRect
*/
- (instancetype)initWithArray:(NSArray<RotatedRect*>*)array;
#pragma mark - Methods
/**
* Allocate specified number of elements
* @param elemNumber Number of elements
*/
- (void)alloc:(int)elemNumber;
/**
* Populate Mat with elements of an array
* @param array Array with which to populate the Mat
*/
- (void)fromArray:(NSArray<RotatedRect*>*)array;
/**
* Output Mat elements as an array of RotatedRect objects
*/
- (NSArray<RotatedRect*>*)toArray;
/**
* Total number of values in Mat
*/
- (int)length;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,87 @@
//
// MatOfRotatedRect.mm
//
// Created by Giles Payne on 2019/12/27.
//
#import "MatOfRotatedRect.h"
#import "Range.h"
#import "RotatedRect.h"
#import "Point2f.h"
#import "Size2f.h"
#import "CvType.h"
#import "ArrayUtil.h"
@implementation MatOfRotatedRect
static const int _depth = CV_32F;
static const int _channels = 5;
#ifdef __cplusplus
- (instancetype)initWithNativeMat:(cv::Mat*)nativeMat {
self = [super initWithNativeMat:nativeMat];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
#endif
- (instancetype)initWithMat:(Mat*)mat {
self = [super initWithMat:mat rowRange:[Range all]];
if (self && ![self empty] && [self checkVector:_channels depth:_depth] < 0) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Incompatible Mat" userInfo:nil];
}
return self;
}
- (instancetype)initWithArray:(NSArray<RotatedRect*>*)array {
self = [super init];
if (self) {
[self fromArray:array];
}
return self;
}
- (void)alloc:(int)elemNumber {
if (elemNumber>0) {
[super create:elemNumber cols:1 type:[CvType makeType:_depth channels:_channels]];
}
}
- (void)fromArray:(NSArray<RotatedRect*>*)array {
NSMutableArray<NSNumber*>* data = [[NSMutableArray alloc] initWithCapacity:array.count * _channels];
for (int index = 0; index < (int)array.count; index++) {
data[_channels * index] = [NSNumber numberWithFloat:array[index].center.x];
data[_channels * index + 1] = [NSNumber numberWithFloat:array[index].center.y];
data[_channels * index + 2] = [NSNumber numberWithFloat:array[index].size.width];
data[_channels * index + 3] = [NSNumber numberWithFloat:array[index].size.height];
data[_channels * index + 4] = [NSNumber numberWithFloat:array[index].angle];
}
[self alloc:(int)array.count];
[self put:0 col:0 data:data];
}
- (NSArray<RotatedRect*>*)toArray {
int length = [self length] / _channels;
NSMutableArray<RotatedRect*>* ret = createArrayWithSize(length, [RotatedRect new]);
if (length > 0) {
NSMutableArray<NSNumber*>* data = createArrayWithSize([self length], @0.0);
[self get:0 col:0 data:data];
for (int index = 0; index < length; index++) {
ret[index] = [[RotatedRect alloc] initWithCenter:[[Point2f alloc] initWithX:data[index * _channels].floatValue y:data[index * _channels + 1].floatValue] size:[[Size2f alloc] initWithWidth:data[index * _channels + 2].floatValue height:data[index * _channels + 3].floatValue] angle:data[index * _channels + 4].floatValue];
}
}
return ret;
}
- (int)length {
int num = [self checkVector:_channels depth:_depth];
if (num < 0) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Incompatible Mat" userInfo:nil];
}
return num * _channels;
}
@end

@ -0,0 +1,38 @@
//
// MinMaxLocResult.h
//
// Created by Giles Payne on 2019/12/28.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Point2i;
NS_ASSUME_NONNULL_BEGIN
/**
* Result of operation to determine global minimum and maximum of an array
*/
@interface MinMaxLocResult : NSObject
#pragma mark - Properties
@property double minVal;
@property double maxVal;
@property Point2i* minLoc;
@property Point2i* maxLoc;
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithMinval:(double)minVal maxVal:(double)maxVal minLoc:(Point2i*)minLoc maxLoc:(Point2i*)maxLoc;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,27 @@
//
// MinMaxLocResult.m
//
// Created by Giles Payne on 2019/12/28.
//
#import "MinMaxLocResult.h"
#import "Point2i.h"
@implementation MinMaxLocResult
- (instancetype)init {
return [self initWithMinval:0 maxVal:0 minLoc:[Point2i new] maxLoc:[Point2i new]];
}
- (instancetype)initWithMinval:(double)minVal maxVal:(double)maxVal minLoc:(Point2i*)minLoc maxLoc:(Point2i*)maxLoc {
self = [super init];
if (self) {
self.minVal = minVal;
self.maxVal = maxVal;
self.minLoc = minLoc;
self.maxLoc = maxLoc;
}
return self;
}
@end

@ -0,0 +1,87 @@
//
// Point2d.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Rect2d;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a two dimensional point the coordinate values of which are of type `double`
*/
@interface Point2d : NSObject
# pragma mark - Properties
@property double x;
@property double y;
#ifdef __cplusplus
@property(readonly) cv::Point2d& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(double)x y:(double)y;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Point2d&)point;
- (void)update:(cv::Point2d&)point;
#endif
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point2d*)point;
/**
* Determine if the point lies with a specified rectangle
* @param rect The rectangle
*/
- (BOOL)inside:(Rect2d*)rect;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point2d*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,107 @@
//
// Point2d.m
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point2d.h"
#import "Rect2d.h"
#import "CVObjcUtil.h"
@implementation Point2d {
cv::Point2d native;
}
- (double)x {
return native.x;
}
- (void)setX:(double)val {
native.x = val;
}
- (double)y {
return native.y;
}
- (void)setY:(double)val {
native.y = val;
}
- (cv::Point2d&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0];
}
- (instancetype)initWithX:(double)x y:(double)y {
self = [super init];
if (self) {
self.x = x;
self.y = y;
}
return self;
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Point2d&)point {
return [[Point2d alloc] initWithX:point.x y:point.y];
}
- (void)update:(cv::Point2d&)point {
self.x = point.x;
self.y = point.y;
}
- (Point2d*) clone {
return [[Point2d alloc] initWithX:self.x y:self.y];
}
- (double)dot:(Point2d*)point {
return self.x * point.x + self.y * point.y;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0;
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point2d class]]) {
return NO;
} else {
Point2d* point = (Point2d*)other;
return self.x == point.x && self.y == point.y;
}
}
- (BOOL)inside:(Rect2d*)rect {
return [rect contains:self];
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
int64_t temp = DOUBLE_TO_BITS(self.x);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.y);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point2d {%lf,%lf}", self.x, self.y];
}
@end

@ -0,0 +1,87 @@
//
// Point2f.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Rect2f;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a two dimensional point the coordinate values of which are of type `float`
*/
@interface Point2f : NSObject
# pragma mark - Properties
@property float x;
@property float y;
#ifdef __cplusplus
@property(readonly) cv::Point2f& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(float)x y:(float)y;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Point2f&)point;
- (void)update:(cv::Point2f&)point;
#endif
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point2f*)point;
/**
* Determine if the point lies with a specified rectangle
* @param rect The rectangle
*/
- (BOOL)inside:(Rect2f*)rect;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point2f*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,105 @@
//
// Point2f.m
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point2f.h"
#import "Rect2f.h"
#import "CVObjcUtil.h"
@implementation Point2f {
cv::Point2f native;
}
- (float)x {
return native.x;
}
- (void)setX:(float)val {
native.x = val;
}
- (float)y {
return native.y;
}
- (void)setY:(float)val {
native.y = val;
}
- (cv::Point2f&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0];
}
- (instancetype)initWithX:(float)x y:(float)y {
self = [super init];
if (self) {
self.x = x;
self.y = y;
}
return self;
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Point2f&)point {
return [[Point2f alloc] initWithX:point.x y:point.y];
}
- (void)update:(cv::Point2f&)point {
self.x = point.x;
self.y = point.y;
}
- (Point2f*) clone {
return [[Point2f alloc] initWithX:self.x y:self.y];
}
- (double)dot:(Point2f*)point {
return self.x * point.x + self.y * point.y;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0;
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point2f class]]) {
return NO;
} else {
Point2f* point = (Point2f*)other;
return self.x == point.x && self.y == point.y;
}
}
- (BOOL)inside:(Rect2f *)rect {
return [rect contains:self];
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + FLOAT_TO_BITS(self.x);
result = prime * result + FLOAT_TO_BITS(self.x);
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point2f {%f,%f}", self.x, self.y];
}
@end

@ -0,0 +1,88 @@
//
// Point2i.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Rect2i;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a two dimensional point the coordinate values of which are of type `int`
*/
NS_SWIFT_NAME(Point)
@interface Point2i : NSObject
# pragma mark - Properties
@property int x;
@property int y;
#ifdef __cplusplus
@property(readonly) cv::Point2i& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(int)x y:(int)y;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Point2i&)point;
- (void)update:(cv::Point2i&)point;
#endif
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point2i*)point;
/**
* Determine if the point lies with a specified rectangle
* @param rect The rectangle
*/
- (BOOL)inside:(Rect2i*)rect;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point2i*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,105 @@
//
// Point2i.m
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point2i.h"
#import "Rect2i.h"
#import "CVObjcUtil.h"
@implementation Point2i {
cv::Point2i native;
}
- (int)x {
return native.x;
}
- (void)setX:(int)val {
native.x = val;
}
- (int)y {
return native.y;
}
- (void)setY:(int)val {
native.y = val;
}
- (cv::Point2i&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0];
}
- (instancetype)initWithX:(int)x y:(int)y {
self = [super init];
if (self) {
self.x = x;
self.y = y;
}
return self;
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Point2i&)point {
return [[Point2i alloc] initWithX:point.x y:point.y];
}
- (void)update:(cv::Point2i&)point {
self.x = point.x;
self.y = point.y;
}
- (Point2i*) clone {
return [[Point2i alloc] initWithX:self.x y:self.y];
}
- (double)dot:(Point2i*)point {
return self.x * point.x + self.y * point.y;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0;
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point2i class]]) {
return NO;
} else {
Point2i* point = (Point2i*)other;
return self.x == point.x && self.y == point.y;
}
}
- (BOOL)inside:(Rect2i*)rect {
return [rect contains:self];
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.x;
result = prime * result + self.y;
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point2i {%d,%d}", self.x, self.y];
}
@end

@ -0,0 +1,84 @@
//
// Point3d.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Point2d;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a three dimensional point the coordinate values of which are of type `double`
*/
@interface Point3d : NSObject
# pragma mark - Properties
@property double x;
@property double y;
@property double z;
#ifdef __cplusplus
@property(readonly) cv::Point3d& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(double)x y:(double)y z:(double)z;
- (instancetype)initWithPoint:(Point2d*)point;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point3d*)point;
/**
* Calculate the cross product of this point and another point
* @param point The other point
*/
- (Point3d*)cross:(Point3d*)point;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point3d*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString *)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,114 @@
//
// Point3d.mm
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point3d.h"
#import "Point2d.h"
#import "CVObjcUtil.h"
@implementation Point3d {
cv::Point3d native;
}
- (double)x {
return native.x;
}
- (void)setX:(double)val {
native.x = val;
}
- (double)y {
return native.y;
}
- (void)setY:(double)val {
native.y = val;
}
- (double)z {
return native.z;
}
- (void)setZ:(double)val {
native.z = val;
}
- (cv::Point3d&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0 z:0];
}
- (instancetype)initWithX:(double)x y:(double)y z:(double)z {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.z = z;
}
return self;
}
- (instancetype)initWithPoint:(Point2d*)point {
return [self initWithX:point.x y:point.y z:0];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].doubleValue : 0.0;
self.y = (vals != nil && vals.count > 1) ? vals[1].doubleValue : 0.0;
self.z = (vals != nil && vals.count > 2) ? vals[2].doubleValue : 0.0;
}
- (Point3d*) clone {
return [[Point3d alloc] initWithX:self.x y:self.y z:self.z];
}
- (double)dot:(Point3d*)point {
return self.x * point.x + self.y * point.y + self.z * point.z;
}
- (Point3d*)cross:(Point3d*)point {
return [[Point3d alloc] initWithX:(self.y * point.z - self.z * point.y) y:(self.z * point.x - self.x * point.z) z:(self.x * point.y - self.y * point.x)];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point3d class]]) {
return NO;
} else {
Point3d* point = (Point3d*)other;
return self.x == point.x && self.y == point.y && self.z == point.z;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
int64_t temp = DOUBLE_TO_BITS(self.x);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.y);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.z);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point3 {%lf,%lf,%lf}", self.x, self.y, self.z];
}
@end

@ -0,0 +1,85 @@
//
// Point3f.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Point2f;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a three dimensional point the coordinate values of which are of type `float`
*/
@interface Point3f : NSObject
# pragma mark - Properties
@property float x;
@property float y;
@property float z;
#ifdef __cplusplus
@property(readonly) cv::Point3f& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(float)x y:(float)y z:(float)z;
- (instancetype)initWithPoint:(Point2f*)point;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point3f*)point;
/**
* Calculate the cross product of this point and another point
* @param point The other point
*/
- (Point3f*)cross:(Point3f*)point;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point3f*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString *)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,111 @@
//
// Point3f.mm
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point3f.h"
#import "Point2f.h"
#import "CVObjcUtil.h"
@implementation Point3f {
cv::Point3f native;
}
- (float)x {
return native.x;
}
- (void)setX:(float)val {
native.x = val;
}
- (float)y {
return native.y;
}
- (void)setY:(float)val {
native.y = val;
}
- (float)z {
return native.z;
}
- (void)setZ:(float)val {
native.z = val;
}
- (cv::Point3f&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0 z:0];
}
- (instancetype)initWithX:(float)x y:(float)y z:(float)z {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.z = z;
}
return self;
}
- (instancetype)initWithPoint:(Point2f*)point {
return [self initWithX:point.x y:point.y z:0];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].floatValue : 0.0;
self.y = (vals != nil && vals.count > 1) ? vals[1].floatValue : 0.0;
self.z = (vals != nil && vals.count > 2) ? vals[2].floatValue : 0.0;
}
- (Point3f*) clone {
return [[Point3f alloc] initWithX:self.x y:self.y z:self.z];
}
- (double)dot:(Point3f*)point {
return self.x * point.x + self.y * point.y + self.z * point.z;
}
- (Point3f*)cross:(Point3f*)point {
return [[Point3f alloc] initWithX:(self.y * point.z - self.z * point.y) y:(self.z * point.x - self.x * point.z) z:(self.x * point.y - self.y * point.x)];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point3f class]]) {
return NO;
} else {
Point3f* point = (Point3f*)other;
return self.x == point.x && self.y == point.y && self.z == point.z;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + FLOAT_TO_BITS(self.x);
result = prime * result + FLOAT_TO_BITS(self.y);
result = prime * result + FLOAT_TO_BITS(self.z);
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point3f {%f,%f,%f}", self.x, self.y, self.z];
}
@end

@ -0,0 +1,84 @@
//
// Point3i.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
@class Point2i;
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a three dimensional point the coordinate values of which are of type `int`
*/
@interface Point3i : NSObject
# pragma mark - Properties
@property int x;
@property int y;
@property int z;
#ifdef __cplusplus
@property(readonly) cv::Point3i& nativeRef;
#endif
# pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(int)x y:(int)y z:(int)z;
- (instancetype)initWithPoint:(Point2i*)point;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
# pragma mark - Methods
/**
* Calculate the dot product of this point and another point
* @param point The other point
*/
- (double)dot:(Point3i*)point;
/**
* Calculate the cross product of this point and another point
* @param point The other point
*/
- (Point3i*)cross:(Point3i*)point;
/**
* Set the point coordinates from the values of an array
* @param vals The array of values from which to set the coordinates
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Point3i*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)other;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString *)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,111 @@
//
// Point3i.mm
//
// Created by Giles Payne on 2019/10/09.
//
#import "Point3i.h"
#import "Point2i.h"
#import "CVObjcUtil.h"
@implementation Point3i {
cv::Point3i native;
}
- (int)x {
return native.x;
}
- (void)setX:(int)val {
native.x = val;
}
- (int)y {
return native.y;
}
- (void)setY:(int)val {
native.y = val;
}
- (int)z {
return native.z;
}
- (void)setZ:(int)val {
native.z = val;
}
- (cv::Point3i&)nativeRef {
return native;
}
- (instancetype)init {
return [self initWithX:0 y:0 z:0];
}
- (instancetype)initWithX:(int)x y:(int)y z:(int)z {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.z = z;
}
return self;
}
- (instancetype)initWithPoint:(Point2i*)point {
return [self initWithX:point.x y:point.y z:0];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].intValue : 0;
self.z = (vals != nil && vals.count > 2) ? vals[2].intValue : 0;
}
- (Point3i*) clone {
return [[Point3i alloc] initWithX:self.x y:self.y z:self.z];
}
- (double)dot:(Point3i*)point {
return self.x * point.x + self.y * point.y + self.z * point.z;
}
- (Point3i*)cross:(Point3i*)point {
return [[Point3i alloc] initWithX:(self.y * point.z - self.z * point.y) y:(self.z * point.x - self.x * point.z) z:(self.x * point.y - self.y * point.x)];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Point3i class]]) {
return NO;
} else {
Point3i* point = (Point3i*)other;
return self.x == point.x && self.y == point.y && self.z == point.z;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.x;
result = prime * result + self.y;
result = prime * result + self.z;
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Point3i {%d,%d,%d}", self.x, self.y, self.z];
}
@end

@ -0,0 +1,93 @@
//
// Range.h
//
// Created by Giles Payne on 2019/10/08.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a range of dimension indices
*/
@interface Range : NSObject
#pragma mark - Properties
@property int start;
@property int end;
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithStart:(int)start end:(int)end;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#pragma mark - Methods
/**
* The size of the range
*/
- (int)size;
/**
* Determines if the range is empty
*/
- (BOOL)empty;
/**
* Creates a range representing all possible indices for a particular dimension
*/
+ (Range*)all;
/**
* Calculates the intersection of the range with another range
* @param r1 The other range
*/
- (Range*)intersection:(Range*)r1;
/**
* Adjusts each of the range limts
* @param delta The amount of the adjustment
*/
- (Range*)shift:(int)delta;
/**
* Set the range limits from the values of an array
* @param vals The array of values from which to set the range limits
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
# pragma mark - Common Methods
/**
* Clone object
*/
- (Range*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)object;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,86 @@
//
// Range.m
//
// Created by Giles Payne on 2019/10/08.
//
#import "Range.h"
@implementation Range
- (instancetype)init {
return [self initWithStart:0 end: 0];
}
- (instancetype)initWithStart:(int)start end:(int)end {
self = [super init];
if (self != nil) {
self.start = start;
self.end = end;
}
return self;
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [self init];
if (self != nil) {
[self set:vals];
}
return self;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.start = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.end = (vals != nil && vals.count > 1 ) ? vals[1].intValue : 0;
}
- (int)size {
return [self empty] ? 0 : self.end - self.start;
}
- (BOOL)empty {
return self.end <= self.start;
}
+ (Range*)all {
return [[Range alloc] initWithStart:INT_MIN end:INT_MAX];
}
- (Range*)intersection:(Range*)r1 {
Range* out = [[Range alloc] initWithStart:MAX(r1.start, self.start) end:MIN(r1.end, self.end)];
out.end = MAX(out.end, out.start);
return out;
}
- (Range*)shift:(int)delta {
return [[Range alloc] initWithStart:self.start + delta end:self.end + delta];
}
- (Range*)clone {
return [[Range alloc] initWithStart:self.start end:self.end];
}
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Range class]]) {
return NO;
} else {
Range* it = (Range*)other;
return self.start == it.start && self.end == it.end;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.start;
result = prime * result + self.end;
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Range {%d, %d}", self.start, self.end];
}
@end

@ -0,0 +1,111 @@
//
// Rect.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
@class Point2d;
@class Size2d;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a rectange the coordinate and dimension values of which are of type `double`
*/
@interface Rect2d : NSObject
#pragma mark - Properties
@property double x;
@property double y;
@property double width;
@property double height;
#ifdef __cplusplus
@property(readonly) cv::Rect2d& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(double)x y:(double)y width:(double)width height:(double)height;
- (instancetype)initWithPoint:(Point2d*)point1 point:(Point2d*)point2;
- (instancetype)initWithPoint:(Point2d*)point size:(Size2d*)size;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Rect2d&)point;
#endif
#pragma mark - Methods
/**
* Returns the top left coordinate of the rectangle
*/
- (Point2d*)tl;
/**
* Returns the bottom right coordinate of the rectangle
*/
- (Point2d*)br;
/**
* Returns the size of the rectangle
*/
- (Size2d*)size;
/**
* Returns the area of the rectangle
*/
- (double)area;
/**
* Determines if the rectangle is empty
*/
- (BOOL)empty;
/**
* Determines if the rectangle contains a given point
* @param point The point
*/
- (BOOL)contains:(Point2d*)point;
/**
* Set the rectangle coordinates and dimensions from the values of an array
* @param vals The array of values from which to set the rectangle coordinates and dimensions
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
#pragma mark - Common Methods
/**
* Clone object
*/
- (Rect2d*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)object;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,155 @@
//
// Rect2d.mm
//
// Created by Giles Payne on 2019/10/09.
//
#import "Rect2d.h"
#import "Point2d.h"
#import "Size2d.h"
#import "CVObjcUtil.h"
@implementation Rect2d {
cv::Rect2d native;
}
- (double)x {
return native.x;
}
- (void)setX:(double)val {
native.x = val;
}
- (double)y {
return native.y;
}
- (void)setY:(double)val {
native.y = val;
}
- (double)width {
return native.width;
}
- (void)setWidth:(double)val {
native.width = val;
}
- (double)height {
return native.height;
}
- (void)setHeight:(double)val {
native.height = val;
}
- (cv::Rect2d&)nativeRef {
return native;
}
- (instancetype)initWithX:(double)x y:(double)y width:(double)width height:(double)height {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.width = width;
self.height = height;
}
return self;
}
- (instancetype)init {
return [self initWithX:0 y:0 width:0 height:0];
}
- (instancetype)initWithPoint:(Point2d*)point1 point:(Point2d*)point2 {
int x = (point1.x < point2.x ? point1.x : point2.x);
int y = (point1.y < point2.y ? point1.y : point2.y);
int width = (point1.x > point2.x ? point1.x : point2.x) - x;
int height = (point1.y > point2.y ? point1.y : point2.y) - y;
return [self initWithX:x y:y width:width height:height];
}
- (instancetype)initWithPoint:(Point2d*)point size:(Size2d*)size {
return [self initWithX:point.x y:point.y width:size.width height:size.height];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Rect2d&)rect {
return [[Rect2d alloc] initWithX:rect.x y:rect.y width:rect.width height:rect.height];
}
- (Rect2d*)clone {
return [[Rect2d alloc] initWithX:self.x y:self.y width:self.width height:self.height];
}
- (Point2d*)tl {
return [[Point2d alloc] initWithX:self.x y:self.y];
}
- (Point2d*)br {
return [[Point2d alloc] initWithX:self.x + self.width y:self.y + self.height];
}
- (Size2d*)size {
return [[Size2d alloc] initWithWidth:self.width height:self.height];
}
- (double)area {
return self.width * self.height;
}
- (BOOL)empty {
return self.width <= 0 || self.height <= 0;
}
- (BOOL)contains:(Point2d*)point {
return self.x <= point.x && point.x < self.x + self.width && self.y <= point.y && point.y < self.y + self.height;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].intValue : 0;
self.width = (vals != nil && vals.count > 2) ? vals[2].intValue : 0;
self.height = (vals != nil && vals.count > 3) ? vals[3].intValue : 0;
}
- (BOOL)isEqual:(id)other{
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Rect2d class]]) {
return NO;
} else {
Rect2d* rect = (Rect2d*)other;
return self.x == rect.x && self.y == rect.y && self.width == rect.width && self.height == rect.height;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
int64_t temp = DOUBLE_TO_BITS(self.x);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.y);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.width);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
temp = DOUBLE_TO_BITS(self.height);
result = prime * result + (int32_t) (temp ^ (temp >> 32));
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Rect2d {%lf,%lf,%lf,%lf}", self.x, self.y, self.width, self.height];
}
@end

@ -0,0 +1,111 @@
//
// Rect.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
@class Point2f;
@class Size2f;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a rectange the coordinate and dimension values of which are of type `float`
*/
@interface Rect2f : NSObject
#pragma mark - Properties
@property float x;
@property float y;
@property float width;
@property float height;
#ifdef __cplusplus
@property(readonly) cv::Rect2f& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(float)x y:(float)y width:(float)width height:(float)height;
- (instancetype)initWithPoint:(Point2f*)point1 point:(Point2f*)point2;
- (instancetype)initWithPoint:(Point2f*)point size:(Size2f*)size;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Rect2f&)point;
#endif
#pragma mark - Methods
/**
* Returns the top left coordinate of the rectangle
*/
- (Point2f*)tl;
/**
* Returns the bottom right coordinate of the rectangle
*/
- (Point2f*)br;
/**
* Returns the size of the rectangle
*/
- (Size2f*)size;
/**
* Returns the area of the rectangle
*/
- (double)area;
/**
* Determines if the rectangle is empty
*/
- (BOOL)empty;
/**
* Determines if the rectangle contains a given point
* @param point The point
*/
- (BOOL)contains:(Point2f*)point;
/**
* Set the rectangle coordinates and dimensions from the values of an array
* @param vals The array of values from which to set the rectangle coordinates and dimensions
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
#pragma mark - Common Methods
/**
* Clone object
*/
- (Rect2f*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)object;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,151 @@
//
// Rect2d.mm
//
// Created by Giles Payne on 2019/10/09.
//
#import "Rect2f.h"
#import "Point2f.h"
#import "Size2f.h"
#import "CVObjcUtil.h"
@implementation Rect2f {
cv::Rect2f native;
}
- (float)x {
return native.x;
}
- (void)setX:(float)val {
native.x = val;
}
- (float)y {
return native.y;
}
- (void)setY:(float)val {
native.y = val;
}
- (float)width {
return native.width;
}
- (void)setWidth:(float)val {
native.width = val;
}
- (float)height {
return native.height;
}
- (void)setHeight:(float)val {
native.height = val;
}
- (cv::Rect2f&)nativeRef {
return native;
}
- (instancetype)initWithX:(float)x y:(float)y width:(float)width height:(float)height {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.width = width;
self.height = height;
}
return self;
}
- (instancetype)init {
return [self initWithX:0 y:0 width:0 height:0];
}
- (instancetype)initWithPoint:(Point2f*)point1 point:(Point2f*)point2 {
int x = (point1.x < point2.x ? point1.x : point2.x);
int y = (point1.y < point2.y ? point1.y : point2.y);
int width = (point1.x > point2.x ? point1.x : point2.x) - x;
int height = (point1.y > point2.y ? point1.y : point2.y) - y;
return [self initWithX:x y:y width:width height:height];
}
- (instancetype)initWithPoint:(Point2f*)point size:(Size2f*)size {
return [self initWithX:point.x y:point.y width:size.width height:size.height];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Rect2f&)rect {
return [[Rect2f alloc] initWithX:rect.x y:rect.y width:rect.width height:rect.height];
}
- (Rect2f*)clone {
return [[Rect2f alloc] initWithX:self.x y:self.y width:self.width height:self.height];
}
- (Point2f*)tl {
return [[Point2f alloc] initWithX:self.x y:self.y];
}
- (Point2f*)br {
return [[Point2f alloc] initWithX:self.x + self.width y:self.y + self.height];
}
- (Size2f*)size {
return [[Size2f alloc] initWithWidth:self.width height:self.height];
}
- (double)area {
return self.width * self.height;
}
- (BOOL)empty {
return self.width <= 0 || self.height <= 0;
}
- (BOOL)contains:(Point2f*)point {
return self.x <= point.x && point.x < self.x + self.width && self.y <= point.y && point.y < self.y + self.height;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].floatValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].floatValue : 0;
self.width = (vals != nil && vals.count > 2) ? vals[2].floatValue : 0;
self.height = (vals != nil && vals.count > 3) ? vals[3].floatValue : 0;
}
- (BOOL)isEqual:(id)other{
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Rect2f class]]) {
return NO;
} else {
Rect2f* rect = (Rect2f*)other;
return self.x == rect.x && self.y == rect.y && self.width == rect.width && self.height == rect.height;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + FLOAT_TO_BITS(self.x);
result = prime * result + FLOAT_TO_BITS(self.y);
result = prime * result + FLOAT_TO_BITS(self.width);
result = prime * result + FLOAT_TO_BITS(self.height);
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Rect2f {%lf,%lf,%lf,%lf}", self.x, self.y, self.width, self.height];
}
@end

@ -0,0 +1,112 @@
//
// Rect2i.h
//
// Created by Giles Payne on 2019/10/09.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
@class Point2i;
@class Size2i;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a rectange the coordinate and dimension values of which are of type `int`
*/
NS_SWIFT_NAME(Rect)
@interface Rect2i : NSObject
#pragma mark - Properties
@property int x;
@property int y;
@property int width;
@property int height;
#ifdef __cplusplus
@property(readonly) cv::Rect2i& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithX:(int)x y:(int)y width:(int)width height:(int)height;
- (instancetype)initWithPoint:(Point2i*)point1 point:(Point2i*)point2;
- (instancetype)initWithPoint:(Point2i*)point size:(Size2i*)size;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::Rect&)point;
#endif
#pragma mark - Methods
/**
* Returns the top left coordinate of the rectangle
*/
- (Point2i*)tl;
/**
* Returns the bottom right coordinate of the rectangle
*/
- (Point2i*)br;
/**
* Returns the size of the rectangle
*/
- (Size2i*)size;
/**
* Returns the area of the rectangle
*/
- (double)area;
/**
* Determines if the rectangle is empty
*/
- (BOOL)empty;
/**
* Determines if the rectangle contains a given point
* @param point The point
*/
- (BOOL)contains:(Point2i*)point;
/**
* Set the rectangle coordinates and dimensions from the values of an array
* @param vals The array of values from which to set the rectangle coordinates and dimensions
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
#pragma mark - Common Methods
/**
* Clone object
*/
- (Rect2i*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)object;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,150 @@
//
// Rect2i.m
//
// Created by Giles Payne on 2019/10/09.
//
#import "Rect2i.h"
#import "Point2i.h"
#import "Size2i.h"
@implementation Rect2i {
cv::Rect2i native;
}
- (int)x {
return native.x;
}
- (void)setX:(int)val {
native.x = val;
}
- (int)y {
return native.y;
}
- (void)setY:(int)val {
native.y = val;
}
- (int)width {
return native.width;
}
- (void)setWidth:(int)val {
native.width = val;
}
- (int)height {
return native.height;
}
- (void)setHeight:(int)val {
native.height = val;
}
- (cv::Rect&)nativeRef {
return native;
}
- (instancetype)initWithX:(int)x y:(int)y width:(int)width height:(int)height {
self = [super init];
if (self) {
self.x = x;
self.y = y;
self.width = width;
self.height = height;
}
return self;
}
- (instancetype)init {
return [self initWithX:0 y:0 width:0 height:0];
}
- (instancetype)initWithPoint:(Point2i*)point1 point:(Point2i*)point2 {
int x = (point1.x < point2.x ? point1.x : point2.x);
int y = (point1.y < point2.y ? point1.y : point2.y);
int width = (point1.x > point2.x ? point1.x : point2.x) - x;
int height = (point1.y > point2.y ? point1.y : point2.y) - y;
return [self initWithX:x y:y width:width height:height];
}
- (instancetype)initWithPoint:(Point2i*)point size:(Size2i*)size {
return [self initWithX:point.x y:point.y width:size.width height:size.height];
}
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals {
self = [super init];
if (self) {
[self set:vals];
}
return self;
}
+ (instancetype)fromNative:(cv::Rect&)rect {
return [[Rect2i alloc] initWithX:rect.x y:rect.y width:rect.width height:rect.height];
}
- (Rect2i*)clone {
return [[Rect2i alloc] initWithX:self.x y:self.y width:self.width height:self.height];
}
- (Point2i*)tl {
return [[Point2i alloc] initWithX:self.x y:self.y];
}
- (Point2i*)br {
return [[Point2i alloc] initWithX:self.x + self.width y:self.y + self.height];
}
- (Size2i*)size {
return [[Size2i alloc] initWithWidth:self.width height:self.height];
}
- (double)area {
return self.width * self.height;
}
- (BOOL)empty {
return self.width <= 0 || self.height <= 0;
}
- (BOOL)contains:(Point2i*)point {
return self.x <= point.x && point.x < self.x + self.width && self.y <= point.y && point.y < self.y + self.height;
}
- (void)set:(NSArray<NSNumber*>*)vals {
self.x = (vals != nil && vals.count > 0) ? vals[0].intValue : 0;
self.y = (vals != nil && vals.count > 1) ? vals[1].intValue : 0;
self.width = (vals != nil && vals.count > 2) ? vals[2].intValue : 0;
self.height = (vals != nil && vals.count > 3) ? vals[3].intValue : 0;
}
- (BOOL)isEqual:(id)other{
if (other == self) {
return YES;
} else if (![other isKindOfClass:[Rect2i class]]) {
return NO;
} else {
Rect2i* rect = (Rect2i*)other;
return self.x == rect.x && self.y == rect.y && self.width == rect.width && self.height == rect.height;
}
}
- (NSUInteger)hash {
int prime = 31;
uint32_t result = 1;
result = prime * result + self.x;
result = prime * result + self.y;
result = prime * result + self.width;
result = prime * result + self.height;
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"Rect2i {%d,%d,%d,%d}", self.x, self.y, self.width, self.height];
}
@end

@ -0,0 +1,86 @@
//
// RotatedRect.h
//
// Created by Giles Payne on 2019/12/26.
//
#pragma once
#ifdef __cplusplus
#import "opencv.hpp"
#endif
@class Point2f;
@class Size2f;
@class Rect2f;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Represents a rotated rectangle on a plane
*/
@interface RotatedRect : NSObject
#pragma mark - Properties
@property Point2f* center;
@property Size2f* size;
@property double angle;
#ifdef __cplusplus
@property(readonly) cv::RotatedRect& nativeRef;
#endif
#pragma mark - Constructors
- (instancetype)init;
- (instancetype)initWithCenter:(Point2f*)center size:(Size2f*)size angle:(double)angle;
- (instancetype)initWithVals:(NSArray<NSNumber*>*)vals;
#ifdef __cplusplus
+ (instancetype)fromNative:(cv::RotatedRect&)rotatedRect;
#endif
#pragma mark - Methods
/**
* Returns the corner points of the rotated rectangle as an array
*/
- (NSArray<Point2f*>*)points;
/**
* Returns the bounding (non-rotated) rectangle of the rotated rectangle
*/
- (Rect2f*)boundingRect;
/**
* Set the rotated rectangle coordinates, dimensions and angle of rotation from the values of an array
* @param vals The array of values from which to set the rotated rectangle coordinates, dimensions and angle of rotation
*/
- (void)set:(NSArray<NSNumber*>*)vals NS_SWIFT_NAME(set(vals:));
#pragma mark - Common Methods
/**
* Clone object
*/
- (RotatedRect*)clone;
/**
* Compare for equality
* @param other Object to compare
*/
- (BOOL)isEqual:(nullable id)object;
/**
* Calculate hash value for this object
*/
- (NSUInteger)hash;
/**
* Returns a string that describes the contents of the object
*/
- (NSString*)description;
@end
NS_ASSUME_NONNULL_END

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save