Merge pull request #3360 from mirab:threshold_triangle
This commit is contained in:
		@@ -430,7 +430,7 @@ Applies a fixed-level threshold to each array element.
 | 
			
		||||
 | 
			
		||||
    :param maxval: Maximum value to use with  ``THRESH_BINARY`` and  ``THRESH_BINARY_INV`` threshold types.
 | 
			
		||||
 | 
			
		||||
    :param type: Threshold type. For details, see  :ocv:func:`threshold` . The ``THRESH_OTSU`` threshold type is not supported.
 | 
			
		||||
    :param type: Threshold type. For details, see  :ocv:func:`threshold` . The ``THRESH_OTSU`` and ``THRESH_TRIANGLE`` threshold types are not supported.
 | 
			
		||||
 | 
			
		||||
    :param stream: Stream for the asynchronous version.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -712,11 +712,11 @@ types of thresholding supported by the function. They are determined by ``type``
 | 
			
		||||
 | 
			
		||||
              \texttt{dst} (x,y) =  \fork{0}{if $\texttt{src}(x,y) > \texttt{thresh}$}{\texttt{src}(x,y)}{otherwise}
 | 
			
		||||
 | 
			
		||||
Also, the special value ``THRESH_OTSU`` may be combined with
 | 
			
		||||
one of the above values. In this case, the function determines the optimal threshold
 | 
			
		||||
value using the Otsu's algorithm and uses it instead of the specified ``thresh`` .
 | 
			
		||||
Also, the special values ``THRESH_OTSU`` or ``THRESH_TRIANGLE`` may be combined with
 | 
			
		||||
one of the above values. In these cases, the function determines the optimal threshold
 | 
			
		||||
value using the Otsu's or Triangle algorithm and uses it instead of the specified ``thresh`` .
 | 
			
		||||
The function returns the computed threshold value.
 | 
			
		||||
Currently, the Otsu's method is implemented only for 8-bit images.
 | 
			
		||||
Currently, the Otsu's and Triangle methods are implemented only for 8-bit images.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. image:: pics/threshold.png
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,8 @@ enum { THRESH_BINARY     = 0, // value = value > threshold ? max_value : 0
 | 
			
		||||
       THRESH_TOZERO     = 3, // value = value > threshold ? value : 0
 | 
			
		||||
       THRESH_TOZERO_INV = 4, // value = value > threshold ? 0 : value
 | 
			
		||||
       THRESH_MASK       = 7,
 | 
			
		||||
       THRESH_OTSU       = 8  // use Otsu algorithm to choose the optimal threshold value
 | 
			
		||||
       THRESH_OTSU       = 8, // use Otsu algorithm to choose the optimal threshold value
 | 
			
		||||
       THRESH_TRIANGLE   = 16  // use Triangle algorithm to choose the optimal threshold value
 | 
			
		||||
     };
 | 
			
		||||
 | 
			
		||||
//! adaptive threshold algorithm
 | 
			
		||||
 
 | 
			
		||||
@@ -551,8 +551,11 @@ enum
 | 
			
		||||
    CV_THRESH_TOZERO      =3,  /* value = value > threshold ? value : 0           */
 | 
			
		||||
    CV_THRESH_TOZERO_INV  =4,  /* value = value > threshold ? 0 : value           */
 | 
			
		||||
    CV_THRESH_MASK        =7,
 | 
			
		||||
    CV_THRESH_OTSU        =8  /* use Otsu algorithm to choose the optimal threshold value;
 | 
			
		||||
    CV_THRESH_OTSU        =8, /* use Otsu algorithm to choose the optimal threshold value;
 | 
			
		||||
                                 combine the flag with one of the above CV_THRESH_* values */
 | 
			
		||||
    CV_THRESH_TRIANGLE    =16  /* use Triangle algorithm to choose the optimal threshold value;
 | 
			
		||||
                                 combine the flag with one of the above CV_THRESH_* values, but not
 | 
			
		||||
                                 with CV_THRESH_OTSU */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Adaptive threshold methods */
 | 
			
		||||
 
 | 
			
		||||
@@ -986,6 +986,110 @@ getThreshVal_Otsu_8u( const Mat& _src )
 | 
			
		||||
    return max_val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static double
 | 
			
		||||
getThreshVal_Triangle_8u( const Mat& _src )
 | 
			
		||||
{
 | 
			
		||||
    Size size = _src.size();
 | 
			
		||||
    int step = (int) _src.step;
 | 
			
		||||
    if( _src.isContinuous() )
 | 
			
		||||
    {
 | 
			
		||||
        size.width *= size.height;
 | 
			
		||||
        size.height = 1;
 | 
			
		||||
        step = size.width;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int N = 256;
 | 
			
		||||
    int i, j, h[N] = {0};
 | 
			
		||||
    for( i = 0; i < size.height; i++ )
 | 
			
		||||
    {
 | 
			
		||||
        const uchar* src = _src.ptr() + step*i;
 | 
			
		||||
        j = 0;
 | 
			
		||||
        #if CV_ENABLE_UNROLLED
 | 
			
		||||
        for( ; j <= size.width - 4; j += 4 )
 | 
			
		||||
        {
 | 
			
		||||
            int v0 = src[j], v1 = src[j+1];
 | 
			
		||||
            h[v0]++; h[v1]++;
 | 
			
		||||
            v0 = src[j+2]; v1 = src[j+3];
 | 
			
		||||
            h[v0]++; h[v1]++;
 | 
			
		||||
        }
 | 
			
		||||
        #endif
 | 
			
		||||
        for( ; j < size.width; j++ )
 | 
			
		||||
            h[src[j]]++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int left_bound = 0, right_bound = 0, max_ind = 0, max = 0;
 | 
			
		||||
    int temp;
 | 
			
		||||
    bool isflipped = false;
 | 
			
		||||
 | 
			
		||||
    for( i = 0; i < N; i++ )
 | 
			
		||||
    {
 | 
			
		||||
        if( h[i] > 0 )
 | 
			
		||||
        {
 | 
			
		||||
            left_bound = i;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if( left_bound > 0 )
 | 
			
		||||
        left_bound--;
 | 
			
		||||
 | 
			
		||||
    for( i = N-1; i > 0; i-- )
 | 
			
		||||
    {
 | 
			
		||||
        if( h[i] > 0 )
 | 
			
		||||
        {
 | 
			
		||||
            right_bound = i;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if( right_bound < N-1 )
 | 
			
		||||
        right_bound++;
 | 
			
		||||
 | 
			
		||||
    for( i = 0; i < N; i++ )
 | 
			
		||||
    {
 | 
			
		||||
        if( h[i] > max)
 | 
			
		||||
        {
 | 
			
		||||
            max = h[i];
 | 
			
		||||
            max_ind = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if( max_ind-left_bound < right_bound-max_ind)
 | 
			
		||||
    {
 | 
			
		||||
        isflipped = true;
 | 
			
		||||
        i = 0, j = N-1;
 | 
			
		||||
        while( i < j )
 | 
			
		||||
        {
 | 
			
		||||
            temp = h[i]; h[i] = h[j]; h[j] = temp;
 | 
			
		||||
            i++; j--;
 | 
			
		||||
        }
 | 
			
		||||
        left_bound = N-1-right_bound;
 | 
			
		||||
        max_ind = N-1-max_ind;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    double thresh = left_bound;
 | 
			
		||||
    double a, b, dist = 0, tempdist;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * We do not need to compute precise distance here. Distance is maximized, so some constants can
 | 
			
		||||
     * be omitted. This speeds up a computation a bit.
 | 
			
		||||
     */
 | 
			
		||||
    a = max; b = left_bound-max_ind;
 | 
			
		||||
    for( i = left_bound+1; i <= max_ind; i++ )
 | 
			
		||||
    {
 | 
			
		||||
        tempdist = a*i + b*h[i];
 | 
			
		||||
        if( tempdist > dist)
 | 
			
		||||
        {
 | 
			
		||||
            dist = tempdist;
 | 
			
		||||
            thresh = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    thresh--;
 | 
			
		||||
 | 
			
		||||
    if( isflipped )
 | 
			
		||||
        thresh = N-1-thresh;
 | 
			
		||||
 | 
			
		||||
    return thresh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ThresholdRunner : public ParallelLoopBody
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
@@ -1085,13 +1189,19 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
 | 
			
		||||
                ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
 | 
			
		||||
 | 
			
		||||
    Mat src = _src.getMat();
 | 
			
		||||
    bool use_otsu = (type & THRESH_OTSU) != 0;
 | 
			
		||||
    int automatic_thresh = (type & ~CV_THRESH_MASK);
 | 
			
		||||
    type &= THRESH_MASK;
 | 
			
		||||
 | 
			
		||||
    if( use_otsu )
 | 
			
		||||
    CV_Assert( automatic_thresh != (CV_THRESH_OTSU | CV_THRESH_TRIANGLE) );
 | 
			
		||||
    if( automatic_thresh == CV_THRESH_OTSU )
 | 
			
		||||
    {
 | 
			
		||||
        CV_Assert( src.type() == CV_8UC1 );
 | 
			
		||||
        thresh = getThreshVal_Otsu_8u(src);
 | 
			
		||||
        thresh = getThreshVal_Otsu_8u( src );
 | 
			
		||||
    }
 | 
			
		||||
    else if( automatic_thresh == CV_THRESH_TRIANGLE )
 | 
			
		||||
    {
 | 
			
		||||
        CV_Assert( src.type() == CV_8UC1 );
 | 
			
		||||
        thresh = getThreshVal_Triangle_8u( src );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _dst.create( src.size(), src.type() );
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user