android - 计数物体和更好的填充孔的方法

标签 android opencv count fill blobs

我是 OpenCV 的新手,正在尝试计算图像中对象的数量。我在使用 MATLAB Image Processing Toolbox 之前就已经这样做了,并且也在 OpenCV (Android) 中采用了相同的方法。

第一步是将图像转换为灰度。然后对其设置阈值,然后计算 Blob 的数量。在 Matlab 中有一个命令 - “bwlabel”,它给出了 Blob 的数量。我在 OpenCV 中找不到这样的东西(同样,我是 OpenCV 和 Android 的菜鸟)。

这是我的代码,

//JPG to Bitmap to MAT
Bitmap i = BitmapFactory.decodeFile(imgPath + "mms.jpg");
Bitmap bmpImg = i.copy(Bitmap.Config.ARGB_8888, false);
Mat srcMat = new Mat ( bmpImg.getHeight(), bmpImg.getWidth(), CvType.CV_8UC3);
Utils.bitmapToMat(bmpImg, srcMat);

enter image description here

//convert to gray scale and save image
Mat gray = new Mat(srcMat.size(), CvType.CV_8UC1);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGB2GRAY,4);
//write bitmap
Boolean bool = Highgui.imwrite(imgPath + "gray.jpg", gray);

enter image description here

//thresholding
Mat threshed = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.adaptiveThreshold(gray, threshed, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 75, 5);//15, 8 were original tests. Casey was 75,10
Core.bitwise_not(threshed, threshed);
Utils.matToBitmap(threshed, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "threshed.jpg", threshed);
Toast.makeText(this, "Thresholded image saved!", Toast.LENGTH_SHORT).show();

enter image description here

在下一步中,我尝试使用先膨胀再腐 eclipse 的方法来填充孔和字母,但是 Blob 会相互附着,最终会给出错误的计数。在调整膨胀和腐 eclipse 参数时,在填充孔洞和让 Blob 相互附着之间需要权衡。

这是代码,

//morphological operations
//dilation
Mat dilated = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.dilate(threshed, dilated, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size (16, 16)));
Utils.matToBitmap(dilated, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "dilated.jpg", dilated);
Toast.makeText(this, "Dilated image saved!", Toast.LENGTH_SHORT).show();

enter image description here

//erosion
Mat eroded = new Mat(bmpImg.getWidth(),bmpImg.getHeight(), CvType.CV_8UC1);
Imgproc.erode(dilated, eroded, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size(15, 15)));
Utils.matToBitmap(eroded, bmpImg);
//write bitmap
bool = Highgui.imwrite(imgPath + "eroded.jpg", eroded);
Toast.makeText(this, "Eroded image saved!", Toast.LENGTH_SHORT).show();

因为有时我的 M&M 巧克力 bean 可能紧挨着! ;)

enter image description here

我也尝试过使用 Hough Circles 但结果非常不可靠(用硬币图像和真实硬币测试)

这是代码,

//hough circles
Mat circles = new Mat();

// parameters
int iCannyUpperThreshold = 100;
int iMinRadius = 20;
int iMaxRadius = 400;
int iAccumulator = 100;

Imgproc.HoughCircles(gray, circles, Imgproc.CV_HOUGH_GRADIENT, 
         1.0, gray.rows() / 8, iCannyUpperThreshold, iAccumulator, 
         iMinRadius, iMaxRadius);

// draw
if (circles.cols() > 0)
{
    Toast.makeText(this, "Coins : " +circles.cols() , Toast.LENGTH_LONG).show();
}
else
{
    Toast.makeText(this, "No coins found", Toast.LENGTH_LONG).show();
}

这种方法的问题是该算法仅限于完美的圆(AFAIK)。因此,当我尝试扫描和计算 table 上的 M&M 巧克力 bean 或硬币时,效果不佳(因为设备的角度会改变)。通过这种方法,有时我得到的更少。检测到的硬币数量,有时更多(我不明白为什么更多??)。

在扫描这张图片时,应用有时会显示 19 个硬币,有时会显示 38 个硬币……我知道还有其他特征可能会被检测为圆圈,但我完全不明白为什么是 38..?

enter image description here

所以我的问题...

  1. 有没有更好的方法来填充孔洞而不连接相邻的 Blob ?
  2. 如何准确计算对象的数量?我不想将我的应用程序限制为仅使用 HoughCircles 方法计算圆圈。

仅供引用:OpenCV-2.4.9-android-sdk。请记住,我也是 OpenCV 和 Android 的新手。

非常感谢任何帮助。

谢谢和干杯!

贾南姆

最佳答案

因此,为了继续,我们将您生成的阈值图像作为输入并进一步修改它。目前的代码是在 C++ 中,但我想你可以轻松地将它转换为 android 平台 Input Image

现在您可以尝试使用洪水填充而不是膨胀或模糊

结果

Flood-filled image

最后现在应用我们得到的轮廓检测算法算法 Final output

上面的代码是

    Mat dst = imread($path to the threshold image); // image should be single channel black and white image
    imshow("dst",dst);

    cv::Mat mask = cv::Mat::zeros(dst.rows + 2, dst.cols + 2, CV_8U);

            // A image with size greater than the present object is created

    cv::floodFill(dst, mask, cv::Point(0,0), 255, 0, cv::Scalar(), cv::Scalar(),  4 + (255 << 8) + cv::FLOODFILL_MASK_ONLY);
    erode(mask,mask,Mat());
    // Now to remove the outer boundary
    rectangle(mask,Rect(0,0,mask.cols,mask.rows), Scalar(255,255,255),2,8,0);
    imshow("Mask",mask);


    Mat copy;
    mask.copyTo(copy);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours( copy, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

    vector<vector<Point> > contours_poly( contours.size() );
    vector<Rect> boundRect( contours.size() );
    vector<Point2f>center( contours.size() );
    vector<float>Distance( contours.size() );
    vector<float>radius( contours.size() );

    Mat drawing = cv::Mat::zeros(mask.rows, mask.cols, CV_8U);
    int num_object = 0;
    for( int i = 0; i < contours.size(); i++ ){
        approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );

            // To get rid of the smaller object and the outer rectangle created
            //because of the additional mask image we enforce a lower limit on area 
            //to remove noise and an upper limit to remove the outer border.    

        if (contourArea(contours_poly[i])>(mask.rows*mask.cols/10000) && contourArea(contours_poly[i])<mask.rows*mask.cols*0.9){
            boundRect[i] = boundingRect( Mat(contours_poly[i]) );
            minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
            circle(drawing,center[i], (int)radius[i], Scalar(255,255,255), 2, 8, 0);
            rectangle(drawing,boundRect[i], Scalar(255,255,255),2,8,0);
            num_object++;
        }
    }

    cout <<"No. of object detected =" <<num_object<<endl;


    imshow("drawing",drawing);

    waitKey(2);
    char key = (char) waitKey(20);
    if(key == 32){
    // You can save your images here using a space

            }

希望能帮到你解决问题

关于android - 计数物体和更好的填充孔的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24204779/

相关文章:

android - fragment 、setRetainInstance(true) 和线程库

java - 如何在选项菜单android中获得更细的字体

OpenCV 像 Matlab 函数 graythresh 一样只得到 Otsu 阈值

Docker:复制失败:stat <file>:文件不存在

opencv - 构建 OpenCV 时出现 Cmake 错误

java - 如何统计Java应用运行时哪个类被使用了多少次

android - 如何在 Android Oreo 中运行隐式广播?

android - 防止 TextView 在 ConstraintLayout 中与另一个重叠?

java - 计算图像中的 "redish/blueish/greenish..."种颜色

r - 动态计数出现次数