Multi otsu(multi-thresholding) with openCV

后端 未结 6 1609
忘掉有多难
忘掉有多难 2020-12-02 23:53

I am trying to carry out multi-thresholding with otsu. The method I am using currently is actually via maximising the between class variance, I have managed to get the same

6条回答
  •  时光取名叫无心
    2020-12-03 00:51

    I found a useful piece of code in this thread. I was looking for a multi-level Otsu implementation for double/float images. So, I tried to generalize example for N-levels with double/float matrix as input. In my code below I am using armadillo library as dependency. But this code can be easily adapted for standard C++ arrays, just replace vec, uvec objects with single dimensional double and integer arrays, mat and umat with two-dimensional. Two other functions from armadillo used here are: vectorise and hist.

    // Input parameters:
    // map - input image (double matrix)
    // mask - region of interest to be thresholded
    // nBins - number of bins
    // nLevels - number of Otsu thresholds
    
    #include 
    #include 
    #include 
    
    mat OtsuFilterMulti(mat map, int nBins, int nLevels) {
    
        mat mapr;   // output thresholded image
        mapr = zeros(map.n_rows, map.n_cols);
    
        unsigned int numElem = 0;
        vec threshold = zeros(nLevels);
        vec q = zeros(nLevels + 1);
        vec mu = zeros(nLevels + 1);
        vec muk = zeros(nLevels + 1);
        uvec binv = zeros(nLevels);
    
        if (nLevels <= 1) return mapr;
    
        numElem = map.n_rows*map.n_cols;
    
    
        uvec histogram = hist(vectorise(map), nBins);
    
        double maxval = map.max();
        double minval = map.min();
        double odelta = (maxval - abs(minval)) / nBins;     // distance between histogram bins
    
        vec oval = zeros(nBins);
        double mt = 0, variance = 0.0, bestVariance = 0.0;
    
        for (int ii = 0; ii < nBins; ii++) {
            oval(ii) = (double)odelta*ii + (double)odelta*0.5;  // centers of histogram bins
            mt += (double)ii*((double)histogram(ii)) / (double)numElem;
        }
    
        for (int ii = 0; ii < nLevels; ii++) {
            binv(ii) = ii;
        }
    
        double sq, smuk;
        int nComb;
    
        nComb = nCombinations(nBins,nLevels);
        std::vector v(nBins);
        std::fill(v.begin(), v.begin() + nLevels, true);
    
        umat ibin = zeros(nComb, nLevels); // indices from combinations will be stored here
    
        int cc = 0;
        int ci = 0;
        do {
            for (int i = 0; i < nBins; ++i) {
                if(ci==nLevels) ci=0;
                    if (v[i]) {
                    ibin(cc,ci) = i;
                    ci++;
                }
            }
            cc++;
        } while (std::prev_permutation(v.begin(), v.end()));
    
        uvec lastIndex = zeros(nLevels);
    
        // Perform operations on pre-calculated indices
        for (int ii = 0; ii < nComb; ii++) {
            for (int jj = 0; jj < nLevels; jj++) {
                smuk = 0;
                sq = 0;
                if (lastIndex(jj) != ibin(ii, jj) || ii == 0) {
                    q(jj) += double(histogram(ibin(ii, jj))) / (double)numElem;
                    muk(jj) += ibin(ii, jj)*(double(histogram(ibin(ii, jj)))) / (double)numElem;
                    mu(jj) = muk(jj) / q(jj);
                    q(jj + 1) = 0.0;
                    muk(jj + 1) = 0.0;
    
                    if (jj>0) {
                        for (int kk = 0; kk <= jj; kk++) {
                            sq += q(kk);
                            smuk += muk(kk);
                        }
                        q(jj + 1) = 1 - sq;
                        muk(jj + 1) = mt - smuk;
                        mu(jj + 1) = muk(jj + 1) / q(jj + 1);
                    }
                    if (jj>0 && jj<(nLevels - 1)) {
                        q(jj + 1) = 0.0;
                        muk(jj + 1) = 0.0;
                    }
    
                    lastIndex(jj) = ibin(ii, jj);
                }
            }
    
            variance = 0.0;
            for (int jj = 0; jj <= nLevels; jj++) {
                variance += q(jj)*(mu(jj) - mt)*(mu(jj) - mt);
            }    
    
            if (variance > bestVariance) {
                bestVariance = variance;
                for (int jj = 0; jj= threshold(ll)) {
                        mapr(jj, kk) = ll+1;
                    }
                }
            }
        }
    
        return mapr;
    }
    
    
    int nCombinations(int n, int r) {
    
        if (r>n) return 0;
        if (r*2 > n) r = n-r;
        if (r == 0) return 1;
    
        int ret = n;
        for( int i = 2; i <= r; ++i ) {
            ret *= (n-i+1);
            ret /= i;
        }
        return ret;
    }
    

提交回复
热议问题