Merge pull request #26387 from sturkmen72:js-imgproc

Add some functions to OpenCV JS API
This commit is contained in:
Alexander Smorkalov 2024-12-19 09:45:23 +03:00 committed by GitHub
commit ebf3c400d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 639 additions and 451 deletions

View File

@ -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": [

View File

@ -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<emscripten::val(const cv::RotatedRect&)>(&binding_utils::rotatedRectPoints));
function("rotatedRectBoundingRect", select_overload<Rect(const cv::RotatedRect&)>(&binding_utils::rotatedRectBoundingRect));
function("rotatedRectBoundingRect2f", select_overload<Rect2f(const cv::RotatedRect&)>(&binding_utils::rotatedRectBoundingRect2f));
emscripten::value_object<cv::KeyPoint>("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<cv::Exception>("Exception")
.field("code", &cv::Exception::code)
.field("msg", &binding_utils::getExceptionMsg, &binding_utils::setExceptionMsg);
emscripten::value_object<binding_utils::Circle>("Circle")
.field("center", &binding_utils::Circle::center)
.field("radius", &binding_utils::Circle::radius);
function("boxPoints", select_overload<emscripten::val(const cv::RotatedRect&)>(&binding_utils::rotatedRectPoints));
function("rotatedRectPoints", select_overload<emscripten::val(const cv::RotatedRect&)>(&binding_utils::rotatedRectPoints));
function("rotatedRectBoundingRect", select_overload<Rect(const cv::RotatedRect&)>(&binding_utils::rotatedRectBoundingRect));
function("rotatedRectBoundingRect2f", select_overload<Rect2f(const cv::RotatedRect&)>(&binding_utils::rotatedRectBoundingRect2f));
function("exceptionFromPtr", &binding_utils::exceptionFromPtr, allow_raw_pointers());
function("minMaxLoc", select_overload<binding_utils::MinMaxLoc(const cv::Mat&, const cv::Mat&)>(&binding_utils::minMaxLoc));
function("minMaxLoc", select_overload<binding_utils::MinMaxLoc(const cv::Mat&)>(&binding_utils::minMaxLoc_1));
function("CV_MAT_DEPTH", &binding_utils::cvMatDepth);
function("getBuildInformation", &binding_utils::getBuildInformation);
#ifdef HAVE_OPENCV_IMGPROC
emscripten::value_object<cv::Moments >("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<cv::Exception>("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::Circle(const cv::Mat&)>(&binding_utils::minEnclosingCircle));
function("floodFill", select_overload<int(cv::Mat&, cv::Mat&, Point, Scalar, emscripten::val, Scalar, Scalar, int)>(&binding_utils::floodFill_wrapper));
function("floodFill", select_overload<int(cv::Mat&, cv::Mat&, Point, Scalar, emscripten::val, Scalar, Scalar)>(&binding_utils::floodFill_wrapper_1));
function("floodFill", select_overload<int(cv::Mat&, cv::Mat&, Point, Scalar, emscripten::val, Scalar)>(&binding_utils::floodFill_wrapper_2));
function("floodFill", select_overload<int(cv::Mat&, cv::Mat&, Point, Scalar, emscripten::val)>(&binding_utils::floodFill_wrapper_3));
function("floodFill", select_overload<int(cv::Mat&, cv::Mat&, Point, Scalar)>(&binding_utils::floodFill_wrapper_4));
#endif
function("minMaxLoc", select_overload<binding_utils::MinMaxLoc(const cv::Mat&, const cv::Mat&)>(&binding_utils::minMaxLoc));
function("minMaxLoc", select_overload<binding_utils::MinMaxLoc(const cv::Mat&)>(&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<emscripten::val(const cv::Mat&, Rect&, TermCriteria)>(&binding_utils::CamShiftWrapper));
function("meanShift", select_overload<emscripten::val(const cv::Mat&, Rect&, TermCriteria)>(&binding_utils::meanShiftWrapper));
emscripten::class_<cv::Tracker >("Tracker")
.function("init", select_overload<void(cv::Tracker&,const cv::Mat&,const Rect&)>(&binding_utils::Tracker_init_wrapper), pure_virtual())
.function("update", select_overload<emscripten::val(cv::Tracker&,const cv::Mat&)>(&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);

View File

@ -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);

View File

@ -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));

View File

@ -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);
}
});

View File

@ -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': [