From 4ee72813e0884841a28fe0e6328e69d4a0644a4b Mon Sep 17 00:00:00 2001 From: rainyl Date: Wed, 27 Nov 2024 22:20:34 +0800 Subject: [PATCH 1/5] add isContourConvex, intersectConvexConvex --- packages/dartcv/lib/src/g/core.yaml | 8 +-- packages/dartcv/lib/src/g/imgproc.g.dart | 51 +++++++++++++++++++ packages/dartcv/lib/src/g/imgproc.yaml | 4 ++ packages/dartcv/lib/src/imgproc/imgproc.dart | 26 ++++++++++ .../dartcv/lib/src/imgproc/imgproc_async.dart | 21 ++++++++ packages/dartcv/src | 2 +- .../test/imgproc/imgproc_async_test.dart | 4 ++ .../dartcv/test/imgproc/imgproc_test.dart | 10 ++++ 8 files changed, 121 insertions(+), 5 deletions(-) diff --git a/packages/dartcv/lib/src/g/core.yaml b/packages/dartcv/lib/src/g/core.yaml index 7e977632..b1e87a0f 100644 --- a/packages/dartcv/lib/src/g/core.yaml +++ b/packages/dartcv/lib/src/g/core.yaml @@ -628,12 +628,12 @@ files: name: registerErrorCallback c:@F@setLogLevel: name: setLogLevel - c:@T@double_t: - name: double_t - c:@T@float_t: - name: float_t c:exception.h@T@ErrorCallback: name: ErrorCallback + c:math.h@T@double_t: + name: double_t + c:math.h@T@float_t: + name: float_t c:types.h@T@CvPoint: name: CvPoint c:types.h@T@CvRect: diff --git a/packages/dartcv/lib/src/g/imgproc.g.dart b/packages/dartcv/lib/src/g/imgproc.g.dart index d71616b4..37711f99 100644 --- a/packages/dartcv/lib/src/g/imgproc.g.dart +++ b/packages/dartcv/lib/src/g/imgproc.g.dart @@ -2714,6 +2714,43 @@ class CvNativeImgproc { ffi.Pointer Function( Mat, Mat, Mat, Mat, int, int, imp1.CvCallback_0)>(); + ffi.Pointer cv_intersectConvexConvex( + VecPoint p1, + VecPoint p2, + ffi.Pointer p12, + bool handleNested, + ffi.Pointer rval, + imp1.CvCallback_0 callback, + ) { + return _cv_intersectConvexConvex( + p1, + p2, + p12, + handleNested, + rval, + callback, + ); + } + + late final _cv_intersectConvexConvexPtr = _lookup< + ffi.NativeFunction< + ffi.Pointer Function( + VecPoint, + VecPoint, + ffi.Pointer, + ffi.Bool, + ffi.Pointer, + imp1.CvCallback_0)>>('cv_intersectConvexConvex'); + late final _cv_intersectConvexConvex = + _cv_intersectConvexConvexPtr.asFunction< + ffi.Pointer Function( + VecPoint, + VecPoint, + ffi.Pointer, + bool, + ffi.Pointer, + imp1.CvCallback_0)>(); + ffi.Pointer cv_invertAffineTransform( Mat src, Mat dst, @@ -2734,6 +2771,20 @@ class CvNativeImgproc { _cv_invertAffineTransformPtr.asFunction< ffi.Pointer Function(Mat, Mat, imp1.CvCallback_0)>(); + bool cv_isContourConvex( + VecPoint contour, + ) { + return _cv_isContourConvex( + contour, + ); + } + + late final _cv_isContourConvexPtr = + _lookup>( + 'cv_isContourConvex'); + late final _cv_isContourConvex = + _cv_isContourConvexPtr.asFunction(); + ffi.Pointer cv_line( Mat img, CvPoint pt1, diff --git a/packages/dartcv/lib/src/g/imgproc.yaml b/packages/dartcv/lib/src/g/imgproc.yaml index 9dbe7fd8..f3a98401 100644 --- a/packages/dartcv/lib/src/g/imgproc.yaml +++ b/packages/dartcv/lib/src/g/imgproc.yaml @@ -206,8 +206,12 @@ files: name: cv_grabCut c:@F@cv_integral: name: cv_integral + c:@F@cv_intersectConvexConvex: + name: cv_intersectConvexConvex c:@F@cv_invertAffineTransform: name: cv_invertAffineTransform + c:@F@cv_isContourConvex: + name: cv_isContourConvex c:@F@cv_line: name: cv_line c:@F@cv_linearPolar: diff --git a/packages/dartcv/lib/src/imgproc/imgproc.dart b/packages/dartcv/lib/src/imgproc/imgproc.dart index 2b6b10d5..9bf9af03 100644 --- a/packages/dartcv/lib/src/imgproc/imgproc.dart +++ b/packages/dartcv/lib/src/imgproc/imgproc.dart @@ -1758,3 +1758,29 @@ Mat accumulateWeighted(InputArray src, InputOutputArray dst, double alpha, {Inpu } return dst; } + +/// Tests a contour convexity. +/// +/// The function tests whether the input contour is convex or not. +/// The contour must be simple, that is, without self-intersections. +/// Otherwise, the function output is undefined. +/// +/// https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga8abf8010377b58cbc16db6734d92941b +bool isContourConvex(VecPoint contour) => cimgproc.cv_isContourConvex(contour.ref); + +/// Finds intersection of two convex polygons. +/// +/// https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga06eed475945f155030f2135a7f25f11d +(double rval, VecPoint p12) intersectConvexConvex( + VecPoint p1, + VecPoint p2, { + VecPoint? p12, + bool handleNested = true, +}) { + final r = calloc(); + final pP12 = p12?.ptr ?? calloc(); + cvRun(() => cimgproc.cv_intersectConvexConvex(p1.ref, p2.ref, pP12, handleNested, r, ffi.nullptr)); + final rval = (r.value, p12 ?? VecPoint.fromPointer(pP12)); + calloc.free(r); + return rval; +} diff --git a/packages/dartcv/lib/src/imgproc/imgproc_async.dart b/packages/dartcv/lib/src/imgproc/imgproc_async.dart index 064986d8..db494772 100644 --- a/packages/dartcv/lib/src/imgproc/imgproc_async.dart +++ b/packages/dartcv/lib/src/imgproc/imgproc_async.dart @@ -2109,3 +2109,24 @@ Future accumulateWeightedAsync( ); } } + +/// Finds intersection of two convex polygons. +/// +/// https://docs.opencv.org/4.x/d3/dc0/group__imgproc__shape.html#ga06eed475945f155030f2135a7f25f11d +Future<(double rval, VecPoint p12)> intersectConvexConvexAsync( + VecPoint p1, + VecPoint p2, { + VecPoint? p12, + bool handleNested = true, +}) { + final r = calloc(); + final pP12 = p12?.ptr ?? calloc(); + return cvRunAsync0( + (callback) => cimgproc.cv_intersectConvexConvex(p1.ref, p2.ref, pP12, handleNested, r, callback), + (c) { + final rval = (r.value, p12 ?? VecPoint.fromPointer(pP12)); + calloc.free(r); + return c.complete(rval); + }, + ); +} diff --git a/packages/dartcv/src b/packages/dartcv/src index 9394c165..3ebed200 160000 --- a/packages/dartcv/src +++ b/packages/dartcv/src @@ -1 +1 @@ -Subproject commit 9394c165f3404a696209eb316d3a3e49cb7a8526 +Subproject commit 3ebed200b29390b117521be774a0eac9e00cb35c diff --git a/packages/dartcv/test/imgproc/imgproc_async_test.dart b/packages/dartcv/test/imgproc/imgproc_async_test.dart index 548b539b..5ed665c2 100644 --- a/packages/dartcv/test/imgproc/imgproc_async_test.dart +++ b/packages/dartcv/test/imgproc/imgproc_async_test.dart @@ -948,4 +948,8 @@ void main() async { expect(p[0], isIn([0, 1])); }); }); + + test('cv.intersectConvexConvexAsync', () { + // TODO add test + }); } diff --git a/packages/dartcv/test/imgproc/imgproc_test.dart b/packages/dartcv/test/imgproc/imgproc_test.dart index 891a50ed..b6fe254c 100644 --- a/packages/dartcv/test/imgproc/imgproc_test.dart +++ b/packages/dartcv/test/imgproc/imgproc_test.dart @@ -974,4 +974,14 @@ void main() async { expect(p[0], isIn([0, 1])); }); }); + + test('cv.isContourConvex', () { + final contour = [cv.Point(0, 0), cv.Point(0, 100), cv.Point(100, 0), cv.Point(100, 100)].asVec(); + final res = cv.isContourConvex(contour); + expect(res, true); + }); + + test('cv.intersectConvexConvex', () { + // TODO add test + }); } From 09fc7055e4bed8c157e07ae8d706466f3d49a00c Mon Sep 17 00:00:00 2001 From: rainyl Date: Wed, 27 Nov 2024 22:27:43 +0800 Subject: [PATCH 2/5] update dartcv_version to 4.10.0.6 --- packages/opencv_core/pubspec.yaml | 2 +- packages/opencv_dart/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencv_core/pubspec.yaml b/packages/opencv_core/pubspec.yaml index dfb3961c..b3b14fa8 100644 --- a/packages/opencv_core/pubspec.yaml +++ b/packages/opencv_core/pubspec.yaml @@ -5,7 +5,7 @@ description: | if you need them, please use `opencv_dart` instead. version: 1.3.3 opencv_version: 4.10.0+10 -dartcv_version: 4.10.0.5 +dartcv_version: 4.10.0.6 repository: https://github.com/rainyl/opencv_dart homepage: https://github.com/rainyl/opencv_dart/tree/main/packages/opencv_core diff --git a/packages/opencv_dart/pubspec.yaml b/packages/opencv_dart/pubspec.yaml index 7e569117..aa12317c 100644 --- a/packages/opencv_dart/pubspec.yaml +++ b/packages/opencv_dart/pubspec.yaml @@ -5,7 +5,7 @@ description: | please use `opencv_core` instead. version: 1.3.3 opencv_version: 4.10.0+10 -dartcv_version: 4.10.0.5 +dartcv_version: 4.10.0.6 repository: https://github.com/rainyl/opencv_dart homepage: https://github.com/rainyl/opencv_dart/tree/main/packages/opencv_dart From 42fe434a9535479300f4515a31232a65ec0caf48 Mon Sep 17 00:00:00 2001 From: rainyl Date: Wed, 27 Nov 2024 22:55:51 +0800 Subject: [PATCH 3/5] remove logging dependency --- packages/dartcv/lib/src/native_lib.dart | 4 +--- packages/dartcv/pubspec.yaml | 1 - packages/dartcv/test/imgproc/imgproc_async_test.dart | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/dartcv/lib/src/native_lib.dart b/packages/dartcv/lib/src/native_lib.dart index 9ffb431e..ae7914c5 100644 --- a/packages/dartcv/lib/src/native_lib.dart +++ b/packages/dartcv/lib/src/native_lib.dart @@ -6,8 +6,6 @@ import 'dart:ffi' as ffi; import 'dart:io'; -import 'package:logging/logging.dart'; - import 'g/calib3d.g.dart' as calib3d; import 'g/contrib.g.dart' as contrib; import 'g/core.g.dart' as core; @@ -42,7 +40,7 @@ ffi.DynamicLibrary loadNativeLibrary(String libName) { try { return ffi.DynamicLibrary.open(libPath); } catch (e) { - Logger("dartcv").warning("$e"); + print("Error loading $libPath, error: $e fallback to process."); return ffi.DynamicLibrary.process(); } } diff --git a/packages/dartcv/pubspec.yaml b/packages/dartcv/pubspec.yaml index 8147efbe..927ee646 100644 --- a/packages/dartcv/pubspec.yaml +++ b/packages/dartcv/pubspec.yaml @@ -11,7 +11,6 @@ environment: dependencies: ffi: ^2.1.3 - logging: ^1.3.0 dev_dependencies: ffigen: ">=13.0.0 <15.0.0" diff --git a/packages/dartcv/test/imgproc/imgproc_async_test.dart b/packages/dartcv/test/imgproc/imgproc_async_test.dart index 5ed665c2..d880d7ad 100644 --- a/packages/dartcv/test/imgproc/imgproc_async_test.dart +++ b/packages/dartcv/test/imgproc/imgproc_async_test.dart @@ -949,7 +949,7 @@ void main() async { }); }); - test('cv.intersectConvexConvexAsync', () { + test('cv.intersectConvexConvexAsync', () async { // TODO add test }); } From e689352230d3d5d8787840ff5950b1b43203a74a Mon Sep 17 00:00:00 2001 From: rainyl Date: Thu, 28 Nov 2024 21:10:36 +0800 Subject: [PATCH 4/5] add test for isContourConvex and intersectConvexConvex --- .gitignore | 1 + packages/dartcv/src | 2 +- .../dartcv/test/images_out/intersections.png | Bin 0 -> 19467 bytes .../test/imgproc/imgproc_async_test.dart | 115 +++++++++++++++- .../dartcv/test/imgproc/imgproc_test.dart | 128 +++++++++++++++++- 5 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 packages/dartcv/test/images_out/intersections.png diff --git a/.gitignore b/.gitignore index 03de607c..ca5beea3 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,4 @@ doc/api/ .flutter-plugins .flutter-plugins-dependencies +Podfile.lock diff --git a/packages/dartcv/src b/packages/dartcv/src index 75b1be38..7bd81ecc 160000 --- a/packages/dartcv/src +++ b/packages/dartcv/src @@ -1 +1 @@ -Subproject commit 75b1be38ac50c58a5c7e18d80a4826a0124c513f +Subproject commit 7bd81ecc6273087926761a0e6e64791e3fecb1d7 diff --git a/packages/dartcv/test/images_out/intersections.png b/packages/dartcv/test/images_out/intersections.png new file mode 100644 index 0000000000000000000000000000000000000000..4ccd00b185d5382f9e359df951fdda45e58320dd GIT binary patch literal 19467 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 + [topLeft, cv.Point(bottomRiht.x, topLeft.y), bottomRiht, cv.Point(topLeft.x, bottomRiht.y)].asVec(); + + Future drawIntersection(cv.Mat image, cv.VecPoint p1, cv.VecPoint p2, + {bool handleNested = true}) async { + final (intersectArea, intersectionPolygon) = + await cv.intersectConvexConvexAsync(p1, p2, handleNested: handleNested); + if (intersectArea > 0) { + final fillColor = + !cv.isContourConvex(p1) || !cv.isContourConvex(p2) ? cv.Scalar(0, 0, 255) : cv.Scalar.all(200); + await cv.fillPolyAsync(image, cv.VecVecPoint.fromVecPoint(intersectionPolygon), fillColor); + } + await cv.polylinesAsync(image, cv.VecVecPoint.fromVecPoint(intersectionPolygon), true, cv.Scalar.black); + return intersectArea; + } + + Future drawDescription( + cv.Mat image, int intersectionArea, String description, cv.Point origin) async { + final caption = "Intersection area: $intersectionArea$description"; + await cv.putTextAsync(image, caption, origin, cv.FONT_HERSHEY_SIMPLEX, 0.6, cv.Scalar.black); + } + + // start testing + final image = cv.Mat.fromScalar(610, 550, cv.MatType.CV_8UC3, cv.Scalar.white); + double intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 10), cv.Point(50, 50)), + makeRectangle(cv.Point(20, 20), cv.Point(60, 60)), + ); + await drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 40)); + + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 70), cv.Point(35, 95)), + makeRectangle(cv.Point(35, 95), cv.Point(60, 120)), + ); + await drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 100)); + + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 130), cv.Point(60, 180)), + makeRectangle(cv.Point(20, 140), cv.Point(50, 170)), + handleNested: true, + ); + await drawDescription(image, intersectionArea.toInt(), " (handleNested true)", cv.Point(70, 160)); + + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 250), cv.Point(60, 300)), + makeRectangle(cv.Point(20, 250), cv.Point(50, 290)), + handleNested: true, + ); + + await drawDescription(image, intersectionArea.toInt(), " (handleNested true)", cv.Point(70, 280)); + + // These rectangles share an edge so handleNested can be false and an intersection is still found + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 310), cv.Point(60, 360)), + makeRectangle(cv.Point(20, 310), cv.Point(50, 350)), + handleNested: false, + ); + + await drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 340)); + + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 370), cv.Point(60, 420)), + makeRectangle(cv.Point(20, 371), cv.Point(50, 410)), + handleNested: false, + ); + + await drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 400)); + + // A vertex of the triangle lies on an edge of the rectangle so handleNested can be false and an intersection is still found + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 430), cv.Point(60, 480)), + [cv.Point(35, 430), cv.Point(20, 470), cv.Point(50, 470)].asVec(), + handleNested: false, + ); + + await drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 460)); + + // Show intersection of overlapping rectangle and triangle + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 490), cv.Point(40, 540)), + [cv.Point(25, 500), cv.Point(25, 530), cv.Point(60, 515)].asVec(), + handleNested: false, + ); + + await drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 520)); + + // This concave polygon is invalid input to intersectConvexConvex so it returns an invalid intersection + final cv.VecPoint notConvex = [ + cv.Point(25, 560), + cv.Point(25, 590), + cv.Point(45, 580), + cv.Point(60, 600), + cv.Point(60, 550), + cv.Point(45, 570), + ].asVec(); + intersectionArea = await drawIntersection( + image, + makeRectangle(cv.Point(10, 550), cv.Point(50, 600)), + notConvex, + handleNested: false, + ); + + await drawDescription(image, intersectionArea.toInt(), " (invalid input: not convex)", cv.Point(70, 580)); + + await cv.imwriteAsync("test/images_out/intersections.png", image); }); } diff --git a/packages/dartcv/test/imgproc/imgproc_test.dart b/packages/dartcv/test/imgproc/imgproc_test.dart index b6fe254c..bedcce1b 100644 --- a/packages/dartcv/test/imgproc/imgproc_test.dart +++ b/packages/dartcv/test/imgproc/imgproc_test.dart @@ -976,12 +976,134 @@ void main() async { }); test('cv.isContourConvex', () { - final contour = [cv.Point(0, 0), cv.Point(0, 100), cv.Point(100, 0), cv.Point(100, 100)].asVec(); - final res = cv.isContourConvex(contour); + final rectangle = [cv.Point(0, 0), cv.Point(100, 0), cv.Point(100, 100), cv.Point(0, 100)].asVec(); + final res = cv.isContourConvex(rectangle); expect(res, true); + + final notConvex = [ + cv.Point(25, 560), + cv.Point(25, 590), + cv.Point(45, 580), + cv.Point(60, 600), + cv.Point(60, 550), + cv.Point(45, 570), + ].asVec(); + expect(cv.isContourConvex(notConvex), false); }); + // https://docs.opencv.org/4.x/df/da5/samples_2cpp_2intersectExample_8cpp-example.html test('cv.intersectConvexConvex', () { - // TODO add test + // helper functions + cv.VecPoint makeRectangle(cv.Point topLeft, cv.Point bottomRiht) => + [topLeft, cv.Point(bottomRiht.x, topLeft.y), bottomRiht, cv.Point(topLeft.x, bottomRiht.y)].asVec(); + + double drawIntersection(cv.Mat image, cv.VecPoint p1, cv.VecPoint p2, {bool handleNested = true}) { + final (intersectArea, intersectionPolygon) = + cv.intersectConvexConvex(p1, p2, handleNested: handleNested); + if (intersectArea > 0) { + final fillColor = + !cv.isContourConvex(p1) || !cv.isContourConvex(p2) ? cv.Scalar(0, 0, 255) : cv.Scalar.all(200); + cv.fillPoly(image, cv.VecVecPoint.fromVecPoint(intersectionPolygon), fillColor); + } + cv.polylines(image, cv.VecVecPoint.fromVecPoint(intersectionPolygon), true, cv.Scalar.black); + return intersectArea; + } + + void drawDescription(cv.Mat image, int intersectionArea, String description, cv.Point origin) { + final caption = "Intersection area: $intersectionArea$description"; + cv.putText(image, caption, origin, cv.FONT_HERSHEY_SIMPLEX, 0.6, cv.Scalar.black); + } + + // start testing + final image = cv.Mat.fromScalar(610, 550, cv.MatType.CV_8UC3, cv.Scalar.white); + double intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 10), cv.Point(50, 50)), + makeRectangle(cv.Point(20, 20), cv.Point(60, 60)), + ); + drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 40)); + + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 70), cv.Point(35, 95)), + makeRectangle(cv.Point(35, 95), cv.Point(60, 120)), + ); + drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 100)); + + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 130), cv.Point(60, 180)), + makeRectangle(cv.Point(20, 140), cv.Point(50, 170)), + handleNested: true, + ); + drawDescription(image, intersectionArea.toInt(), " (handleNested true)", cv.Point(70, 160)); + + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 250), cv.Point(60, 300)), + makeRectangle(cv.Point(20, 250), cv.Point(50, 290)), + handleNested: true, + ); + + drawDescription(image, intersectionArea.toInt(), " (handleNested true)", cv.Point(70, 280)); + + // These rectangles share an edge so handleNested can be false and an intersection is still found + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 310), cv.Point(60, 360)), + makeRectangle(cv.Point(20, 310), cv.Point(50, 350)), + handleNested: false, + ); + + drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 340)); + + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 370), cv.Point(60, 420)), + makeRectangle(cv.Point(20, 371), cv.Point(50, 410)), + handleNested: false, + ); + + drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 400)); + + // A vertex of the triangle lies on an edge of the rectangle so handleNested can be false and an intersection is still found + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 430), cv.Point(60, 480)), + [cv.Point(35, 430), cv.Point(20, 470), cv.Point(50, 470)].asVec(), + handleNested: false, + ); + + drawDescription(image, intersectionArea.toInt(), " (handleNested false)", cv.Point(70, 460)); + + // Show intersection of overlapping rectangle and triangle + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 490), cv.Point(40, 540)), + [cv.Point(25, 500), cv.Point(25, 530), cv.Point(60, 515)].asVec(), + handleNested: false, + ); + + drawDescription(image, intersectionArea.toInt(), "", cv.Point(70, 520)); + + // This concave polygon is invalid input to intersectConvexConvex so it returns an invalid intersection + final cv.VecPoint notConvex = [ + cv.Point(25, 560), + cv.Point(25, 590), + cv.Point(45, 580), + cv.Point(60, 600), + cv.Point(60, 550), + cv.Point(45, 570), + ].asVec(); + intersectionArea = drawIntersection( + image, + makeRectangle(cv.Point(10, 550), cv.Point(50, 600)), + notConvex, + handleNested: false, + ); + + drawDescription(image, intersectionArea.toInt(), " (invalid input: not convex)", cv.Point(70, 580)); + + cv.imwrite("test/images_out/intersections.png", image); }); } From 4ffaef13b8ee5a3e61229cdeb1a8e8cc9d197b93 Mon Sep 17 00:00:00 2001 From: rainyl Date: Thu, 28 Nov 2024 13:19:44 +0000 Subject: [PATCH 5/5] Commit SVG reports --- packages/opencv_core/images/opencv_core_size_report.svg | 4 ++-- packages/opencv_dart/images/opencv_dart_size_report.svg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/opencv_core/images/opencv_core_size_report.svg b/packages/opencv_core/images/opencv_core_size_report.svg index 4cb8d6fc..378be0e2 100644 --- a/packages/opencv_core/images/opencv_core_size_report.svg +++ b/packages/opencv_core/images/opencv_core_size_report.svg @@ -68,9 +68,9 @@ Total: - 70.61 MB + 70.62 MB Package: - 47.41 MB + 47.42 MB diff --git a/packages/opencv_dart/images/opencv_dart_size_report.svg b/packages/opencv_dart/images/opencv_dart_size_report.svg index 40e033fb..61400062 100644 --- a/packages/opencv_dart/images/opencv_dart_size_report.svg +++ b/packages/opencv_dart/images/opencv_dart_size_report.svg @@ -68,9 +68,9 @@ Total: - 176.22 MB + 176.23 MB Package: - 153.02 MB + 153.03 MB