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,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = intermodes;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
*
|
|
10
9
|
* see https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java
|
|
@@ -12,60 +11,50 @@ exports.default = intermodes;
|
|
|
12
11
|
* "The analysis of cell images", Annals of the NewYork Academy of Sciences 128: 1035-1053
|
|
13
12
|
*
|
|
14
13
|
*/
|
|
14
|
+
|
|
15
15
|
function intermodes(histogram) {
|
|
16
16
|
let iHisto = histogram.slice();
|
|
17
17
|
let iter = 0;
|
|
18
|
-
|
|
19
18
|
while (!bimodalTest(iHisto)) {
|
|
20
19
|
// smooth with a 3 point running mean filter
|
|
21
20
|
let previous = 0;
|
|
22
21
|
let current = 0;
|
|
23
22
|
let next = iHisto[0];
|
|
24
|
-
|
|
25
23
|
for (let i = 0; i < histogram.length - 1; i++) {
|
|
26
24
|
previous = current;
|
|
27
25
|
current = next;
|
|
28
26
|
next = iHisto[i + 1];
|
|
29
27
|
iHisto[i] = (previous + current + next) / 3;
|
|
30
28
|
}
|
|
31
|
-
|
|
32
29
|
iHisto[histogram.length - 1] = (current + next) / 3;
|
|
33
30
|
iter++;
|
|
34
|
-
|
|
35
31
|
if (iter > 10000) {
|
|
36
32
|
throw new Error('Intermodes Threshold not found after 10000 iterations');
|
|
37
33
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
34
|
+
}
|
|
40
35
|
|
|
36
|
+
// The threshold is the mean between the two peaks.
|
|
41
37
|
let tt = 0;
|
|
42
|
-
|
|
43
38
|
for (let i = 1; i < histogram.length - 1; i++) {
|
|
44
39
|
if (iHisto[i - 1] < iHisto[i] && iHisto[i + 1] < iHisto[i]) {
|
|
45
40
|
tt += i;
|
|
46
41
|
}
|
|
47
42
|
}
|
|
48
|
-
|
|
49
43
|
return Math.floor(tt / 2.0);
|
|
50
44
|
}
|
|
51
|
-
|
|
52
45
|
function bimodalTest(iHisto) {
|
|
53
46
|
let b = false;
|
|
54
47
|
let modes = 0;
|
|
55
|
-
|
|
56
48
|
for (let k = 1; k < iHisto.length - 1; k++) {
|
|
57
49
|
if (iHisto[k - 1] < iHisto[k] && iHisto[k + 1] < iHisto[k]) {
|
|
58
50
|
modes++;
|
|
59
|
-
|
|
60
51
|
if (modes > 2) {
|
|
61
52
|
return false;
|
|
62
53
|
}
|
|
63
54
|
}
|
|
64
55
|
}
|
|
65
|
-
|
|
66
56
|
if (modes === 2) {
|
|
67
57
|
b = true;
|
|
68
58
|
}
|
|
69
|
-
|
|
70
59
|
return b;
|
|
71
60
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = isodata;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
* see https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java
|
|
10
9
|
* Isodata: Ridler, TW & Calvard, S (1978), "Picture thresholding using an iterative selection method"
|
|
@@ -13,13 +12,9 @@ exports.default = isodata;
|
|
|
13
12
|
*/
|
|
14
13
|
function isodata(histogram) {
|
|
15
14
|
let l; // the average grey value of pixels with intensities < g
|
|
16
|
-
|
|
17
15
|
let toth; // the the average grey value of pixels with intensities > g
|
|
18
|
-
|
|
19
16
|
let totl; // the total the average grey value of pixels with intensities < g
|
|
20
|
-
|
|
21
17
|
let h; // the average grey value of pixels with intensities > g
|
|
22
|
-
|
|
23
18
|
let g = 0; // threshold value
|
|
24
19
|
|
|
25
20
|
for (let i = 1; i < histogram.length; i++) {
|
|
@@ -28,39 +23,30 @@ function isodata(histogram) {
|
|
|
28
23
|
break;
|
|
29
24
|
}
|
|
30
25
|
}
|
|
31
|
-
|
|
32
26
|
while (true) {
|
|
33
27
|
l = 0;
|
|
34
28
|
totl = 0;
|
|
35
|
-
|
|
36
29
|
for (let i = 0; i < g; i++) {
|
|
37
30
|
totl = totl + histogram[i];
|
|
38
31
|
l = l + histogram[i] * i;
|
|
39
32
|
}
|
|
40
|
-
|
|
41
33
|
h = 0;
|
|
42
34
|
toth = 0;
|
|
43
|
-
|
|
44
35
|
for (let i = g + 1; i < histogram.length; i++) {
|
|
45
36
|
toth += histogram[i];
|
|
46
37
|
h += histogram[i] * i;
|
|
47
38
|
}
|
|
48
|
-
|
|
49
39
|
if (totl > 0 && toth > 0) {
|
|
50
40
|
l /= totl;
|
|
51
41
|
h /= toth;
|
|
52
|
-
|
|
53
42
|
if (g === Math.round((l + h) / 2.0)) {
|
|
54
43
|
break;
|
|
55
44
|
}
|
|
56
45
|
}
|
|
57
|
-
|
|
58
46
|
g++;
|
|
59
|
-
|
|
60
47
|
if (g > histogram.length - 2) {
|
|
61
48
|
throw new Error('Threshold not found');
|
|
62
49
|
}
|
|
63
50
|
}
|
|
64
|
-
|
|
65
51
|
return g;
|
|
66
52
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = li;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
* see http://rsb.info.nih.gov/ij/developer/source/ij/process/AutoThresholder.java.html
|
|
10
9
|
* The method is present in: Implements Li's Minimum Cross Entropy thresholding method
|
|
@@ -18,80 +17,53 @@ exports.default = li;
|
|
|
18
17
|
* @param total - the number of pixels in the image
|
|
19
18
|
* @returns {number} - the threshold
|
|
20
19
|
*/
|
|
20
|
+
|
|
21
21
|
function li(histogram, total) {
|
|
22
22
|
let threshold;
|
|
23
|
-
let sumBack;
|
|
24
|
-
/* sum of the
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
/* sum of the object pixels at a given threshold */
|
|
28
|
-
|
|
29
|
-
let numBack;
|
|
30
|
-
/* number of background pixels at a given threshold */
|
|
31
|
-
|
|
32
|
-
let numObj;
|
|
33
|
-
/* number of object pixels at a given threshold */
|
|
34
|
-
|
|
23
|
+
let sumBack; /* sum of the background pixels at a given threshold */
|
|
24
|
+
let sumObj; /* sum of the object pixels at a given threshold */
|
|
25
|
+
let numBack; /* number of background pixels at a given threshold */
|
|
26
|
+
let numObj; /* number of object pixels at a given threshold */
|
|
35
27
|
let oldThresh;
|
|
36
28
|
let newThresh;
|
|
37
|
-
let meanBack;
|
|
38
|
-
/* mean of the
|
|
39
|
-
|
|
40
|
-
let
|
|
41
|
-
/* mean of the object pixels at a given threshold */
|
|
42
|
-
|
|
43
|
-
let mean;
|
|
44
|
-
/* mean gray-level in the image */
|
|
45
|
-
|
|
46
|
-
let tolerance;
|
|
47
|
-
/* threshold tolerance */
|
|
48
|
-
|
|
29
|
+
let meanBack; /* mean of the background pixels at a given threshold */
|
|
30
|
+
let meanObj; /* mean of the object pixels at a given threshold */
|
|
31
|
+
let mean; /* mean gray-level in the image */
|
|
32
|
+
let tolerance; /* threshold tolerance */
|
|
49
33
|
let temp;
|
|
50
34
|
tolerance = 0.5;
|
|
51
|
-
/* Calculate the mean gray-level */
|
|
52
35
|
|
|
36
|
+
/* Calculate the mean gray-level */
|
|
53
37
|
mean = 0.0;
|
|
54
|
-
|
|
55
38
|
for (let ih = 0; ih < histogram.length; ih++) {
|
|
56
39
|
mean += ih * histogram[ih];
|
|
57
40
|
}
|
|
58
|
-
|
|
59
41
|
mean /= total;
|
|
60
42
|
/* Initial estimate */
|
|
61
|
-
|
|
62
43
|
newThresh = mean;
|
|
63
|
-
|
|
64
44
|
do {
|
|
65
45
|
oldThresh = newThresh;
|
|
66
|
-
threshold = oldThresh + 0.5 | 0;
|
|
67
|
-
/* range */
|
|
46
|
+
threshold = oldThresh + 0.5 | 0; /* range */
|
|
68
47
|
|
|
69
48
|
/* Calculate the means of background and object pixels */
|
|
70
|
-
|
|
71
49
|
/* Background */
|
|
72
|
-
|
|
73
50
|
sumBack = 0;
|
|
74
51
|
numBack = 0;
|
|
75
|
-
|
|
76
52
|
for (let ih = 0; ih <= threshold; ih++) {
|
|
77
53
|
sumBack += ih * histogram[ih];
|
|
78
54
|
numBack += histogram[ih];
|
|
79
55
|
}
|
|
80
|
-
|
|
81
56
|
meanBack = numBack === 0 ? 0.0 : sumBack / numBack;
|
|
82
|
-
/* Object */
|
|
83
57
|
|
|
58
|
+
/* Object */
|
|
84
59
|
sumObj = 0;
|
|
85
60
|
numObj = 0;
|
|
86
|
-
|
|
87
61
|
for (let ih = threshold + 1; ih < histogram.length; ih++) {
|
|
88
62
|
sumObj += ih * histogram[ih];
|
|
89
63
|
numObj += histogram[ih];
|
|
90
64
|
}
|
|
91
|
-
|
|
92
65
|
meanObj = numObj === 0 ? 0.0 : sumObj / numObj;
|
|
93
66
|
temp = (meanBack - meanObj) / (Math.log(meanBack) - Math.log(meanObj));
|
|
94
|
-
|
|
95
67
|
if (temp < -Number.EPSILON) {
|
|
96
68
|
newThresh = temp - 0.5 | 0;
|
|
97
69
|
} else {
|
|
@@ -99,8 +71,6 @@ function li(histogram, total) {
|
|
|
99
71
|
}
|
|
100
72
|
/* Stop the iterations when the difference between the
|
|
101
73
|
new and old threshold values is less than the tolerance */
|
|
102
|
-
|
|
103
74
|
} while (Math.abs(newThresh - oldThresh) > tolerance);
|
|
104
|
-
|
|
105
75
|
return threshold;
|
|
106
76
|
}
|
|
@@ -4,16 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = mask;
|
|
7
|
-
|
|
8
7
|
var _converter = require("../../../util/converter");
|
|
9
|
-
|
|
10
8
|
var _Image = _interopRequireDefault(require("../../Image"));
|
|
11
|
-
|
|
12
9
|
var _getThreshold = _interopRequireDefault(require("../../utility/getThreshold"));
|
|
13
|
-
|
|
14
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
|
|
16
11
|
const THRESHOLD = 'threshold';
|
|
12
|
+
|
|
17
13
|
/**
|
|
18
14
|
* Creation of binary mask is based on the determination of a threshold
|
|
19
15
|
* You may either choose among the provided algorithm or just specify a threshold value
|
|
@@ -26,7 +22,6 @@ const THRESHOLD = 'threshold';
|
|
|
26
22
|
* @param {boolean} [options.invert=false] - Invert the resulting image
|
|
27
23
|
* @return {Image} - Binary image containing the mask
|
|
28
24
|
*/
|
|
29
|
-
|
|
30
25
|
function mask(options = {}) {
|
|
31
26
|
let {
|
|
32
27
|
algorithm = THRESHOLD,
|
|
@@ -38,27 +33,22 @@ function mask(options = {}) {
|
|
|
38
33
|
components: 1,
|
|
39
34
|
bitDepth: [8, 16]
|
|
40
35
|
});
|
|
41
|
-
|
|
42
36
|
if (algorithm === THRESHOLD) {
|
|
43
37
|
threshold = (0, _converter.getThreshold)(threshold, this.maxValue);
|
|
44
38
|
} else {
|
|
45
39
|
threshold = _getThreshold.default.call(this, options);
|
|
46
40
|
}
|
|
47
|
-
|
|
48
41
|
let newImage = new _Image.default(this.width, this.height, {
|
|
49
42
|
kind: 'BINARY',
|
|
50
43
|
parent: this
|
|
51
44
|
});
|
|
52
45
|
let ptr = 0;
|
|
53
|
-
|
|
54
46
|
if (this.alpha && useAlpha) {
|
|
55
47
|
for (let i = 0; i < this.data.length; i += this.channels) {
|
|
56
48
|
let value = this.data[i] + (this.maxValue - this.data[i]) * (this.maxValue - this.data[i + 1]) / this.maxValue;
|
|
57
|
-
|
|
58
49
|
if (invert && value <= threshold || !invert && value >= threshold) {
|
|
59
50
|
newImage.setBit(ptr);
|
|
60
51
|
}
|
|
61
|
-
|
|
62
52
|
ptr++;
|
|
63
53
|
}
|
|
64
54
|
} else {
|
|
@@ -66,10 +56,8 @@ function mask(options = {}) {
|
|
|
66
56
|
if (invert && this.data[i] <= threshold || !invert && this.data[i] >= threshold) {
|
|
67
57
|
newImage.setBit(ptr);
|
|
68
58
|
}
|
|
69
|
-
|
|
70
59
|
ptr++;
|
|
71
60
|
}
|
|
72
61
|
}
|
|
73
|
-
|
|
74
62
|
return newImage;
|
|
75
63
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = maxEntropy;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
* see http://rsb.info.nih.gov/ij/developer/source/ij/process/AutoThresholder.java.html
|
|
10
9
|
* The method is present in: Implements Kapur-Sahoo-Wong (Maximum Entropy) thresholding method:
|
|
@@ -14,86 +13,70 @@ exports.default = maxEntropy;
|
|
|
14
13
|
* total - the number of pixels in the image
|
|
15
14
|
* @returns {number} - the threshold
|
|
16
15
|
*/
|
|
16
|
+
|
|
17
17
|
function maxEntropy(histogram, total) {
|
|
18
18
|
let normHisto = new Array(histogram.length); // normalized histogram
|
|
19
|
-
|
|
20
19
|
for (let ih = 0; ih < histogram.length; ih++) {
|
|
21
20
|
normHisto[ih] = histogram[ih] / total;
|
|
22
21
|
}
|
|
23
|
-
|
|
24
22
|
let P1 = new Array(histogram.length); // cumulative normalized histogram
|
|
25
|
-
|
|
26
23
|
let P2 = new Array(histogram.length);
|
|
27
24
|
P1[0] = normHisto[0];
|
|
28
25
|
P2[0] = 1.0 - P1[0];
|
|
29
|
-
|
|
30
26
|
for (let ih = 1; ih < histogram.length; ih++) {
|
|
31
27
|
P1[ih] = P1[ih - 1] + normHisto[ih];
|
|
32
28
|
P2[ih] = 1.0 - P1[ih];
|
|
33
29
|
}
|
|
34
|
-
/* Determine the first non-zero bin */
|
|
35
|
-
|
|
36
30
|
|
|
31
|
+
/* Determine the first non-zero bin */
|
|
37
32
|
let firstBin = 0;
|
|
38
|
-
|
|
39
33
|
for (let ih = 0; ih < histogram.length; ih++) {
|
|
40
34
|
if (Math.abs(P1[ih]) >= Number.EPSILON) {
|
|
41
35
|
firstBin = ih;
|
|
42
36
|
break;
|
|
43
37
|
}
|
|
44
38
|
}
|
|
45
|
-
/* Determine the last non-zero bin */
|
|
46
|
-
|
|
47
39
|
|
|
40
|
+
/* Determine the last non-zero bin */
|
|
48
41
|
let lastBin = histogram.length - 1;
|
|
49
|
-
|
|
50
42
|
for (let ih = histogram.length - 1; ih >= firstBin; ih--) {
|
|
51
43
|
if (Math.abs(P2[ih]) >= Number.EPSILON) {
|
|
52
44
|
lastBin = ih;
|
|
53
45
|
break;
|
|
54
46
|
}
|
|
55
|
-
}
|
|
56
|
-
// and find the threshold that maximizes it
|
|
57
|
-
|
|
47
|
+
}
|
|
58
48
|
|
|
49
|
+
// Calculate the total entropy each gray-level
|
|
50
|
+
// and find the threshold that maximizes it
|
|
59
51
|
let threshold = -1;
|
|
60
52
|
let totEnt; // total entropy
|
|
61
|
-
|
|
62
53
|
let maxEnt = Number.MIN_VALUE; // max entropy
|
|
63
|
-
|
|
64
54
|
let entBack; // entropy of the background pixels at a given threshold
|
|
65
|
-
|
|
66
55
|
let entObj; // entropy of the object pixels at a given threshold
|
|
67
56
|
|
|
68
57
|
for (let it = firstBin; it <= lastBin; it++) {
|
|
69
58
|
/* Entropy of the background pixels */
|
|
70
59
|
entBack = 0.0;
|
|
71
|
-
|
|
72
60
|
for (let ih = 0; ih <= it; ih++) {
|
|
73
61
|
if (histogram[ih] !== 0) {
|
|
74
62
|
entBack -= normHisto[ih] / P1[it] * Math.log(normHisto[ih] / P1[it]);
|
|
75
63
|
}
|
|
76
64
|
}
|
|
77
|
-
/* Entropy of the object pixels */
|
|
78
|
-
|
|
79
65
|
|
|
66
|
+
/* Entropy of the object pixels */
|
|
80
67
|
entObj = 0.0;
|
|
81
|
-
|
|
82
68
|
for (let ih = it + 1; ih < histogram.length; ih++) {
|
|
83
69
|
if (histogram[ih] !== 0) {
|
|
84
70
|
entObj -= normHisto[ih] / P2[it] * Math.log(normHisto[ih] / P2[it]);
|
|
85
71
|
}
|
|
86
72
|
}
|
|
87
|
-
/* Total entropy */
|
|
88
|
-
|
|
89
73
|
|
|
74
|
+
/* Total entropy */
|
|
90
75
|
totEnt = entBack + entObj;
|
|
91
|
-
|
|
92
76
|
if (maxEnt < totEnt) {
|
|
93
77
|
maxEnt = totEnt;
|
|
94
78
|
threshold = it;
|
|
95
79
|
}
|
|
96
80
|
}
|
|
97
|
-
|
|
98
81
|
return threshold;
|
|
99
82
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = mean;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
* The method is present in: Uses the mean of grey levels as the threshold. It is described in:
|
|
10
9
|
* Glasbey, CA (1993), "An analysis of histogram-based thresholding algorithms",
|
|
@@ -13,12 +12,11 @@ exports.default = mean;
|
|
|
13
12
|
* @param total - the number of pixels in the image
|
|
14
13
|
* @returns {number} - the threshold
|
|
15
14
|
*/
|
|
15
|
+
|
|
16
16
|
function mean(histogram, total) {
|
|
17
17
|
let sum = 0;
|
|
18
|
-
|
|
19
18
|
for (let i = 0; i < histogram.length; i++) {
|
|
20
19
|
sum += i * histogram[i];
|
|
21
20
|
}
|
|
22
|
-
|
|
23
21
|
return Math.floor(sum / total);
|
|
24
22
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = minError;
|
|
7
|
-
|
|
8
7
|
/*
|
|
9
8
|
* see http://rsb.info.nih.gov/ij/developer/source/ij/process/AutoThresholder.java.html
|
|
10
9
|
* The method is present in: An iterative implementation of Kittler and Illingworth's Minimum Error
|
|
@@ -13,21 +12,19 @@ exports.default = minError;
|
|
|
13
12
|
* @param total - the number of pixels in the image
|
|
14
13
|
* @returns {number} - the threshold
|
|
15
14
|
*/
|
|
15
|
+
|
|
16
16
|
function minError(histogram, total) {
|
|
17
17
|
let threshold;
|
|
18
18
|
let Tprev = -2;
|
|
19
19
|
let mu, nu, p, q, sigma2, tau2, w0, w1, w2, sqterm, temp;
|
|
20
|
-
/* Calculate the mean gray-level */
|
|
21
20
|
|
|
21
|
+
/* Calculate the mean gray-level */
|
|
22
22
|
let mean = 0.0;
|
|
23
|
-
|
|
24
23
|
for (let ih = 0; ih < histogram.length; ih++) {
|
|
25
24
|
mean += ih * histogram[ih];
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
mean /= total;
|
|
29
27
|
threshold = mean;
|
|
30
|
-
|
|
31
28
|
while (threshold !== Tprev) {
|
|
32
29
|
// Calculate some statistics.
|
|
33
30
|
let sumA1 = sumA(histogram, threshold);
|
|
@@ -41,59 +38,51 @@ function minError(histogram, total) {
|
|
|
41
38
|
p = sumA1 / sumA2;
|
|
42
39
|
q = (sumA2 - sumA1) / sumA2;
|
|
43
40
|
sigma2 = sumC1 / sumA1 - mu * mu;
|
|
44
|
-
tau2 = (sumC2 - sumC1) / (sumA2 - sumA1) - nu * nu;
|
|
41
|
+
tau2 = (sumC2 - sumC1) / (sumA2 - sumA1) - nu * nu;
|
|
45
42
|
|
|
43
|
+
// The terms of the quadratic equation to be solved.
|
|
46
44
|
w0 = 1.0 / sigma2 - 1.0 / tau2;
|
|
47
45
|
w1 = mu / sigma2 - nu / tau2;
|
|
48
|
-
w2 = mu * mu / sigma2 - nu * nu / tau2 + Math.log10(sigma2 * (q * q) / (tau2 * (p * p)));
|
|
46
|
+
w2 = mu * mu / sigma2 - nu * nu / tau2 + Math.log10(sigma2 * (q * q) / (tau2 * (p * p)));
|
|
49
47
|
|
|
48
|
+
// If the next threshold would be imaginary, return with the current one.
|
|
50
49
|
sqterm = w1 * w1 - w0 * w2;
|
|
51
|
-
|
|
52
50
|
if (sqterm < 0) {
|
|
53
51
|
return threshold;
|
|
54
|
-
}
|
|
55
|
-
|
|
52
|
+
}
|
|
56
53
|
|
|
54
|
+
// The updated threshold is the integer part of the solution of the quadratic equation.
|
|
57
55
|
Tprev = threshold;
|
|
58
56
|
temp = (w1 + Math.sqrt(sqterm)) / w0;
|
|
59
|
-
|
|
60
57
|
if (isNaN(temp)) {
|
|
61
58
|
threshold = Tprev;
|
|
62
59
|
} else {
|
|
63
60
|
threshold = Math.floor(temp);
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
|
-
|
|
67
63
|
return threshold;
|
|
68
|
-
}
|
|
64
|
+
}
|
|
69
65
|
|
|
66
|
+
// aux func
|
|
70
67
|
|
|
71
68
|
function sumA(y, j) {
|
|
72
69
|
let x = 0;
|
|
73
|
-
|
|
74
70
|
for (let i = 0; i <= j; i++) {
|
|
75
71
|
x += y[i];
|
|
76
72
|
}
|
|
77
|
-
|
|
78
73
|
return x;
|
|
79
74
|
}
|
|
80
|
-
|
|
81
75
|
function sumB(y, j) {
|
|
82
76
|
let x = 0;
|
|
83
|
-
|
|
84
77
|
for (let i = 0; i <= j; i++) {
|
|
85
78
|
x += i * y[i];
|
|
86
79
|
}
|
|
87
|
-
|
|
88
80
|
return x;
|
|
89
81
|
}
|
|
90
|
-
|
|
91
82
|
function sumC(y, j) {
|
|
92
83
|
let x = 0;
|
|
93
|
-
|
|
94
84
|
for (let i = 0; i <= j; i++) {
|
|
95
85
|
x += i * i * y[i];
|
|
96
86
|
}
|
|
97
|
-
|
|
98
87
|
return x;
|
|
99
88
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = minimum;
|
|
7
|
-
|
|
8
7
|
// see https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java
|
|
9
8
|
// J. M. S. Prewitt and M. L. Mendelsohn, "The analysis of cell images," in
|
|
10
9
|
// Annals of the New York Academy of Sciences, vol. 128, pp. 1035-1053, 1966.
|
|
@@ -17,81 +16,62 @@ function minimum(histogram) {
|
|
|
17
16
|
// validate that the histogram has at least two color values
|
|
18
17
|
return 0;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
let iterations = 0; // number of iterations of the smoothing process
|
|
22
|
-
|
|
23
20
|
let threshold = -1;
|
|
24
21
|
let max = -1; // maximum color value with a greater number of pixels to 0
|
|
25
|
-
|
|
26
22
|
let histogramCopy = new Array(histogram.length); // a copy of the histogram
|
|
27
|
-
|
|
28
23
|
for (let i = 0; i < histogram.length; i++) {
|
|
29
24
|
histogramCopy[i] = histogram[i];
|
|
30
|
-
|
|
31
25
|
if (histogram[i] > 0) {
|
|
32
26
|
max = i;
|
|
33
27
|
}
|
|
34
28
|
}
|
|
35
|
-
|
|
36
29
|
while (!bimodalTest(histogramCopy)) {
|
|
37
30
|
histogramCopy = smoothed(histogramCopy);
|
|
38
31
|
iterations++;
|
|
39
|
-
|
|
40
32
|
if (iterations > 10000) {
|
|
41
33
|
// if they occur more than 10000 iterations it returns -1
|
|
42
34
|
return threshold;
|
|
43
35
|
}
|
|
44
36
|
}
|
|
45
|
-
|
|
46
37
|
threshold = minimumBetweenPeeks(histogramCopy, max);
|
|
47
38
|
return threshold;
|
|
48
39
|
}
|
|
49
|
-
|
|
50
40
|
function smoothed(histogram) {
|
|
51
41
|
// Smooth with a 3 point running mean filter
|
|
52
42
|
let auHistogram = new Array(histogram.length); // a copy of the histograma for the smoothing process
|
|
53
|
-
|
|
54
43
|
for (let i = 1; i < histogram.length - 1; i++) {
|
|
55
44
|
auHistogram[i] = (histogram[i - 1] + histogram[i] + histogram[i + 1]) / 3;
|
|
56
45
|
}
|
|
57
|
-
|
|
58
46
|
auHistogram[0] = (histogram[0] + histogram[1]) / 3;
|
|
59
47
|
auHistogram[histogram.length - 1] = (histogram[histogram.length - 2] + histogram[histogram.length - 1]) / 3;
|
|
60
48
|
return auHistogram;
|
|
61
49
|
}
|
|
62
|
-
|
|
63
50
|
function minimumBetweenPeeks(histogramBimodal, max) {
|
|
64
51
|
let threshold;
|
|
65
|
-
|
|
66
52
|
for (let i = 1; i < max; i++) {
|
|
67
53
|
if (histogramBimodal[i - 1] > histogramBimodal[i] && histogramBimodal[i + 1] >= histogramBimodal[i]) {
|
|
68
54
|
threshold = i;
|
|
69
55
|
break;
|
|
70
56
|
}
|
|
71
57
|
}
|
|
72
|
-
|
|
73
58
|
return threshold;
|
|
74
59
|
}
|
|
75
|
-
|
|
76
60
|
function bimodalTest(histogram) {
|
|
77
61
|
// It is responsible for determining if a histogram is bimodal
|
|
78
62
|
let len = histogram.length;
|
|
79
63
|
let isBimodal = false;
|
|
80
64
|
let peaks = 0;
|
|
81
|
-
|
|
82
65
|
for (let k = 1; k < len - 1; k++) {
|
|
83
66
|
if (histogram[k - 1] < histogram[k] && histogram[k + 1] < histogram[k]) {
|
|
84
67
|
peaks++;
|
|
85
|
-
|
|
86
68
|
if (peaks > 2) {
|
|
87
69
|
return false;
|
|
88
70
|
}
|
|
89
71
|
}
|
|
90
72
|
}
|
|
91
|
-
|
|
92
73
|
if (peaks === 2) {
|
|
93
74
|
isBimodal = true;
|
|
94
75
|
}
|
|
95
|
-
|
|
96
76
|
return isBimodal;
|
|
97
77
|
}
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = moments;
|
|
7
|
-
|
|
8
7
|
// see https://github.com/fiji/Auto_Threshold/blob/master/src/main/java/fiji/threshold/Auto_Threshold.java
|
|
9
8
|
// W. Tsai, "Moment-preserving thresholding: a new approach," Computer Vision,
|
|
10
9
|
// Graphics, and Image Processing, vol. 29, pp. 377-393, 1985.
|
|
@@ -21,19 +20,14 @@ function moments(histogram, total) {
|
|
|
21
20
|
let m3 = 0.0;
|
|
22
21
|
let sum = 0.0;
|
|
23
22
|
let p0;
|
|
24
|
-
let cd, c0, c1, z0, z1;
|
|
25
|
-
/* auxiliary variables */
|
|
26
|
-
|
|
23
|
+
let cd, c0, c1, z0, z1; /* auxiliary variables */
|
|
27
24
|
let threshold = -1;
|
|
28
25
|
let histogramLength = histogram.length;
|
|
29
26
|
let normalizedHistogram = new Array(histogramLength);
|
|
30
|
-
|
|
31
27
|
for (let i = 0; i < histogramLength; i++) {
|
|
32
28
|
normalizedHistogram[i] = histogram[i] / total;
|
|
33
29
|
}
|
|
34
30
|
/* Calculate the first, second, and third order moments */
|
|
35
|
-
|
|
36
|
-
|
|
37
31
|
for (let i = 0; i < histogramLength; i++) {
|
|
38
32
|
m1 += i * normalizedHistogram[i];
|
|
39
33
|
m2 += i * i * normalizedHistogram[i];
|
|
@@ -44,27 +38,20 @@ function moments(histogram, total) {
|
|
|
44
38
|
of the target binary image. This leads to 4 equalities whose solutions
|
|
45
39
|
are given in the Appendix of Ref. 1
|
|
46
40
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
41
|
cd = m0 * m2 - m1 * m1; // determinant of the matriz of hankel for moments 2x2
|
|
50
|
-
|
|
51
42
|
c0 = (-m2 * m2 + m1 * m3) / cd;
|
|
52
|
-
c1 = (m0 * -m3 + m2 * m1) / cd;
|
|
53
|
-
|
|
43
|
+
c1 = (m0 * -m3 + m2 * m1) / cd;
|
|
44
|
+
// new two gray values where z0<z1
|
|
54
45
|
z0 = 0.5 * (-c1 - Math.sqrt(c1 * c1 - 4.0 * c0));
|
|
55
46
|
z1 = 0.5 * (-c1 + Math.sqrt(c1 * c1 - 4.0 * c0));
|
|
56
|
-
p0 = (z1 - m1) / (z1 - z0);
|
|
57
|
-
/* Fraction of the object pixels in the target binary image (p0z0+p1z1=m1) */
|
|
47
|
+
p0 = (z1 - m1) / (z1 - z0); /* Fraction of the object pixels in the target binary image (p0z0+p1z1=m1) */
|
|
58
48
|
// The threshold is the gray-level closest to the p0-tile of the normalized histogram
|
|
59
|
-
|
|
60
49
|
for (let i = 0; i < histogramLength; i++) {
|
|
61
50
|
sum += normalizedHistogram[i];
|
|
62
|
-
|
|
63
51
|
if (sum > p0) {
|
|
64
52
|
threshold = i;
|
|
65
53
|
break;
|
|
66
54
|
}
|
|
67
55
|
}
|
|
68
|
-
|
|
69
56
|
return threshold;
|
|
70
57
|
}
|