本文介绍了计数对象填充孔的更好方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

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

I am new to OpenCV and am trying to count the number of objects in an image. I have done this before using MATLAB Image Processing Toolbox and adapted the same approach in OpenCV (Android) also.

第一步是将图像转换为灰度.然后将其阈值化,然后计算斑点的数量.在Matlab中,有一个命令-"bwlabel",它给出了斑点的数量.我在OpenCV中找不到这样的东西(再次,我在OpenCV和Android中都是菜鸟.)

The first step was to convert an image to gray scale. Then to threshold it and then counting the number of blobs. In Matlab there is a command - "bwlabel", which gives the number of blobs. I couldn't find such thing in OpenCV (again, I am a noob in OpenCV as well as 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);
//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);
//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();

在下一步中,我尝试使用膨胀和侵蚀填充填充孔和字母,但斑点彼此附着,最终将产生错误的计数.在调整膨胀和腐蚀参数时,要在填充孔和使斑点彼此附着之间进行权衡.

In the next step, I tried to fill the holes and letters using dilation followed by an erosion but the blobs gets attached to each other which will ultimately give a wrong count. There is a tradeoff between filling holes and getting the blobs attached to each other on tuning the parameters for dilation and erosion.

这是代码,

//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();
//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可能彼此相邻! ;)

Because sometimes my M&Ms might be just next to each other! ;)

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

I also tried to use Hough Circles but the result is very unreliable (tested with coin images as well as real coins)

这是代码,

//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).因此,当我尝试扫描和计数躺在我桌上的M& Ms或硬币时,它不能很好地工作(因为设备的角度发生了变化).使用这种方法,有时我会得到更少的反对.的硬币数量有时甚至更多(我不知道为什么还要更多?).

The problem with this approach is that the algorithm is limited to perfect circles only (AFAIK). So, it doesn't work well when I try to scan and count M&Ms or coins lying on my desk (because angle of the device changes). With this approach, sometimes I get less no. of coins detected and sometimes more (I don't get it why more??).

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

On scanning this image the app sometimes shows 19 coins and sometimes 38 coins counted...I know there are other features which may be detected as circles but I totally don't get it why 38..?

所以我的问题...

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

仅供参考:OpenCV-2.4.9-android-sdk.请记住,我也是OpenCV和Android的新手.

FYI : OpenCV-2.4.9-android-sdk. Kindly keep in mind that I am a newbie in OpenCV and Android too.

非常感谢您的帮助.

感谢&干杯!

Jainam

推荐答案

因此,我们将您生成的阈值图像作为输入,然后对其进行进一步修改.目前的代码是C ++,但我想您可以轻松将其转换为android平台

So to proceed we take your threshold image which you have generated as input and further modify it. The present code is in C++ but I guess you can easily convert it into android platform

现在,您可以尝试进行泛洪填充,而不必进行扩散或模糊处理

Now instead of dilation or blurring you can try flood fill

结果

现在终于应用轮廓检测​​算法算法,我们得到

Finally now applying the contour detection algorithm algorithm we get

上面的代码是

    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

            }

我希望这可以帮助您解决问题

I hope this helps you in solving your problem

这篇关于计数对象填充孔的更好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 07:35