Как различить два разных типа отклонений в кривизне объекта? - PullRequest
0 голосов
/ 28 июня 2018

Я работал над проектом, который требует найти дефект в луке. Второе изображение, которое прикреплено, показывает ненормальный лук. Вы можете видеть, что лук состоит из двух меньших луковых близнецов. Что интересно, человеческий глаз может легко обнаружить, что не так со структурой.

Можно провести структурный анализ и заметить, что нормальный лук имеет почти гладкую кривизну, а ненормальный - нет. Таким образом, я просто хочу построить алгоритм классификации, основанный на краях объекта.

Однако бывают случаи, когда кожура лука делает изгиб нерегулярным. Посмотрите на изображение, есть небольшая часть кожи, которая находится вне фактической кривизны. Я хочу различить выпуклую часть из-за того, что кожа отличается от деформаций, возникших в точке соприкосновения двух подразделов, а затем реконструировать контур объекта для дальнейшего анализа.

Есть ли математическая вещь, которая помогла бы мне здесь, учитывая тот факт, что у меня есть большинство точек, которые делают внешний край лука, включая две неровности?

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 голосов
/ 28 июня 2018

ОК, поэтому, если вы посмотрите на первые две фотографии вашего лука, вы увидите, что они имеют круглую форму (за исключением пиковых пилингов), а «дефектная» имеет более овальную форму. Что вы можете попробовать, так это найти свой контур (после того, как вы, конечно, примените преобразование изображения) и определить его центральные точки. Затем вы можете измерить расстояние от центра контура до каждой точки контура. Вы можете сделать это, используя 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

OK

расстояния выше максимума: 37

расстояние выше минимального: 0

Вывод показывает, что есть 37 точек за пределами (красный цвет), но лук все еще в порядке.

Результат 2:

enter image description here

дефект

расстояния выше максимума: 553

расстояния выше минимального: 13

И здесь вы можете видеть, что есть больше точек за пределами (красный цвет), и лук не в порядке.

Надеюсь, это даст хотя бы представление о том, как решить вашу проблему. Ура!

0 голосов
/ 28 июня 2018

Я бы посоветовал вам попробовать HuMoments, поскольку вы уже извлекли форму ваших объектов. Это позволит вам рассчитать расстояние между двумя формами, то есть между вашим ненормальным луком и эталонным луком.

Дескриптор формы Hu Moments доступен для Python с использованием OpenCV. Если 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 (объект1, объект2, метод, параметр = 0) → float

Подробнее

Таким образом, когда форма лука определяется как ненормальная, вам придется заполнить эту форму и применить некоторую бинарную морфологию , чтобы стереть несовершенство и извлечь форму без несовершенства.

  1. Заполните свою форму
  2. Нанести отверстие (эрозия с последующим расширением) структурным элементом диска, чтобы избавиться от неровностей
  3. Извлечение контуров снова
  4. У вас должна быть форма без каких-либо нарушений. Если нет, вернитесь к шагу 2 и измените размер элемента конструкции
...