gpt4 book ai didi

android - Opencv提高阈值的准确性

转载 作者:IT老高 更新时间:2023-10-28 23:01:07 24 4
gpt4 key购买 nike

我正在开发一个预计会使用 opencv 删除图像背景的应用程序,起初我尝试使用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;

}

负责色调的方法:

    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;
}

输入和输出的样本:[ Input Image1] Output Image

输入图像 2 和输出: enter image description here enter image description here

输入图像 3 和输出: enter image description here enter image description here

最佳答案

确实,正如其他人所说,您不太可能仅通过色调阈值获得好的结果。您可以使用类似于 GrabCut 的内容,但更快。

在后台,GrabCut 计算前景和背景直方图,然后根据这些直方图计算每个像素为 FG/BG 的概率,然后使用 graph cut 优化生成的概率图来获得一个分割。

最后一步是最昂贵的,根据应用程序可能会被忽略。相反,您可以将阈值应用于概率图以获得分割。它可能(并且将会)比 GrabCut 更糟,但会比您当前的方法更好。

这种方法需要考虑一些要点。直方图模型的选择在这里非常重要。您可以在某些空间(如 YUV 或 HSV)中考虑 2 个 channel ,考虑 3 个 RGB channel ,或者考虑 2 个归一化 RGB channel 。您还必须为这些直方图选择合适的 bin 大小。太小的 bin 会导致“过度训练”,而太大会降低精度。简而言之,这些之间的权衡是一个单独讨论的主题 - 我建议使用 RGB,每个 channel 有 64 个 bin,然后看看哪些更改对您的数据更好。

此外,如果您使用插值来获取 bin 之间的值,您可以获得更好的粗分级结果。过去我使用过三线性插值,与根本没有插值相比,它有点好。

但请记住,在没有事先了解对象形状的情况下,无论是使用 GrabCut、阈值还是这种方法,都无法保证您的分割是正确的。

关于android - Opencv提高阈值的准确性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33977051/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com