不同材质的图像分割问题

信息处理 matlab opencv 计算机视觉 边缘检测 图像分割
2022-01-17 04:52:05

嗨 CV/模式识别社区,

我有一个关于图像分割的严重问题。场景是炉内的气氛,让我发疯。而且我需要在短时间内(<10 秒)检测不同材料(玻璃、陶瓷、铝、铱、..)的物体轮廓,而不仅仅是一种特殊情况。我还需要代码的连续像素行中的轮廓。因此,还需要链码或所谓的边界/轮廓跟踪,因此开孔并不好。背景中有非线性噪声,大约是灰尘、颗粒或其他,不时出现。

欢迎使用 Matlab 或 OpenCV 建议。

为了更清楚,我发布了我的目标的另一张图像和一个半透明的物体,它也需要被检测到。还有更多需要注意的例子。 示例1 示例2 示例3 例子4

正如您在图像#1 中看到的那样,图像的右侧和靠近恒星的外轮廓附近有粒子,这就是物体。整体对比度也不是很好。物体本身位于地下,与轮廓检测无关。图像#2 显示了一个半透明的对象,这也是可能的。

我想找到该对象的轮廓/周长,例如在下一个屏幕(红线)上。两个矩形(黄色)标记起点(左)和终点(右)。蓝线是可以忽略的。 示例2

起初我以为只用过滤器就可以解决那种肮脏的气氛的问题。但是在投入大量时间之后,我才意识到,我必须显着消除或减少噪音以增加前景和背景的对比度。我尝试了很多方法,比如直方图均衡、Otsu 自适应均衡、线性滤波器(例如高斯)、非线性滤波器(中值、扩散)、主动轮廓、k-Means、Fuzzy-c-means 以及 Canny for pure边缘检测结合形态算子。

  • Canny:粒子和大气造成了孔洞,但我需要物体的完整轮廓。仍然对形态算子进行闭合、膨胀还不够好。由于滞后,Canny 仍然是我研究过的所有方法中最好的结果。
  • 活动轮廓:它们也适用于边缘/渐变,它们在对象内部初始化后表现得非常疯狂,这可能是由导致“开放”对象的边缘映射引起的。据我所知,轮廓必须关闭。尝试了不同的衍生产品(GVF/VFC/Classic Snake)。
  • k-均值:结果包括炉内气氛,因为背​​景有雾。模糊 c 均值也是如此。我选择了两个集群,因为将对象与背景分开。更多的集群导致更弱的结果。
  • 直方图/Otsu:由于非常接近的灰色强度(恕我直言!),它将对象与背景合并。尝试使用本地和全局方法。
  • 过滤器:特别是 GLPF 或其他 LPF 会涂抹边缘,效果不太好,甚至无法减少雾气。
  • 非线性滤波器保留边缘。他们中的大多数人在计算大图像时花费的时间太长。现在采取了快速双边过滤器。结果见下文。

因此,对于后处理步骤来说,没有一种方法足够好,因为对象片段的获得结果与现有算法的竞争很差。现有算法非常本地化,因此适用于这种非常特殊的场景。

所以我问你,如果我完全错过了什么......我不知道如何处理以及我应该如何获得良好的轮廓结果,没有间隙或孔......是否有可能不对CCD和物理环境?提前致谢!

到目前为止的最后一种方法(经过一夜的 MO 实验):

  • 双边过滤器(边缘保留,但平滑同质区域)
  • Canny(西格玛 = 2,阈值 = [0.04 0.08])
  • 形态运算 (MO): bwareopen, closing, remove&bridge
  • bwlabel仅选择轮廓的周边,从而消除不需要的噪声。还没有更新的截图,但它适用于明星。玻璃有一个连接到外轮廓的内轮廓,这也可以在下面的屏幕截图中看到。

所以恐怕我需要一个特殊的算法来遍历外轮廓。这将是邻域的一些顺时针/逆时针查找。如果有角点,顺时针/逆时针步骤可以切换。如果有间隙,请增加半径并再次查看。如果有两个或多个可能的以下点,则取与前一个方向相同的点。你认为,轮廓跟随算法有意义吗?

玻璃边缘 星星

4个回答

您可以尝试以下方法:

  • 高效的基于图的图像分割: http ://www.cs.brown.edu/~pff/segment/ (可用代码)

  • 基于 GraphCut 的分割: http ://www.csd.uwo.ca/~olga/OldCode.html (可用代码)

  • 首先使用稀疏方法对图像进行去噪: http: //spams-devel.gforge.inria.fr/(代码可用)

我认为您过早地放弃了阈值技术。看看你的直方图,它显然是三模态的:( 我手动删除了图像右侧的白色列,我假设它们不是图像的一部分 - 请在运行我的代码之前拍摄此图像)

在此处输入图像描述

查看第一组中的所有值:

在此处输入图像描述

为了在三模态直方图中找到模式,可以使用具有强度的 K-means 聚类。K=3以下 Matlab 代码可th1=67在您的代码中找到。这个想法是假设你有 3 个集合,并计算每个集合的加权质心。然后,将每个强度级别分配给它自己的集群。当加权质心停止移动时,您停止。这是在图像上找到两个阈值的结果,显示在直方图上。

在此处输入图像描述

function [th1,th2]=SegmentHistTo3()
    im = imread('http://i.stack.imgur.com/U2sc5.png');
    h = imhist(im(:,:,1)); %# Calculate histogram

    th1new = round(256/3); %# Initial thresholds
    th2new = round(256*2/3);
    th1 = 0;
    th2 = 0;

    while (th1~=th1new) || (th2~=th2new) %# While the centroids keep on moving
        th1 = th1new;
        th2 = th2new;

        wa1 = WeightedAverage(h,1,th1);  %# Calculate 3 weighted averages
        wa2 = WeightedAverage(h,th1+1,th2);
        wa3 = WeightedAverage(h,th2,numel(h));

        th1new = round( (wa1+wa2)/2 );  %# The thresholds are middle points between the averages
        th2new = round( (wa2+wa3)/2 );
    end

    figure; hist( double( reshape(im(:,:,1),1,[]) ),256);
    hold on;
    plot( [th1 th1],[0 max(h)],'r','LineWidth',2);
    plot( [th2 th2],[0 max(h)],'r','LineWidth',2);

    figure;imshow( im(:,:,1)<th1);
end

function wa = WeightedAverage(region,th1,th2)    
    regionNonEmpty(th1:th2) = region(th1:th2);
    wa = sum( regionNonEmpty .* (1:numel(regionNonEmpty))) / sum(regionNonEmpty);    
end

之后解决问题是小菜一碟,简单的做一些简单的形态学操作,比如开。

正如上面所建议的,阈值对这个图像非常有效,它本质上是二进制的,除了一个恒定的阈值不会因为光照不均匀而起作用。您需要自适应阈值。

我的建议是使用简单模型(可能是平面 [3 DOF] 或二次 [6 DOF])进行背景重建,方法是在光照区域中采样少量值。最好的办法是使用小的 ROI 来平均化噪声。然后通过减去(或除以)背景值来纠正阴影。

如果人工交互不是一种选择,您可以通过首先直接 Otsu 自动搜索背景区域并考虑远低于阈值的均匀 ROI(低方差)。在第一次背景重建之后,您可能可以通过将此过程应用于平面校正图像来改进。

整个过程可以实现远低于一秒。

我认为最好的方法是使用主动轮廓。如果您不知道什么是活动轮廓,请在 youtube 上观看此视频http://www.youtube.com/watch?v=ijNe7f3QVdA

基本上,你需要给一个初始化分割,它会改善形状。我的建议是本文讨论的方法之一,并使用活动轮廓作为第二步,即。作为改进步骤。

这是您可以使用的活动轮廓的实现 http://www.mathworks.com/matlabcentral/fileexchange/19567