-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilter.worker.js
128 lines (109 loc) · 4.12 KB
/
filter.worker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
importScripts('opencv/opencv.js');
cv.onRuntimeInitialized = () => postMessage({type: 'RUNTIME_INITIALIZED'});
addEventListener('message', function handleMessage({data}) {
const imgMat = cv.matFromImageData(data);
const [points, highestFillRatio, image] = calculateBoundingRectPoints(imgMat);
let imageData;
if (image) {
imageData = convertToImageData(image);
image.delete();
}
imgMat.delete();
postMessage({
type: 'FRAME',
imageData,
points,
fillRatio: highestFillRatio,
}, imageData && [imageData.data.buffer]);
});
function convertToImageData(imgMat) {
return new ImageData(new Uint8ClampedArray(imgMat.data, imgMat.cols, imgMat.rows), imgMat.cols);
}
function findCorners(biggestContour) {
if (!biggestContour) {
return;
}
let points;
let epsilon = 0.03 * cv.arcLength(biggestContour, true);
let approx = new cv.Mat();
cv.approxPolyDP(biggestContour, approx, epsilon, true);
if (approx.rows === 4) {
points = [];
for (let i = 0; i < 4; i++) {
points.push(new cv.Point(approx.intAt(i * 2), approx.intAt(i * 2 + 1)));
}
}
approx.delete();
return points;
}
function calculateBoundingRectPoints(imgMat) {
const contours = new cv.MatVector();
const hierarchy = new cv.Mat();
const debugMat = new cv.Mat();
let highestFillRatio = 0;
let points;
let biggestContour;
cv.cvtColor(imgMat, debugMat, cv.COLOR_BGR2GRAY);
cv.medianBlur(debugMat, debugMat, 7);
cv.Canny(debugMat, debugMat, 80, 190);
cv.findContours(debugMat, contours, hierarchy, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE);
for (let i = 0; i < contours.size(); ++i) {
let currentContour = contours.get(i);
let boundingArea = imgMat.cols * imgMat.rows;
let contourArea = cv.contourArea(currentContour);
let fillRatio = contourArea / boundingArea;
if (highestFillRatio < fillRatio) {
highestFillRatio = fillRatio;
biggestContour = currentContour;
}
}
let image;
points = findCorners(biggestContour);
if (points) {
const boundingRect = cv.minAreaRect(biggestContour);
const boundingRectPoints = cv.RotatedRect.points(boundingRect);
transformImage(imgMat, convertPointsTo1DArray(points), convertPointsTo1DArray(boundingRectPoints));
image = clipImage(imgMat, boundingRect);
}
contours.delete();
hierarchy.delete();
debugMat.delete();
return [points, highestFillRatio, image];
}
function convertPointsTo1DArray(points) {
return [
points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y,
points[3].x, points[3].y,
];
}
function transformImage(mat, sourcePoints, targetPoints) {
let dsize = new cv.Size(mat.cols, mat.rows);
let srcTri = cv.matFromArray(4, 1, cv.CV_32FC2, sourcePoints);
let dstTri = cv.matFromArray(4, 1, cv.CV_32FC2, targetPoints);
let M = cv.getPerspectiveTransform(srcTri, dstTri);
cv.warpPerspective(mat, mat, M, dsize, cv.INTER_LINEAR, cv.BORDER_CONSTANT, new cv.Scalar());
M.delete();
srcTri.delete();
dstTri.delete();
}
function clipImage(imgMat, boundingRect) {
const scalingFactor = 2;
boundingRect.center = {x: boundingRect.center.x * scalingFactor, y: boundingRect.center.y * scalingFactor};
const translationM = cv.matFromArray(2, 3, cv.CV_64FC1, [1, 0, (scalingFactor - 1) / 2 * imgMat.cols, 0, 1, (scalingFactor - 1) / 2 * imgMat.rows]);
const rotationM = cv.getRotationMatrix2D(boundingRect.center, boundingRect.angle, 1);
const dstSize = new cv.Size(imgMat.cols * scalingFactor, imgMat.rows * scalingFactor);
const roi = new cv.Rect(
boundingRect.center.x - boundingRect.size.width / 2,
boundingRect.center.y - boundingRect.size.height / 2,
boundingRect.size.width,
boundingRect.size.height,
);
const dst = new cv.Mat(dstSize, cv.CV_8UC4);
cv.warpAffine(imgMat, dst, translationM, dstSize);
//cv.warpAffine(dst, dst, rotationM, dstSize);
translationM.delete();
rotationM.delete();
return dst;
}