From 7cc3d7afd9b70851324dd77ead2e9a001629d6a9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb <trehleb@gmail.com> Date: Wed, 21 Apr 2021 07:26:50 +0200 Subject: [PATCH 1/5] Test that two images are identical for the Seam Carving algorithm. --- .husky/pre-commit | 1 + .../__tests__/resizeImageWidth.test.js | 40 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index bec1c08a1a..a29a4166ea 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,6 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" +# @TODO: Implement the pre-commit checks. # npm run lint # npm run test diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index b6400a3522..bd9340fc71 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -4,6 +4,40 @@ import resizeImageWidth from '../resizeImageWidth'; const testImageBeforePath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-before.jpg'; const testImageAfterPath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg'; +/** + * Compares two images and finds the number of different pixels. + * + * @param {ImageData} imgA - ImageData for the first image. + * @param {ImageData} imgB - ImageData for the second image. + * @param {number} threshold - Color difference threshold [0..255]. Smaller - stricter. + * @returns {number} - Number of different pixels. + */ +function pixelsDiff(imgA, imgB, threshold = 0) { + if (imgA.width !== imgB.width || imgA.height !== imgB.height) { + throw new Error('Images must have the same size'); + } + + let differentPixels = 0; + const numColorParams = 4; // RGBA + + for (let pixelIndex = 0; pixelIndex < imgA.data.length; pixelIndex += numColorParams) { + // Get pixel's color for each image. + const [aR, aG, aB] = imgA.data.subarray(pixelIndex, pixelIndex + numColorParams); + const [bR, bG, bB] = imgB.data.subarray(pixelIndex, pixelIndex + numColorParams); + + // Get average pixel's color for each image (make them greyscale). + const aAvgColor = Math.floor((aR + aG + aB) / 3); + const bAvgColor = Math.floor((bR + bG + bB) / 3); + + // Compare pixel colors. + if (Math.abs(aAvgColor - bAvgColor) > threshold) { + differentPixels += 1; + } + } + + return differentPixels; +} + describe('resizeImageWidth', () => { it('should perform content-aware image width reduction', () => { // @see: https://jestjs.io/docs/asynchronous @@ -21,6 +55,7 @@ describe('resizeImageWidth', () => { const canvasAfter = createCanvas(imgAfter.width, imgAfter.height); const ctxAfter = canvasAfter.getContext('2d'); ctxAfter.drawImage(imgAfter, 0, 0, imgAfter.width, imgAfter.height); + const imgDataAfter = ctxAfter.getImageData(0, 0, imgAfter.width, imgAfter.height); const toWidth = Math.floor(imgBefore.width / 2); @@ -44,8 +79,9 @@ describe('resizeImageWidth', () => { expect(imgDataTest.width).toBe(imgAfter.width); expect(imgDataTest.height).toBe(imgAfter.height); - // @TODO: Check that images are identical. - // expect(canvasTest.toDataURL()).toEqual(canvasAfter.toDataURL()); + const colorThreshold = 10; + const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); + expect(differentPixels).toBe(0); }); }); }); From d4285412a17bf4071e48830761a01d97761d2d81 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb <trehleb@gmail.com> Date: Wed, 21 Apr 2021 07:31:07 +0200 Subject: [PATCH 2/5] Tune the Seam Carving tests. --- .../seam-carving/__tests__/resizeImageWidth.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index bd9340fc71..7c44aafb03 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -79,7 +79,7 @@ describe('resizeImageWidth', () => { expect(imgDataTest.width).toBe(imgAfter.width); expect(imgDataTest.height).toBe(imgAfter.height); - const colorThreshold = 10; + const colorThreshold = 50; const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); expect(differentPixels).toBe(0); }); From c89241a5b5f56e5f5dbecfc03ae2643e0c9517e9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb <trehleb@gmail.com> Date: Wed, 21 Apr 2021 07:33:12 +0200 Subject: [PATCH 3/5] Tune the Seam Carving tests. --- .../seam-carving/__tests__/resizeImageWidth.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index 7c44aafb03..9e52d3c515 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -79,7 +79,8 @@ describe('resizeImageWidth', () => { expect(imgDataTest.width).toBe(imgAfter.width); expect(imgDataTest.height).toBe(imgAfter.height); - const colorThreshold = 50; + const pixelsTreshold = 50; + const colorThreshold = 100; const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); expect(differentPixels).toBe(0); }); From 0adad2b7ff24ee43b60d23829f8b7da35ac45f75 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb <trehleb@gmail.com> Date: Wed, 21 Apr 2021 07:36:50 +0200 Subject: [PATCH 4/5] Tune the Seam Carving tests. --- .../seam-carving/__tests__/resizeImageWidth.test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index 9e52d3c515..8f91391caa 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -79,10 +79,13 @@ describe('resizeImageWidth', () => { expect(imgDataTest.width).toBe(imgAfter.width); expect(imgDataTest.height).toBe(imgAfter.height); - const pixelsTreshold = 50; - const colorThreshold = 100; + const colorThreshold = 50; const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); - expect(differentPixels).toBe(0); + + // Allow 10% of pixels to be different + const pixelsThreshold = Math.floor(imgAfter.width * imgAfter.height); + + expect(differentPixels).toBeLessThanOrEqual(pixelsThreshold); }); }); }); From 4b39862bbacddd2bc0505ff57ee9c0c000031e2e Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb <trehleb@gmail.com> Date: Wed, 21 Apr 2021 07:37:43 +0200 Subject: [PATCH 5/5] Tune the Seam Carving tests. --- .../seam-carving/__tests__/resizeImageWidth.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index 8f91391caa..9afed97123 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -83,7 +83,7 @@ describe('resizeImageWidth', () => { const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); // Allow 10% of pixels to be different - const pixelsThreshold = Math.floor(imgAfter.width * imgAfter.height); + const pixelsThreshold = Math.floor((imgAfter.width * imgAfter.height) / 10); expect(differentPixels).toBeLessThanOrEqual(pixelsThreshold); });