【问题标题】:Finding largest blob in image查找图像中最大的 blob
【发布时间】:2016-08-21 03:00:06
【问题描述】:

我在使用 EmguCV 从图像中提取 blob 时遇到一些问题。我在网上看到的所有东西都使用 Contours 对象,但我猜想它是从 EmguCV3.0 中删除的?每次尝试使用它时都会出现异常。我没有发现很多最近的/相关的 SO 主题并没有过时。

基本上,我有一张叶子的照片。背景可能是白色、绿色、黑色等。我想从根本上移除背景,以便我可以在不干扰背景的情况下对叶子执行操作。我只是不确定我要去哪里错了:

        Image<Bgr, Byte> Original = Core.CurrentLeaf.GetImageBGR;
        Image<Gray, Byte> imgBinary = Original.Convert<Gray, Byte>();
        imgBinary.PyrDown().PyrUp(); // Smoothen a little bit
        imgBinary = imgBinary.ThresholdBinaryInv(new Gray(100), new Gray(255)); // Apply inverse suppression

        // Now, copy pixels from original image that are black in the mask, to a new Mat.  Then scan?
        Image<Gray, Byte> imgMask;
        imgMask = imgBinary.Copy(imgBinary);
        CvInvoke.cvCopy(Original, imgMask, imgBinary);

        VectorOfVectorOfPoint contoursDetected = new VectorOfVectorOfPoint();
        CvInvoke.FindContours(imgBinary, contoursDetected, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);

        var contoursArray = new List<VectorOfPoint>();
        int count = contoursDetected.Size;
        for (int i = 0; i < count; i++)
        {
            using (VectorOfPoint currContour = contoursDetected[i])
            {
                contoursArray.Add(currContour);
            }
        }

有了这个,我得到一个带有一点点白线的黑色图像。我来回绞尽脑汁,也想不出什么来。任何指针将不胜感激!

【问题讨论】:

    标签: opencv image-processing emgucv


    【解决方案1】:
    1. 我认为您需要在每个轮廓上使用 ContourArea 来找出哪个是最大的区域。
    2. 找到最大轮廓后,您需要使用 FillPoly 填充它(因为轮廓只是 blob 的放置线,而不是其中的所有像素)并创建一个掩码,该掩码作为值为 1 的叶像素和所有内容否则为 0。
    3. 最终使用遮罩从原始图像中提取叶子像素

    我对c#不是很精通,所以我在python中附上了opencv的代码给你一些帮助。

    生成的图像:

    希望这会有所帮助。

    import cv2
    import numpy as np
    
    # Read image
    
    Irgb = cv2.imread('leaf.jpg')
    R,G,B = cv2.split(Irgb)
    
    # Do some denosiong on the red chnnale (The red channel gave better result than the gray because it is has more contrast
    Rfilter = cv2.bilateralFilter(R,25,25,10)
    
    # Threshold image
    ret, Ithres = cv2.threshold(Rfilter,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
    
    # Find the largest contour and extract it
    im, contours, hierarchy = cv2.findContours(Ithres,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE )
    
    maxContour = 0
    for contour in contours:
        contourSize = cv2.contourArea(contour)
        if contourSize > maxContour:
            maxContour = contourSize
            maxContourData = contour
    
    # Create a mask from the largest contour
    mask = np.zeros_like(Ithres)
    cv2.fillPoly(mask,[maxContourData],1)
    
    # Use mask to crop data from original image
    finalImage = np.zeros_like(Irgb)
    finalImage[:,:,0] = np.multiply(R,mask)
    finalImage[:,:,1] = np.multiply(G,mask)
    finalImage[:,:,2] = np.multiply(B,mask)
    cv2.imshow('final',finalImage)
    

    【讨论】:

    • 您能提供一些帮助将其转换为 C# 吗?我了解 python,但在转换为 C# 以使其部分适应我的应用程序时遇到问题。
    • 我只能帮助处理与 c# 中的 opencv 相关的事情。告诉我你在代码的哪一行遇到问题我会尽力帮助。
    【解决方案2】:

    我建议您研究 Otsu 阈值。它为您提供了一个阈值,您可以使用该阈值将图像分为两类(背景和前景)。使用 OpenCV 的阈值方法,您可以在必要时创建掩码。

    【讨论】:

      猜你喜欢
      • 2012-03-20
      • 2019-09-16
      • 2013-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 2012-03-11
      相关资源
      最近更新 更多