Skip to content

Commit 6267d8a

Browse files
test: add and improve test cases for transform functions (#441)
1 parent d280f46 commit 6267d8a

17 files changed

+198
-34
lines changed

src/compute/__tests__/histogram.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ test('throw if slots is not a power of 2', () => {
9898
[0, 255, 255, 255, 0],
9999
[0, 0, 0, 0, 0],
100100
]);
101-
expect(() => image.histogram({ slots: 7 })).toThrowError(
101+
expect(() => image.histogram({ slots: 7 })).toThrow(
102102
'slots must be a power of 2, for example: 64, 256, 1024',
103103
);
104104
});

src/filters/__tests__/convolution.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('convolution functions', () => {
1616
},
1717
);
1818

19-
const expected = testUtils.load('opencv/testConv.png');
19+
const expected = testUtils.load('opencv/testConvolution.png');
2020

2121
expect(convoluted).toMatchImage(expected);
2222
});
@@ -32,7 +32,7 @@ describe('convolution functions', () => {
3232
borderType: 'reflect',
3333
});
3434

35-
const expected = testUtils.load('opencv/testConv.png');
35+
const expected = testUtils.load('opencv/testConvolution.png');
3636
expect(convoluted).toMatchImage(expected);
3737
});
3838

src/filters/__tests__/gaussianBlur.test.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { GaussianBlurOptions, gaussianBlur } from '../gaussianBlur';
1+
import {
2+
GaussianBlurOptions,
3+
gaussianBlur,
4+
GaussianBlurSigmaOptions,
5+
} from '../gaussianBlur';
26

37
test('symmetrical kernel, should return the kernel itself', () => {
48
const image = testUtils.createGreyImage([
@@ -102,26 +106,20 @@ test('x and y kernels', () => {
102106

103107
expect(() => {
104108
return image.gaussianBlur(options);
105-
}).toThrowError(
109+
}).toThrow(
106110
'you must either define sigma or sigmaX and sigmaY in the options argument',
107111
);
108112
});
109113

110-
test.skip('gaussian blur should have same result as opencv', () => {
114+
test('gaussian blur should have same result as opencv', () => {
111115
const img = testUtils.load('opencv/test.png');
112-
const options: GaussianBlurOptions = {
116+
const options: GaussianBlurSigmaOptions = {
113117
borderType: 'reflect',
114118
size: 3,
115-
sigmaX: 1,
116-
sigmaY: 1,
119+
sigma: 1,
117120
};
118121
const blurred = gaussianBlur(img, options);
119122

120-
// const grey = convertColor(img, ImageKind.GREY);
121-
// const greyBlurred = gaussianBlur(grey, options);
122-
// console.log(greyBlurred.data);
123-
124123
const expected = testUtils.load('opencv/testGaussianBlur.png');
125-
// write('gaussian.png', blurred);
126-
expect(expected).toMatchImage(blurred);
124+
expect(blurred).toMatchImage(expected);
127125
});

src/geometry/__tests__/transform.test.ts

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
test('compare result of translation with opencv', () => {
1+
//To look at the equivalent opencv code go to generate.py in test/img/opencv
2+
//folder.
3+
test('compare result of translation with opencv with default parameters', () => {
24
const img = testUtils.load('opencv/test.png');
35
const translation = [
46
[1, 0, 2],
@@ -9,23 +11,106 @@ test('compare result of translation with opencv', () => {
911
height: 20,
1012
});
1113

12-
expect(transformed).toMatchImage('opencv/testTranslation.png');
14+
expect(transformed).toMatchImage('opencv/testTranslate.png');
1315
});
1416

15-
// is this the expected result for the fullImage option??
16-
test.skip('fullImage = true', () => {
17+
test('compare result of clockwise rotation with opencv', () => {
1718
const img = testUtils.load('opencv/test.png');
18-
const translation = [
19-
[1, 0, 2],
20-
[0, 1, 10],
21-
];
22-
const transformed = img.transform(translation, {
23-
width: 16,
24-
height: 15,
25-
fullImage: true,
26-
});
19+
const transformed = img.transform(
20+
[
21+
[0, -1, img.width + 1],
22+
[1, 0, 0],
23+
],
24+
{
25+
inverse: false,
26+
fullImage: false,
27+
width: 10,
28+
height: 8,
29+
borderType: 'constant',
30+
borderValue: 0,
31+
interpolationType: 'bilinear',
32+
},
33+
);
34+
expect(transformed).toMatchImage('opencv/testClockwiseRot90.png');
35+
});
2736

28-
expect(transformed).toMatchImage('opencv/testTranslation.png');
37+
test('compare result of anti-clockwise rotation with opencv', () => {
38+
const img = testUtils.load('opencv/test.png');
39+
const transformed = img.transform(
40+
[
41+
[0, 1, 0],
42+
[-1, 0, img.width - 1],
43+
],
44+
{
45+
inverse: false,
46+
fullImage: false,
47+
width: 10,
48+
height: 8,
49+
borderType: 'constant',
50+
borderValue: 0,
51+
interpolationType: 'bilinear',
52+
},
53+
);
54+
expect(transformed).toMatchImage('opencv/testAntiClockwiseRot90.png');
55+
});
56+
57+
test('get a vertical reflection of an image', () => {
58+
const img = testUtils.load('opencv/test.png');
59+
const transformed = img.transform(
60+
[
61+
[1, 0, 0],
62+
[0, -1, img.height - 1],
63+
],
64+
{
65+
inverse: false,
66+
fullImage: false,
67+
borderType: 'constant',
68+
borderValue: 0,
69+
interpolationType: 'bilinear',
70+
},
71+
);
72+
expect(transformed).toMatchImage('opencv/testReflect.png');
73+
});
74+
//problematic test1
75+
//Scaling with test image works only if the image is scaled by 2 or by 4.
76+
test('get a scale of an image to 32*40', () => {
77+
const img = testUtils.load('opencv/test.png');
78+
const transformed = img.transform(
79+
[
80+
[4, 0, 0],
81+
[0, 4, 0],
82+
],
83+
{
84+
inverse: false,
85+
fullImage: false,
86+
width: img.width * 4,
87+
height: img.height * 4,
88+
borderType: 'constant',
89+
borderValue: 0,
90+
interpolationType: 'bilinear',
91+
},
92+
);
93+
expect(transformed).toMatchImage('opencv/testScale.png');
94+
});
95+
96+
test('affineTransformation', () => {
97+
const img = testUtils.load('opencv/test.png');
98+
const transformed = img.transform(
99+
[
100+
[2, 1, 2],
101+
[-1, 1, 2],
102+
],
103+
{
104+
inverse: false,
105+
fullImage: false,
106+
interpolationType: 'bilinear',
107+
borderType: 'constant',
108+
},
109+
);
110+
// OpenCV bilinear interpolation is less precise for speed.
111+
expect(transformed).toMatchImage('opencv/testAffineTransform.png', {
112+
error: 3,
113+
});
29114
});
30115

31116
test('should throw if matrix has wrong size', () => {

src/geometry/__tests__/transformRotate.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ test('rotate + scale compared to opencv (nearest)', () => {
1010
center: { column: 2, row: 4 },
1111
});
1212

13-
expect(rotated).toMatchImage('opencv/testRotate.png');
13+
expect(rotated).toMatchImage('opencv/testInterpolate.png');
1414
});
1515

1616
test('rotate + scale compared to opencv (bilinear)', () => {
@@ -22,6 +22,7 @@ test('rotate + scale compared to opencv (bilinear)', () => {
2222
interpolationType: 'bilinear',
2323
center: { column: 2, row: 4 },
2424
});
25+
// OpenCV bilinear interpolation is less precise for speed.
2526
expect(rotated).toMatchImage('opencv/testRotateBilinear.png', { error: 5 });
2627
});
2728

@@ -35,6 +36,7 @@ test('rotate + scale compared to opencv (bicubic)', () => {
3536
center: { column: 2, row: 4 },
3637
});
3738

39+
// OpenCV bilinear interpolation is less precise for speed.
3840
expect(rotated).toMatchImage('opencv/testRotateBicubic.png', { error: 13 });
3941
});
4042

src/utils/geometry/__tests__/removeClosePoints.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ test('test error handling', () => {
9898
distance: 0,
9999
});
100100
return result;
101-
}).toThrowError(
101+
}).toThrow(
102102
'image channel must be specified or image must have only one channel',
103103
);
104104
});

test/TestImagePath.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,19 @@ export type TestImagePath =
2727
| 'formats/tif/rgba8-multi.tif'
2828
| 'formats/tif/palette.tif'
2929
| 'opencv/test.png'
30+
| 'opencv/testAffineTransform.png'
3031
| 'opencv/testBlur.png'
31-
| 'opencv/testConv.png'
32+
| 'opencv/testConvolution.png'
3233
| 'opencv/testGaussianBlur.png'
33-
| 'opencv/testRotate.png'
34+
| 'opencv/testInterpolate.png'
3435
| 'opencv/testRotateBicubic.png'
3536
| 'opencv/testRotateBilinear.png'
36-
| 'opencv/testTranslation.png'
37+
| 'opencv/testTranslate.png'
3738
| 'opencv/testResizeBilinear.png'
39+
| 'opencv/testAntiClockwiseRot90.png'
40+
| 'opencv/testClockwiseRot90.png'
41+
| 'opencv/testScale.png'
42+
| 'opencv/testReflect.png'
3843
| 'various/grayscale_by_zimmyrose.png'
3944
| 'various/alphabet.jpg'
4045
| 'various/without-metadata.jpg'

test/img/opencv/generate.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import numpy as np
2+
import cv2 as cv
3+
4+
img = cv.imread('./test.png')
5+
assert img is not None, "file could not be read, check with os.path.exists()"
6+
rows, cols = img.shape[0], img.shape[1]
7+
8+
# Image scaling by 10.
9+
scale = 4
10+
M = np.float32([[scale, 0, 0], [0, scale, 0]])
11+
dst = cv.warpAffine(img, M, dsize=(cols * scale, rows * scale), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT,
12+
borderValue=0)
13+
cv.imwrite('testScale.png', dst)
14+
15+
# Image resizing by 10.
16+
dst = cv.resize(img, (80, 100), interpolation=cv.INTER_LINEAR)
17+
cv.imwrite('testResizeBilinear.png', dst)
18+
19+
# Image rotate counter-clockwise by 90 degrees
20+
M = np.float32([[0, 1, 0], [-1, 0, cols - 1]])
21+
dst = cv.warpAffine(img, M, (rows, cols), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT)
22+
cv.imwrite('testAntiClockwiseRot90.png', dst)
23+
24+
# Image rotate clockwise by 90 degrees
25+
M = np.float32([[0, -1, cols + 1], [1, 0, 0]])
26+
dst = cv.warpAffine(img, M, (rows, cols), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT)
27+
cv.imwrite('testClockwiseRot90.png', dst)
28+
29+
# Image interpolation
30+
matrix = cv.getRotationMatrix2D((2, 4), angle=30, scale=0.8)
31+
dst = cv.warpAffine(img, matrix, dsize=(cols, rows), flags=cv.INTER_NEAREST, borderMode=cv.BORDER_REFLECT)
32+
cv.imwrite('testInterpolate.png', dst)
33+
34+
# Image bilinear interpolation
35+
matrix = cv.getRotationMatrix2D((2, 4), angle=30, scale=1.4)
36+
dst = cv.warpAffine(img, matrix, dsize=(cols, rows), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_REFLECT)
37+
cv.imwrite('testRotateBilinear.png', dst)
38+
39+
# Image bicubic interpolation
40+
matrix = cv.getRotationMatrix2D((2, 4), angle=30, scale=1.4)
41+
dst = cv.warpAffine(img, matrix, dsize=(cols, rows), flags=cv.INTER_CUBIC, borderMode=cv.BORDER_REFLECT)
42+
cv.imwrite('testRotateBicubic.png', dst)
43+
44+
# Image reflection
45+
M = np.float32([[1, 0, 0], [0, -1, rows - 1]])
46+
dst = cv.warpAffine(img, M, (cols, rows), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT)
47+
cv.imwrite('testReflect.png', dst)
48+
49+
# Image translation
50+
M = np.float32([[1, 0, 2], [0, 1, 4]])
51+
dst = cv.warpAffine(img, M, (16, 20))
52+
cv.imwrite('testTranslate.png', dst)
53+
54+
# Image affine transformation
55+
M = np.float32([[2, 1, 2], [-1, 1, 2]])
56+
dst = cv.warpAffine(img, M, (cols, rows), flags=cv.INTER_LINEAR, borderMode=cv.BORDER_CONSTANT)
57+
cv.imwrite('testAffineTransform.png', dst)
58+
59+
# Image blur
60+
dst = cv.blur(img, (3, 5), borderType=cv.BORDER_REFLECT)
61+
cv.imwrite('testBlur.png', dst)
62+
63+
# Image gaussian blur
64+
kernel = cv.getGaussianKernel(3, 1)
65+
dst = cv.sepFilter2D(img, -1, kernel, kernel, borderType=cv.BORDER_REFLECT)
66+
cv.imwrite('testGaussianBlur.png', dst)
67+
68+
# Image convolution
69+
kernelX = np.float32([[0.1, 0.2, 0.3]])
70+
71+
kernelY = np.float32([[0.4, 0.5, 0.6, -0.3, -0.4]])
72+
73+
dst = cv.sepFilter2D(img, ddepth=-1, kernelX=kernelX, kernelY=kernelY, borderType=cv.BORDER_REFLECT)
74+
cv.imwrite('testConvolution.png', dst)
146 Bytes
Loading
132 Bytes
Loading

0 commit comments

Comments
 (0)