diff --git a/modules/imgproc/misc/js/gen_dict.json b/modules/imgproc/misc/js/gen_dict.json index 7b8c959fdd..a26808e38b 100644 --- a/modules/imgproc/misc/js/gen_dict.json +++ b/modules/imgproc/misc/js/gen_dict.json @@ -2,82 +2,105 @@ "whitelist": { "": [ - "Canny", - "GaussianBlur", - "Laplacian", - "HoughLines", - "HoughLinesP", - "HoughCircles", - "Scharr", - "Sobel", "adaptiveThreshold", + "applyColorMap", "approxPolyDP", + "approxPolyN", "arcLength", + "arrowedLine", "bilateralFilter", + "blendLinear", "blur", "boundingRect", "boxFilter", "calcBackProject", "calcHist", + "Canny", "circle", + "clipLine", "compareHist", "connectedComponents", "connectedComponentsWithStats", "contourArea", + "convertMaps", "convexHull", "convexityDefects", "cornerHarris", "cornerMinEigenVal", "createCLAHE", + "createHanningWindow", "createLineSegmentDetector", "cvtColor", "demosaicing", "dilate", "distanceTransform", "distanceTransformWithLabels", + "divSpectrums", "drawContours", + "drawMarker", "ellipse", "ellipse2Poly", "equalizeHist", "erode", + "fillConvexPoly", + "fillPoly", "filter2D", "findContours", + "findContoursLinkRuns", "fitEllipse", + "fitEllipseAMS", + "fitEllipseDirect", "fitLine", "floodFill", + "GaussianBlur", "getAffineTransform", + "getFontScaleFromHeight", "getPerspectiveTransform", + "getRectSubPix", "getRotationMatrix2D", "getStructuringElement", "goodFeaturesToTrack", "grabCut", + "HoughCircles", + "HoughLines", + "HoughLinesP", + "HuMoments", "integral", "integral2", + "intersectConvexConvex", + "invertAffineTransform", "isContourConvex", + "Laplacian", "line", "matchShapes", "matchTemplate", "medianBlur", "minAreaRect", "minEnclosingCircle", + "minEnclosingTriangle", "moments", "morphologyEx", "pointPolygonTest", + "polylines", + "preCornerDetect", "putText", "pyrDown", "pyrUp", "rectangle", "remap", "resize", + "rotatedRectangleIntersection", + "Scharr", "sepFilter2D", + "Sobel", + "spatialGradient", + "sqrBoxFilter", + "stackBlur", "threshold", "warpAffine", "warpPerspective", "warpPolar", - "watershed", - "fillPoly", - "fillConvexPoly", - "polylines" + "watershed" ], "CLAHE": ["apply", "collectGarbage", "getClipLimit", "getTilesGridSize", "setClipLimit", "setTilesGridSize"], "segmentation_IntelligentScissorsMB": [ diff --git a/modules/js/src/core_bindings.cpp b/modules/js/src/core_bindings.cpp index 58ff004cde..9065be5d07 100644 --- a/modules/js/src/core_bindings.cpp +++ b/modules/js/src/core_bindings.cpp @@ -378,7 +378,6 @@ namespace binding_utils return result; } - void Tracker_init_wrapper(cv::Tracker& arg0, const cv::Mat& arg1, const Rect& arg2) { return arg0.init(arg1, arg2); @@ -619,10 +618,6 @@ EMSCRIPTEN_BINDINGS(binding_utils) .field("size", &cv::RotatedRect::size) .field("angle", &cv::RotatedRect::angle); - function("rotatedRectPoints", select_overload(&binding_utils::rotatedRectPoints)); - function("rotatedRectBoundingRect", select_overload(&binding_utils::rotatedRectBoundingRect)); - function("rotatedRectBoundingRect2f", select_overload(&binding_utils::rotatedRectBoundingRect2f)); - emscripten::value_object("KeyPoint") .field("angle", &cv::KeyPoint::angle) .field("class_id", &cv::KeyPoint::class_id) @@ -649,10 +644,25 @@ EMSCRIPTEN_BINDINGS(binding_utils) .field("minLoc", &binding_utils::MinMaxLoc::minLoc) .field("maxLoc", &binding_utils::MinMaxLoc::maxLoc); + emscripten::value_object("Exception") + .field("code", &cv::Exception::code) + .field("msg", &binding_utils::getExceptionMsg, &binding_utils::setExceptionMsg); + emscripten::value_object("Circle") .field("center", &binding_utils::Circle::center) .field("radius", &binding_utils::Circle::radius); + function("boxPoints", select_overload(&binding_utils::rotatedRectPoints)); + function("rotatedRectPoints", select_overload(&binding_utils::rotatedRectPoints)); + function("rotatedRectBoundingRect", select_overload(&binding_utils::rotatedRectBoundingRect)); + function("rotatedRectBoundingRect2f", select_overload(&binding_utils::rotatedRectBoundingRect2f)); + function("exceptionFromPtr", &binding_utils::exceptionFromPtr, allow_raw_pointers()); + function("minMaxLoc", select_overload(&binding_utils::minMaxLoc)); + function("minMaxLoc", select_overload(&binding_utils::minMaxLoc_1)); + function("CV_MAT_DEPTH", &binding_utils::cvMatDepth); + function("getBuildInformation", &binding_utils::getBuildInformation); + +#ifdef HAVE_OPENCV_IMGPROC emscripten::value_object("Moments") .field("m00", &cv::Moments::m00) .field("m10", &cv::Moments::m10) @@ -679,49 +689,24 @@ EMSCRIPTEN_BINDINGS(binding_utils) .field("nu12", &cv::Moments::nu12) .field("nu03", &cv::Moments::nu03); - emscripten::value_object("Exception") - .field("code", &cv::Exception::code) - .field("msg", &binding_utils::getExceptionMsg, &binding_utils::setExceptionMsg); - - function("exceptionFromPtr", &binding_utils::exceptionFromPtr, allow_raw_pointers()); - -#ifdef HAVE_OPENCV_IMGPROC function("minEnclosingCircle", select_overload(&binding_utils::minEnclosingCircle)); - function("floodFill", select_overload(&binding_utils::floodFill_wrapper)); - function("floodFill", select_overload(&binding_utils::floodFill_wrapper_1)); - function("floodFill", select_overload(&binding_utils::floodFill_wrapper_2)); - function("floodFill", select_overload(&binding_utils::floodFill_wrapper_3)); - function("floodFill", select_overload(&binding_utils::floodFill_wrapper_4)); -#endif - - function("minMaxLoc", select_overload(&binding_utils::minMaxLoc)); - - function("minMaxLoc", select_overload(&binding_utils::minMaxLoc_1)); - -#ifdef HAVE_OPENCV_IMGPROC function("morphologyDefaultBorderValue", &cv::morphologyDefaultBorderValue); #endif - function("CV_MAT_DEPTH", &binding_utils::cvMatDepth); - #ifdef HAVE_OPENCV_VIDEO function("CamShift", select_overload(&binding_utils::CamShiftWrapper)); - function("meanShift", select_overload(&binding_utils::meanShiftWrapper)); emscripten::class_("Tracker") .function("init", select_overload(&binding_utils::Tracker_init_wrapper), pure_virtual()) .function("update", select_overload(&binding_utils::Tracker_update_wrapper), pure_virtual()); - #endif - function("getBuildInformation", &binding_utils::getBuildInformation); - #ifdef HAVE_PTHREADS_PF function("parallel_pthreads_set_threads_num", &cv::parallel_pthreads_set_threads_num); function("parallel_pthreads_get_threads_num", &cv::parallel_pthreads_get_threads_num); diff --git a/modules/js/test/test_core.js b/modules/js/test/test_core.js index bfd9d2cd0d..3cd352ef83 100644 --- a/modules/js/test/test_core.js +++ b/modules/js/test/test_core.js @@ -4,8 +4,380 @@ QUnit.module('Core', {}); +QUnit.test('test_operations_on_arrays', function(assert) { + // Transpose + { + let mat1 = cv.Mat.eye(9, 7, cv.CV_8UC3); + let mat2 = new cv.Mat(); + + cv.transpose(mat1, mat2); + + // Verify result. + let size = mat2.size(); + assert.equal(mat2.channels(), 3); + assert.equal(size.height, 7); + assert.equal(size.width, 9); + } + + // Concat + { + let mat = cv.Mat.ones({height: 10, width: 5}, cv.CV_8UC3); + let mat2 = cv.Mat.eye({height: 10, width: 5}, cv.CV_8UC3); + let mat3 = cv.Mat.eye({height: 10, width: 5}, cv.CV_8UC3); + + let out = new cv.Mat(); + let input = new cv.MatVector(); + input.push_back(mat); + input.push_back(mat2); + input.push_back(mat3); + + cv.vconcat(input, out); + + // Verify result. + let size = out.size(); + assert.equal(out.channels(), 3); + assert.equal(size.height, 30); + assert.equal(size.width, 5); + assert.equal(out.elemSize1(), 1); + + cv.hconcat(input, out); + + // Verify result. + size = out.size(); + assert.equal(out.channels(), 3); + assert.equal(size.height, 10); + assert.equal(size.width, 15); + assert.equal(out.elemSize1(), 1); + + input.delete(); + out.delete(); + } + + // Min, Max + { + let data1 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]); + let data2 = new Uint8Array([0, 4, 0, 8, 0, 12, 0, 16, 0]); + + let expectedMin = new Uint8Array([0, 2, 0, 4, 0, 6, 0, 8, 0]); + let expectedMax = new Uint8Array([1, 4, 3, 8, 5, 12, 7, 16, 9]); + + let dataPtr = cv._malloc(3*3*1); + let dataPtr2 = cv._malloc(3*3*1); + + let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); + dataHeap.set(new Uint8Array(data1.buffer)); + + let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); + dataHeap2.set(new Uint8Array(data2.buffer)); + + let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); + let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); + let mat3 = new cv.Mat(); + + cv.min(mat1, mat2, mat3); + + // Verify result. + let size = mat2.size(); + assert.equal(mat2.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedMin); + + cv.max(mat1, mat2, mat3); + + // Verify result. + size = mat2.size(); + assert.equal(mat2.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedMax); + + cv._free(dataPtr); + cv._free(dataPtr2); + } + + // Bitwise operations + { + let data1 = new Uint8Array([0, 1, 2, 4, 8, 16, 32, 64, 128]); + let data2 = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255]); + + let expectedAnd = new Uint8Array([0, 1, 2, 4, 8, 16, 32, 64, 128]); + let expectedOr = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255]); + let expectedXor = new Uint8Array([255, 254, 253, 251, 247, 239, 223, 191, 127]); + + let expectedNot = new Uint8Array([255, 254, 253, 251, 247, 239, 223, 191, 127]); + + let dataPtr = cv._malloc(3*3*1); + let dataPtr2 = cv._malloc(3*3*1); + + let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); + dataHeap.set(new Uint8Array(data1.buffer)); + + let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); + dataHeap2.set(new Uint8Array(data2.buffer)); + + let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); + let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); + let mat3 = new cv.Mat(); + let none = new cv.Mat(); + + cv.bitwise_not(mat1, mat3, none); + + // Verify result. + let size = mat3.size(); + assert.equal(mat3.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedNot); + + cv.bitwise_and(mat1, mat2, mat3, none); + + // Verify result. + size = mat3.size(); + assert.equal(mat3.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedAnd); + + cv.bitwise_or(mat1, mat2, mat3, none); + + // Verify result. + size = mat3.size(); + assert.equal(mat3.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedOr); + + cv.bitwise_xor(mat1, mat2, mat3, none); + + // Verify result. + size = mat3.size(); + assert.equal(mat3.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(mat3.data, expectedXor); + + cv._free(dataPtr); + cv._free(dataPtr2); + } + + // Arithmetic operations + { + let data1 = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]); + let data2 = new Uint8Array([0, 2, 4, 6, 8, 10, 12, 14, 16]); + let data3 = new Uint8Array([0, 1, 0, 1, 0, 1, 0, 1, 0]); + + // |data1 - data2| + let expectedAbsDiff = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]); + let expectedAdd = new Uint8Array([0, 3, 6, 9, 12, 15, 18, 21, 24]); + + const alpha = 4; + const beta = -1; + const gamma = 3; + // 4*data1 - data2 + 3 + let expectedWeightedAdd = new Uint8Array([3, 5, 7, 9, 11, 13, 15, 17, 19]); + + let dataPtr = cv._malloc(3*3*1); + let dataPtr2 = cv._malloc(3*3*1); + let dataPtr3 = cv._malloc(3*3*1); + + let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); + dataHeap.set(new Uint8Array(data1.buffer)); + let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); + dataHeap2.set(new Uint8Array(data2.buffer)); + let dataHeap3 = new Uint8Array(cv.HEAPU8.buffer, dataPtr3, 3*3*1); + dataHeap3.set(new Uint8Array(data3.buffer)); + + let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); + let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); + let mat3 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr3, 0); + + let dst = new cv.Mat(); + let none = new cv.Mat(); + + cv.absdiff(mat1, mat2, dst); + + // Verify result. + let size = dst.size(); + assert.equal(dst.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(dst.data, expectedAbsDiff); + + cv.add(mat1, mat2, dst, none, -1); + + // Verify result. + size = dst.size(); + assert.equal(dst.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + assert.deepEqual(dst.data, expectedAdd); + + cv.addWeighted(mat1, alpha, mat2, beta, gamma, dst, -1); + + // Verify result. + size = dst.size(); + assert.equal(dst.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + assert.deepEqual(dst.data, expectedWeightedAdd); + + // default parameter + cv.addWeighted(mat1, alpha, mat2, beta, gamma, dst); + + // Verify result. + size = dst.size(); + assert.equal(dst.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + + assert.deepEqual(dst.data, expectedWeightedAdd); + + mat1.delete(); + mat2.delete(); + mat3.delete(); + dst.delete(); + none.delete(); + } + + // Invert + { + let inv1 = new cv.Mat(); + let inv2 = new cv.Mat(); + let inv3 = new cv.Mat(); + let inv4 = new cv.Mat(); + + let data1 = new Float32Array([1, 0, 0, + 0, 1, 0, + 0, 0, 1]); + let data2 = new Float32Array([0, 0, 0, + 0, 5, 0, + 0, 0, 0]); + let data3 = new Float32Array([1, 1, 1, 0, + 0, 3, 1, 2, + 2, 3, 1, 0, + 1, 0, 2, 1]); + let data4 = new Float32Array([1, 4, 5, + 4, 2, 2, + 5, 2, 2]); + + let expected1 = new Float32Array([1, 0, 0, + 0, 1, 0, + 0, 0, 1]); + // Inverse does not exist! + let expected3 = new Float32Array([-3, -1/2, 3/2, 1, + 1, 1/4, -1/4, -1/2, + 3, 1/4, -5/4, -1/2, + -3, 0, 1, 1]); + let expected4 = new Float32Array([0, -1, 1, + -1, 23/2, -9, + 1, -9, 7]); + + let dataPtr1 = cv._malloc(3*3*4); + let dataPtr2 = cv._malloc(3*3*4); + let dataPtr3 = cv._malloc(4*4*4); + let dataPtr4 = cv._malloc(3*3*4); + + let dataHeap = new Float32Array(cv.HEAP32.buffer, dataPtr1, 3*3); + dataHeap.set(new Float32Array(data1.buffer)); + let dataHeap2 = new Float32Array(cv.HEAP32.buffer, dataPtr2, 3*3); + dataHeap2.set(new Float32Array(data2.buffer)); + let dataHeap3 = new Float32Array(cv.HEAP32.buffer, dataPtr3, 4*4); + dataHeap3.set(new Float32Array(data3.buffer)); + let dataHeap4 = new Float32Array(cv.HEAP32.buffer, dataPtr4, 3*3); + dataHeap4.set(new Float32Array(data4.buffer)); + + let mat1 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr1, 0); + let mat2 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr2, 0); + let mat3 = new cv.Mat(4, 4, cv.CV_32FC1, dataPtr3, 0); + let mat4 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr4, 0); + + QUnit.assert.deepEqualWithTolerance = function( value, expected, tolerance ) { + for (let i = 0; i < value.length; i= i+1) { + this.pushResult( { + result: Math.abs(value[i]-expected[i]) < tolerance, + actual: value[i], + expected: expected[i], + } ); + } + }; + + cv.invert(mat1, inv1, 0); + + // Verify result. + let size = inv1.size(); + assert.equal(inv1.channels(), 1); + assert.equal(size.height, 3); + assert.equal(size.width, 3); + assert.deepEqualWithTolerance(inv1.data32F, expected1, 0.0001); + + cv.invert(mat2, inv2, 0); + + // Verify result. + assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); + + cv.invert(mat3, inv3, 0); + + // Verify result. + size = inv3.size(); + assert.equal(inv3.channels(), 1); + assert.equal(size.height, 4); + assert.equal(size.width, 4); + assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); + + cv.invert(mat3, inv3, 1); + + // Verify result. + assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); + + cv.invert(mat4, inv4, 2); + + // Verify result. + assert.deepEqualWithTolerance(inv4.data32F, expected4, 0.0001); + + cv.invert(mat4, inv4, 3); + + // Verify result. + assert.deepEqualWithTolerance(inv4.data32F, expected4, 0.0001); + + mat1.delete(); + mat2.delete(); + mat3.delete(); + mat4.delete(); + inv1.delete(); + inv2.delete(); + inv3.delete(); + inv4.delete(); + } + + //Rotate + { + let dst = new cv.Mat(); + let src = cv.matFromArray(3, 2, cv.CV_8U, [1,2,3,4,5,6]); + + cv.rotate(src, dst, cv.ROTATE_90_CLOCKWISE); + + let size = dst.size(); + assert.equal(size.height, 2, "ROTATE_HEIGHT"); + assert.equal(size.width, 3, "ROTATE_WIGTH"); + + let expected = new Uint8Array([5,3,1,6,4,2]); + + assert.deepEqual(dst.data, expected); + + dst.delete(); + src.delete(); + } +}); + QUnit.test('test_LUT', function(assert) { - // test LUT { let src = cv.matFromArray(3, 3, cv.CV_8UC1, [255, 128, 0, 0, 128, 255, 1, 2, 254]); let lutTable = []; @@ -18,7 +390,7 @@ QUnit.test('test_LUT', function(assert) { cv.LUT(src, lut, dst); - //console.log(dst.data); + // Verify result. assert.equal(dst.ucharAt(0), 0); assert.equal(dst.ucharAt(1), 127); assert.equal(dst.ucharAt(2), 255); diff --git a/modules/js/test/test_imgproc.js b/modules/js/test/test_imgproc.js index 65b3cb74af..24da9b9266 100644 --- a/modules/js/test/test_imgproc.js +++ b/modules/js/test/test_imgproc.js @@ -70,6 +70,54 @@ QUnit.module('Image Processing', {}); +QUnit.test('applyColorMap', function(assert) { + { + let src = cv.matFromArray(2, 1, cv.CV_8U, [50,100]); + cv.applyColorMap(src, src, cv.COLORMAP_BONE); + + // Verify result. + let expected = new Uint8Array([60,44,44,119,89,87]); + + assert.deepEqual(src.data, expected); + src.delete(); + } +}); + +QUnit.test('blendLinear', function(assert) { + { + let src1 = cv.matFromArray(2, 1, cv.CV_8U, [50,100]); + let src2 = cv.matFromArray(2, 1, cv.CV_8U, [200,20]); + let weights1 = cv.matFromArray(2, 1, cv.CV_32F, [0.4,0.5]); + let weights2 = cv.matFromArray(2, 1, cv.CV_32F, [0.6,0.5]); + let dst = new cv.Mat(); + cv.blendLinear(src1, src2, weights1, weights2, dst); + + // Verify result. + let expected = new Uint8Array([140,60]); + + assert.deepEqual(dst.data, expected); + src1.delete(); + src2.delete(); + weights1.delete(); + weights2.delete(); + dst.delete(); + } +}); + +QUnit.test('createHanningWindow', function(assert) { + { + let dst = new cv.Mat(); + cv.createHanningWindow(dst, new cv.Size(5, 3), cv.CV_32F); + + // Verify result. + let expected = cv.matFromArray(3, 5, cv.CV_32F, [0.,0.,0.,0.,0.,0.,0.70710677,1.,0.70710677,0.,0.,0.,0.,0.,0.]); + + assert.deepEqual(dst.data, expected.data); + dst.delete(); + expected.delete(); + } +}); + QUnit.test('test_imgProc', function(assert) { // calcHist { @@ -127,6 +175,7 @@ QUnit.test('test_imgProc', function(assert) { dest.delete(); source.delete(); } + // equalizeHist { let source = new cv.Mat(10, 10, cv.CV_8UC1); @@ -196,7 +245,9 @@ QUnit.test('test_imgProc', function(assert) { expected_img.delete(); compare_result.delete(); } +}); +QUnit.test('Drawing Functions', function(assert) { // fillPoly { let img_width = 6; @@ -359,6 +410,7 @@ QUnit.test('test_shape', function(assert) { }); QUnit.test('test_min_enclosing', function(assert) { + // minEnclosingCircle { let points = new cv.Mat(4, 1, cv.CV_32FC2); @@ -378,6 +430,31 @@ QUnit.test('test_min_enclosing', function(assert) { points.delete(); } + + // minEnclosingTriangle + { + let dst = cv.Mat.zeros(80, 80, cv.CV_8U); + let contours = new cv.MatVector(); + let hierarchy = new cv.Mat(); + let triangle = new cv.Mat(); + + cv.drawMarker(dst, new cv.Point(40, 40), new cv.Scalar(255)); + cv.findContoursLinkRuns(dst,contours,hierarchy); + cv.minEnclosingTriangle(contours.get(0),triangle); + + // Verify result. + const triangleData = triangle.data32F; + assert.deepEqual(triangleData[0], triangleData[4]); + assert.deepEqual(triangleData[1], 20); + assert.deepEqual(triangleData[2], 30); + assert.deepEqual(triangleData[3], 40); + assert.deepEqual(triangleData[5], 60); + + dst.delete(); + contours.delete(); + hierarchy.delete(); + triangle.delete(); + } }); QUnit.test('test_filter', function(assert) { @@ -427,6 +504,58 @@ QUnit.test('test_filter', function(assert) { assert.equal(mat2.channels(), 1); assert.equal(size.height, 7); assert.equal(size.width, 7); + mat1.delete(); + mat2.delete(); + } + + // spatialGradient + { + let src = cv.matFromArray(4, 4, cv.CV_8U, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]); + let dx = new cv.Mat(); + let dy = new cv.Mat(); + cv.spatialGradient(src, dx, dy); + + // Verify result. + let expected_dx = new cv.Mat(); + let expected_dy = new cv.Mat(); + cv.Sobel(src, expected_dx, cv.CV_16SC1, 1, 0, 3); + cv.Sobel(src, expected_dy, cv.CV_16SC1, 0, 1, 3); + + assert.deepEqual(dx.data, expected_dx.data); + assert.deepEqual(dy.data, expected_dy.data); + + src.delete(); + dx.delete(); + dy.delete(); + expected_dx.delete(); + expected_dy.delete(); + } + + // sqrBoxFilter + { + let src = cv.matFromArray(2, 3, cv.CV_8U, [1,2,1,1,2,1]); + let dst = new cv.Mat(); + cv.sqrBoxFilter(src, dst, cv.CV_32F, new cv.Size(3, 3)); + + // Verify result. + let expected = cv.matFromArray(2, 3, cv.CV_32F,[3.0,2.0,3.0,3.0,2.0,3.0]); + + assert.deepEqual(dst.data, expected.data); + src.delete(); + dst.delete(); + expected.delete(); + } + + // stackBlur + { + let src = cv.matFromArray(2, 3, cv.CV_8U, [10,25,30,45,50,60]); + cv.stackBlur(src, src, new cv.Size(3, 3)); + + // Verify result. + let expected = new Uint8Array([22,29,36,38,43,50]); + + assert.deepEqual(src.data, expected); + src.delete(); } // medianBlur @@ -438,23 +567,12 @@ QUnit.test('test_filter', function(assert) { // Verify result. let size = mat2.size(); + assert.equal(mat2.channels(), 3); assert.equal(size.height, 9); assert.equal(size.width, 9); - } - - // Transpose - { - let mat1 = cv.Mat.eye(9, 9, cv.CV_8UC3); - let mat2 = new cv.Mat(); - - cv.transpose(mat1, mat2); - - // Verify result. - let size = mat2.size(); - assert.equal(mat2.channels(), 3); - assert.equal(size.height, 9); - assert.equal(size.width, 9); + mat1.delete(); + mat2.delete(); } // bilateralFilter @@ -481,8 +599,9 @@ QUnit.test('test_filter', function(assert) { mat1.delete(); mat2.delete(); } +}); - // Watershed +QUnit.test('test_watershed', function(assert) { { let mat = cv.Mat.ones(11, 11, cv.CV_8UC3); let out = new cv.Mat(11, 11, cv.CV_32SC1); @@ -499,44 +618,9 @@ QUnit.test('test_filter', function(assert) { mat.delete(); out.delete(); } +}); - // Concat - { - let mat = cv.Mat.ones({height: 10, width: 5}, cv.CV_8UC3); - let mat2 = cv.Mat.eye({height: 10, width: 5}, cv.CV_8UC3); - let mat3 = cv.Mat.eye({height: 10, width: 5}, cv.CV_8UC3); - - - let out = new cv.Mat(); - let input = new cv.MatVector(); - input.push_back(mat); - input.push_back(mat2); - input.push_back(mat3); - - cv.vconcat(input, out); - - // Verify result. - let size = out.size(); - assert.equal(out.channels(), 3); - assert.equal(size.height, 30); - assert.equal(size.width, 5); - assert.equal(out.elemSize1(), 1); - - cv.hconcat(input, out); - - // Verify result. - size = out.size(); - assert.equal(out.channels(), 3); - assert.equal(size.height, 10); - assert.equal(size.width, 15); - assert.equal(out.elemSize1(), 1); - - input.delete(); - out.delete(); - } - - - // distanceTransform letiants +QUnit.test('test_distanceTransform', function(assert) { { let mat = cv.Mat.ones(11, 11, cv.CV_8UC1); let out = new cv.Mat(11, 11, cv.CV_32FC1); @@ -551,7 +635,6 @@ QUnit.test('test_filter', function(assert) { assert.equal(size.width, 11); assert.equal(out.elemSize1(), 4); - cv.distanceTransformWithLabels(mat, out, labels, cv.DIST_L2, maskSize, cv.DIST_LABEL_CCOMP); @@ -572,200 +655,9 @@ QUnit.test('test_filter', function(assert) { out.delete(); labels.delete(); } +}); - // Min, Max - { - let data1 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]); - let data2 = new Uint8Array([0, 4, 0, 8, 0, 12, 0, 16, 0]); - - let expectedMin = new Uint8Array([0, 2, 0, 4, 0, 6, 0, 8, 0]); - let expectedMax = new Uint8Array([1, 4, 3, 8, 5, 12, 7, 16, 9]); - - let dataPtr = cv._malloc(3*3*1); - let dataPtr2 = cv._malloc(3*3*1); - - let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); - dataHeap.set(new Uint8Array(data1.buffer)); - - let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); - dataHeap2.set(new Uint8Array(data2.buffer)); - - - let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); - let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); - - let mat3 = new cv.Mat(); - - cv.min(mat1, mat2, mat3); - // Verify result. - let size = mat2.size(); - assert.equal(mat2.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedMin); - - - cv.max(mat1, mat2, mat3); - // Verify result. - size = mat2.size(); - assert.equal(mat2.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedMax); - - cv._free(dataPtr); - cv._free(dataPtr2); - } - - // Bitwise operations - { - let data1 = new Uint8Array([0, 1, 2, 4, 8, 16, 32, 64, 128]); - let data2 = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255]); - - let expectedAnd = new Uint8Array([0, 1, 2, 4, 8, 16, 32, 64, 128]); - let expectedOr = new Uint8Array([255, 255, 255, 255, 255, 255, 255, 255, 255]); - let expectedXor = new Uint8Array([255, 254, 253, 251, 247, 239, 223, 191, 127]); - - let expectedNot = new Uint8Array([255, 254, 253, 251, 247, 239, 223, 191, 127]); - - let dataPtr = cv._malloc(3*3*1); - let dataPtr2 = cv._malloc(3*3*1); - - let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); - dataHeap.set(new Uint8Array(data1.buffer)); - - let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); - dataHeap2.set(new Uint8Array(data2.buffer)); - - - let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); - let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); - - let mat3 = new cv.Mat(); - let none = new cv.Mat(); - - cv.bitwise_not(mat1, mat3, none); - // Verify result. - let size = mat3.size(); - assert.equal(mat3.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedNot); - - cv.bitwise_and(mat1, mat2, mat3, none); - // Verify result. - size = mat3.size(); - assert.equal(mat3.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedAnd); - - - cv.bitwise_or(mat1, mat2, mat3, none); - // Verify result. - size = mat3.size(); - assert.equal(mat3.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedOr); - - cv.bitwise_xor(mat1, mat2, mat3, none); - // Verify result. - size = mat3.size(); - assert.equal(mat3.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(mat3.data, expectedXor); - - cv._free(dataPtr); - cv._free(dataPtr2); - } - - // Arithmetic operations - { - let data1 = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]); - let data2 = new Uint8Array([0, 2, 4, 6, 8, 10, 12, 14, 16]); - let data3 = new Uint8Array([0, 1, 0, 1, 0, 1, 0, 1, 0]); - - // |data1 - data2| - let expectedAbsDiff = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]); - let expectedAdd = new Uint8Array([0, 3, 6, 9, 12, 15, 18, 21, 24]); - - const alpha = 4; - const beta = -1; - const gamma = 3; - // 4*data1 - data2 + 3 - let expectedWeightedAdd = new Uint8Array([3, 5, 7, 9, 11, 13, 15, 17, 19]); - - let dataPtr = cv._malloc(3*3*1); - let dataPtr2 = cv._malloc(3*3*1); - let dataPtr3 = cv._malloc(3*3*1); - - let dataHeap = new Uint8Array(cv.HEAPU8.buffer, dataPtr, 3*3*1); - dataHeap.set(new Uint8Array(data1.buffer)); - let dataHeap2 = new Uint8Array(cv.HEAPU8.buffer, dataPtr2, 3*3*1); - dataHeap2.set(new Uint8Array(data2.buffer)); - let dataHeap3 = new Uint8Array(cv.HEAPU8.buffer, dataPtr3, 3*3*1); - dataHeap3.set(new Uint8Array(data3.buffer)); - - let mat1 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr, 0); - let mat2 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr2, 0); - let mat3 = new cv.Mat(3, 3, cv.CV_8UC1, dataPtr3, 0); - - let dst = new cv.Mat(); - let none = new cv.Mat(); - - cv.absdiff(mat1, mat2, dst); - // Verify result. - let size = dst.size(); - assert.equal(dst.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(dst.data, expectedAbsDiff); - - cv.add(mat1, mat2, dst, none, -1); - // Verify result. - size = dst.size(); - assert.equal(dst.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(dst.data, expectedAdd); - - cv.addWeighted(mat1, alpha, mat2, beta, gamma, dst, -1); - // Verify result. - size = dst.size(); - assert.equal(dst.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(dst.data, expectedWeightedAdd); - - // default parameter - cv.addWeighted(mat1, alpha, mat2, beta, gamma, dst); - // Verify result. - size = dst.size(); - assert.equal(dst.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - - assert.deepEqual(dst.data, expectedWeightedAdd); - - mat1.delete(); - mat2.delete(); - mat3.delete(); - dst.delete(); - none.delete(); - } - - // Integral letiants +QUnit.test('test_integral', function(assert) { { let mat = cv.Mat.eye({height: 100, width: 100}, cv.CV_8UC3); let sum = new cv.Mat(); @@ -797,162 +689,55 @@ QUnit.test('test_filter', function(assert) { sqSum.delete(); title.delete(); } +}); - // Mean, meanSTDev +QUnit.test('test_rotatedRectangleIntersection', function(assert) { { - let mat = cv.Mat.eye({height: 100, width: 100}, cv.CV_8UC3); - let sum = new cv.Mat(); - let sqSum = new cv.Mat(); - let title = new cv.Mat(); + let dst = cv.Mat.zeros(80, 80, cv.CV_8U); + let contours = new cv.MatVector(); + let hierarchy = new cv.Mat(); + let intersectionPoints = new cv.Mat(); - cv.integral(mat, sum, -1); + cv.drawMarker(dst, new cv.Point(40, 40), new cv.Scalar(255)); + cv.findContoursLinkRuns(dst,contours,hierarchy); + let rr1 = cv.minAreaRect(contours.get(0)); + let rr2 = cv.minAreaRect(contours.get(0)); + let rr3 = new cv.RotatedRect({x: 40, y: 40}, {height: 10, width: 20}, 45); + + let intersectionType = cv.rotatedRectangleIntersection(rr1, rr2, intersectionPoints); // Verify result. - let size = sum.size(); - assert.equal(sum.channels(), 3); - assert.equal(size.height, 100+1); - assert.equal(size.width, 100+1); + assert.deepEqual(intersectionType, cv.INTERSECT_FULL); + intersectionPoints.convertTo(intersectionPoints, cv.CV_32S); + let intersectionPointsData = intersectionPoints.data32S; + assert.deepEqual(intersectionPointsData[0], 30); + assert.deepEqual(intersectionPointsData[1], 40); + assert.deepEqual(intersectionPointsData[2], 40); + assert.deepEqual(intersectionPointsData[3], 30); + assert.deepEqual(intersectionPointsData[4], 50); + assert.deepEqual(intersectionPointsData[5], 40); + assert.deepEqual(intersectionPointsData[6], 40); + assert.deepEqual(intersectionPointsData[7], 50); + + intersectionType = cv.rotatedRectangleIntersection(rr1, rr3, intersectionPoints); - cv.integral2(mat, sum, sqSum, -1, -1); // Verify result. - size = sum.size(); - assert.equal(sum.channels(), 3); - assert.equal(size.height, 100+1); - assert.equal(size.width, 100+1); - - size = sqSum.size(); - assert.equal(sqSum.channels(), 3); - assert.equal(size.height, 100+1); - assert.equal(size.width, 100+1); - - mat.delete(); - sum.delete(); - sqSum.delete(); - title.delete(); - } - - // Invert - { - let inv1 = new cv.Mat(); - let inv2 = new cv.Mat(); - let inv3 = new cv.Mat(); - let inv4 = new cv.Mat(); - - - let data1 = new Float32Array([1, 0, 0, - 0, 1, 0, - 0, 0, 1]); - let data2 = new Float32Array([0, 0, 0, - 0, 5, 0, - 0, 0, 0]); - let data3 = new Float32Array([1, 1, 1, 0, - 0, 3, 1, 2, - 2, 3, 1, 0, - 1, 0, 2, 1]); - let data4 = new Float32Array([1, 4, 5, - 4, 2, 2, - 5, 2, 2]); - - let expected1 = new Float32Array([1, 0, 0, - 0, 1, 0, - 0, 0, 1]); - // Inverse does not exist! - let expected3 = new Float32Array([-3, -1/2, 3/2, 1, - 1, 1/4, -1/4, -1/2, - 3, 1/4, -5/4, -1/2, - -3, 0, 1, 1]); - let expected4 = new Float32Array([0, -1, 1, - -1, 23/2, -9, - 1, -9, 7]); - - let dataPtr1 = cv._malloc(3*3*4); - let dataPtr2 = cv._malloc(3*3*4); - let dataPtr3 = cv._malloc(4*4*4); - let dataPtr4 = cv._malloc(3*3*4); - - let dataHeap = new Float32Array(cv.HEAP32.buffer, dataPtr1, 3*3); - dataHeap.set(new Float32Array(data1.buffer)); - let dataHeap2 = new Float32Array(cv.HEAP32.buffer, dataPtr2, 3*3); - dataHeap2.set(new Float32Array(data2.buffer)); - let dataHeap3 = new Float32Array(cv.HEAP32.buffer, dataPtr3, 4*4); - dataHeap3.set(new Float32Array(data3.buffer)); - let dataHeap4 = new Float32Array(cv.HEAP32.buffer, dataPtr4, 3*3); - dataHeap4.set(new Float32Array(data4.buffer)); - - let mat1 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr1, 0); - let mat2 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr2, 0); - let mat3 = new cv.Mat(4, 4, cv.CV_32FC1, dataPtr3, 0); - let mat4 = new cv.Mat(3, 3, cv.CV_32FC1, dataPtr4, 0); - - QUnit.assert.deepEqualWithTolerance = function( value, expected, tolerance ) { - for (let i = 0; i < value.length; i= i+1) { - this.pushResult( { - result: Math.abs(value[i]-expected[i]) < tolerance, - actual: value[i], - expected: expected[i], - } ); - } - }; - - cv.invert(mat1, inv1, 0); - // Verify result. - let size = inv1.size(); - assert.equal(inv1.channels(), 1); - assert.equal(size.height, 3); - assert.equal(size.width, 3); - assert.deepEqualWithTolerance(inv1.data32F, expected1, 0.0001); - - - cv.invert(mat2, inv2, 0); - // Verify result. - assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); - - cv.invert(mat3, inv3, 0); - // Verify result. - size = inv3.size(); - assert.equal(inv3.channels(), 1); - assert.equal(size.height, 4); - assert.equal(size.width, 4); - assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); - - cv.invert(mat3, inv3, 1); - // Verify result. - assert.deepEqualWithTolerance(inv3.data32F, expected3, 0.0001); - - cv.invert(mat4, inv4, 2); - // Verify result. - assert.deepEqualWithTolerance(inv4.data32F, expected4, 0.0001); - - cv.invert(mat4, inv4, 3); - // Verify result. - assert.deepEqualWithTolerance(inv4.data32F, expected4, 0.0001); - - mat1.delete(); - mat2.delete(); - mat3.delete(); - mat4.delete(); - inv1.delete(); - inv2.delete(); - inv3.delete(); - inv4.delete(); - } - //Rotate - { - let dst = new cv.Mat(); - let src = cv.matFromArray(3, 2, cv.CV_8U, [1,2,3,4,5,6]); - - cv.rotate(src, dst, cv.ROTATE_90_CLOCKWISE); - - let size = dst.size(); - assert.equal(size.height, 2, "ROTATE_HEIGHT"); - assert.equal(size.width, 3, "ROTATE_WIGTH"); - - let expected = new Uint8Array([5,3,1,6,4,2]); - - assert.deepEqual(dst.data, expected); + assert.deepEqual(intersectionType, cv.INTERSECT_PARTIAL); + intersectionPoints.convertTo(intersectionPoints, cv.CV_32S); + intersectionPointsData = intersectionPoints.data32S; + assert.deepEqual(intersectionPointsData[0], 39); + assert.deepEqual(intersectionPointsData[1], 31); + assert.deepEqual(intersectionPointsData[2], 49); + assert.deepEqual(intersectionPointsData[3], 41); + assert.deepEqual(intersectionPointsData[4], 41); + assert.deepEqual(intersectionPointsData[5], 49); + assert.deepEqual(intersectionPointsData[6], 31); + assert.deepEqual(intersectionPointsData[7], 39); dst.delete(); - src.delete(); + contours.delete(); + hierarchy.delete(); + intersectionPoints.delete(); } }); @@ -973,7 +758,6 @@ QUnit.test('warpPolar', function(assert) { ]); }); - QUnit.test('IntelligentScissorsMB', function(assert) { const lines = new cv.Mat(50, 100, cv.CV_8U, new cv.Scalar(0)); lines.row(10).setTo(new cv.Scalar(255)); diff --git a/modules/js/test/test_utils.js b/modules/js/test/test_utils.js index 03096aec74..c02b4f682a 100644 --- a/modules/js/test/test_utils.js +++ b/modules/js/test/test_utils.js @@ -245,5 +245,8 @@ QUnit.test('test_rotated_rect', function(assert) { assert.equal(points[0].x, cv.RotatedRect.boundingRect2f(rect).x); assert.equal(points[1].y, cv.RotatedRect.boundingRect2f(rect).y); + + let points1 = cv.boxPoints(rect); + assert.deepEqual(points, points1); } }); diff --git a/platforms/js/opencv_js.config.py b/platforms/js/opencv_js.config.py index 70b1ad9ff9..28989471bd 100644 --- a/platforms/js/opencv_js.config.py +++ b/platforms/js/opencv_js.config.py @@ -16,84 +16,105 @@ core = { imgproc = { '': [ - 'Canny', - 'GaussianBlur', - 'Laplacian', - 'HoughLines', - 'HoughLinesP', - 'HoughCircles', - 'Scharr', - 'Sobel', 'adaptiveThreshold', + 'applyColorMap', 'approxPolyDP', + 'approxPolyN', 'arcLength', + 'arrowedLine', 'bilateralFilter', + 'blendLinear', 'blur', 'boundingRect', 'boxFilter', 'calcBackProject', 'calcHist', + 'Canny', 'circle', + 'clipLine', 'compareHist', 'connectedComponents', 'connectedComponentsWithStats', 'contourArea', + 'convertMaps', 'convexHull', 'convexityDefects', 'cornerHarris', 'cornerMinEigenVal', 'createCLAHE', + 'createHanningWindow', 'createLineSegmentDetector', 'cvtColor', 'demosaicing', 'dilate', 'distanceTransform', 'distanceTransformWithLabels', + 'divSpectrums', 'drawContours', + 'drawMarker', 'ellipse', 'ellipse2Poly', 'equalizeHist', 'erode', + 'fillConvexPoly', + 'fillPoly', 'filter2D', 'findContours', + 'findContoursLinkRuns', 'fitEllipse', + 'fitEllipseAMS', + 'fitEllipseDirect', 'fitLine', 'floodFill', + 'GaussianBlur', 'getAffineTransform', + 'getFontScaleFromHeight', 'getPerspectiveTransform', + 'getRectSubPix', 'getRotationMatrix2D', 'getStructuringElement', 'goodFeaturesToTrack', 'grabCut', - #'initUndistortRectifyMap', # 4.x: moved to calib3d + 'HoughLines', + 'HoughLinesP', + 'HoughCircles', + 'HuMoments', 'integral', 'integral2', + 'intersectConvexConvex', + 'invertAffineTransform', 'isContourConvex', + 'Laplacian', 'line', 'matchShapes', 'matchTemplate', 'medianBlur', 'minAreaRect', 'minEnclosingCircle', + 'minEnclosingTriangle', 'moments', 'morphologyEx', 'pointPolygonTest', + 'polylines', + 'preCornerDetect', 'putText', 'pyrDown', 'pyrUp', 'rectangle', 'remap', 'resize', + 'rotatedRectangleIntersection', + 'Scharr', 'sepFilter2D', + 'Sobel', + 'spatialGradient', + 'sqrBoxFilter', + 'stackBlur', 'threshold', - #'undistort', # 4.x: moved to calib3d 'warpAffine', 'warpPerspective', 'warpPolar', 'watershed', - 'fillPoly', - 'fillConvexPoly', - 'polylines', ], 'CLAHE': ['apply', 'collectGarbage', 'getClipLimit', 'getTilesGridSize', 'setClipLimit', 'setTilesGridSize'], 'segmentation_IntelligentScissorsMB': [