Próbuję wykryć liczbę rur na tym obrazie. Do tego używam OpenCV i detekcji opartej na Pythonie. Na podstawie istniejących odpowiedzi na podobne pytania udało mi się wymyślić następujące kroki
- Otwórz obraz
- Filtruj to
- Zastosuj wykrywanie krawędzi
- Użyj konturów
- Sprawdź liczbę
Całkowita liczba rur wynosi ~ 909, gdy liczymy to ręcznie dajemy lub bierzemy 4.
Po zastosowaniu filtra
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('images/input-rectpipe-1.jpg')
blur_hor = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((11,1,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
blur_vert = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((1,11,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
mask = ((img[:,:,0]>blur_hor*1.2) | (img[:,:,0]>blur_vert*1.2)).astype(np.uint8)*255
Dostaję ten zamaskowany obraz
Wygląda to dość dokładnie pod względem liczby widocznych prostokątów, które pokazuje. Jednak gdy próbuję policzyć i narysować obwiednię na górze obrazu, wykrywa on również wiele niechcianych regionów. W przypadku okręgów HoughCircles umożliwia zdefiniowanie maksymalnego i minimalnego promienia. Czy jest coś podobnego dla prostokątów, co może poprawić dokładność. Ponadto jestem otwarty na sugestie dotyczące alternatywnych podejść do tego problemu.
ret,thresh = cv2.threshold(mask,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
count = 0
for i in range(len(contours)):
count = count+1
x,y,w,h = cv2.boundingRect(contours[i])
rect = cv2.minAreaRect(contours[i])
area = cv2.contourArea(contours[i])
box = cv2.boxPoints(rect)
ratio = w/h
M = cv2.moments(contours[i])
if M["m00"] == 0.0:
cX = int(M["m10"] / 1 )
cY = int(M["m01"] / 1 )
if M["m00"] != 0.0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
if (area > 50 and area < 220 and hierarchy[0][i][2] < 0 and (ratio > .5 and ratio < 2)):
#cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
cv2.circle(img, (cX, cY), 1, (255, 255, 255), -1)
count = count + 1
print(count)
cv2.imshow("m",mask)
cv2.imshow("f",img)
cv2.waitKey(0)
AKTUALIZACJA Na podstawie drugiej odpowiedzi przekonwertowałem kod c ++ na kod python i uzyskałem bliższe wyniki, ale wciąż brakuje kilku oczywistych prostokątów.
Odpowiedzi:
Oczywiście możesz je filtrować według ich obszaru. Wziąłem twój obraz binarny i kontynuowałem pracę jak poniżej:
1- Wykonaj pętlę na wszystkich konturach znalezionych w findContours
2- W pętli sprawdź, czy każdy kontur jest konturem wewnętrznym, czy nie
3- Z tych, które są konturami wewnętrznymi, sprawdź ich obszar, a jeśli obszar jest w dopuszczalnym zakresie, sprawdź stosunek szerokości do wysokości każdego konturu, a na koniec, jeśli jest również dobry, policz ten kontur jako rurę.
Zrobiłem powyższą metodę na twoim obrazie binarnym i znalazłem 794 rury :
(Niektóre pola zostały jednak utracone, należy zmienić parametry detektora krawędzi, aby uzyskać więcej oddzielnych pól na obrazie).
a oto kod (Jest to C ++, ale łatwo przekonwertowany na Python):
źródło
Istnieje wiele metod rozwiązania tego problemu, ale wątpię, czy będzie jedna metoda bez jakiegoś rodzaju działań reklamowych. Oto kolejna próba tego problemu.
Zamiast korzystać z informacji o krawędzi, sugeruję filtr podobny do LBP (lokalnego wzorca binarnego), który porównuje otaczający piksel z wartością środkową. Jeśli określony procent otaczającego piksela jest większy niż środkowy piksel, środkowy piksel zostanie oznaczony jako 255. jeśli warunek nie zostanie spełniony, piksel środkowy będzie oznaczony jako 0.
Ta metoda oparta na intensywności opiera się na założeniu, że środek rury jest zawsze ciemniejszy niż krawędzie rury. Ponieważ porównuje intensywność, powinien działać dobrze, dopóki pozostanie pewien kontrast.
Dzięki temu procesowi uzyskasz obraz z binarnymi blokami BLOB dla każdej rury i niektórych dźwięków. Będziesz musiał je usunąć z pewnymi znanymi warunkami, takimi jak rozmiar, kształt, wypełnienie, kolor itp. Warunek można znaleźć w danym kodzie.
Wynik przetwarzania podobnego do LBP
Po oczyszczeniu w procesie morfologicznym
Ostateczny wynik z czerwonymi ramkami pokazującymi wszystkich kandydujących obiektów blob i żółtymi segmentami pokazującymi obiekty blob spełniające wszystkie ustawione przez nas warunki. Poniżej i na górze wiązki rur znajdują się fałszywe alarmy, ale można je pominąć w niektórych warunkach brzegowych.
Znaleziono ogółem rurę: 943
źródło