在嘈杂的背景中难以检测到小物体。有什么方法可以解决这个问题吗?

9
我可以帮您进行翻译。以下是翻译的结果:

我正在尝试制作一个计算机视觉程序,它可以检测垃圾和随意扔在嘈杂背景中的垃圾,比如沙滩(由于沙子而嘈杂)。

原始图像:

enter image description here

使用非图像处理方法进行Canny边缘检测:

enter image description here

我意识到一定的图像处理技术将帮助我实现忽略嘈杂的沙质背景并检测地面上所有垃圾和物体的目标。
我尝试了中值模糊处理,调整参数,得到了以下结果:

enter image description here

它在忽略沙地背景方面表现良好,但它未能检测到地面上的其他许多物体,可能是因为它被模糊了(不太确定)。
有没有改进算法或图像处理技术的方法,可以忽略嘈杂的沙地背景,同时允许Canny边缘检测找到所有物体,并使程序检测和绘制所有物体的轮廓。
代码:
from pyimagesearch.transform import four_point_transform
from matplotlib import pyplot as plt
import numpy as np
import cv2
import imutils

im = cv2.imread('images/beach_trash_3.jpg')


#cv2.imshow('Original', im)

# Histogram equalization to improve contrast




###
#im = np.fliplr(im)

im = imutils.resize(im, height = 500)

imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)

# Contour detection
#ret,thresh = cv2.threshold(imgray,127,255,0)

#imgray = cv2.GaussianBlur(imgray, (5, 5), 200)
imgray = cv2.medianBlur(imgray, 11)

cv2.imshow('Blurred', imgray)

'''
hist,bins = np.histogram(imgray.flatten(),256,[0,256])
plt_one = plt.figure(1)
cdf = hist.cumsum()
cdf_normalized = cdf * hist.max()/ cdf.max()

cdf_m = np.ma.masked_equal(cdf,0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m,0).astype('uint8')
imgray = cdf[imgray]

cv2.imshow('Histogram Normalization', imgray)
'''
'''
imgray = cv2.adaptiveThreshold(imgray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)
'''

thresh = imgray

#imgray = cv2.medianBlur(imgray,5)
#imgray = cv2.Canny(imgray,10,500)
thresh = cv2.Canny(imgray,75,200)
#thresh = imgray
cv2.imshow('Canny', thresh)


contours, hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

cnts = sorted(contours, key = cv2.contourArea, reverse = True)[:5]

test = im.copy()
cv2.drawContours(test, cnts, -1,(0,255,0),2)
cv2.imshow('All contours', test)

print '---------------------------------------------'
#####  Code to show each contour #####
main = np.array([[]])
for c in cnts:
    epsilon = 0.02*cv2.arcLength(c,True)
    approx = cv2.approxPolyDP(c,epsilon,True)

    test = im.copy()
    cv2.drawContours(test, [approx], -1,(0,255,0),2)
    #print 'Contours: ', contours
    if len(approx) == 4:
        print 'Found rectangle'
        print 'Approx.shape: ', approx.shape
        print 'Test.shape: ', test.shape

        # frame_f = frame_f[y: y+h, x: x+w]
        frame_f = test[approx[0,0,1]:approx[2,0,1], approx[0,0,0]:approx[2,0,0]]

        print 'frame_f.shape: ', frame_f.shape
        main = np.append(main, approx[None,:][None,:])
        print 'main: ', main


    # Uncomment in order to show all rectangles in image
    #cv2.imshow('Show Ya', test)


    #print 'Approx: ', approx.shape
    #cv2.imshow('Show Ya', frame_f)
    cv2.waitKey()
print '---------------------------------------------'
cv2.drawContours(im, cnts, -1,(0,255,0),2)
print main.shape
print main
cv2.imshow('contour-test', im)
cv2.waitKey()

我不确定这个问题是否属于离题,因为您似乎在询问应该使用哪个算法的建议。 - Rohit Gupta
1
尝试在HSV图像(H通道)上使用模糊和Canny算法,而不是灰度图像。或者可以使用双边滤波器代替中值滤波器。 - Micka
2
你能够发布原始输入图像的完整尺寸吗?不要进行任何修改和添加,也不要使用有损压缩。这对于想向你展示一些算法的人来说会很好。 - Micka
也许可以使用纹理分析来检测沙子? - Alessandro Jacopson
1
沙子检测的一个例子:HALATCI,Ibrahim等人。行星探测车的地形分类和分类器融合。在:2007年IEEE航空航天会议。IEEE,2007年。第1-11页。http://web.mit.edu/mobility/publications/Iagnemma_Aero_07b.pdf - Alessandro Jacopson
1
这将会有所帮助。它有点类似于下面Ankit建议的第一种方法。我用算法测试了给定的图像,结果得到了一个合理的分割。 - dhanushka
3个回答

4
我理解您的问题是:您想从一个变化的背景中(沙子灰度取决于许多其他条件)分离出前景对象。
有各种方法可以解决这种问题: 方法1: 从您的图像中可以清楚地看出,背景颜色像素始终比前景颜色像素多,开始初始分割的最简单方法是:
  1. 将图像转换为灰度。
  2. 创建其直方图。
  3. 找到直方图的峰值索引,即具有最大像素的索引。
上述三个步骤给您提供了背景的概念,但游戏并没有结束,现在您可以将此索引值放在中心,并取其周围的一定范围,例如:如果峰值索引为207(如您的情况),请选择75到225之间的灰度级范围并阈值图像。根据您的背景性质,上述方法可用于前景对象检测,在分割后,您必须执行一些后处理步骤,如形态学分析,以分割出不同的对象。提取对象后,您可以应用一些分类内容进行更精细的分割以消除误报。 方法2: 玩弄图像像素的一些统计数据,例如制作一小组灰度值并将其标记为类1和2,例如沙子为1,前景为2,从两个类中找出均值和方差(标准偏差),并计算每个类的概率(num_pix_per_class / total_num_pix),现在存储这些统计数据以备后用,然后回到图像并逐个应用高斯pdf:1/2*pisigma(exp(-(pix - mean)/2*sigma));在mean处放置先前计算的平均值,在sigma处放置先前计算的标准偏差。应用第3阶段后,您将获得每个像素的两个类的两个概率值,只需选择具有更高概率的类。 方法3: 方法3比上述两种方法更复杂:您可以使用一些基于纹理的操作来分割沙子类型的纹理,但是对于应用基于纹理的方法,我建议使用监督分类而不是无监督分类(如k-means)。 您可以使用的不同纹理特征包括: 基础:
  1. 在定义的邻域内的灰度级范围。
  2. 局部均值和方差或熵。
  3. 灰度共生矩阵(GLCM)。
高级:
  1. 本地二进制模式。
  2. 小波变换。
  3. Gabor变换等。

注意: 我认为你应该尝试一下第一和第二种方法。这可以解决很多工作。 :)


@user3377126,你能否分享一下你在1、2、3方法之间的经验和建议? - newbie
2015年提出了一些建议的方法,现在我将选择任何基于深度学习的目标检测器的一种,比如Yolo或SSD。 - Ankit Dixit

2
为了获得更好的结果,您应该应用许多算法。OpenCV教程总是关注于OpenCV的一个特性。真正的计算机视觉应用程序应该尽可能使用多种技术和算法。
我曾经在嘈杂的图片中检测生物细胞,并通过应用一些上下文信息获得了非常好的结果:
- 细胞的预期大小 - 所有细胞具有相似的大小 - 预期的细胞数量
因此,我改变了许多参数并尝试检测我正在寻找的内容。
如果使用边缘检测,则沙子会产生相当随机的形状。尝试更改Canny参数并检测线条、矩形、圆形等更可能与垃圾相关的形状。记住每个参数集中检测到的对象的位置,并在最后将优先权给予检测到形状最多的位置(区域)。
使用颜色分离。颜色直方图中的峰值可能是垃圾的提示,因为沙子颜色的分布应该更加均匀。
对于一些经常出现的小物体,比如香烟蒂,您可以应用对象匹配
附言: 很酷的应用程序!只是出于好奇,你打算用四轴飞行器扫描海滩吗?

你有其他关于如何系统地组合多个检测器的参考资料吗? - Micka
1
不是全部都是硬编码,有些部分我使用了SVM。一开始,我花费了很多时间在OpenCV中寻找“适当的现成解决方案”,以便“不重复造轮子”。最终,我使用了我的代码和OpenCV的某些组合。后来,一个OpenCV专家告诉我,不要太字面理解OpenCV。他们无法考虑到所有的用例。我甚至自己实现了自动特征选择,以便能够考虑上下文或领域信息。 - Valentin H

0

如果您想在这种均匀的背景上检测物体,那么您应该从检测图像中的主要颜色开始。这样,您就可以检测所有的沙子,而对象将出现在其余的部分。您可以查看Arnaud LeTrotter和Ludovic Llucia发表的论文,他们都使用了这种“主颜色检测”技术。


1
背景绝不是均匀的!沙子可能是干的或湿的,沙子的颜色也可能不同。阴影、时间的变化会显著改变颜色等。 - Valentin H
对于给定的图像,它应该是均匀的!他们使用的算法对每个图像进行计算,而不是一次性计算所有图像。 - FiReTiTi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接