mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-23 09:38:56 +08:00
rewrite niBlackThreshold function
- no for-loops - support all thresholding types - support any input image depth - add Doxygen comments
This commit is contained in:
@@ -52,8 +52,8 @@
|
|||||||
@{
|
@{
|
||||||
@defgroup ximgproc_edge Structured forests for fast edge detection
|
@defgroup ximgproc_edge Structured forests for fast edge detection
|
||||||
|
|
||||||
This module contains implementations of modern structured edge detection algorithms, i.e. algorithms
|
This module contains implementations of modern structured edge detection algorithms,
|
||||||
which somehow takes into account pixel affinities in natural images.
|
i.e. algorithms which somehow takes into account pixel affinities in natural images.
|
||||||
|
|
||||||
@defgroup ximgproc_filters Filters
|
@defgroup ximgproc_filters Filters
|
||||||
|
|
||||||
@@ -63,13 +63,47 @@ which somehow takes into account pixel affinities in natural images.
|
|||||||
@}
|
@}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace cv {
|
namespace cv
|
||||||
namespace ximgproc {
|
{
|
||||||
CV_EXPORTS_W
|
namespace ximgproc
|
||||||
void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue,
|
{
|
||||||
int type, int blockSize, double delta );
|
|
||||||
|
|
||||||
} // namespace ximgproc
|
//! @addtogroup ximgproc
|
||||||
} //namespace cv
|
//! @{
|
||||||
|
|
||||||
#endif
|
/** @brief Applies Niblack thresholding to input image.
|
||||||
|
|
||||||
|
The function transforms a grayscale image to a binary image according to the formulae:
|
||||||
|
- **THRESH_BINARY**
|
||||||
|
\f[dst(x,y) = \fork{\texttt{maxValue}}{if \(src(x,y) > T(x,y)\)}{0}{otherwise}\f]
|
||||||
|
- **THRESH_BINARY_INV**
|
||||||
|
\f[dst(x,y) = \fork{0}{if \(src(x,y) > T(x,y)\)}{\texttt{maxValue}}{otherwise}\f]
|
||||||
|
where \f$T(x,y)\f$ is a threshold calculated individually for each pixel.
|
||||||
|
|
||||||
|
The threshold value \f$T(x, y)\f$ is the mean minus \f$ delta \f$ times standard deviation
|
||||||
|
of \f$\texttt{blockSize} \times\texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$.
|
||||||
|
|
||||||
|
The function can't process the image in-place.
|
||||||
|
|
||||||
|
@param _src Source 8-bit single-channel image.
|
||||||
|
@param _dst Destination image of the same size and the same type as src.
|
||||||
|
@param maxValue Non-zero value assigned to the pixels for which the condition is satisfied,
|
||||||
|
used with the THRESH_BINARY and THRESH_BINARY_INV thresholding types.
|
||||||
|
@param type Thresholding type, see cv::ThresholdTypes.
|
||||||
|
@param blockSize Size of a pixel neighborhood that is used to calculate a threshold value
|
||||||
|
for the pixel: 3, 5, 7, and so on.
|
||||||
|
@param delta Constant multiplied with the standard deviation and subtracted from the mean.
|
||||||
|
Normally, it is taken to be a real number between 0 and 1.
|
||||||
|
|
||||||
|
@sa threshold, adaptiveThreshold
|
||||||
|
*/
|
||||||
|
CV_EXPORTS_W void niBlackThreshold( InputArray _src, OutputArray _dst,
|
||||||
|
double maxValue, int type,
|
||||||
|
int blockSize, double delta );
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __OPENCV_XIMGPROC_HPP__
|
||||||
|
@@ -49,51 +49,58 @@ namespace ximgproc {
|
|||||||
void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue,
|
void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue,
|
||||||
int type, int blockSize, double delta )
|
int type, int blockSize, double delta )
|
||||||
{
|
{
|
||||||
|
// Input grayscale image
|
||||||
Mat src = _src.getMat();
|
Mat src = _src.getMat();
|
||||||
CV_Assert( src.type() == CV_8UC1 );
|
CV_Assert(src.channels() == 1);
|
||||||
CV_Assert(blockSize % 2 == 1 && blockSize > 1);
|
CV_Assert(blockSize % 2 == 1 && blockSize > 1);
|
||||||
Size size = src.size();
|
type &= THRESH_MASK;
|
||||||
|
|
||||||
_dst.create( size, src.type() );
|
// Compute local threshold (T = mean + k * stddev)
|
||||||
Mat dst = _dst.getMat();
|
// using mean and standard deviation in the neighborhood of each pixel
|
||||||
|
// (intermediate calculations are done with floating-point precision)
|
||||||
if( maxValue < 0 )
|
Mat thresh;
|
||||||
{
|
{
|
||||||
dst = Scalar(0);
|
// note that: Var[X] = E[X^2] - E[X]^2
|
||||||
return;
|
Mat mean, sqmean, stddev;
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate and store the mean and mean of squares in the neighborhood
|
|
||||||
// of each pixel and store them in Mat mean and sqmean.
|
|
||||||
Mat_<float> mean(size), sqmean(size);
|
|
||||||
|
|
||||||
if( src.data != dst.data )
|
|
||||||
mean = dst;
|
|
||||||
|
|
||||||
boxFilter(src, mean, CV_32F, Size(blockSize, blockSize),
|
boxFilter(src, mean, CV_32F, Size(blockSize, blockSize),
|
||||||
Point(-1,-1), true, BORDER_REPLICATE);
|
Point(-1,-1), true, BORDER_REPLICATE);
|
||||||
sqrBoxFilter(src, sqmean, CV_32F, Size(blockSize, blockSize),
|
sqrBoxFilter(src, sqmean, CV_32F, Size(blockSize, blockSize),
|
||||||
Point(-1,-1), true, BORDER_REPLICATE);
|
Point(-1,-1), true, BORDER_REPLICATE);
|
||||||
|
sqrt(sqmean - mean.mul(mean), stddev);
|
||||||
// Compute (k * standard deviation) in the neighborhood of each pixel
|
thresh = mean + stddev * static_cast<float>(delta);
|
||||||
// and store in Mat stddev. Also threshold the values in the src matrix to compute dst matrix.
|
thresh.convertTo(thresh, src.depth());
|
||||||
Mat_<float> stddev(size);
|
|
||||||
int i, j, threshold;
|
|
||||||
uchar imaxval = saturate_cast<uchar>(maxValue);
|
|
||||||
for(i = 0; i < size.height; ++i)
|
|
||||||
{
|
|
||||||
for(j = 0; j < size.width; ++j)
|
|
||||||
{
|
|
||||||
stddev.at<float>(i, j) = saturate_cast<float>(delta) * cvRound( sqrt(sqmean.at<float>(i, j) -
|
|
||||||
mean.at<float>(i, j)*mean.at<float>(i, j)) );
|
|
||||||
threshold = cvRound(mean.at<float>(i, j) + stddev.at<float>(i, j));
|
|
||||||
if(src.at<uchar>(i, j) > threshold)
|
|
||||||
dst.at<uchar>(i, j) = (type == THRESH_BINARY) ? imaxval : 0;
|
|
||||||
else
|
|
||||||
dst.at<uchar>(i, j) = (type == THRESH_BINARY) ? 0 : imaxval;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare output image
|
||||||
|
_dst.create(src.size(), src.type());
|
||||||
|
Mat dst = _dst.getMat();
|
||||||
|
CV_Assert(src.data != dst.data); // no inplace processing
|
||||||
|
|
||||||
|
// Apply thresholding: ( pixel > threshold ) ? foreground : background
|
||||||
|
Mat mask;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case THRESH_BINARY: // dst = (src > thresh) ? maxval : 0
|
||||||
|
case THRESH_BINARY_INV: // dst = (src > thresh) ? 0 : maxval
|
||||||
|
compare(src, thresh, mask, (type == THRESH_BINARY ? CMP_GT : CMP_LE));
|
||||||
|
dst.setTo(0);
|
||||||
|
dst.setTo(maxValue, mask);
|
||||||
|
break;
|
||||||
|
case THRESH_TRUNC: // dst = (src > thresh) ? thresh : src
|
||||||
|
compare(src, thresh, mask, CMP_GT);
|
||||||
|
src.copyTo(dst);
|
||||||
|
thresh.copyTo(dst, mask);
|
||||||
|
break;
|
||||||
|
case THRESH_TOZERO: // dst = (src > thresh) ? src : 0
|
||||||
|
case THRESH_TOZERO_INV: // dst = (src > thresh) ? 0 : src
|
||||||
|
compare(src, thresh, mask, (type == THRESH_TOZERO ? CMP_GT : CMP_LE));
|
||||||
|
dst.setTo(0);
|
||||||
|
src.copyTo(dst, mask);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CV_Error( CV_StsBadArg, "Unknown threshold type" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ximgproc
|
} // namespace ximgproc
|
||||||
|
Reference in New Issue
Block a user