Skip to content

Commit f0b246a

Browse files
authored
Adding a Seam Carving algorithm with Dynamic Programming implementation. (trekhleb#693)
* Adding a Seam Carving algorithm with Dynamic Programming implementation. * Adding a Seam Carving algorithm with Dynamic Programming implementation. * Adding a Seam Carving algorithm with Dynamic Programming implementation. * Testing Husky integration. * Testing Husky integration.
1 parent 028ffa6 commit f0b246a

File tree

13 files changed

+2838
-1193
lines changed

13 files changed

+2838
-1193
lines changed

.husky/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_

.husky/pre-commit

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
. "$(dirname "$0")/_/husky.sh"
3+
4+
# npm run lint
5+
# npm run test

.huskyrc.json

Lines changed: 0 additions & 5 deletions
This file was deleted.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ a set of rules that precisely define a sequence of operations.
152152
* `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)
153153
* `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm
154154
* `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm
155+
* **Image Processing**
156+
* `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
155157
* **Uncategorized**
156158
* `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower)
157159
* `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm
@@ -203,6 +205,7 @@ algorithm is an abstraction higher than a computer program.
203205
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
204206
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
205207
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
208+
* `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm
206209
* `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
207210
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
208211
* `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)

package-lock.json

Lines changed: 1464 additions & 1186 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"lint": "eslint ./src/**",
88
"test": "jest",
99
"coverage": "npm run test -- --coverage",
10-
"ci": "npm run lint && npm run coverage"
10+
"ci": "npm run lint && npm run coverage",
11+
"prepare": "husky install"
1112
},
1213
"repository": {
1314
"type": "git",
@@ -37,13 +38,14 @@
3738
"@babel/cli": "7.12.10",
3839
"@babel/preset-env": "7.12.11",
3940
"@types/jest": "26.0.19",
41+
"canvas": "^2.7.0",
4042
"eslint": "7.16.0",
4143
"eslint-config-airbnb": "18.2.1",
4244
"eslint-plugin-import": "2.22.1",
4345
"eslint-plugin-jest": "24.1.3",
4446
"eslint-plugin-jsx-a11y": "6.4.1",
4547
"eslint-plugin-react": "7.21.5",
46-
"husky": "4.3.6",
48+
"husky": "6.0.0",
4749
"jest": "26.6.3"
4850
},
4951
"dependencies": {}

src/algorithms/image-processing/seam-carving/README.md

Lines changed: 509 additions & 0 deletions
Large diffs are not rendered by default.

src/algorithms/image-processing/seam-carving/README.ru-RU.md

Lines changed: 509 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { createCanvas, loadImage } from 'canvas';
2+
import resizeImageWidth from '../resizeImageWidth';
3+
4+
const testImageBeforePath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-before.jpg';
5+
const testImageAfterPath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg';
6+
7+
describe('resizeImageWidth', () => {
8+
it('should perform content-aware image width reduction', () => {
9+
// @see: https://jestjs.io/docs/asynchronous
10+
return Promise.all([
11+
loadImage(testImageBeforePath),
12+
loadImage(testImageAfterPath),
13+
]).then(([imgBefore, imgAfter]) => {
14+
// Original image.
15+
const canvasBefore = createCanvas(imgBefore.width, imgBefore.height);
16+
const ctxBefore = canvasBefore.getContext('2d');
17+
ctxBefore.drawImage(imgBefore, 0, 0, imgBefore.width, imgBefore.height);
18+
const imgDataBefore = ctxBefore.getImageData(0, 0, imgBefore.width, imgBefore.height);
19+
20+
// Resized image saved.
21+
const canvasAfter = createCanvas(imgAfter.width, imgAfter.height);
22+
const ctxAfter = canvasAfter.getContext('2d');
23+
ctxAfter.drawImage(imgAfter, 0, 0, imgAfter.width, imgAfter.height);
24+
25+
const toWidth = Math.floor(imgBefore.width / 2);
26+
27+
const {
28+
img: resizedImg,
29+
size: resizedSize,
30+
} = resizeImageWidth({ img: imgDataBefore, toWidth });
31+
32+
expect(resizedImg).toBeDefined();
33+
expect(resizedSize).toBeDefined();
34+
35+
// Resized image generated.
36+
const canvasTest = createCanvas(resizedSize.w, resizedSize.h);
37+
const ctxTest = canvasTest.getContext('2d');
38+
ctxTest.putImageData(resizedImg, 0, 0, 0, 0, resizedSize.w, resizedSize.h);
39+
const imgDataTest = ctxTest.getImageData(0, 0, resizedSize.w, resizedSize.h);
40+
41+
expect(resizedSize).toEqual({ w: toWidth, h: imgBefore.height });
42+
expect(imgDataTest.width).toBe(toWidth);
43+
expect(imgDataTest.height).toBe(imgBefore.height);
44+
expect(imgDataTest.width).toBe(imgAfter.width);
45+
expect(imgDataTest.height).toBe(imgAfter.height);
46+
47+
// @TODO: Check that images are identical.
48+
// expect(canvasTest.toDataURL()).toEqual(canvasAfter.toDataURL());
49+
});
50+
});
51+
});
Loading

0 commit comments

Comments
 (0)