Opencv增加阈值的准确性

lif*_*der 22 android opencv

我正在开发一个应用程序,预计将使用opencv删除图像背景,起初我尝试使用抓取,但它太慢,结果并不总是准确,然后我尝试使用阈值,虽然结果还没有关闭th grabcut ,它的速度非常快,看起来更好,所以我的代码首先查看图像色调并分析它的哪一部分显得更多,该部分被视为背景,问题有时会得到前景作为背景如下是我的代码:

private Bitmap backGrndErase()
{

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.skirt);
    Log.d(TAG, "bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight());


    bitmap = ResizeImage.getResizedBitmap(bitmap, calculatePercentage(40, bitmap.getWidth()), calculatePercentage(40, bitmap.getHeight()));

    Mat frame = new Mat();
    Utils.bitmapToMat(bitmap, frame);

    Mat hsvImg = new Mat();
    List<Mat> hsvPlanes = new ArrayList<>();
    Mat thresholdImg = new Mat();

    // int thresh_type = Imgproc.THRESH_BINARY_INV;
    //if (this.inverse.isSelected())
    int thresh_type = Imgproc.THRESH_BINARY;

    // threshold the image with the average hue value
    hsvImg.create(frame.size(), CvType.CV_8U);
    Imgproc.cvtColor(frame, hsvImg, Imgproc.COLOR_BGR2HSV);
    Core.split(hsvImg, hsvPlanes);

    // get the average hue value of the image
    double threshValue = this.getHistAverage(hsvImg, hsvPlanes.get(0));

    Imgproc.threshold(hsvPlanes.get(0), thresholdImg, threshValue, mThresholdValue, thresh_type);
   // Imgproc.adaptiveThreshold(hsvPlanes.get(0), thresholdImg, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 11, 2);

    Imgproc.blur(thresholdImg, thresholdImg, new Size(5, 5));

    // dilate to fill gaps, erode to smooth edges
    Imgproc.dilate(thresholdImg, thresholdImg, new Mat(), new Point(-1, -1), 1);
    Imgproc.erode(thresholdImg, thresholdImg, new Mat(), new Point(-1, -1), 3);

    Imgproc.threshold(thresholdImg, thresholdImg, threshValue, mThresholdValue, Imgproc.THRESH_BINARY);
    //Imgproc.adaptiveThreshold(thresholdImg, thresholdImg, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 11, 2);

    // create the new image
    Mat foreground = new Mat(frame.size(), CvType.CV_8UC3, new Scalar(255, 255, 255));
    frame.copyTo(foreground, thresholdImg);


    Utils.matToBitmap(foreground,bitmap);
    //return foreground;

    alreadyRun = true;
    return  bitmap;

}
Run Code Online (Sandbox Code Playgroud)

负责Hue的方法:

    private double getHistAverage(Mat hsvImg, Mat hueValues)
{
    // init
    double average = 0.0;
    Mat hist_hue = new Mat();
    // 0-180: range of Hue values
    MatOfInt histSize = new MatOfInt(180);
    List<Mat> hue = new ArrayList<>();
    hue.add(hueValues);

    // compute the histogram
    Imgproc.calcHist(hue, new MatOfInt(0), new Mat(), hist_hue, histSize, new MatOfFloat(0, 179));

    // get the average Hue value of the image
    // (sum(bin(h)*h))/(image-height*image-width)
    // -----------------
    // equivalent to get the hue of each pixel in the image, add them, and
    // divide for the image size (height and width)
    for (int h = 0; h < 180; h++)
    {
        // for each bin, get its value and multiply it for the corresponding
        // hue
        average += (hist_hue.get(h, 0)[0] * h);
    }

    // return the average hue of the image
    average = average / hsvImg.size().height / hsvImg.size().width;
    return average;
}
Run Code Online (Sandbox Code Playgroud)

输入和输出的样本:[输入图像1] 输出图像

输入图像2和输出: 在此输入图像描述 在此输入图像描述

输入图像3和输出: 在此输入图像描述 在此输入图像描述

hoa*_*oid 0

我会再次尝试 Grabcut,它是可用的最佳分割方法之一。这是 我得到的结果

cv::Mat bgModel,fgModel; // the models (internally used)
cv::grabCut(image,// input image
            object_mask,// segmentation result
            rectang,// rectangle containing foreground
            bgModel,fgModel, // models
            5,// number of iterations
            cv::GC_INIT_WITH_RECT); // use rectangle
// Get the pixels marked as likely foreground
cv::compare(object_mask,cv::GC_PR_FGD,object_mask,cv::CMP_EQ);
cv::threshold(object_mask, object_mask, 0,255, CV_THRESH_BINARY);  //ensure the mask is binary
Run Code Online (Sandbox Code Playgroud)

Grabcut 的唯一问题是您必须提供一个包含要提取的对象的矩形作为输入。除此之外它的效果非常好。