image-js 0.35.2 → 0.35.4

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.
Files changed (170) hide show
  1. package/index.d.ts +3 -10
  2. package/lib/browser/environment.js +0 -6
  3. package/lib/browser/worker/extend.js +0 -3
  4. package/lib/browser/worker/process/background.js +0 -12
  5. package/lib/browser/worker/worker.js +0 -17
  6. package/lib/image/Image.js +18 -51
  7. package/lib/image/compute/colorHistogram.js +0 -8
  8. package/lib/image/compute/countAlphaPixels.js +0 -3
  9. package/lib/image/compute/extendedPoints.js +2 -7
  10. package/lib/image/compute/histogram.js +6 -25
  11. package/lib/image/compute/localMaxima.js +2 -10
  12. package/lib/image/compute/max.js +0 -5
  13. package/lib/image/compute/mean.js +0 -4
  14. package/lib/image/compute/median.js +0 -4
  15. package/lib/image/compute/min.js +0 -5
  16. package/lib/image/compute/minimalBoundingRectangle.js +5 -18
  17. package/lib/image/compute/moment.js +0 -3
  18. package/lib/image/compute/monotoneChainConvexHull.js +0 -3
  19. package/lib/image/compute/points.js +0 -3
  20. package/lib/image/compute/relativePosition.js +2 -8
  21. package/lib/image/compute/sum.js +0 -5
  22. package/lib/image/core/bitMethods.js +0 -11
  23. package/lib/image/core/checkProcessable.js +0 -13
  24. package/lib/image/core/environment.js +0 -8
  25. package/lib/image/core/export.js +0 -38
  26. package/lib/image/core/extend.js +0 -13
  27. package/lib/image/core/getRGBAData.js +0 -15
  28. package/lib/image/core/kind.js +4 -28
  29. package/lib/image/core/kindNames.js +1 -0
  30. package/lib/image/core/load.js +1 -53
  31. package/lib/image/core/mediaTypes.js +0 -2
  32. package/lib/image/core/valueMethods.js +0 -13
  33. package/lib/image/extend.js +7 -83
  34. package/lib/image/filter/abs.js +0 -3
  35. package/lib/image/filter/add.js +2 -8
  36. package/lib/image/filter/background.js +0 -9
  37. package/lib/image/filter/blurFilter.js +0 -6
  38. package/lib/image/filter/divide.js +0 -8
  39. package/lib/image/filter/flipX.js +0 -5
  40. package/lib/image/filter/flipY.js +0 -4
  41. package/lib/image/filter/gaussianFilter.js +0 -5
  42. package/lib/image/filter/gradientFilter.js +0 -11
  43. package/lib/image/filter/hypotenuse.js +0 -13
  44. package/lib/image/filter/invert.js +0 -9
  45. package/lib/image/filter/level.js +1 -19
  46. package/lib/image/filter/medianFilter.js +0 -15
  47. package/lib/image/filter/multiply.js +0 -10
  48. package/lib/image/filter/scharrFilter.js +0 -4
  49. package/lib/image/filter/sobelFilter.js +0 -4
  50. package/lib/image/filter/subtract.js +0 -8
  51. package/lib/image/filter/subtractImage.js +0 -10
  52. package/lib/image/internal/checks.js +1 -9
  53. package/lib/image/internal/clamp.js +0 -1
  54. package/lib/image/internal/copy.js +0 -2
  55. package/lib/image/internal/copyAlphaChannel.js +0 -1
  56. package/lib/image/internal/getImageParameters.js +0 -1
  57. package/lib/image/internal/getOutputImage.js +1 -13
  58. package/lib/image/model/model.js +1 -1
  59. package/lib/image/morphology/blackHat.js +0 -5
  60. package/lib/image/morphology/close.js +0 -5
  61. package/lib/image/morphology/dilate.js +0 -40
  62. package/lib/image/morphology/erode.js +0 -40
  63. package/lib/image/morphology/morphologicalGradient.js +0 -5
  64. package/lib/image/morphology/open.js +0 -5
  65. package/lib/image/morphology/topHat.js +0 -5
  66. package/lib/image/operator/cannyEdge.js +0 -3
  67. package/lib/image/operator/convolution.js +9 -34
  68. package/lib/image/operator/convolutionSeparable.js +0 -10
  69. package/lib/image/operator/extract.js +4 -13
  70. package/lib/image/operator/floodFill.js +2 -15
  71. package/lib/image/operator/getSeparatedKernel.js +0 -2
  72. package/lib/image/operator/paintLabels.js +2 -13
  73. package/lib/image/operator/paintMasks.js +2 -12
  74. package/lib/image/operator/paintPoints.js +0 -9
  75. package/lib/image/operator/paintPolygon.js +0 -14
  76. package/lib/image/operator/paintPolygons.js +0 -4
  77. package/lib/image/operator/paintPolyline.js +0 -7
  78. package/lib/image/operator/paintPolylines.js +0 -4
  79. package/lib/image/roi/Roi.js +27 -208
  80. package/lib/image/roi/RoiLayer.js +1 -22
  81. package/lib/image/roi/RoiMap.js +5 -38
  82. package/lib/image/roi/creator/fromMask.js +4 -22
  83. package/lib/image/roi/creator/fromMaskConnectedComponentLabelingAlgorithm.js +2 -20
  84. package/lib/image/roi/creator/fromMaxima.js +10 -43
  85. package/lib/image/roi/creator/fromPoints.js +2 -10
  86. package/lib/image/roi/creator/fromWaterShed.js +6 -17
  87. package/lib/image/roi/feretDiameters.js +9 -21
  88. package/lib/image/roi/manager.js +30 -119
  89. package/lib/image/roi/util/commonBorderLength.js +5 -16
  90. package/lib/image/roi/util/mergeRoi.js +2 -21
  91. package/lib/image/transform/cmyk.js +0 -9
  92. package/lib/image/transform/colorDepth.js +0 -12
  93. package/lib/image/transform/crop.js +0 -20
  94. package/lib/image/transform/cropAlpha.js +0 -11
  95. package/lib/image/transform/grey.js +0 -17
  96. package/lib/image/transform/greyAlgorithms.js +1 -24
  97. package/lib/image/transform/hsl.js +0 -16
  98. package/lib/image/transform/hsv.js +0 -15
  99. package/lib/image/transform/insert.js +0 -6
  100. package/lib/image/transform/mask/huang.js +3 -18
  101. package/lib/image/transform/mask/intermodes.js +3 -14
  102. package/lib/image/transform/mask/isodata.js +0 -14
  103. package/lib/image/transform/mask/li.js +12 -42
  104. package/lib/image/transform/mask/mask.js +1 -13
  105. package/lib/image/transform/mask/maxEntropy.js +8 -25
  106. package/lib/image/transform/mask/mean.js +1 -3
  107. package/lib/image/transform/mask/minError.js +10 -21
  108. package/lib/image/transform/mask/minimum.js +0 -20
  109. package/lib/image/transform/mask/moments.js +4 -17
  110. package/lib/image/transform/mask/otsu.js +1 -7
  111. package/lib/image/transform/mask/percentile.js +0 -8
  112. package/lib/image/transform/mask/renyiEntropy.js +8 -34
  113. package/lib/image/transform/mask/shanbhag.js +8 -25
  114. package/lib/image/transform/mask/thresholdAlgorithms.js +1 -17
  115. package/lib/image/transform/mask/triangle.js +13 -29
  116. package/lib/image/transform/mask/yen.js +2 -14
  117. package/lib/image/transform/pad.js +0 -20
  118. package/lib/image/transform/resize/nearestNeighbor.js +0 -6
  119. package/lib/image/transform/resize/resize.js +0 -16
  120. package/lib/image/transform/rgba.js +0 -9
  121. package/lib/image/transform/rgba8.js +0 -3
  122. package/lib/image/transform/rotate.js +0 -29
  123. package/lib/image/transform/rotateFree.js +0 -31
  124. package/lib/image/transform/warping.js +2 -35
  125. package/lib/image/utility/combineChannels.js +0 -11
  126. package/lib/image/utility/getBestMatch.js +2 -13
  127. package/lib/image/utility/getChannel.js +0 -10
  128. package/lib/image/utility/getClosestCommonParent.js +6 -23
  129. package/lib/image/utility/getColumn.js +0 -4
  130. package/lib/image/utility/getIntersection.js +2 -18
  131. package/lib/image/utility/getMatrix.js +0 -7
  132. package/lib/image/utility/getPixelsArray.js +0 -5
  133. package/lib/image/utility/getPixelsGrid.js +0 -11
  134. package/lib/image/utility/getRow.js +0 -4
  135. package/lib/image/utility/getSimilarity.js +3 -17
  136. package/lib/image/utility/getThreshold.js +0 -4
  137. package/lib/image/utility/setBorder.js +0 -16
  138. package/lib/image/utility/setChannel.js +0 -6
  139. package/lib/image/utility/setMatrix.js +3 -6
  140. package/lib/image/utility/split.js +2 -15
  141. package/lib/index.js +0 -12
  142. package/lib/kernel/kernel.js +0 -3
  143. package/lib/kernel/laplacianOfGaussian.js +1 -7
  144. package/lib/node_modules/test/binary.js +0 -3
  145. package/lib/node_modules/test/oneRoi.js +0 -2
  146. package/lib/stack/Stack.js +2 -35
  147. package/lib/stack/compute/histogram.js +0 -4
  148. package/lib/stack/compute/histograms.js +0 -4
  149. package/lib/stack/compute/max.js +0 -3
  150. package/lib/stack/compute/median.js +0 -4
  151. package/lib/stack/compute/min.js +0 -3
  152. package/lib/stack/extend.js +1 -11
  153. package/lib/stack/transform/matchAndCrop.js +6 -19
  154. package/lib/stack/utility/averageImage.js +0 -9
  155. package/lib/stack/utility/maxImage.js +0 -7
  156. package/lib/stack/utility/minImage.js +0 -7
  157. package/lib/util/Shape.js +3 -40
  158. package/lib/util/base64.js +3 -14
  159. package/lib/util/channel.js +1 -35
  160. package/lib/util/color.js +1 -25
  161. package/lib/util/converter.js +1 -13
  162. package/lib/util/deepValue.js +0 -3
  163. package/lib/util/histogram.js +1 -12
  164. package/lib/util/kernel.js +2 -12
  165. package/lib/util/matrix.js +0 -13
  166. package/lib/util/points.js +12 -35
  167. package/lib/util/value.js +0 -7
  168. package/lib/util/zerosMatrix.js +0 -3
  169. package/package.json +1 -1
  170. package/src/image/utility/setMatrix.js +4 -0
@@ -4,32 +4,19 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _monotoneChainConvexHull = _interopRequireDefault(require("monotone-chain-convex-hull"));
9
-
10
8
  var _robustPointInPolygon = _interopRequireDefault(require("robust-point-in-polygon"));
11
-
12
9
  var _Shape = _interopRequireDefault(require("../../util/Shape"));
13
-
14
10
  var _points = require("../../util/points");
15
-
16
11
  var _Image = _interopRequireDefault(require("../Image"));
17
-
18
12
  var _minimalBoundingRectangle = _interopRequireDefault(require("../compute/minimalBoundingRectangle"));
19
-
20
13
  var KindNames = _interopRequireWildcard(require("../core/kindNames"));
21
-
22
14
  var _feretDiameters = _interopRequireDefault(require("./feretDiameters"));
23
-
24
15
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
25
-
26
16
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
27
-
28
17
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
29
-
30
18
  // Many measurements:
31
19
  // https://www.sympatec.com/en/particle-measurement/glossary/particle-shape/#
32
-
33
20
  /**
34
21
  * Class to manage Region Of Interests
35
22
  * @class Roi
@@ -47,6 +34,7 @@ class Roi {
47
34
  this.surface = 0;
48
35
  this.computed = {};
49
36
  }
37
+
50
38
  /**
51
39
  * Returns a binary image (mask) for the corresponding ROI
52
40
  * @param {object} [options]
@@ -54,56 +42,43 @@ class Roi {
54
42
  * @param {string} [options.kind='normal'] - 'contour', 'box', 'filled', 'center', 'hull' or 'normal'
55
43
  * @return {Image} - Returns a mask (1 bit Image)
56
44
  */
57
-
58
-
59
45
  getMask(options = {}) {
60
46
  const {
61
47
  scale = 1,
62
48
  kind = ''
63
49
  } = options;
64
50
  let mask;
65
-
66
51
  switch (kind) {
67
52
  case 'contour':
68
53
  mask = this.contourMask;
69
54
  break;
70
-
71
55
  case 'box':
72
56
  mask = this.boxMask;
73
57
  break;
74
-
75
58
  case 'filled':
76
59
  mask = this.filledMask;
77
60
  break;
78
-
79
61
  case 'center':
80
62
  mask = this.centerMask;
81
63
  break;
82
-
83
64
  case 'mbr':
84
65
  mask = this.mbrFilledMask;
85
66
  break;
86
-
87
67
  case 'hull':
88
68
  mask = this.convexHullFilledMask;
89
69
  break;
90
-
91
70
  case 'hullContour':
92
71
  mask = this.convexHullMask;
93
72
  break;
94
-
95
73
  case 'mbrContour':
96
74
  mask = this.mbrMask;
97
75
  break;
98
-
99
76
  case 'feret':
100
77
  mask = this.feretMask;
101
78
  break;
102
-
103
79
  default:
104
80
  mask = this.mask;
105
81
  }
106
-
107
82
  if (scale < 1) {
108
83
  // by reassigning the mask we loose the parent and therefore the position
109
84
  // we will have to force it back
@@ -114,34 +89,28 @@ class Roi {
114
89
  mask.position[0] += this.minX;
115
90
  mask.position[1] += this.minY;
116
91
  }
117
-
118
92
  return mask;
119
93
  }
120
-
121
94
  get mean() {
122
- throw new Error('Roi mean not implemented yet'); // return [this.meanX,this.meanY];
95
+ throw new Error('Roi mean not implemented yet');
96
+ // return [this.meanX,this.meanY];
123
97
  }
124
98
 
125
99
  get center() {
126
100
  if (!this.computed.center) {
127
101
  this.computed.center = [this.width / 2 >> 0, this.height / 2 >> 0];
128
102
  }
129
-
130
103
  return this.computed.center;
131
104
  }
132
-
133
105
  get ratio() {
134
106
  return this.width / this.height;
135
107
  }
136
-
137
108
  get width() {
138
109
  return this.maxX - this.minX + 1;
139
110
  }
140
-
141
111
  get height() {
142
112
  return this.maxY - this.minY + 1;
143
113
  }
144
-
145
114
  _computExternalIDs() {
146
115
  // take all the borders and remove the internal one ...
147
116
  let borders = this.borderIDs;
@@ -149,7 +118,6 @@ class Roi {
149
118
  this.computed.externalIDs = [];
150
119
  this.computed.externalLengths = [];
151
120
  let internals = this.internalIDs;
152
-
153
121
  for (let i = 0; i < borders.length; i++) {
154
122
  if (!internals.includes(borders[i])) {
155
123
  this.computed.externalIDs.push(borders[i]);
@@ -157,62 +125,50 @@ class Roi {
157
125
  }
158
126
  }
159
127
  }
160
-
161
128
  get externalIDs() {
162
129
  if (this.computed.externalIDs) {
163
130
  return this.computed.externalIDs;
164
131
  }
165
-
166
132
  this._computExternalIDs();
167
-
168
133
  return this.computed.externalIDs;
169
134
  }
170
-
171
135
  get externalLengths() {
172
136
  if (this.computed.externalLengths) {
173
137
  return this.computed.externalLengths;
174
138
  }
175
-
176
139
  this._computExternalIDs();
177
-
178
140
  return this.computed.externalLengths;
179
141
  }
180
-
181
142
  _computeBorderIDs() {
182
143
  let borders = getBorders(this);
183
144
  this.computed.borderIDs = borders.ids;
184
145
  this.computed.borderLengths = borders.lengths;
185
146
  }
147
+
186
148
  /**
187
149
  Retrieve all the IDs (array of number) of the regions that are in contact with this
188
150
  specific region. It may be external or internal
189
151
  */
190
-
191
-
192
152
  get borderIDs() {
193
153
  if (this.computed.borderIDs) {
194
154
  return this.computed.borderIDs;
195
155
  }
196
-
197
156
  this._computeBorderIDs();
198
-
199
157
  return this.computed.borderIDs;
200
158
  }
159
+
201
160
  /**
202
161
  Retrieve all the length (array of number) of the contacts with this
203
162
  specific region. It may be external or internal
204
163
  */
205
-
206
-
207
164
  get borderLengths() {
208
165
  if (this.computed.borderLengths) {
209
166
  return this.computed.borderLengths;
210
167
  }
211
-
212
168
  this._computeBorderIDs();
213
-
214
169
  return this.computed.borderLengths;
215
170
  }
171
+
216
172
  /**
217
173
  Retrieve all the IDs or the Roi touching the box surrouding the region
218
174
  It should really be an array to solve complex cases related to border effect
@@ -233,66 +189,56 @@ class Roi {
233
189
  The cross will be surrouned by 4 differents zones
234
190
  However in most of the cases it will be an array of one element
235
191
  */
236
-
237
-
238
192
  get boxIDs() {
239
193
  if (!this.computed.boxIDs) {
240
194
  this.computed.boxIDs = getBoxIDs(this);
241
195
  }
242
-
243
196
  return this.computed.boxIDs;
244
197
  }
245
-
246
198
  get internalIDs() {
247
199
  if (!this.computed.internalIDs) {
248
200
  this.computed.internalIDs = getInternalIDs(this);
249
201
  }
250
-
251
202
  return this.computed.internalIDs;
252
203
  }
204
+
253
205
  /**
254
206
  Number of pixels of the Roi that touch the rectangle
255
207
  This is useful for the calculation of the border
256
208
  because we will ignore those special pixels of the rectangle
257
209
  border that don't have neighbours all around them.
258
210
  */
259
-
260
-
261
211
  get box() {
262
212
  // points of the Roi that touch the rectangular shape
263
213
  if (!this.computed.box) {
264
214
  this.computed.box = getBox(this);
265
215
  }
266
-
267
216
  return this.computed.box;
268
217
  }
218
+
269
219
  /**
270
220
  Calculates the number of pixels that are in the external border of the Roi
271
221
  Contour are all the pixels that touch an external "zone".
272
222
  All the pixels that touch the box are part of the border and
273
223
  are calculated in the getBoxPixels procedure
274
224
  */
275
-
276
-
277
225
  get external() {
278
226
  if (!this.computed.external) {
279
227
  this.computed.external = getExternal(this);
280
228
  }
281
-
282
229
  return this.computed.external;
283
230
  }
231
+
284
232
  /**
285
233
  Calculates information about holes
286
234
  */
287
-
288
-
289
235
  get holesInfo() {
290
236
  if (!this.computed.holesInfo) {
291
237
  this.computed.holesInfo = getHolesInfo(this);
292
238
  }
293
-
294
239
  return this.computed.holesInfo;
295
240
  }
241
+
296
242
  /**
297
243
  Calculates the number of pixels that are involved in border
298
244
  Border are all the pixels that touch another "zone". It could be external
@@ -300,20 +246,16 @@ class Roi {
300
246
  All the pixels that touch the box are part of the border and
301
247
  are calculated in the getBoxPixels procedure
302
248
  */
303
-
304
-
305
249
  get border() {
306
250
  if (!this.computed.border) {
307
251
  this.computed.border = getBorder(this);
308
252
  }
309
-
310
253
  return this.computed.border;
311
254
  }
255
+
312
256
  /**
313
257
  Returns a binary image (mask) containing only the border of the mask
314
258
  */
315
-
316
-
317
259
  get contourMask() {
318
260
  if (!this.computed.contourMask) {
319
261
  let img = new _Image.default(this.width, this.height, {
@@ -321,7 +263,6 @@ class Roi {
321
263
  position: [this.minX, this.minY],
322
264
  parent: this.map.parent
323
265
  });
324
-
325
266
  for (let x = 0; x < this.width; x++) {
326
267
  for (let y = 0; y < this.height; y++) {
327
268
  if (this.map.data[x + this.minX + (y + this.minY) * this.map.width] === this.id) {
@@ -336,13 +277,10 @@ class Roi {
336
277
  }
337
278
  }
338
279
  }
339
-
340
280
  this.computed.contourMask = img;
341
281
  }
342
-
343
282
  return this.computed.contourMask;
344
283
  }
345
-
346
284
  get boxMask() {
347
285
  if (!this.computed.boxMask) {
348
286
  let img = new _Image.default(this.width, this.height, {
@@ -350,27 +288,22 @@ class Roi {
350
288
  position: [this.minX, this.minY],
351
289
  parent: this.map.parent
352
290
  });
353
-
354
291
  for (let x = 0; x < this.width; x++) {
355
292
  img.setBitXY(x, 0);
356
293
  img.setBitXY(x, this.height - 1);
357
294
  }
358
-
359
295
  for (let y = 0; y < this.height; y++) {
360
296
  img.setBitXY(0, y);
361
297
  img.setBitXY(this.width - 1, y);
362
298
  }
363
-
364
299
  this.computed.boxMask = img;
365
300
  }
366
-
367
301
  return this.computed.boxMask;
368
302
  }
303
+
369
304
  /**
370
305
  Returns a binary image containing the mask
371
306
  */
372
-
373
-
374
307
  get mask() {
375
308
  if (!this.computed.mask) {
376
309
  let img = new _Image.default(this.width, this.height, {
@@ -378,7 +311,6 @@ class Roi {
378
311
  position: [this.minX, this.minY],
379
312
  parent: this.map.parent
380
313
  });
381
-
382
314
  for (let x = 0; x < this.width; x++) {
383
315
  for (let y = 0; y < this.height; y++) {
384
316
  if (this.map.data[x + this.minX + (y + this.minY) * this.map.width] === this.id) {
@@ -386,13 +318,10 @@ class Roi {
386
318
  }
387
319
  }
388
320
  }
389
-
390
321
  this.computed.mask = img;
391
322
  }
392
-
393
323
  return this.computed.mask;
394
324
  }
395
-
396
325
  get filledMask() {
397
326
  if (!this.computed.filledMask) {
398
327
  let img = new _Image.default(this.width, this.height, {
@@ -400,24 +329,19 @@ class Roi {
400
329
  position: [this.minX, this.minY],
401
330
  parent: this.map.parent
402
331
  });
403
-
404
332
  for (let x = 0; x < this.width; x++) {
405
333
  for (let y = 0; y < this.height; y++) {
406
334
  let target = x + this.minX + (y + this.minY) * this.map.width;
407
-
408
335
  if (this.internalIDs.includes(this.map.data[target])) {
409
336
  img.setBitXY(x, y);
410
337
  } // by default a pixel is to 0 so no problems, it will be transparent
411
-
412
338
  }
413
339
  }
414
340
 
415
341
  this.computed.filledMask = img;
416
342
  }
417
-
418
343
  return this.computed.filledMask;
419
344
  }
420
-
421
345
  get centerMask() {
422
346
  if (!this.computed.centerMask) {
423
347
  let img = new _Shape.default({
@@ -427,13 +351,12 @@ class Roi {
427
351
  img.position = [this.minX + this.center[0] - 1, this.minY + this.center[1] - 1];
428
352
  this.computed.centerMask = img;
429
353
  }
430
-
431
354
  return this.computed.centerMask;
432
355
  }
433
-
434
356
  get convexHull() {
435
357
  if (!this.computed.convexHull) {
436
- const calculationPoints = []; // slow approach, we check all the points
358
+ const calculationPoints = [];
359
+ // slow approach, we check all the points
437
360
  // for each point we take the 4 corners !!!!
438
361
 
439
362
  for (let x = 0; x < this.width; x++) {
@@ -456,7 +379,6 @@ class Roi {
456
379
  }
457
380
  }
458
381
  }
459
-
460
382
  const convexHull = (0, _monotoneChainConvexHull.default)(calculationPoints);
461
383
  this.computed.convexHull = {
462
384
  polyline: convexHull,
@@ -464,10 +386,8 @@ class Roi {
464
386
  perimeter: (0, _points.perimeter)(convexHull)
465
387
  };
466
388
  }
467
-
468
389
  return this.computed.convexHull;
469
390
  }
470
-
471
391
  get convexHullMask() {
472
392
  if (!this.computed.convexHullMask) {
473
393
  const convexHull = this.convexHull;
@@ -481,10 +401,8 @@ class Roi {
481
401
  });
482
402
  this.computed.convexHullMask = img;
483
403
  }
484
-
485
404
  return this.computed.convexHullMask;
486
405
  }
487
-
488
406
  get convexHullFilledMask() {
489
407
  if (!this.computed.convexHullFilledMask) {
490
408
  const convexHull = this.convexHull;
@@ -493,7 +411,6 @@ class Roi {
493
411
  position: [this.minX, this.minY],
494
412
  parent: this.map.parent
495
413
  });
496
-
497
414
  for (let x = 0; x < this.width; x++) {
498
415
  for (let y = 0; y < this.height; y++) {
499
416
  if ((0, _robustPointInPolygon.default)(convexHull.polyline, [x, y]) !== 1) {
@@ -501,19 +418,15 @@ class Roi {
501
418
  }
502
419
  }
503
420
  }
504
-
505
421
  this.computed.convexHullFilledMask = img;
506
422
  }
507
-
508
423
  return this.computed.convexHullFilledMask;
509
424
  }
510
-
511
425
  get mbr() {
512
426
  if (!this.computed.mbr) {
513
427
  let mbr = (0, _minimalBoundingRectangle.default)({
514
428
  originalPoints: this.convexHull.polyline
515
429
  });
516
-
517
430
  if (mbr.length === 0) {
518
431
  this.computed.mbr = {
519
432
  width: 0,
@@ -539,70 +452,58 @@ class Roi {
539
452
  };
540
453
  }
541
454
  }
542
-
543
455
  return this.computed.mbr;
544
456
  }
545
-
546
457
  get fillRatio() {
547
458
  return this.surface / (this.surface + this.holesInfo.surface);
548
459
  }
549
-
550
460
  get feretDiameters() {
551
461
  if (!this.computed.feretDiameters) {
552
462
  this.computed.feretDiameters = (0, _feretDiameters.default)({
553
463
  originalPoints: this.convexHull.polyline
554
464
  });
555
465
  }
556
-
557
466
  return this.computed.feretDiameters;
558
467
  }
468
+
559
469
  /**
560
470
  * Diameter of a circle of equal projection area
561
471
  */
562
-
563
-
564
472
  get eqpc() {
565
473
  if (!this.computed.eqpc) {
566
474
  this.computed.eqpc = 2 * Math.sqrt(this.surface / Math.PI);
567
475
  }
568
-
569
476
  return this.computed.eqpc;
570
477
  }
478
+
571
479
  /**
572
480
  * Get the category in which each external pixel belongs
573
481
  */
574
-
575
-
576
482
  get perimeterInfo() {
577
483
  if (!this.computed.perimeterInfo) {
578
484
  this.computed.perimeterInfo = getPerimeterInfo(this);
579
485
  }
580
-
581
486
  return this.computed.perimeterInfo;
582
487
  }
488
+
583
489
  /**
584
490
  * Return the perimeter of the ROI
585
491
  */
586
-
587
-
588
492
  get perimeter() {
589
493
  let info = this.perimeterInfo;
590
494
  let delta = 2 - Math.sqrt(2);
591
495
  return info.one + info.two * 2 + info.three * 3 + info.four * 4 - delta * (info.two + info.three * 2 + info.four);
592
496
  }
497
+
593
498
  /**
594
499
  * Diameter of a circle of equal perimeter
595
500
  */
596
-
597
-
598
501
  get ped() {
599
502
  if (!this.computed.ped) {
600
503
  this.computed.ped = this.perimeter / Math.PI;
601
504
  }
602
-
603
505
  return this.computed.ped;
604
506
  }
605
-
606
507
  get feretMask() {
607
508
  if (!this.computed.feretMask) {
608
509
  const image = new _Image.default(this.width + 1, this.height + 1, {
@@ -614,14 +515,11 @@ class Roi {
614
515
  image.paintPolyline(this.feretDiameters.maxLine);
615
516
  this.computed.feretMask = image;
616
517
  }
617
-
618
518
  return this.computed.feretMask;
619
519
  }
620
-
621
520
  get mbrMask() {
622
521
  if (!this.computed.mbrMask) {
623
522
  let rectangle = (0, _points.round)(this.mbr.rectangle);
624
-
625
523
  if (rectangle.length > 0) {
626
524
  // the problem is that the rectangle may be outside the roi
627
525
  const minMax = (0, _points.minMax)(rectangle);
@@ -643,10 +541,8 @@ class Roi {
643
541
  });
644
542
  }
645
543
  }
646
-
647
544
  return this.computed.mbrMask;
648
545
  }
649
-
650
546
  get mbrFilledMask() {
651
547
  if (!this.computed.mbrFilledMask) {
652
548
  const img = new _Image.default(this.width, this.height, {
@@ -655,7 +551,6 @@ class Roi {
655
551
  parent: this.map.parent
656
552
  });
657
553
  const mbr = this.mask.minimalBoundingRectangle();
658
-
659
554
  for (let x = 0; x < this.width; x++) {
660
555
  for (let y = 0; y < this.height; y++) {
661
556
  if ((0, _robustPointInPolygon.default)(mbr, [x, y]) !== 1) {
@@ -663,92 +558,72 @@ class Roi {
663
558
  }
664
559
  }
665
560
  }
666
-
667
561
  this.computed.mbrFilledMask = img;
668
562
  }
669
-
670
563
  return this.computed.mbrFilledMask;
671
564
  }
672
-
673
565
  get points() {
674
566
  if (!this.computed.points) {
675
567
  let points = [];
676
-
677
568
  for (let y = 0; y < this.height; y++) {
678
569
  for (let x = 0; x < this.width; x++) {
679
570
  let target = (y + this.minY) * this.map.width + x + this.minX;
680
-
681
571
  if (this.map.data[target] === this.id) {
682
572
  points.push([x, y]);
683
573
  }
684
574
  }
685
575
  }
686
-
687
576
  this.computed.points = points;
688
577
  }
689
-
690
578
  return this.computed.points;
691
579
  }
692
-
693
580
  get maxLengthPoints() {
694
581
  if (!this.computed.maxLengthPoints) {
695
582
  let maxLength = 0;
696
583
  let maxLengthPoints;
697
584
  const points = this.points;
698
-
699
585
  for (let i = 0; i < points.length; i++) {
700
586
  for (let j = i + 1; j < points.length; j++) {
701
587
  let currentML = Math.pow(points[i][0] - points[j][0], 2) + Math.pow(points[i][1] - points[j][1], 2);
702
-
703
588
  if (currentML >= maxLength) {
704
589
  maxLength = currentML;
705
590
  maxLengthPoints = [points[i], points[j]];
706
591
  }
707
592
  }
708
593
  }
709
-
710
594
  this.computed.maxLengthPoints = maxLengthPoints;
711
595
  }
712
-
713
596
  return this.computed.maxLengthPoints;
714
597
  }
598
+
715
599
  /**
716
600
  Calculates the maximum length between two pixels of the Roi.
717
601
  */
718
-
719
-
720
602
  get maxLength() {
721
603
  if (!this.computed.maxLength) {
722
604
  let maxLength = Math.sqrt(Math.pow(this.maxLengthPoints[0][0] - this.maxLengthPoints[1][0], 2) + Math.pow(this.maxLengthPoints[0][1] - this.maxLengthPoints[1][1], 2));
723
605
  this.computed.maxLength = maxLength;
724
606
  }
725
-
726
607
  return this.computed.maxLength;
727
608
  }
728
-
729
609
  get roundness() {
730
610
  /*Slide 24 https://static.horiba.com/fileadmin/Horiba/Products/Scientific/Particle_Characterization/Webinars/Slides/TE011.pdf */
731
611
  return 4 * this.surface / (Math.PI * this.feretDiameters.max ** 2);
732
612
  }
733
-
734
613
  get sphericity() {
735
614
  return 2 * Math.sqrt(this.surface * Math.PI) / this.perimeter;
736
615
  }
737
-
738
616
  get solidity() {
739
617
  return this.surface / this.convexHull.surface;
740
618
  }
741
-
742
619
  get angle() {
743
620
  if (!this.computed.angle) {
744
621
  let points = this.maxLengthPoints;
745
622
  let angle = -Math.atan2(points[0][1] - points[1][1], points[0][0] - points[1][0]) * 180 / Math.PI;
746
623
  this.computed.angle = angle;
747
624
  }
748
-
749
625
  return this.computed.angle;
750
626
  }
751
-
752
627
  toJSON() {
753
628
  return {
754
629
  id: this.id,
@@ -776,39 +651,31 @@ class Roi {
776
651
  perimeter: this.perimeter
777
652
  };
778
653
  }
654
+ }
779
655
 
780
- } // TODO we should follow the region in order to increase the speed
781
-
782
-
656
+ // TODO we should follow the region in order to increase the speed
783
657
  exports.default = Roi;
784
-
785
658
  function getBorders(roi) {
786
659
  let roiMap = roi.map;
787
660
  let data = roiMap.data;
788
661
  let surroudingIDs = new Set(); // allows to get a unique list without indexOf
789
-
790
662
  let surroundingBorders = new Map();
791
663
  let visitedData = new Set();
792
664
  let dx = [+1, 0, -1, 0];
793
665
  let dy = [0, +1, 0, -1];
794
-
795
666
  for (let x = roi.minX; x <= roi.maxX; x++) {
796
667
  for (let y = roi.minY; y <= roi.maxY; y++) {
797
668
  let target = x + y * roiMap.width;
798
-
799
669
  if (data[target] === roi.id) {
800
670
  for (let dir = 0; dir < 4; dir++) {
801
671
  let newX = x + dx[dir];
802
672
  let newY = y + dy[dir];
803
-
804
673
  if (newX >= 0 && newY >= 0 && newX < roiMap.width && newY < roiMap.height) {
805
674
  let neighbour = newX + newY * roiMap.width;
806
-
807
675
  if (data[neighbour] !== roi.id && !visitedData.has(neighbour)) {
808
676
  visitedData.add(neighbour);
809
677
  surroudingIDs.add(data[neighbour]);
810
678
  let surroundingBorder = surroundingBorders.get(data[neighbour]);
811
-
812
679
  if (!surroundingBorder) {
813
680
  surroundingBorders.set(data[neighbour], 1);
814
681
  } else {
@@ -820,7 +687,6 @@ function getBorders(roi) {
820
687
  }
821
688
  }
822
689
  }
823
-
824
690
  let ids = Array.from(surroudingIDs);
825
691
  let borderLengths = ids.map(function (id) {
826
692
  return surroundingBorders.get(id);
@@ -830,46 +696,41 @@ function getBorders(roi) {
830
696
  lengths: borderLengths
831
697
  };
832
698
  }
833
-
834
699
  function getBoxIDs(roi) {
835
700
  let surroundingIDs = new Set(); // allows to get a unique list without indexOf
836
701
 
837
702
  let roiMap = roi.map;
838
- let data = roiMap.data; // we check the first line and the last line
703
+ let data = roiMap.data;
839
704
 
705
+ // we check the first line and the last line
840
706
  for (let y of [0, roi.height - 1]) {
841
707
  for (let x = 0; x < roi.width; x++) {
842
708
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
843
-
844
709
  if (x - roi.minX > 0 && data[target] === roi.id && data[target - 1] !== roi.id) {
845
710
  let value = data[target - 1];
846
711
  surroundingIDs.add(value);
847
712
  }
848
-
849
713
  if (roiMap.width - x - roi.minX > 1 && data[target] === roi.id && data[target + 1] !== roi.id) {
850
714
  let value = data[target + 1];
851
715
  surroundingIDs.add(value);
852
716
  }
853
717
  }
854
- } // we check the first column and the last column
855
-
718
+ }
856
719
 
720
+ // we check the first column and the last column
857
721
  for (let x of [0, roi.width - 1]) {
858
722
  for (let y = 0; y < roi.height; y++) {
859
723
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
860
-
861
724
  if (y - roi.minY > 0 && data[target] === roi.id && data[target - roiMap.width] !== roi.id) {
862
725
  let value = data[target - roiMap.width];
863
726
  surroundingIDs.add(value);
864
727
  }
865
-
866
728
  if (roiMap.height - y - roi.minY > 1 && data[target] === roi.id && data[target + roiMap.width] !== roi.id) {
867
729
  let value = data[target + roiMap.width];
868
730
  surroundingIDs.add(value);
869
731
  }
870
732
  }
871
733
  }
872
-
873
734
  return Array.from(surroundingIDs); // the selection takes the whole rectangle
874
735
  }
875
736
 
@@ -878,49 +739,38 @@ function getBox(roi) {
878
739
  let roiMap = roi.map;
879
740
  let data = roiMap.data;
880
741
  let topBottom = [0];
881
-
882
742
  if (roi.height > 1) {
883
743
  topBottom[1] = roi.height - 1;
884
744
  }
885
-
886
745
  for (let y of topBottom) {
887
746
  for (let x = 1; x < roi.width - 1; x++) {
888
747
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
889
-
890
748
  if (data[target] === roi.id) {
891
749
  total++;
892
750
  }
893
751
  }
894
752
  }
895
-
896
753
  let leftRight = [0];
897
-
898
754
  if (roi.width > 1) {
899
755
  leftRight[1] = roi.width - 1;
900
756
  }
901
-
902
757
  for (let x of leftRight) {
903
758
  for (let y = 0; y < roi.height; y++) {
904
759
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
905
-
906
760
  if (data[target] === roi.id) {
907
761
  total++;
908
762
  }
909
763
  }
910
764
  }
911
-
912
765
  return total;
913
766
  }
914
-
915
767
  function getBorder(roi) {
916
768
  let total = 0;
917
769
  let roiMap = roi.map;
918
770
  let data = roiMap.data;
919
-
920
771
  for (let x = 1; x < roi.width - 1; x++) {
921
772
  for (let y = 1; y < roi.height - 1; y++) {
922
773
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
923
-
924
774
  if (data[target] === roi.id) {
925
775
  // if a point around is not roi.id it is a border
926
776
  if (data[target - 1] !== roi.id || data[target + 1] !== roi.id || data[target - roiMap.width] !== roi.id || data[target + roiMap.width] !== roi.id) {
@@ -929,10 +779,8 @@ function getBorder(roi) {
929
779
  }
930
780
  }
931
781
  }
932
-
933
782
  return total + roi.box;
934
783
  }
935
-
936
784
  function getPerimeterInfo(roi) {
937
785
  let roiMap = roi.map;
938
786
  let data = roiMap.data;
@@ -940,61 +788,49 @@ function getPerimeterInfo(roi) {
940
788
  let two = 0;
941
789
  let three = 0;
942
790
  let four = 0;
943
-
944
791
  for (let x = 0; x < roi.width; x++) {
945
792
  for (let y = 0; y < roi.height; y++) {
946
793
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
947
-
948
794
  if (data[target] === roi.id) {
949
795
  let nbAround = 0;
950
-
951
796
  if (x === 0) {
952
797
  nbAround++;
953
798
  } else if (roi.externalIDs.includes(data[target - 1])) {
954
799
  nbAround++;
955
800
  }
956
-
957
801
  if (x === roi.width - 1) {
958
802
  nbAround++;
959
803
  } else if (roi.externalIDs.includes(data[target + 1])) {
960
804
  nbAround++;
961
805
  }
962
-
963
806
  if (y === 0) {
964
807
  nbAround++;
965
808
  } else if (roi.externalIDs.includes(data[target - roiMap.width])) {
966
809
  nbAround++;
967
810
  }
968
-
969
811
  if (y === roi.height - 1) {
970
812
  nbAround++;
971
813
  } else if (roi.externalIDs.includes(data[target + roiMap.width])) {
972
814
  nbAround++;
973
815
  }
974
-
975
816
  switch (nbAround) {
976
817
  case 1:
977
818
  one++;
978
819
  break;
979
-
980
820
  case 2:
981
821
  two++;
982
822
  break;
983
-
984
823
  case 3:
985
824
  three++;
986
825
  break;
987
-
988
826
  case 4:
989
827
  four++;
990
828
  break;
991
-
992
829
  default:
993
830
  }
994
831
  }
995
832
  }
996
833
  }
997
-
998
834
  return {
999
835
  one,
1000
836
  two,
@@ -1002,16 +838,13 @@ function getPerimeterInfo(roi) {
1002
838
  four
1003
839
  };
1004
840
  }
1005
-
1006
841
  function getExternal(roi) {
1007
842
  let total = 0;
1008
843
  let roiMap = roi.map;
1009
844
  let data = roiMap.data;
1010
-
1011
845
  for (let x = 1; x < roi.width - 1; x++) {
1012
846
  for (let y = 1; y < roi.height - 1; y++) {
1013
847
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
1014
-
1015
848
  if (data[target] === roi.id) {
1016
849
  // if a point around is not roi.id it is a border
1017
850
  if (roi.externalIDs.includes(data[target - 1]) || roi.externalIDs.includes(data[target + 1]) || roi.externalIDs.includes(data[target - roiMap.width]) || roi.externalIDs.includes(data[target + roiMap.width])) {
@@ -1020,71 +853,58 @@ function getExternal(roi) {
1020
853
  }
1021
854
  }
1022
855
  }
1023
-
1024
856
  return total + roi.box;
1025
857
  }
1026
-
1027
858
  function getHolesInfo(roi) {
1028
859
  let surface = 0;
1029
860
  let width = roi.map.width;
1030
861
  let data = roi.map.data;
1031
-
1032
862
  for (let x = 1; x < roi.width - 1; x++) {
1033
863
  for (let y = 1; y < roi.height - 1; y++) {
1034
864
  let target = (y + roi.minY) * width + x + roi.minX;
1035
-
1036
865
  if (roi.internalIDs.includes(data[target]) && data[target] !== roi.id) {
1037
866
  surface++;
1038
867
  }
1039
868
  }
1040
869
  }
1041
-
1042
870
  return {
1043
871
  number: roi.internalIDs.length - 1,
1044
872
  surface
1045
873
  };
1046
874
  }
875
+
1047
876
  /*
1048
877
  We will calculate all the ids of the map that are "internal"
1049
878
  This will allow to extract the 'plain' image
1050
879
  */
1051
-
1052
-
1053
880
  function getInternalIDs(roi) {
1054
881
  let internal = [roi.id];
1055
882
  let roiMap = roi.map;
1056
883
  let data = roiMap.data;
1057
-
1058
884
  if (roi.height > 2) {
1059
885
  for (let x = 0; x < roi.width; x++) {
1060
886
  let target = roi.minY * roiMap.width + x + roi.minX;
1061
-
1062
887
  if (internal.includes(data[target])) {
1063
888
  let id = data[target + roiMap.width];
1064
-
1065
889
  if (!internal.includes(id) && !roi.boxIDs.includes(id)) {
1066
890
  internal.push(id);
1067
891
  }
1068
892
  }
1069
893
  }
1070
894
  }
1071
-
1072
895
  let array = new Array(4);
1073
-
1074
896
  for (let x = 1; x < roi.width - 1; x++) {
1075
897
  for (let y = 1; y < roi.height - 1; y++) {
1076
898
  let target = (y + roi.minY) * roiMap.width + x + roi.minX;
1077
-
1078
899
  if (internal.includes(data[target])) {
1079
900
  // we check if one of the neighbour is not yet in
901
+
1080
902
  array[0] = data[target - 1];
1081
903
  array[1] = data[target + 1];
1082
904
  array[2] = data[target - roiMap.width];
1083
905
  array[3] = data[target + roiMap.width];
1084
-
1085
906
  for (let i = 0; i < 4; i++) {
1086
907
  let id = array[i];
1087
-
1088
908
  if (!internal.includes(id) && !roi.boxIDs.includes(id)) {
1089
909
  internal.push(id);
1090
910
  }
@@ -1092,6 +912,5 @@ function getInternalIDs(roi) {
1092
912
  }
1093
913
  }
1094
914
  }
1095
-
1096
915
  return internal;
1097
916
  }