c – 带掩码的OpenCV阈值

前端之家收集整理的这篇文章主要介绍了c – 带掩码的OpenCV阈值前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用OpenCV的cv :: threshold函数(更具体的THRESH_OTSU),只是我想用掩码(任何形状)来做,所以在计算过程中忽略外部(背景).

图像是单通道(必须如此),红色波纹仅用于标记图像上的示例多边形.

我尝试使用adaptiveThreshold,但有一些问题使我的情况不合适.

解决方法

通常,您可以使用cv :: threshold简单地计算阈值,然后使用反转掩码在dst上复制src图像.
// Apply cv::threshold on all image
thresh = cv::threshold(src,dst,thresh,maxval,type);

// Copy original image on inverted mask
src.copyTo(dst,~mask);

但是,使用THRESH_OTSU,您还需要仅在屏蔽图像上计算阈值.以下代码是thresh.cpp中static double getThreshVal_Otsu_8u(const Mat& _src)的修改版本:

double otsu_8u_with_mask(const Mat1b src,const Mat1b& mask)
{
    const int N = 256;
    int M = 0;
    int i,j,h[N] = { 0 };
    for (i = 0; i < src.rows; i++)
    {
        const uchar* psrc = src.ptr(i);
        const uchar* pmask = mask.ptr(i);
        for (j = 0; j < src.cols; j++)
        {
            if (pmask[j])
            {
                h[psrc[j]]++;
                ++M;
            }
        }
    }

    double mu = 0,scale = 1. / (M);
    for (i = 0; i < N; i++)
        mu += i*(double)h[i];

    mu *= scale;
    double mu1 = 0,q1 = 0;
    double max_sigma = 0,max_val = 0;

    for (i = 0; i < N; i++)
    {
        double p_i,q2,mu2,sigma;

        p_i = h[i] * scale;
        mu1 *= q1;
        q1 += p_i;
        q2 = 1. - q1;

        if (std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON)
            continue;

        mu1 = (mu1 + i*p_i) / q1;
        mu2 = (mu - q1*mu1) / q2;
        sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
        if (sigma > max_sigma)
        {
            max_sigma = sigma;
            max_val = i;
        }
    }
    return max_val;
}

然后,您可以将所有函数包装在一个函数中,此处称为threshold_with_mask,它将为您包装所有不同的案例.如果没有掩码,或者掩码是全白的,则使用cv :: threshold.否则,使用上述方法之一.请注意,此包装器仅适用于CV_8UC1映像(为简单起见,您可以轻松地将其扩展为与其他类型一起使用,如果需要),并接受所有THRESH_XXX组合作为原始cv :: threshold.

double threshold_with_mask(Mat1b& src,Mat1b& dst,double thresh,double maxval,int type,const Mat1b& mask = Mat1b())
{
    if (mask.empty() || (mask.rows == src.rows && mask.cols == src.cols && countNonZero(mask) == src.rows * src.cols))
    {
        // If empty mask,or all-white mask,use cv::threshold
        thresh = cv::threshold(src,type);
    }
    else
    {
        // Use mask
        bool use_otsu = (type & THRESH_OTSU) != 0;
        if (use_otsu)
        {
            // If OTSU,get thresh value on mask only
            thresh = otsu_8u_with_mask(src,mask);
            // Remove THRESH_OTSU from type
            type &= THRESH_MASK;
        }

        // Apply cv::threshold on all image
        thresh = cv::threshold(src,type);

        // Copy original image on inverted mask
        src.copyTo(dst,~mask);
    }
    return thresh;
}

以下是完整的参考代码

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

// Modified from thresh.cpp
// static double getThreshVal_Otsu_8u(const Mat& _src)

double otsu_8u_with_mask(const Mat1b src,q2) > 1. - FLT_EPSILON)
            continue;

        mu1 = (mu1 + i*p_i) / q1;
        mu2 = (mu - q1*mu1) / q2;
        sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
        if (sigma > max_sigma)
        {
            max_sigma = sigma;
            max_val = i;
        }
    }

    return max_val;
}

double threshold_with_mask(Mat1b& src,~mask);
    }
    return thresh;
}


int main()
{
    // Load an image
    Mat1b img = imread("D:\\SO\\img\\nice.jpg",IMREAD_GRAYSCALE);

    // Apply OpenCV version
    Mat1b cvth;
    double cvth_value = threshold(img,cvth,100,255,THRESH_OTSU);

    // Create a binary mask
    Mat1b mask(img.rows,img.cols,uchar(0));
    rectangle(mask,Rect(100,200,200),Scalar(255),CV_FILLED);

    // Apply threshold with a mask
    Mat1b th;
    double th_value = threshold_with_mask(img,th,THRESH_OTSU,mask);

    // Show results
    imshow("cv::threshod",cvth);
    imshow("threshold_with_balue",th);
    waitKey();

    return 0;
}
原文链接:https://www.f2er.com/c/116822.html

猜你在找的C&C++相关文章