Подсчет яиц тутового шелкопряда с помощью OpenCV - PullRequest
1 голос
/ 09 июня 2019

Я пытаюсь написать скрипт на python для подсчета количества яиц тутового шелкопряда. Некоторые изображения действительно крошечные, а некоторые имеют перекрывающиеся эллипсы / круги, что делает его немного сложным. Я пробовал следующие подходы:

im = cv2.imread('eggs1.png')
hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
th, bw = cv2.threshold(hsv[:, :, 2], 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
morph = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel)
dist = cv2.distanceTransform(morph, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
borderSize = 75
distborder = cv2.copyMakeBorder(dist, borderSize, borderSize, borderSize, borderSize, 
                                cv2.BORDER_CONSTANT | cv2.BORDER_ISOLATED, 0)
gap = 10                                
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*(borderSize-gap)+1, 2*(borderSize-gap)+1))
kernel2 = cv2.copyMakeBorder(kernel2, gap, gap, gap, gap, 
                                cv2.BORDER_CONSTANT | cv2.BORDER_ISOLATED, 0)
distTempl = cv2.distanceTransform(kernel2, cv2.DIST_L2, cv2.DIST_MASK_PRECISE)
nxcor = cv2.matchTemplate(distborder, distTempl, cv2.TM_CCOEFF_NORMED)
mn, mx, _, _ = cv2.minMaxLoc(nxcor)
th, peaks = cv2.threshold(nxcor, mx*0.5, 255, cv2.THRESH_BINARY)
peaks8u = cv2.convertScaleAbs(peaks)
contours, hierarchy = cv2.findContours(peaks8u, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
peaks8u = cv2.convertScaleAbs(peaks)    # to use as mask
for i in range(len(contours)):
    x, y, w, h = cv2.boundingRect(contours[i])
    _, mx, _, mxloc = cv2.minMaxLoc(dist[y:y+h, x:x+w], peaks8u[y:y+h, x:x+w])
    cv2.circle(im, (int(mxloc[0]+x), int(mxloc[1]+y)), int(mx), (255, 0, 0), 2)
    cv2.rectangle(im, (x, y), (x+w, y+h), (0, 255, 255), 2)
    cv2.drawContours(im, contours, i, (0, 0, 255), 2)

cv2.imshow('circles', im)
cv2.waitKey(0)
cv2.destroyAllWindows()
gray = cv2.imread("eggs2.jpg", 0)

## threshold
th, threshed = cv2.threshold(gray, 100, 255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)

## findcontours
cnts = cv2.findContours(threshed, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]


## filter by area
s1= 3
s2 = 20
xcnts = []
for cnt in cnts:
    if s1<cv2.contourArea(cnt) <s2:
        xcnts.append(cnt)

print("Dots number: {}".format(len(xcnts)))

и

import cv2
import numpy as np

img = cv2.imread('image4.jpg', 0)
seed_pt = (184,252)
fill_color = 50
mask = np.zeros_like(img)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
for th in range(60, 120):
    prev_mask = mask.copy()
    mask = cv2.threshold(img, th, 255, cv2.THRESH_BINARY)[1]
    mask = cv2.floodFill(mask, None, seed_pt, fill_color)[1]
    mask = cv2.bitwise_or(mask, prev_mask)
    mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
cv2.imshow('image',mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

Обнаружение контура было самым близким, но не удалось, когда используются изображения типа this one Вот некоторые из этих изображений: 1, 2

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

1 Ответ

0 голосов
/ 10 июня 2019

Как отмечают люди (Крис Луенго, Мика и Райриенг), первое изображение будет довольно сложным для работы. Тем не менее, я вижу один способ (не уверен, что он будет работать хорошо, но надеюсь, что это так).

Яйца могут быть другого цвета, поэтому использование порога HSV / RGB может не всегда работать или всегда требует настройки. Я бы порекомендовал попробовать поработать с алгоритмами обнаружения ребер. В частности, обратите внимание на методы Лапласа, Канни и Собеля.

Так что в основном эти методы ищут радикальные изменения цвета на изображении. Рассмотрим оператор Собеля, он работает путем свертки соответствующих масок и скользящего окна вдоль изображения. Эта свертка дает числовую дифференциацию региона, поэтому чем больше изменяется цвет, тем больше вывод оператора. Если вы хотите, вы можете пороговое значение, чтобы получить двоичное изображение.

Example of Sobel operator on Lena

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

Этот подход, конечно, сводится к тому же подходу, что и пороговое значение HSV / RGB, но может быть полезен при подсчете наложенных яиц.

Если у вас много (буквально много) времени и данных для работы, вы можете использовать машинное обучение (HOG + SVM, RCNN и т. Д.). Но для этого потребуется много данных и времени.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...