jscanify 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/jscanify.js CHANGED
@@ -1,254 +1,255 @@
1
- /*! jscanify v1.2.0 | (c) ColonelParrot and other contributors | MIT License */
2
-
3
- (function (global, factory) {
4
- typeof exports === "object" && typeof module !== "undefined"
5
- ? (module.exports = factory())
6
- : typeof define === "function" && define.amd
7
- ? define(factory)
8
- : (global.jscanify = factory());
9
- })(this, function () {
10
- "use strict";
11
-
12
- /**
13
- * Calculates distance between two points. Each point must have `x` and `y` property
14
- * @param {*} p1 point 1
15
- * @param {*} p2 point 2
16
- * @returns distance between two points
17
- */
18
- function distance(p1, p2) {
19
- return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
20
- }
21
-
22
- class jscanify {
23
- constructor() {}
24
-
25
- /**
26
- * Finds the contour of the paper within the image
27
- * @param {*} img image to process (cv.Mat)
28
- * @returns the biggest contour inside the image
29
- */
30
- findPaperContour(img) {
31
- const imgGray = new cv.Mat();
32
- cv.cvtColor(img, imgGray, cv.COLOR_RGBA2GRAY);
33
-
34
- const imgBlur = new cv.Mat();
35
- cv.GaussianBlur(
36
- imgGray,
37
- imgBlur,
38
- new cv.Size(5, 5),
39
- 0,
40
- 0,
41
- cv.BORDER_DEFAULT
42
- );
43
-
44
- const imgThresh = new cv.Mat();
45
- cv.threshold(
46
- imgBlur,
47
- imgThresh,
48
- 0,
49
- 255,
50
- cv.THRESH_BINARY + cv.THRESH_OTSU
51
- );
52
-
53
- let contours = new cv.MatVector();
54
- let hierarchy = new cv.Mat();
55
-
56
- cv.findContours(
57
- imgThresh,
58
- contours,
59
- hierarchy,
60
- cv.RETR_CCOMP,
61
- cv.CHAIN_APPROX_SIMPLE
62
- );
63
- let maxArea = 0;
64
- let maxContourIndex = -1;
65
- for (let i = 0; i < contours.size(); ++i) {
66
- let contourArea = cv.contourArea(contours.get(i));
67
- if (contourArea > maxArea) {
68
- maxArea = contourArea;
69
- maxContourIndex = i;
70
- }
71
- }
72
-
73
- const maxContour = contours.get(maxContourIndex);
74
-
75
- imgGray.delete();
76
- imgBlur.delete();
77
- imgThresh.delete();
78
- contours.delete();
79
- hierarchy.delete();
80
- return maxContour;
81
- }
82
-
83
- /**
84
- * Highlights the paper detected inside the image.
85
- * @param {*} image image to process
86
- * @param {*} options options for highlighting. Accepts `color` and `thickness` parameter
87
- * @returns `HTMLCanvasElement` with original image and paper highlighted
88
- */
89
- highlightPaper(image, options) {
90
- options = options || {};
91
- options.color = options.color || "orange";
92
- options.thickness = options.thickness || 10;
93
- const canvas = document.createElement("canvas");
94
- const ctx = canvas.getContext("2d");
95
- const img = cv.imread(image);
96
-
97
- const maxContour = this.findPaperContour(img);
98
- cv.imshow(canvas, img);
99
- if (maxContour) {
100
- const {
101
- topLeftCorner,
102
- topRightCorner,
103
- bottomLeftCorner,
104
- bottomRightCorner,
105
- } = this.getCornerPoints(maxContour, img);
106
-
107
- if (
108
- topLeftCorner &&
109
- topRightCorner &&
110
- bottomLeftCorner &&
111
- bottomRightCorner
112
- ) {
113
- ctx.strokeStyle = options.color;
114
- ctx.lineWidth = options.thickness;
115
- ctx.beginPath();
116
- ctx.moveTo(...Object.values(topLeftCorner));
117
- ctx.lineTo(...Object.values(topRightCorner));
118
- ctx.lineTo(...Object.values(bottomRightCorner));
119
- ctx.lineTo(...Object.values(bottomLeftCorner));
120
- ctx.lineTo(...Object.values(topLeftCorner));
121
- ctx.stroke();
122
- }
123
- }
124
-
125
- img.delete();
126
- return canvas;
127
- }
128
-
129
- /**
130
- * Extracts and undistorts the image detected within the frame.
131
- * @param {*} image image to process
132
- * @param {*} resultWidth desired result paper width
133
- * @param {*} resultHeight desired result paper height
134
- * @param {*} onComplete callback with `HTMLCanvasElement` passed - the unwarped paper
135
- * @param {*} cornerPoints optional custom corner points, in case automatic corner points are incorrect
136
- */
137
- extractPaper(image, resultWidth, resultHeight, cornerPoints) {
138
- const canvas = document.createElement("canvas");
139
-
140
- const img = cv.imread(image);
141
-
142
- const maxContour = this.findPaperContour(img);
143
-
144
- const {
145
- topLeftCorner,
146
- topRightCorner,
147
- bottomLeftCorner,
148
- bottomRightCorner,
149
- } = cornerPoints || this.getCornerPoints(maxContour, img);
150
- let warpedDst = new cv.Mat();
151
-
152
- let dsize = new cv.Size(resultWidth, resultHeight);
153
- let srcTri = cv.matFromArray(4, 1, cv.CV_32FC2, [
154
- topLeftCorner.x,
155
- topLeftCorner.y,
156
- topRightCorner.x,
157
- topRightCorner.y,
158
- bottomLeftCorner.x,
159
- bottomLeftCorner.y,
160
- bottomRightCorner.x,
161
- bottomRightCorner.y,
162
- ]);
163
-
164
- let dstTri = cv.matFromArray(4, 1, cv.CV_32FC2, [
165
- 0,
166
- 0,
167
- resultWidth,
168
- 0,
169
- 0,
170
- resultHeight,
171
- resultWidth,
172
- resultHeight,
173
- ]);
174
-
175
- let M = cv.getPerspectiveTransform(srcTri, dstTri);
176
- cv.warpPerspective(
177
- img,
178
- warpedDst,
179
- M,
180
- dsize,
181
- cv.INTER_LINEAR,
182
- cv.BORDER_CONSTANT,
183
- new cv.Scalar()
184
- );
185
-
186
- cv.imshow(canvas, warpedDst);
187
-
188
- img.delete()
189
- warpedDst.delete()
190
- return canvas;
191
- }
192
-
193
- /**
194
- * Calculates the corner points of a contour.
195
- * @param {*} contour contour from {@link findPaperContour}
196
- * @returns object with properties `topLeftCorner`, `topRightCorner`, `bottomLeftCorner`, `bottomRightCorner`, each with `x` and `y` property
197
- */
198
- getCornerPoints(contour) {
199
- let rect = cv.minAreaRect(contour);
200
- const center = rect.center;
201
-
202
- let topLeftCorner;
203
- let topLeftCornerDist = 0;
204
-
205
- let topRightCorner;
206
- let topRightCornerDist = 0;
207
-
208
- let bottomLeftCorner;
209
- let bottomLeftCornerDist = 0;
210
-
211
- let bottomRightCorner;
212
- let bottomRightCornerDist = 0;
213
-
214
- for (let i = 0; i < contour.data32S.length; i += 2) {
215
- const point = { x: contour.data32S[i], y: contour.data32S[i + 1] };
216
- const dist = distance(point, center);
217
- if (point.x < center.x && point.y < center.y) {
218
- // top left
219
- if (dist > topLeftCornerDist) {
220
- topLeftCorner = point;
221
- topLeftCornerDist = dist;
222
- }
223
- } else if (point.x > center.x && point.y < center.y) {
224
- // top right
225
- if (dist > topRightCornerDist) {
226
- topRightCorner = point;
227
- topRightCornerDist = dist;
228
- }
229
- } else if (point.x < center.x && point.y > center.y) {
230
- // bottom left
231
- if (dist > bottomLeftCornerDist) {
232
- bottomLeftCorner = point;
233
- bottomLeftCornerDist = dist;
234
- }
235
- } else if (point.x > center.x && point.y > center.y) {
236
- // bottom right
237
- if (dist > bottomRightCornerDist) {
238
- bottomRightCorner = point;
239
- bottomRightCornerDist = dist;
240
- }
241
- }
242
- }
243
-
244
- return {
245
- topLeftCorner,
246
- topRightCorner,
247
- bottomLeftCorner,
248
- bottomRightCorner,
249
- };
250
- }
251
- }
252
-
253
- return jscanify;
254
- });
1
+ /*! jscanify v1.3.1 | (c) ColonelParrot and other contributors | MIT License */
2
+
3
+ (function (global, factory) {
4
+ typeof exports === "object" && typeof module !== "undefined"
5
+ ? (module.exports = factory())
6
+ : typeof define === "function" && define.amd
7
+ ? define(factory)
8
+ : (global.jscanify = factory());
9
+ })(this, function () {
10
+ "use strict";
11
+
12
+ /**
13
+ * Calculates distance between two points. Each point must have `x` and `y` property
14
+ * @param {*} p1 point 1
15
+ * @param {*} p2 point 2
16
+ * @returns distance between two points
17
+ */
18
+ function distance(p1, p2) {
19
+ return Math.hypot(p1.x - p2.x, p1.y - p2.y);
20
+ }
21
+
22
+ class jscanify {
23
+ constructor() { }
24
+
25
+ /**
26
+ * Finds the contour of the paper within the image
27
+ * @param {*} img image to process (cv.Mat)
28
+ * @returns the biggest contour inside the image
29
+ */
30
+ findPaperContour(img) {
31
+ const imgGray = new cv.Mat();
32
+ cv.Canny(img, imgGray, 50, 200);
33
+
34
+ const imgBlur = new cv.Mat();
35
+ cv.GaussianBlur(
36
+ imgGray,
37
+ imgBlur,
38
+ new cv.Size(3, 3),
39
+ 0,
40
+ 0,
41
+ cv.BORDER_DEFAULT
42
+ );
43
+
44
+ const imgThresh = new cv.Mat();
45
+ cv.threshold(
46
+ imgBlur,
47
+ imgThresh,
48
+ 0,
49
+ 255,
50
+ cv.THRESH_OTSU
51
+ );
52
+
53
+ let contours = new cv.MatVector();
54
+ let hierarchy = new cv.Mat();
55
+
56
+ cv.findContours(
57
+ imgThresh,
58
+ contours,
59
+ hierarchy,
60
+ cv.RETR_CCOMP,
61
+ cv.CHAIN_APPROX_SIMPLE
62
+ );
63
+
64
+ let maxArea = 0;
65
+ let maxContourIndex = -1;
66
+ for (let i = 0; i < contours.size(); ++i) {
67
+ let contourArea = cv.contourArea(contours.get(i));
68
+ if (contourArea > maxArea) {
69
+ maxArea = contourArea;
70
+ maxContourIndex = i;
71
+ }
72
+ }
73
+
74
+ const maxContour = contours.get(maxContourIndex);
75
+
76
+ imgGray.delete();
77
+ imgBlur.delete();
78
+ imgThresh.delete();
79
+ contours.delete();
80
+ hierarchy.delete();
81
+ return maxContour;
82
+ }
83
+
84
+ /**
85
+ * Highlights the paper detected inside the image.
86
+ * @param {*} image image to process
87
+ * @param {*} options options for highlighting. Accepts `color` and `thickness` parameter
88
+ * @returns `HTMLCanvasElement` with original image and paper highlighted
89
+ */
90
+ highlightPaper(image, options) {
91
+ options = options || {};
92
+ options.color = options.color || "orange";
93
+ options.thickness = options.thickness || 10;
94
+ const canvas = document.createElement("canvas");
95
+ const ctx = canvas.getContext("2d");
96
+ const img = cv.imread(image);
97
+
98
+ const maxContour = this.findPaperContour(img);
99
+ cv.imshow(canvas, img);
100
+ if (maxContour) {
101
+ const {
102
+ topLeftCorner,
103
+ topRightCorner,
104
+ bottomLeftCorner,
105
+ bottomRightCorner,
106
+ } = this.getCornerPoints(maxContour, img);
107
+
108
+ if (
109
+ topLeftCorner &&
110
+ topRightCorner &&
111
+ bottomLeftCorner &&
112
+ bottomRightCorner
113
+ ) {
114
+ ctx.strokeStyle = options.color;
115
+ ctx.lineWidth = options.thickness;
116
+ ctx.beginPath();
117
+ ctx.moveTo(...Object.values(topLeftCorner));
118
+ ctx.lineTo(...Object.values(topRightCorner));
119
+ ctx.lineTo(...Object.values(bottomRightCorner));
120
+ ctx.lineTo(...Object.values(bottomLeftCorner));
121
+ ctx.lineTo(...Object.values(topLeftCorner));
122
+ ctx.stroke();
123
+ }
124
+ }
125
+
126
+ img.delete();
127
+ return canvas;
128
+ }
129
+
130
+ /**
131
+ * Extracts and undistorts the image detected within the frame.
132
+ * @param {*} image image to process
133
+ * @param {*} resultWidth desired result paper width
134
+ * @param {*} resultHeight desired result paper height
135
+ * @param {*} cornerPoints optional custom corner points, in case automatic corner points are incorrect
136
+ * @returns `HTMLCanvasElement` containing undistorted image
137
+ */
138
+ extractPaper(image, resultWidth, resultHeight, cornerPoints) {
139
+ const canvas = document.createElement("canvas");
140
+
141
+ const img = cv.imread(image);
142
+
143
+ const maxContour = this.findPaperContour(img);
144
+
145
+ const {
146
+ topLeftCorner,
147
+ topRightCorner,
148
+ bottomLeftCorner,
149
+ bottomRightCorner,
150
+ } = cornerPoints || this.getCornerPoints(maxContour, img);
151
+ let warpedDst = new cv.Mat();
152
+
153
+ let dsize = new cv.Size(resultWidth, resultHeight);
154
+ let srcTri = cv.matFromArray(4, 1, cv.CV_32FC2, [
155
+ topLeftCorner.x,
156
+ topLeftCorner.y,
157
+ topRightCorner.x,
158
+ topRightCorner.y,
159
+ bottomLeftCorner.x,
160
+ bottomLeftCorner.y,
161
+ bottomRightCorner.x,
162
+ bottomRightCorner.y,
163
+ ]);
164
+
165
+ let dstTri = cv.matFromArray(4, 1, cv.CV_32FC2, [
166
+ 0,
167
+ 0,
168
+ resultWidth,
169
+ 0,
170
+ 0,
171
+ resultHeight,
172
+ resultWidth,
173
+ resultHeight,
174
+ ]);
175
+
176
+ let M = cv.getPerspectiveTransform(srcTri, dstTri);
177
+ cv.warpPerspective(
178
+ img,
179
+ warpedDst,
180
+ M,
181
+ dsize,
182
+ cv.INTER_LINEAR,
183
+ cv.BORDER_CONSTANT,
184
+ new cv.Scalar()
185
+ );
186
+
187
+ cv.imshow(canvas, warpedDst);
188
+
189
+ img.delete()
190
+ warpedDst.delete()
191
+ return canvas;
192
+ }
193
+
194
+ /**
195
+ * Calculates the corner points of a contour.
196
+ * @param {*} contour contour from {@link findPaperContour}
197
+ * @returns object with properties `topLeftCorner`, `topRightCorner`, `bottomLeftCorner`, `bottomRightCorner`, each with `x` and `y` property
198
+ */
199
+ getCornerPoints(contour) {
200
+ let rect = cv.minAreaRect(contour);
201
+ const center = rect.center;
202
+
203
+ let topLeftCorner;
204
+ let topLeftCornerDist = 0;
205
+
206
+ let topRightCorner;
207
+ let topRightCornerDist = 0;
208
+
209
+ let bottomLeftCorner;
210
+ let bottomLeftCornerDist = 0;
211
+
212
+ let bottomRightCorner;
213
+ let bottomRightCornerDist = 0;
214
+
215
+ for (let i = 0; i < contour.data32S.length; i += 2) {
216
+ const point = { x: contour.data32S[i], y: contour.data32S[i + 1] };
217
+ const dist = distance(point, center);
218
+ if (point.x < center.x && point.y < center.y) {
219
+ // top left
220
+ if (dist > topLeftCornerDist) {
221
+ topLeftCorner = point;
222
+ topLeftCornerDist = dist;
223
+ }
224
+ } else if (point.x > center.x && point.y < center.y) {
225
+ // top right
226
+ if (dist > topRightCornerDist) {
227
+ topRightCorner = point;
228
+ topRightCornerDist = dist;
229
+ }
230
+ } else if (point.x < center.x && point.y > center.y) {
231
+ // bottom left
232
+ if (dist > bottomLeftCornerDist) {
233
+ bottomLeftCorner = point;
234
+ bottomLeftCornerDist = dist;
235
+ }
236
+ } else if (point.x > center.x && point.y > center.y) {
237
+ // bottom right
238
+ if (dist > bottomRightCornerDist) {
239
+ bottomRightCorner = point;
240
+ bottomRightCornerDist = dist;
241
+ }
242
+ }
243
+ }
244
+
245
+ return {
246
+ topLeftCorner,
247
+ topRightCorner,
248
+ bottomLeftCorner,
249
+ bottomRightCorner,
250
+ };
251
+ }
252
+ }
253
+
254
+ return jscanify;
255
+ });