diff --git a/src/types/opencv/Mat.ts b/src/types/opencv/Mat.ts index d60fcde..4106a15 100644 --- a/src/types/opencv/Mat.ts +++ b/src/types/opencv/Mat.ts @@ -787,6 +787,12 @@ export declare class Mat extends EmscriptenEmbindInstance { */ public clone(): Mat; + /** + * Creates a deep copy of the Mat with independent data buffer. + * This method ensures the copied Mat has its own data that is independent of the original. + */ + public mat_clone(): Mat; + /** * The method makes a new header for the specified matrix column and returns it. This is an O(1) * operation, regardless of the matrix size. The underlying data of the new matrix is shared with the diff --git a/test/Mat.test.ts b/test/Mat.test.ts index 6b1453d..afc2cdb 100644 --- a/test/Mat.test.ts +++ b/test/Mat.test.ts @@ -75,4 +75,95 @@ describe("Mat", () => { throw translateException(err); } }); + + it("should test Mat.clone() behavior to reproduce issue #85", async () => { + try { + console.log("Testing Mat.clone() behavior..."); + + // Create a 1x1 matrix with zeros + const m1 = cv.Mat.zeros(1, 1, cv.CV_8U); + const m2 = m1.clone(); + + // Check initial values + const m1_initial = m1.ucharAt(0); + const m2_initial = m2.ucharAt(0); + console.log(`Initial: m1 = ${m1_initial}, m2 = ${m2_initial}`); + + // Modify m1 through its data array + m1.data[0] = 1; + + // Check values after modification + const m1_after = m1.ucharAt(0); + const m2_after = m2.ucharAt(0); + console.log(`After modifying m1.data[0]: m1 = ${m1_after}, m2 = ${m2_after}`); + + // This test documents the current buggy behavior of clone() + expect(m1_after).toBe(1); + expect(m2_after).toBe(1); // Bug: clone() shares data + + m1.delete(); + m2.delete(); + } catch (err) { + throw translateException(err); + } + }); + + it("should test Mat.mat_clone() fixes the clone issue #85", async () => { + try { + console.log("Testing Mat.mat_clone() fix..."); + + // Create a 1x1 matrix with zeros + const m1 = cv.Mat.zeros(1, 1, cv.CV_8U); + const m2 = m1.mat_clone(); + + // Check initial values + const m1_initial = m1.ucharAt(0); + const m2_initial = m2.ucharAt(0); + console.log(`Initial: m1 = ${m1_initial}, m2 = ${m2_initial}`); + + // Modify m1 through its data array + m1.data[0] = 1; + + // Check values after modification + const m1_after = m1.ucharAt(0); + const m2_after = m2.ucharAt(0); + console.log(`After modifying m1.data[0]: m1 = ${m1_after}, m2 = ${m2_after}`); + + // Expected behavior: m1 = 1, m2 = 0 (independent copies) + expect(m1_after).toBe(1); + expect(m2_after).toBe(0); // Fixed: mat_clone() creates independent copies + + m1.delete(); + m2.delete(); + } catch (err) { + throw translateException(err); + } + }); + + it("should test Mat.mat_clone() works with different Mat sizes and types", async () => { + try { + console.log("Testing Mat.mat_clone() with different types..."); + + // Test with a 3x3 matrix of different type + const m1 = cv.Mat.ones(3, 3, cv.CV_32F); + const m2 = m1.mat_clone(); + + // Verify dimensions and type are preserved + expect(m2.rows).toBe(m1.rows); + expect(m2.cols).toBe(m1.cols); + expect(m2.type()).toBe(m1.type()); + + // Modify first element of m1 + m1.data32F[0] = 42.5; + + // Check that m2 is not affected + expect(m1.data32F[0]).toBe(42.5); + expect(m2.data32F[0]).toBe(1.0); // Should remain original value + + m1.delete(); + m2.delete(); + } catch (err) { + throw translateException(err); + } + }); });