Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/types/opencv/Mat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
91 changes: 91 additions & 0 deletions test/Mat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
});