【问题标题】:How do I discriminate two different type of abnormalities in curvature of the object?如何区分物体曲率的两种不同类型的异常?
【发布时间】:2018-12-07 02:33:24
【问题描述】:

我一直在从事一个需要发现洋葱缺陷的项目。附加的第二张图片显示了一个异常的洋葱。您可以看到洋葱由两个较小的洋葱双胞胎组成。有趣的是,人眼可以很容易地发现结构有什么问题。

可以进行结构分析并观察到正常的洋葱具有几乎平滑的曲率,而异常的则没有。因此很简单,我想建立一个基于对象边缘的分类算法。

但有时洋葱皮会使曲线变得不规则。看图片,有一小部分皮肤在实际曲率之外。我想区分由于皮肤引起的凸起部分与在两个子部分相交处产生的畸形,然后重建对象的轮廓以进行进一步分析。

考虑到我拥有构成洋葱外缘的大部分点,包括两个不规则部分,是否有数学上的东西可以帮助我?

[

请看下面的代码:

import cv2
import numpy as np 
import sys

cv2.ocl.setUseOpenCL(False)


cv2.namedWindow('test', cv2.WINDOW_NORMAL)
cv2.namedWindow('orig', cv2.WINDOW_NORMAL)
cv2.resizeWindow('test', 600,600)
cv2.resizeWindow('orig', 600,600)





image = cv2.imread('./buffer/crp'+str(sys.argv[1])+'.JPG')

tim = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
hsv_image =  cv2.cvtColor(image,cv2.COLOR_BGR2HSV)
frame_threshed = cv2.inRange(hsv_image, np.array([70,0,0],np.uint8), 
                np.array([140,255,255],np.uint8))

canvas = np.zeros(image.shape, np.uint8)
framhreshed=cv2.threshold(frame_threshed,10,255,cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3),np.uint8)
frame_threshed = cv2.erode(frame_threshed,kernel,iterations = 1)
kernel = np.ones((5,5),np.uint8)
frame_threshed = cv2.erode(frame_threshed,kernel,iterations = 1)
kernel = np.ones((7,7),np.uint8)
frame_threshed = cv2.erode(frame_threshed,kernel,iterations = 1)

_, cnts, hierarchy = cv2.findContours(frame_threshed.copy(), 
cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts= sorted(cnts, key=cv2.contourArea, reverse=True)

big_contours = [c for c in cnts if cv2.contourArea(c) > 100000]

for cnt in big_contours:
perimeter = cv2.arcLength(cnt,True)
epsilon = 0.0015*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
# print(len(approx))
hull = cv2.convexHull(cnt,returnPoints = False)
# try:
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(canvas,start,end,[255,0,0],2)
    cv2.circle(canvas,far,5,[255,255,255],-1)

cv2.drawContours(image, [approx], -1, (0, 0, 255), 5)
cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 5)



cv2.imshow('orig',image)
cv2.imshow('test',canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

【问题讨论】:

    标签: python-3.x opencv image-processing machine-learning computer-vision


    【解决方案1】:

    我建议您尝试 HuMoments,因为您已经提取了对象的形状。它可以让你计算两个形状之间的距离,基本上是你的异常洋葱和参考洋葱之间的距离。

    Hu Moments 形状描述符可用于使用 OpenCV 的 Python。如果image 是二进制的,你可以这样使用:

    # Reference image
    shapeArray1 = cv2.HuMoments(cv2.moments(image1)).flatten()
    # Abnormal image
    shapeArray2 = cv2.HuMoments(cv2.moments(image2)).flatten()
    # Calculation of distance between both arrays
    # Threshold based on the distancce
    # Classification as abnormal or normal
    

    MatchShapes 也可以完成这项工作。它需要两个轮廓的二值图像来返回一个计算两者之间距离的浮点数。

    Python:cv.MatchShapes(object1, object2, method, parameter=0) → float

    More details

    因此,当检测到洋葱形状异常时,您必须填充此形状并应用一些binary morphology 以消除缺陷并提取没有缺陷的形状。

    1. 填满你的形状
    2. 应用带有圆盘结构元素的开口(侵蚀后膨胀)以消除不规则性
    3. 再次提取轮廓
    4. 您应该有一个没有违规行为的表格。如果不是,请返回第 2 步并更改结构元素的大小

    【讨论】:

    • 它会帮助我检测由于干燥的叶子倾向于向外的凸起吗?
    • @NikhilPandey 这将帮助您发现洋葱形状不完美的事实(距离更重要)。但它不会告诉你缺陷在哪里,那是下一步。让我编辑我的答案以帮助您进行检测。
    【解决方案2】:

    好的,所以如果您查看洋葱的前两张图片,您会发现它们具有圆形(剥皮峰除外),而“缺陷”则更多的是椭圆形。您可以尝试的是找到您的轮廓(当然在您应用图像转换之后)并确定它的中心点。然后你可以测量从轮廓中心到轮廓每个点的距离。您可以使用 scipy(ckd.tree()tree.query())或简单地通过数学公式计算两点之间的距离 sqrt(x2-x1)^2+(y2-y1)^2。然后你可以说,如果一些点超出范围,它仍然是一个好的洋葱,但如果有很多点超出范围,那么它就是一个有缺陷的洋葱。为了演示,我画了两个示例图像。

    代码示例:

    import cv2
    import numpy as np
    import scipy
    from scipy import spatial
    
    
    img = cv2.imread('oniond.png')
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret,thresh = cv2.threshold(gray_image,180,255,cv2.THRESH_BINARY_INV)
    im2, cnts, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    cnt = max(cnts, key=cv2.contourArea)
    list_distance = []
    points_minmax = []
    
    M = cv2.moments(cnt)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
    center = (cX, cY)
    
    for i in cnt:
        tree = spatial.cKDTree(i)
        mindist, minid = tree.query(center)
        list_distance.append(mindist)
        if float(mindist) < 100:
            points_minmax.append(i)
        elif float(mindist) > 140:
            points_minmax.append(i)
        else:
            pass
    
    reshape = np.reshape(list_distance, (-1,1))
    
    under_min = [i for i in list_distance if i < 100]
    over_max = [i for i in list_distance if i > 140]
    
    for i in points_minmax:
        cv2.line(img,center,(i[0,0],i[0,1]),(0,0,255),2)
    
    if len(over_max) > 50:
        print('defect')
        print('distances over maximum: ', len(over_max))
        print('distances over minimum: ', len(under_min ))
    
    elif len(under_min ) > 50:
        print('defect')
        print('distances over maximum: ', len(over_max))
        print('distances over minimum: ', len(under_min ))
    
    else:
        print('OK')
        print('distances over maximum: ', len(over_max))
        print('distances over minimum: ', len(under_min ))
    
    cv2.imshow('img', img)
    

    结果:

    好的

    最大距离:37

    最小距离:0

    输出显示有 37 个点越界(红色),但洋葱仍然可以。

    结果 2:

    缺陷

    最大距离:553

    最小距离:13

    而这里你可以看到越界点越多(红色),洋葱也不行。

    希望这至少能让您了解如何解决您的问题。干杯!

    【讨论】:

    • 伟大的直觉。我脑子里也有类似的事情。但是,存在一个限制,即顶视图不是将要处理的唯一视图。想象一下在地板上扔满这样的桶。现在我认为洋葱的侧面投影是一个有待解决的挑战。你怎么看?
    • 嘿!是的,处理方面是一个问题……如果有人想对此类产品进行视觉检查,则必须研究对象的物理特性(就像您说的扔一个桶,看看会发生什么)。可能由于权重分布,它具有自我定位的特点。如果没有,那么您必须帮助其正确定位(振动给料机、传送带......)或考虑添加另一个(或几个)相机。
    • 也许你甚至可以制作一个算法来检测它位于哪一侧(比如它是否在另一侧,它的尺寸较小或类似的东西)。问题还在于闪电,它可以帮助并节省大量编写脚本的时间(如同轴漫射、O 形环、背光……)。
    • 你提到的所有事情都向我保证,如果在 RGB 中完成它是一种多变量图像分析。现在我正在尝试将轮廓的最大轴与水平轴对齐,并从左到右、从上到下取垂直距离。我希望这可以揭示那些双曲率的特征曲线,无论它们在哪一边。会及时通知您。
    • @Jeru Luke:谢谢...意义重大,因为我刚刚开始学习。
    猜你喜欢
    • 2023-01-24
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多