如何区分物体曲率的两种不同类型的异常?

时间:2018-06-28 05:57:29

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

我一直在从事一个需要发现洋葱缺陷的项目。附加的第二张图像显示洋葱异常。您会看到洋葱是由两个较小的洋葱双胞胎组成的。有趣的是,人眼可以轻松检测出结构的错误。

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

但是有时洋葱皮会使曲线不规则。看到图像,一小部分皮肤不在实际曲率范围内。我要区分由于皮肤与两个子部分相交处产生的变形而导致的凸起部分,然后重建对象轮廓以进行进一步分析。

考虑到我拥有构成洋葱外缘(包括两个不规则处)的大部分要点,是否存在数学上的事情对我有帮助?

Healthy onion with deformity bulging out [Another deformed image[2]

请参见下面的代码:

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()

2 个答案:

答案 0 :(得分:3)

我建议您尝试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)→浮点数

More details

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

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

答案 1 :(得分:3)

好的,所以,如果您查看洋葱的前两张图片,您会发现它们呈圆形(果皮峰除外),而“缺陷”则呈椭圆形。您可以尝试找到轮廓(当然是在应用了图像变换之后)并确定其中心点。然后,您可以测量从轮廓中心到轮廓每个点的距离。您可以使用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)

结果:

enter image description here

最大距离:37

距离超过最小值:0

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

结果2:

enter image description here

缺陷

最远距离:553

距离超过最小值:13

在这里您可以看到有更多的点超出范围(红色),并且洋葱不适合。

希望这至少可以为您解决问题的思路。干杯!