From cfd9a630ff8cacd17880b16b27f32781eaac6bb7 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 07:39:58 +0200 Subject: [PATCH] Test that two images are identical for the Seam Carving algorithm. (#694) * Test that two images are identical for the Seam Carving algorithm. * Tune the Seam Carving tests. * Tune the Seam Carving tests. * Tune the Seam Carving tests. * Tune the Seam Carving tests. --- .husky/pre-commit | 1 + .../__tests__/resizeImageWidth.test.js | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index bec1c08a..a29a4166 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 b6400a35..9afed971 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,13 @@ 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 = 50; + const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); + + // Allow 10% of pixels to be different + const pixelsThreshold = Math.floor((imgAfter.width * imgAfter.height) / 10); + + expect(differentPixels).toBeLessThanOrEqual(pixelsThreshold); }); }); });