image-js 0.35.1 → 0.35.3
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/index.d.ts +99 -35
- package/lib/browser/environment.js +0 -6
- package/lib/browser/worker/extend.js +0 -3
- package/lib/browser/worker/process/background.js +0 -12
- package/lib/browser/worker/worker.js +0 -17
- package/lib/image/Image.js +18 -51
- package/lib/image/compute/colorHistogram.js +0 -8
- package/lib/image/compute/countAlphaPixels.js +0 -3
- package/lib/image/compute/extendedPoints.js +2 -7
- package/lib/image/compute/histogram.js +6 -25
- package/lib/image/compute/localMaxima.js +2 -10
- package/lib/image/compute/max.js +0 -5
- package/lib/image/compute/mean.js +0 -4
- package/lib/image/compute/median.js +0 -4
- package/lib/image/compute/min.js +0 -5
- package/lib/image/compute/minimalBoundingRectangle.js +5 -18
- package/lib/image/compute/moment.js +0 -3
- package/lib/image/compute/monotoneChainConvexHull.js +0 -3
- package/lib/image/compute/points.js +0 -3
- package/lib/image/compute/relativePosition.js +2 -8
- package/lib/image/compute/sum.js +0 -5
- package/lib/image/core/bitMethods.js +0 -11
- package/lib/image/core/checkProcessable.js +0 -13
- package/lib/image/core/environment.js +0 -8
- package/lib/image/core/export.js +0 -38
- package/lib/image/core/extend.js +0 -13
- package/lib/image/core/getRGBAData.js +0 -15
- package/lib/image/core/kind.js +4 -28
- package/lib/image/core/kindNames.js +1 -0
- package/lib/image/core/load.js +1 -53
- package/lib/image/core/mediaTypes.js +0 -2
- package/lib/image/core/valueMethods.js +0 -13
- package/lib/image/extend.js +7 -83
- package/lib/image/filter/abs.js +0 -3
- package/lib/image/filter/add.js +2 -8
- package/lib/image/filter/background.js +0 -9
- package/lib/image/filter/blurFilter.js +0 -6
- package/lib/image/filter/divide.js +0 -8
- package/lib/image/filter/flipX.js +0 -5
- package/lib/image/filter/flipY.js +0 -4
- package/lib/image/filter/gaussianFilter.js +0 -5
- package/lib/image/filter/gradientFilter.js +0 -10
- package/lib/image/filter/hypotenuse.js +0 -13
- package/lib/image/filter/invert.js +0 -9
- package/lib/image/filter/level.js +1 -19
- package/lib/image/filter/medianFilter.js +0 -15
- package/lib/image/filter/multiply.js +0 -10
- package/lib/image/filter/scharrFilter.js +0 -4
- package/lib/image/filter/sobelFilter.js +0 -4
- package/lib/image/filter/subtract.js +0 -8
- package/lib/image/filter/subtractImage.js +0 -10
- package/lib/image/internal/checks.js +1 -9
- package/lib/image/internal/clamp.js +0 -1
- package/lib/image/internal/copy.js +0 -2
- package/lib/image/internal/copyAlphaChannel.js +0 -1
- package/lib/image/internal/getImageParameters.js +0 -1
- package/lib/image/internal/getOutputImage.js +1 -13
- package/lib/image/model/model.js +1 -1
- package/lib/image/morphology/blackHat.js +0 -5
- package/lib/image/morphology/close.js +0 -5
- package/lib/image/morphology/dilate.js +0 -40
- package/lib/image/morphology/erode.js +0 -40
- package/lib/image/morphology/morphologicalGradient.js +0 -5
- package/lib/image/morphology/open.js +0 -5
- package/lib/image/morphology/topHat.js +0 -5
- package/lib/image/operator/cannyEdge.js +0 -3
- package/lib/image/operator/convolution.js +9 -34
- package/lib/image/operator/convolutionSeparable.js +0 -10
- package/lib/image/operator/extract.js +4 -13
- package/lib/image/operator/floodFill.js +2 -15
- package/lib/image/operator/getSeparatedKernel.js +0 -2
- package/lib/image/operator/paintLabels.js +8 -19
- package/lib/image/operator/paintMasks.js +2 -12
- package/lib/image/operator/paintPoints.js +0 -9
- package/lib/image/operator/paintPolygon.js +1 -15
- package/lib/image/operator/paintPolygons.js +2 -6
- package/lib/image/operator/paintPolyline.js +0 -7
- package/lib/image/operator/paintPolylines.js +1 -5
- package/lib/image/roi/Roi.js +27 -207
- package/lib/image/roi/RoiLayer.js +1 -22
- package/lib/image/roi/RoiMap.js +5 -38
- package/lib/image/roi/creator/fromMask.js +4 -22
- package/lib/image/roi/creator/fromMaskConnectedComponentLabelingAlgorithm.js +2 -20
- package/lib/image/roi/creator/fromMaxima.js +10 -43
- package/lib/image/roi/creator/fromPoints.js +2 -10
- package/lib/image/roi/creator/fromWaterShed.js +6 -17
- package/lib/image/roi/feretDiameters.js +9 -21
- package/lib/image/roi/manager.js +30 -119
- package/lib/image/roi/util/commonBorderLength.js +5 -16
- package/lib/image/roi/util/mergeRoi.js +2 -21
- package/lib/image/transform/cmyk.js +0 -9
- package/lib/image/transform/colorDepth.js +0 -12
- package/lib/image/transform/crop.js +0 -20
- package/lib/image/transform/cropAlpha.js +0 -11
- package/lib/image/transform/grey.js +0 -16
- package/lib/image/transform/greyAlgorithms.js +1 -24
- package/lib/image/transform/hsl.js +0 -16
- package/lib/image/transform/hsv.js +0 -15
- package/lib/image/transform/insert.js +0 -6
- package/lib/image/transform/mask/huang.js +3 -18
- package/lib/image/transform/mask/intermodes.js +3 -14
- package/lib/image/transform/mask/isodata.js +0 -14
- package/lib/image/transform/mask/li.js +12 -42
- package/lib/image/transform/mask/mask.js +1 -13
- package/lib/image/transform/mask/maxEntropy.js +8 -25
- package/lib/image/transform/mask/mean.js +1 -3
- package/lib/image/transform/mask/minError.js +10 -21
- package/lib/image/transform/mask/minimum.js +0 -20
- package/lib/image/transform/mask/moments.js +4 -17
- package/lib/image/transform/mask/otsu.js +1 -7
- package/lib/image/transform/mask/percentile.js +0 -8
- package/lib/image/transform/mask/renyiEntropy.js +8 -34
- package/lib/image/transform/mask/shanbhag.js +8 -25
- package/lib/image/transform/mask/thresholdAlgorithms.js +1 -17
- package/lib/image/transform/mask/triangle.js +13 -29
- package/lib/image/transform/mask/yen.js +2 -14
- package/lib/image/transform/pad.js +0 -20
- package/lib/image/transform/resize/nearestNeighbor.js +0 -6
- package/lib/image/transform/resize/resize.js +0 -16
- package/lib/image/transform/rgba.js +0 -9
- package/lib/image/transform/rgba8.js +0 -3
- package/lib/image/transform/rotate.js +0 -29
- package/lib/image/transform/rotateFree.js +0 -31
- package/lib/image/transform/warping.js +2 -35
- package/lib/image/utility/combineChannels.js +0 -11
- package/lib/image/utility/getBestMatch.js +2 -13
- package/lib/image/utility/getChannel.js +0 -10
- package/lib/image/utility/getClosestCommonParent.js +6 -23
- package/lib/image/utility/getColumn.js +0 -4
- package/lib/image/utility/getIntersection.js +2 -18
- package/lib/image/utility/getMatrix.js +0 -7
- package/lib/image/utility/getPixelsArray.js +0 -5
- package/lib/image/utility/getPixelsGrid.js +0 -11
- package/lib/image/utility/getRow.js +0 -4
- package/lib/image/utility/getSimilarity.js +3 -17
- package/lib/image/utility/getThreshold.js +0 -4
- package/lib/image/utility/setBorder.js +0 -16
- package/lib/image/utility/setChannel.js +0 -6
- package/lib/image/utility/setMatrix.js +0 -6
- package/lib/image/utility/split.js +2 -15
- package/lib/index.js +0 -12
- package/lib/kernel/kernel.js +0 -3
- package/lib/kernel/laplacianOfGaussian.js +1 -7
- package/lib/node_modules/test/binary.js +0 -3
- package/lib/node_modules/test/oneRoi.js +0 -2
- package/lib/stack/Stack.js +2 -35
- package/lib/stack/compute/histogram.js +0 -4
- package/lib/stack/compute/histograms.js +0 -4
- package/lib/stack/compute/max.js +0 -3
- package/lib/stack/compute/median.js +0 -4
- package/lib/stack/compute/min.js +0 -3
- package/lib/stack/extend.js +1 -11
- package/lib/stack/transform/matchAndCrop.js +6 -19
- package/lib/stack/utility/averageImage.js +0 -9
- package/lib/stack/utility/maxImage.js +0 -7
- package/lib/stack/utility/minImage.js +0 -7
- package/lib/util/Shape.js +3 -40
- package/lib/util/base64.js +3 -14
- package/lib/util/channel.js +1 -35
- package/lib/util/color.js +1 -25
- package/lib/util/converter.js +1 -13
- package/lib/util/deepValue.js +0 -3
- package/lib/util/histogram.js +1 -12
- package/lib/util/kernel.js +2 -12
- package/lib/util/matrix.js +0 -13
- package/lib/util/points.js +12 -35
- package/lib/util/value.js +0 -7
- package/lib/util/zerosMatrix.js +0 -3
- package/package.json +2 -2
- package/src/image/operator/paintLabels.js +6 -6
- package/src/image/operator/paintPolygon.js +1 -1
- package/src/image/operator/paintPolygons.js +2 -2
- package/src/image/operator/paintPolylines.js +1 -1
|
@@ -4,11 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _Roi = _interopRequireDefault(require("./Roi"));
|
|
9
|
-
|
|
10
8
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* A layer that is caracterised by a {@link RoiMap} and that will
|
|
14
11
|
* generated automatically the corresponding ROI.
|
|
@@ -28,6 +25,7 @@ class RoiLayer {
|
|
|
28
25
|
this.options = options;
|
|
29
26
|
this.roi = this.createRoi();
|
|
30
27
|
}
|
|
28
|
+
|
|
31
29
|
/**
|
|
32
30
|
* Roi are created from a roiMap
|
|
33
31
|
* The roiMap contains mainty an array of identifiers that define
|
|
@@ -36,19 +34,15 @@ class RoiLayer {
|
|
|
36
34
|
* @instance
|
|
37
35
|
* @return {Roi[]}
|
|
38
36
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
37
|
createRoi() {
|
|
42
38
|
// we need to find all all the different IDs there is in the data
|
|
43
39
|
let data = this.roiMap.data;
|
|
44
40
|
let mapIDs = {};
|
|
45
41
|
this.roiMap.positive = 0;
|
|
46
42
|
this.roiMap.negative = 0;
|
|
47
|
-
|
|
48
43
|
for (let i = 0; i < data.length; i++) {
|
|
49
44
|
if (data[i] && !mapIDs[data[i]]) {
|
|
50
45
|
mapIDs[data[i]] = true;
|
|
51
|
-
|
|
52
46
|
if (data[i] > 0) {
|
|
53
47
|
this.roiMap.positive++;
|
|
54
48
|
} else {
|
|
@@ -56,58 +50,43 @@ class RoiLayer {
|
|
|
56
50
|
}
|
|
57
51
|
}
|
|
58
52
|
}
|
|
59
|
-
|
|
60
53
|
let rois = {};
|
|
61
|
-
|
|
62
54
|
for (let mapID in mapIDs) {
|
|
63
55
|
rois[mapID] = new _Roi.default(this.roiMap, mapID * 1);
|
|
64
56
|
}
|
|
65
|
-
|
|
66
57
|
let width = this.roiMap.width;
|
|
67
58
|
let height = this.roiMap.height;
|
|
68
|
-
|
|
69
59
|
for (let y = 0; y < height; y++) {
|
|
70
60
|
for (let x = 0; x < width; x++) {
|
|
71
61
|
let target = y * width + x;
|
|
72
|
-
|
|
73
62
|
if (data[target] !== 0) {
|
|
74
63
|
const mapID = data[target];
|
|
75
64
|
const roi = rois[mapID];
|
|
76
|
-
|
|
77
65
|
if (x < roi.minX) {
|
|
78
66
|
roi.minX = x;
|
|
79
67
|
}
|
|
80
|
-
|
|
81
68
|
if (x > roi.maxX) {
|
|
82
69
|
roi.maxX = x;
|
|
83
70
|
}
|
|
84
|
-
|
|
85
71
|
if (y < roi.minY) {
|
|
86
72
|
roi.minY = y;
|
|
87
73
|
}
|
|
88
|
-
|
|
89
74
|
if (y > roi.maxY) {
|
|
90
75
|
roi.maxY = y;
|
|
91
76
|
}
|
|
92
|
-
|
|
93
77
|
roi.meanX += x;
|
|
94
78
|
roi.meanY += y;
|
|
95
79
|
roi.surface++;
|
|
96
80
|
}
|
|
97
81
|
}
|
|
98
82
|
}
|
|
99
|
-
|
|
100
83
|
let roiArray = [];
|
|
101
|
-
|
|
102
84
|
for (let mapID in mapIDs) {
|
|
103
85
|
rois[mapID].meanX /= rois[mapID].surface;
|
|
104
86
|
rois[mapID].meanY /= rois[mapID].surface;
|
|
105
87
|
roiArray.push(rois[mapID]);
|
|
106
88
|
}
|
|
107
|
-
|
|
108
89
|
return roiArray;
|
|
109
90
|
}
|
|
110
|
-
|
|
111
91
|
}
|
|
112
|
-
|
|
113
92
|
exports.default = RoiLayer;
|
package/lib/image/roi/RoiMap.js
CHANGED
|
@@ -4,13 +4,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _commonBorderLength = _interopRequireDefault(require("./util/commonBorderLength"));
|
|
9
|
-
|
|
10
8
|
var _mergeRoi = _interopRequireDefault(require("./util/mergeRoi"));
|
|
11
|
-
|
|
12
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
-
|
|
14
10
|
/**
|
|
15
11
|
* The roiMap is an array of the size of the original image data that contains
|
|
16
12
|
* positive and negative numbers. When the number is common, it corresponds
|
|
@@ -19,6 +15,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
19
15
|
* @class RoiMap
|
|
20
16
|
* @private
|
|
21
17
|
*/
|
|
18
|
+
|
|
22
19
|
class RoiMap {
|
|
23
20
|
constructor(parent, data) {
|
|
24
21
|
this.parent = parent;
|
|
@@ -28,49 +25,39 @@ class RoiMap {
|
|
|
28
25
|
this.negative = 0;
|
|
29
26
|
this.positive = 0;
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
get total() {
|
|
33
29
|
return this.negative + this.positive;
|
|
34
30
|
}
|
|
35
|
-
|
|
36
31
|
get minMax() {
|
|
37
32
|
let min = Number.MAX_SAFE_INTEGER;
|
|
38
33
|
let max = Number.MIN_SAFE_INTEGER;
|
|
39
|
-
|
|
40
34
|
for (let i = 0; i < this.data.length; i++) {
|
|
41
35
|
if (this.data[i] < min) min = this.data[i];
|
|
42
36
|
if (this.data[i] > max) max = this.data[i];
|
|
43
37
|
}
|
|
44
|
-
|
|
45
38
|
return {
|
|
46
39
|
min,
|
|
47
40
|
max
|
|
48
41
|
};
|
|
49
42
|
}
|
|
50
|
-
|
|
51
43
|
get commonBorderLength() {
|
|
52
44
|
return (0, _commonBorderLength.default)(this);
|
|
53
45
|
}
|
|
54
|
-
|
|
55
46
|
mergeRoi(options = {}) {
|
|
56
47
|
return _mergeRoi.default.call(this, options);
|
|
57
48
|
}
|
|
58
|
-
|
|
59
49
|
mergeRois(rois) {
|
|
60
50
|
const first = rois[0];
|
|
61
51
|
const others = rois.slice(1);
|
|
62
|
-
|
|
63
52
|
for (let i = 0; i < this.data.length; i++) {
|
|
64
53
|
if (others.includes(this.data[i])) {
|
|
65
54
|
this.data[i] = first;
|
|
66
55
|
}
|
|
67
56
|
}
|
|
68
57
|
}
|
|
69
|
-
|
|
70
58
|
rowsInfo() {
|
|
71
59
|
let rowsInfo = new Array(this.height);
|
|
72
60
|
let currentRow = 0;
|
|
73
|
-
|
|
74
61
|
for (let i = 0; i < this.data.length; i += this.width) {
|
|
75
62
|
let info = {
|
|
76
63
|
row: currentRow,
|
|
@@ -87,27 +74,21 @@ class RoiMap {
|
|
|
87
74
|
let changes = [];
|
|
88
75
|
let previous = this.data[i];
|
|
89
76
|
let current = 0;
|
|
90
|
-
|
|
91
77
|
for (let j = i; j < i + this.width; j++) {
|
|
92
78
|
let value = this.data[j];
|
|
93
|
-
|
|
94
79
|
if (previous !== value) {
|
|
95
80
|
previous = value;
|
|
96
81
|
changes.push(current);
|
|
97
82
|
current = 0;
|
|
98
83
|
}
|
|
99
|
-
|
|
100
84
|
current++;
|
|
101
|
-
|
|
102
85
|
if (value > 0) {
|
|
103
86
|
info.positivePixel++;
|
|
104
|
-
|
|
105
87
|
if (!positives[value]) {
|
|
106
88
|
positives[value] = true;
|
|
107
89
|
}
|
|
108
90
|
} else if (value < 0) {
|
|
109
91
|
info.negativePixel++;
|
|
110
|
-
|
|
111
92
|
if (!negatives[value]) {
|
|
112
93
|
negatives[value] = true;
|
|
113
94
|
}
|
|
@@ -115,23 +96,19 @@ class RoiMap {
|
|
|
115
96
|
info.zeroPixel++;
|
|
116
97
|
}
|
|
117
98
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
99
|
+
changes.push(current);
|
|
100
|
+
// TODO use median package
|
|
121
101
|
info.medianChange = changes.sort((a, b) => a - b)[Math.floor(changes.length / 2)];
|
|
122
102
|
info.positiveRoiIDs = Object.keys(positives);
|
|
123
103
|
info.negativeRoiIDs = Object.keys(negatives);
|
|
124
104
|
info.positiveRoi = info.positiveRoiIDs.length;
|
|
125
105
|
info.negativeRoi = info.negativeRoiIDs.length;
|
|
126
106
|
}
|
|
127
|
-
|
|
128
107
|
return rowsInfo;
|
|
129
108
|
}
|
|
130
|
-
|
|
131
109
|
colsInfo() {
|
|
132
110
|
let colsInfo = new Array(this.width);
|
|
133
111
|
let currentCol = 0;
|
|
134
|
-
|
|
135
112
|
for (let i = 0; i < this.width; i++) {
|
|
136
113
|
let info = {
|
|
137
114
|
col: currentCol,
|
|
@@ -148,27 +125,21 @@ class RoiMap {
|
|
|
148
125
|
let changes = [];
|
|
149
126
|
let previous = this.data[i];
|
|
150
127
|
let current = 0;
|
|
151
|
-
|
|
152
128
|
for (let j = i; j < i + this.data.length; j += this.width) {
|
|
153
129
|
let value = this.data[j];
|
|
154
|
-
|
|
155
130
|
if (previous !== value) {
|
|
156
131
|
previous = value;
|
|
157
132
|
changes.push(current);
|
|
158
133
|
current = 0;
|
|
159
134
|
}
|
|
160
|
-
|
|
161
135
|
current++;
|
|
162
|
-
|
|
163
136
|
if (value > 0) {
|
|
164
137
|
info.positivePixel++;
|
|
165
|
-
|
|
166
138
|
if (!positives[value]) {
|
|
167
139
|
positives[value] = true;
|
|
168
140
|
}
|
|
169
141
|
} else if (value < 0) {
|
|
170
142
|
info.negativePixel++;
|
|
171
|
-
|
|
172
143
|
if (!negatives[value]) {
|
|
173
144
|
negatives[value] = true;
|
|
174
145
|
}
|
|
@@ -176,19 +147,15 @@ class RoiMap {
|
|
|
176
147
|
info.zeroPixel++;
|
|
177
148
|
}
|
|
178
149
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
150
|
+
changes.push(current);
|
|
151
|
+
// TODO use median package
|
|
182
152
|
info.medianChange = changes.sort((a, b) => a - b)[Math.floor(changes.length / 2)];
|
|
183
153
|
info.positiveRoiIDs = Object.keys(positives);
|
|
184
154
|
info.negativeRoiIDs = Object.keys(negatives);
|
|
185
155
|
info.positiveRoi = info.positiveRoiIDs.length;
|
|
186
156
|
info.negativeRoi = info.negativeRoiIDs.length;
|
|
187
157
|
}
|
|
188
|
-
|
|
189
158
|
return colsInfo;
|
|
190
159
|
}
|
|
191
|
-
|
|
192
160
|
}
|
|
193
|
-
|
|
194
161
|
exports.default = RoiMap;
|
|
@@ -4,11 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = fromMask;
|
|
7
|
-
|
|
8
7
|
var _RoiMap = _interopRequireDefault(require("../RoiMap"));
|
|
9
|
-
|
|
10
8
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
-
|
|
12
9
|
/**
|
|
13
10
|
* @memberof RoiManager
|
|
14
11
|
* @instance
|
|
@@ -21,15 +18,14 @@ function fromMask(mask, options = {}) {
|
|
|
21
18
|
allowCorners = false
|
|
22
19
|
} = options;
|
|
23
20
|
const MAX_ARRAY = 0x00ffff; // 65535 should be enough for most of the cases
|
|
24
|
-
// based on a binary image we will create plenty of small images
|
|
25
21
|
|
|
22
|
+
// based on a binary image we will create plenty of small images
|
|
26
23
|
let data = new Int16Array(mask.size); // maxValue: 32767, minValue: -32768
|
|
27
|
-
// split will always return an array of images
|
|
28
24
|
|
|
25
|
+
// split will always return an array of images
|
|
29
26
|
let positiveID = 0;
|
|
30
27
|
let negativeID = 0;
|
|
31
28
|
let xToProcess = new Uint16Array(MAX_ARRAY + 1); // assign dynamically ????
|
|
32
|
-
|
|
33
29
|
let yToProcess = new Uint16Array(MAX_ARRAY + 1); // mask +1 is of course mandatory !!!
|
|
34
30
|
|
|
35
31
|
for (let x = 0; x < mask.width; x++) {
|
|
@@ -40,25 +36,21 @@ function fromMask(mask, options = {}) {
|
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
}
|
|
43
|
-
|
|
44
39
|
function analyseSurface(x, y) {
|
|
45
40
|
let from = 0;
|
|
46
41
|
let to = 0;
|
|
47
42
|
let targetState = mask.getBitXY(x, y);
|
|
48
43
|
let id = targetState ? ++positiveID : --negativeID;
|
|
49
|
-
|
|
50
44
|
if (positiveID > 32767 || negativeID < -32768) {
|
|
51
45
|
throw new Error('Too many regions of interest');
|
|
52
46
|
}
|
|
53
|
-
|
|
54
47
|
xToProcess[0] = x;
|
|
55
48
|
yToProcess[0] = y;
|
|
56
|
-
|
|
57
49
|
while (from <= to) {
|
|
58
50
|
let currentX = xToProcess[from & MAX_ARRAY];
|
|
59
51
|
let currentY = yToProcess[from & MAX_ARRAY];
|
|
60
|
-
data[currentY * mask.width + currentX] = id;
|
|
61
|
-
|
|
52
|
+
data[currentY * mask.width + currentX] = id;
|
|
53
|
+
// need to check all around mask pixel
|
|
62
54
|
if (currentX > 0 && data[currentY * mask.width + currentX - 1] === 0 && mask.getBitXY(currentX - 1, currentY) === targetState) {
|
|
63
55
|
// LEFT
|
|
64
56
|
to++;
|
|
@@ -66,7 +58,6 @@ function fromMask(mask, options = {}) {
|
|
|
66
58
|
yToProcess[to & MAX_ARRAY] = currentY;
|
|
67
59
|
data[currentY * mask.width + currentX - 1] = -32768;
|
|
68
60
|
}
|
|
69
|
-
|
|
70
61
|
if (currentY > 0 && data[(currentY - 1) * mask.width + currentX] === 0 && mask.getBitXY(currentX, currentY - 1) === targetState) {
|
|
71
62
|
// TOP
|
|
72
63
|
to++;
|
|
@@ -74,7 +65,6 @@ function fromMask(mask, options = {}) {
|
|
|
74
65
|
yToProcess[to & MAX_ARRAY] = currentY - 1;
|
|
75
66
|
data[(currentY - 1) * mask.width + currentX] = -32768;
|
|
76
67
|
}
|
|
77
|
-
|
|
78
68
|
if (currentX < mask.width - 1 && data[currentY * mask.width + currentX + 1] === 0 && mask.getBitXY(currentX + 1, currentY) === targetState) {
|
|
79
69
|
// RIGHT
|
|
80
70
|
to++;
|
|
@@ -82,7 +72,6 @@ function fromMask(mask, options = {}) {
|
|
|
82
72
|
yToProcess[to & MAX_ARRAY] = currentY;
|
|
83
73
|
data[currentY * mask.width + currentX + 1] = -32768;
|
|
84
74
|
}
|
|
85
|
-
|
|
86
75
|
if (currentY < mask.height - 1 && data[(currentY + 1) * mask.width + currentX] === 0 && mask.getBitXY(currentX, currentY + 1) === targetState) {
|
|
87
76
|
// BOTTOM
|
|
88
77
|
to++;
|
|
@@ -90,7 +79,6 @@ function fromMask(mask, options = {}) {
|
|
|
90
79
|
yToProcess[to & MAX_ARRAY] = currentY + 1;
|
|
91
80
|
data[(currentY + 1) * mask.width + currentX] = -32768;
|
|
92
81
|
}
|
|
93
|
-
|
|
94
82
|
if (allowCorners) {
|
|
95
83
|
if (currentX > 0 && currentY > 0 && data[(currentY - 1) * mask.width + currentX - 1] === 0 && mask.getBitXY(currentX - 1, currentY - 1) === targetState) {
|
|
96
84
|
// TOP LEFT
|
|
@@ -99,7 +87,6 @@ function fromMask(mask, options = {}) {
|
|
|
99
87
|
yToProcess[to & MAX_ARRAY] = currentY - 1;
|
|
100
88
|
data[(currentY - 1) * mask.width + currentX - 1] = -32768;
|
|
101
89
|
}
|
|
102
|
-
|
|
103
90
|
if (currentX < mask.width - 1 && currentY > 0 && data[(currentY - 1) * mask.width + currentX + 1] === 0 && mask.getBitXY(currentX + 1, currentY - 1) === targetState) {
|
|
104
91
|
// TOP RIGHT
|
|
105
92
|
to++;
|
|
@@ -107,7 +94,6 @@ function fromMask(mask, options = {}) {
|
|
|
107
94
|
yToProcess[to & MAX_ARRAY] = currentY - 1;
|
|
108
95
|
data[(currentY - 1) * mask.width + currentX + 1] = -32768;
|
|
109
96
|
}
|
|
110
|
-
|
|
111
97
|
if (currentX > 0 && currentY < mask.height - 1 && data[(currentY + 1) * mask.width + currentX - 1] === 0 && mask.getBitXY(currentX - 1, currentY + 1) === targetState) {
|
|
112
98
|
// BOTTOM LEFT
|
|
113
99
|
to++;
|
|
@@ -115,7 +101,6 @@ function fromMask(mask, options = {}) {
|
|
|
115
101
|
yToProcess[to & MAX_ARRAY] = currentY + 1;
|
|
116
102
|
data[(currentY + 1) * mask.width + currentX - 1] = -32768;
|
|
117
103
|
}
|
|
118
|
-
|
|
119
104
|
if (currentX < mask.width - 1 && currentY < mask.height - 1 && data[(currentY + 1) * mask.width + currentX + 1] === 0 && mask.getBitXY(currentX + 1, currentY + 1) === targetState) {
|
|
120
105
|
// BOTTOM RIGHT
|
|
121
106
|
to++;
|
|
@@ -124,14 +109,11 @@ function fromMask(mask, options = {}) {
|
|
|
124
109
|
data[(currentY + 1) * mask.width + currentX + 1] = -32768;
|
|
125
110
|
}
|
|
126
111
|
}
|
|
127
|
-
|
|
128
112
|
from++;
|
|
129
|
-
|
|
130
113
|
if (to - from > MAX_ARRAY) {
|
|
131
114
|
throw new Error('analyseMask can not finish, the array to manage internal data is not big enough.' + 'You could improve mask by changing MAX_ARRAY');
|
|
132
115
|
}
|
|
133
116
|
}
|
|
134
117
|
}
|
|
135
|
-
|
|
136
118
|
return new _RoiMap.default(mask, data);
|
|
137
119
|
}
|
|
@@ -4,43 +4,37 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = fromMaskConnectedComponentLabelingAlgorithm;
|
|
7
|
-
|
|
8
7
|
var _mlDisjointSet = _interopRequireDefault(require("ml-disjoint-set"));
|
|
9
|
-
|
|
10
8
|
var _RoiMap = _interopRequireDefault(require("../RoiMap"));
|
|
11
|
-
|
|
12
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
-
|
|
14
10
|
/*
|
|
15
11
|
This algorithm is nice and is therefore kept here
|
|
16
12
|
However it seems to be slower than the get mask and
|
|
17
13
|
also provides only the positive ROI
|
|
18
14
|
We therefore don't expose it in the roiManager
|
|
19
15
|
*/
|
|
16
|
+
|
|
20
17
|
const direction4X = [-1, 0];
|
|
21
18
|
const direction4Y = [0, -1];
|
|
22
19
|
const neighbours4 = [null, null];
|
|
23
20
|
const direction8X = [-1, -1, 0, 1];
|
|
24
21
|
const direction8Y = [0, -1, -1, -1];
|
|
25
22
|
const neighbours8 = [null, null, null, null];
|
|
23
|
+
|
|
26
24
|
/*
|
|
27
25
|
Implementation of the connected-component labeling algorithm
|
|
28
26
|
*/
|
|
29
|
-
|
|
30
27
|
function fromMaskConnectedComponentLabelingAlgorithm(mask, options = {}) {
|
|
31
28
|
const {
|
|
32
29
|
allowCorners = false
|
|
33
30
|
} = options;
|
|
34
31
|
let neighbours = 4;
|
|
35
|
-
|
|
36
32
|
if (allowCorners) {
|
|
37
33
|
neighbours = 8;
|
|
38
34
|
}
|
|
39
|
-
|
|
40
35
|
let directionX;
|
|
41
36
|
let directionY;
|
|
42
37
|
let neighboursList;
|
|
43
|
-
|
|
44
38
|
if (neighbours === 8) {
|
|
45
39
|
directionX = direction8X;
|
|
46
40
|
directionY = direction8Y;
|
|
@@ -52,7 +46,6 @@ function fromMaskConnectedComponentLabelingAlgorithm(mask, options = {}) {
|
|
|
52
46
|
} else {
|
|
53
47
|
throw new RangeError(`unsupported neighbours count: ${neighbours}`);
|
|
54
48
|
}
|
|
55
|
-
|
|
56
49
|
const size = mask.size;
|
|
57
50
|
const width = mask.width;
|
|
58
51
|
const height = mask.height;
|
|
@@ -60,40 +53,32 @@ function fromMaskConnectedComponentLabelingAlgorithm(mask, options = {}) {
|
|
|
60
53
|
const data = new Uint32Array(size);
|
|
61
54
|
const linked = new _mlDisjointSet.default();
|
|
62
55
|
let currentLabel = 1;
|
|
63
|
-
|
|
64
56
|
for (let j = 0; j < height; j++) {
|
|
65
57
|
for (let i = 0; i < width; i++) {
|
|
66
58
|
// true means out of background
|
|
67
59
|
const index = i + j * width;
|
|
68
|
-
|
|
69
60
|
if (mask.getBit(index)) {
|
|
70
61
|
let smallestNeighbour = null;
|
|
71
|
-
|
|
72
62
|
for (let k = 0; k < neighboursList.length; k++) {
|
|
73
63
|
const ii = i + directionX[k];
|
|
74
64
|
const jj = j + directionY[k];
|
|
75
|
-
|
|
76
65
|
if (ii >= 0 && jj >= 0 && ii < width && jj < height) {
|
|
77
66
|
const index = ii + jj * width;
|
|
78
67
|
let neighbour = labels[index];
|
|
79
|
-
|
|
80
68
|
if (!neighbour) {
|
|
81
69
|
neighboursList[k] = null;
|
|
82
70
|
} else {
|
|
83
71
|
neighboursList[k] = neighbour;
|
|
84
|
-
|
|
85
72
|
if (!smallestNeighbour || neighboursList[k].value < smallestNeighbour.value) {
|
|
86
73
|
smallestNeighbour = neighboursList[k];
|
|
87
74
|
}
|
|
88
75
|
}
|
|
89
76
|
}
|
|
90
77
|
}
|
|
91
|
-
|
|
92
78
|
if (!smallestNeighbour) {
|
|
93
79
|
labels[index] = linked.add(currentLabel++);
|
|
94
80
|
} else {
|
|
95
81
|
labels[index] = smallestNeighbour;
|
|
96
|
-
|
|
97
82
|
for (let k = 0; k < neighboursList.length; k++) {
|
|
98
83
|
if (neighboursList[k] && neighboursList[k] !== smallestNeighbour) {
|
|
99
84
|
linked.union(smallestNeighbour, neighboursList[k]);
|
|
@@ -103,16 +88,13 @@ function fromMaskConnectedComponentLabelingAlgorithm(mask, options = {}) {
|
|
|
103
88
|
}
|
|
104
89
|
}
|
|
105
90
|
}
|
|
106
|
-
|
|
107
91
|
for (let j = 0; j < height; j++) {
|
|
108
92
|
for (let i = 0; i < width; i++) {
|
|
109
93
|
const index = i + j * width;
|
|
110
|
-
|
|
111
94
|
if (mask.getBit(index)) {
|
|
112
95
|
data[index] = linked.find(labels[index]).value;
|
|
113
96
|
}
|
|
114
97
|
}
|
|
115
98
|
}
|
|
116
|
-
|
|
117
99
|
return new _RoiMap.default(mask, data);
|
|
118
100
|
}
|