@@ -49,52 +49,59 @@ namespace ximgproc {
49
49
void niBlackThreshold ( InputArray _src, OutputArray _dst, double maxValue,
50
50
int type, int blockSize, double delta )
51
51
{
52
+ // Input grayscale image
52
53
Mat src = _src.getMat ();
53
- CV_Assert ( src.type () == CV_8UC1 );
54
- CV_Assert ( blockSize % 2 == 1 && blockSize > 1 );
55
- Size size = src. size () ;
54
+ CV_Assert (src.channels () == 1 );
55
+ CV_Assert (blockSize % 2 == 1 && blockSize > 1 );
56
+ type &= THRESH_MASK ;
56
57
57
- _dst. create ( size, src. type () );
58
- Mat dst = _dst. getMat ();
59
-
60
- if ( maxValue < 0 )
58
+ // Compute local threshold (T = mean + k * stddev)
59
+ // using mean and standard deviation in the neighborhood of each pixel
60
+ // (intermediate calculations are done with floating-point precision)
61
+ Mat thresh;
61
62
{
62
- dst = Scalar (0 );
63
- return ;
63
+ // note that: Var[X] = E[X^2] - E[X]^2
64
+ Mat mean, sqmean, stddev;
65
+ boxFilter (src, mean, CV_32F, Size (blockSize, blockSize),
66
+ Point (-1 ,-1 ), true , BORDER_REPLICATE);
67
+ sqrBoxFilter (src, sqmean, CV_32F, Size (blockSize, blockSize),
68
+ Point (-1 ,-1 ), true , BORDER_REPLICATE);
69
+ sqrt (sqmean - mean.mul (mean), stddev);
70
+ thresh = mean + stddev * static_cast <float >(delta);
71
+ thresh.convertTo (thresh, src.depth ());
64
72
}
65
73
66
- // Calculate and store the mean and mean of squares in the neighborhood
67
- // of each pixel and store them in Mat mean and sqmean.
68
- Mat_<float > mean (size), sqmean (size);
69
-
70
- if ( src.data != dst.data )
71
- mean = dst;
72
-
73
- boxFilter ( src, mean, CV_64F, Size (blockSize, blockSize),
74
- Point (-1 ,-1 ), true , BORDER_REPLICATE );
75
- sqrBoxFilter ( src, sqmean, CV_64F, Size (blockSize, blockSize),
76
- Point (-1 ,-1 ), true , BORDER_REPLICATE );
74
+ // Prepare output image
75
+ _dst.create (src.size (), src.type ());
76
+ Mat dst = _dst.getMat ();
77
+ CV_Assert (src.data != dst.data ); // no inplace processing
77
78
78
- // Compute (k * standard deviation) in the neighborhood of each pixel
79
- // and store in Mat stddev. Also threshold the values in the src matrix to compute dst matrix.
80
- Mat_<float > stddev (size);
81
- int i, j, threshold;
82
- uchar imaxval = saturate_cast<uchar>(maxValue);
83
- for (i = 0 ; i < size.height ; ++i)
79
+ // Apply thresholding: ( pixel > threshold ) ? foreground : background
80
+ Mat mask;
81
+ switch (type)
84
82
{
85
- for (j = 0 ; j < size.width ; ++j)
86
- {
87
- stddev.at <float >(i, j) = saturate_cast<float >(delta) * cvRound ( sqrt (sqmean.at <float >(i, j) -
88
- mean.at <float >(i, j)*mean.at <float >(i, j)) );
89
- threshold = cvRound (mean.at <float >(i, j) + stddev.at <float >(i, j));
90
- if (src.at <uchar>(i, j) > threshold)
91
- dst.at <uchar>(i, j) = (type == THRESH_BINARY) ? imaxval : 0 ;
92
- else
93
- dst.at <uchar>(i, j) = (type == THRESH_BINARY) ? 0 : imaxval;
94
- }
83
+ case THRESH_BINARY: // dst = (src > thresh) ? maxval : 0
84
+ case THRESH_BINARY_INV: // dst = (src > thresh) ? 0 : maxval
85
+ compare (src, thresh, mask, (type == THRESH_BINARY ? CMP_GT : CMP_LE));
86
+ dst.setTo (0 );
87
+ dst.setTo (maxValue, mask);
88
+ break ;
89
+ case THRESH_TRUNC: // dst = (src > thresh) ? thresh : src
90
+ compare (src, thresh, mask, CMP_GT);
91
+ src.copyTo (dst);
92
+ thresh.copyTo (dst, mask);
93
+ break ;
94
+ case THRESH_TOZERO: // dst = (src > thresh) ? src : 0
95
+ case THRESH_TOZERO_INV: // dst = (src > thresh) ? 0 : src
96
+ compare (src, thresh, mask, (type == THRESH_TOZERO ? CMP_GT : CMP_LE));
97
+ dst.setTo (0 );
98
+ src.copyTo (dst, mask);
99
+ break ;
100
+ default :
101
+ CV_Error ( CV_StsBadArg, " Unknown threshold type" );
102
+ break ;
95
103
}
96
-
97
104
}
98
105
99
106
} // namespace ximgproc
100
- } // namespace cv
107
+ } // namespace cv
0 commit comments