Jak wykryć obiekt na obrazach?
Potrzebuję rozwiązania Pythona.
Mam 40-60 zdjęć(zestaw Happy Holiday). Muszę wykryć obiekt na tych wszystkich obrazach.
Nie znam rozmiaru obiektu, formy, lokalizacji na obrazku, nie mam żadnego szablonu obiektu. Wiem tylko jedno: ten obiekt jest obecny na prawie wszystkich obrazach. Nazwałem go UFO.
Przykład:
Jak widać na przykładzie, od obrazu do obrazu wszystko się zmienia z wyjątkiem UFO. Po wykryciu muszę dostać:
Współrzędna X lewy górny róg
Współrzędna Y lewego górnego rogu
Szerokość niebieskiego obszaru obiektu (zaznaczam region na przykładzie jako czerwony prostokąt)
Wysokość obszaru obiektu niebieskiego
2 answers
Gdy masz dane obrazu jako tablicę, możesz użyć wbudowanej funkcji numpy, aby to zrobić łatwo i szybko:
import numpy as np
import PIL
image = PIL.Image.open("14767594_in.png")
image_data = np.asarray(image)
image_data_blue = image_data[:,:,2]
median_blue = np.median(image_data_blue)
non_empty_columns = np.where(image_data_blue.max(axis=0)>median_blue)[0]
non_empty_rows = np.where(image_data_blue.max(axis=1)>median_blue)[0]
boundingBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
print boundingBox
Dam ci, za pierwsze zdjęcie:
(78, 156, 27, 166)
Więc twoje pożądane dane to:
- lewy górny róg to (x, y):
(27, 78)
- width:
166 - 27 = 139
- wysokość:
156 - 78 = 78
Wybrałem, że "każdy piksel o wartości niebieskiej większej niż mediana wszystkich wartości niebieskich" należy do Twojego obiektu. Oczekuję, że to zadziała dla Ciebie; jeśli nie, spróbuj coś innego lub podać kilka przykładów, gdzie to nie działa.
Edycja Przerobiłem mój kod na bardziej ogólny. Ponieważ dwa zdjęcia, o tym samym kształcie-kolorze, nie są wystarczająco ogólne (jak wskazuje Twój komentarz) tworzę więcej próbek syntetycznie.
def create_sample_set(mask, N=36, shape_color=[0,0,1.,1.]):
rv = np.ones((N, mask.shape[0], mask.shape[1], 4),dtype=np.float)
mask = mask.astype(bool)
for i in range(N):
for j in range(3):
current_color_layer = rv[i,:,:,j]
current_color_layer[:,:] *= np.random.random()
current_color_layer[mask] = np.ones((mask.sum())) * shape_color[j]
return rv
Tutaj kolor kształtu jest regulowany. Dla każdego z N = 26 obrazów wybierany jest losowy kolor tła. Możliwe byłoby również umieszczenie szumu w tle, nie zmieniłoby to wynik.
Następnie przeczytałem twój przykładowy obraz, stworzyłem z niego maskę kształtu i użyłem jej do tworzenia przykładowych obrazów. Rysuję je na siatce.
# create set of sample image and plot them
image = PIL.Image.open("14767594_in.png")
image_data = np.asarray(image)
image_data_blue = image_data[:,:,2]
median_blue = np.median(image_data_blue)
sample_images = create_sample_set(image_data_blue>median_blue)
plt.figure(1)
for i in range(36):
plt.subplot(6,6,i+1)
plt.imshow(sample_images[i,...])
plt.axis("off")
plt.subplots_adjust(0,0,1,1,0,0)
Dla innej wartości shape_color
(parametr do create_sample_set(...)
), może to wyglądać następująco:
Następnie ustalę zmienność na piksel, używając odchylenia standardowego. Jak powiedziałeś, obiekt znajduje się na (prawie) wszystkich obrazach w tej samej pozycji. Więc variabiliy w tych obrazach będzie niski, podczas gdy dla inne piksele, będzie znacznie wyższa.
# determine per-pixel variablility, std() over all images
variability = sample_images.std(axis=0).sum(axis=2)
# show image of these variabilities
plt.figure(2)
plt.imshow(variability, cmap=plt.cm.gray, interpolation="nearest", origin="lower")
Wreszcie, jak w moim pierwszym fragmencie kodu, określ obwiednię. Teraz podaję również jego fabułę.
# determine bounding box
mean_variability = variability.mean()
non_empty_columns = np.where(variability.min(axis=0)<mean_variability)[0]
non_empty_rows = np.where(variability.min(axis=1)<mean_variability)[0]
boundingBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
# plot and print boundingBox
bb = boundingBox
plt.plot([bb[2], bb[3], bb[3], bb[2], bb[2]],
[bb[0], bb[0],bb[1], bb[1], bb[0]],
"r-")
plt.xlim(0,variability.shape[1])
plt.ylim(variability.shape[0],0)
print boundingBox
plt.show()
To jest to. Mam nadzieję, że tym razem będzie wystarczająco ogólne.
Kompletny skrypt do kopiowania i wklejania:
import numpy as np
import PIL
import matplotlib.pyplot as plt
def create_sample_set(mask, N=36, shape_color=[0,0,1.,1.]):
rv = np.ones((N, mask.shape[0], mask.shape[1], 4),dtype=np.float)
mask = mask.astype(bool)
for i in range(N):
for j in range(3):
current_color_layer = rv[i,:,:,j]
current_color_layer[:,:] *= np.random.random()
current_color_layer[mask] = np.ones((mask.sum())) * shape_color[j]
return rv
# create set of sample image and plot them
image = PIL.Image.open("14767594_in.png")
image_data = np.asarray(image)
image_data_blue = image_data[:,:,2]
median_blue = np.median(image_data_blue)
sample_images = create_sample_set(image_data_blue>median_blue)
plt.figure(1)
for i in range(36):
plt.subplot(6,6,i+1)
plt.imshow(sample_images[i,...])
plt.axis("off")
plt.subplots_adjust(0,0,1,1,0,0)
# determine per-pixel variablility, std() over all images
variability = sample_images.std(axis=0).sum(axis=2)
# show image of these variabilities
plt.figure(2)
plt.imshow(variability, cmap=plt.cm.gray, interpolation="nearest", origin="lower")
# determine bounding box
mean_variability = variability.mean()
non_empty_columns = np.where(variability.min(axis=0)<mean_variability)[0]
non_empty_rows = np.where(variability.min(axis=1)<mean_variability)[0]
boundingBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
# plot and print boundingBox
bb = boundingBox
plt.plot([bb[2], bb[3], bb[3], bb[2], bb[2]],
[bb[0], bb[0],bb[1], bb[1], bb[0]],
"r-")
plt.xlim(0,variability.shape[1])
plt.ylim(variability.shape[0],0)
print boundingBox
plt.show()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-11 07:54:36
Tworzę drugą odpowiedź zamiast rozszerzać moją pierwszą odpowiedź jeszcze bardziej. Stosuję to samo podejście, ale na nowych przykładach. Jedyną różnicą jest to, że używam zestawu ustalonych progów zamiast wyznaczania go automatycznie. Jeśli możesz się nim bawić, to powinno wystarczyć.
import numpy as np
import PIL
import matplotlib.pyplot as plt
import glob
filenames = glob.glob("14767594/*.jpg")
images = [np.asarray(PIL.Image.open(fn)) for fn in filenames]
sample_images = np.concatenate([image.reshape(1,image.shape[0], image.shape[1],image.shape[2])
for image in images], axis=0)
plt.figure(1)
for i in range(sample_images.shape[0]):
plt.subplot(2,2,i+1)
plt.imshow(sample_images[i,...])
plt.axis("off")
plt.subplots_adjust(0,0,1,1,0,0)
# determine per-pixel variablility, std() over all images
variability = sample_images.std(axis=0).sum(axis=2)
# show image of these variabilities
plt.figure(2)
plt.imshow(variability, cmap=plt.cm.gray, interpolation="nearest", origin="lower")
# determine bounding box
thresholds = [5,10,20]
colors = ["r","b","g"]
for threshold, color in zip(thresholds, colors): #variability.mean()
non_empty_columns = np.where(variability.min(axis=0)<threshold)[0]
non_empty_rows = np.where(variability.min(axis=1)<threshold)[0]
boundingBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
# plot and print boundingBox
bb = boundingBox
plt.plot([bb[2], bb[3], bb[3], bb[2], bb[2]],
[bb[0], bb[0],bb[1], bb[1], bb[0]],
"%s-"%![enter image description here][1]color,
label="threshold %s" % threshold)
print boundingBox
plt.xlim(0,variability.shape[1])
plt.ylim(variability.shape[0],0)
plt.legend()
plt.show()
Produkowane działki:
Twoje wymagania są ściśle związane z ERP w neurologii poznawczej. Im więcej obrazów wejściowych masz, tym lepsze będzie to podejście wraz ze wzrostem stosunku sygnału do szumu.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 14:48:40