web-dev-qa-db-fra.com

Comment détecter un objet sur des images?

J'ai besoin d'une solution python.

J'ai 40-60 images (ensemble Happy Holiday). J'ai besoin de détecter un objet sur toutes ces images.

Je ne connais pas la taille de l'objet, le formulaire, l'emplacement sur l'image, je n'ai pas de modèle d'objet. Je ne connais qu'une chose: cet objet est présent dans presque toutes les images. Je l'ai appelé OVNI.

Exemple: enter image description hereenter image description hereenter image description hereenter image description here

Comme on le voit dans l'exemple, d'une image à l'autre, tout change sauf l'OVNI. Après la détection, je dois obtenir:

Coordonnée X du coin supérieur gauche

Coordonnée Y du coin supérieur gauche

largeur de la zone d'objet bleu (j'ai marqué la région sur l'exemple comme rectangle rouge)

hauteur de la zone d'objet bleu

21
Alex

Lorsque vous avez les données d'image sous forme de tableau, vous pouvez utiliser la fonction numpy intégrée pour le faire facilement et rapidement:

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

vous donnera, pour la première image:

(78, 156, 27, 166)

Vos données souhaitées sont donc:

  • le coin supérieur gauche est (x, y): (27, 78)
  • largeur: 166 - 27 = 139
  • hauteur: 156 - 78 = 78

J'ai choisi que "chaque pixel avec une valeur bleue supérieure à la médiane de toutes les valeurs bleues" appartient à votre objet. Je m'attends à ce que cela fonctionne pour vous; sinon, essayez autre chose ou donnez des exemples où cela ne fonctionne pas.

EDIT J'ai retravaillé mon code pour être plus général. Comme deux images, avec la même couleur de forme, ne sont pas assez générales (comme votre commentaire l'indique), je crée plus d'échantillons synthétiquement.

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

Ici, la couleur de la forme est réglable. Pour chacune des N = 26 images, une couleur de fond aléatoire est choisie. Il serait également possible de mettre du bruit en arrière-plan, cela ne changerait pas le résultat.

Ensuite, je lis votre exemple d'image, je crée un masque de forme et je l'utilise pour créer des exemples d'images. Je les trace sur une grille.

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

Blue shapes

Pour une autre valeur de shape_color (Paramètre à create_sample_set(...)), cela pourrait ressembler à:

Green shapes

Ensuite, je vais déterminer la variabilité par pixel en fonction de l'écart-type. Comme vous l'avez dit, l'objet est sur (presque) toutes les images à la même position. La variabilité de ces images sera donc faible, tandis que pour les autres pixels, elle sera significativement plus élevée.

# 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")

Enfin, comme dans mon premier extrait de code, déterminez la zone de délimitation. Maintenant, j'en donne également un aperçu.

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

BoundingBox and extracted shape

C'est tout. J'espère que c'est assez général cette fois.

Script complet pour copier-coller:

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()
28
Thorsten Kranz

Je crée une deuxième réponse au lieu d'étendre ma première réponse encore plus. J'utilise la même approche, mais sur vos nouveaux exemples. La seule différence est: j'utilise un ensemble de seuils fixes au lieu de le déterminer automatiquement. Si vous pouvez jouer avec, cela devrait suffire.

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

Parcelles produites:

Input imagesOutputs

Vos besoins sont étroitement liés à ERP en neuroscience cognitive. Plus vous avez d'images en entrée, plus cette approche fonctionnera mieux à mesure que le rapport signal/bruit augmente.

10
Thorsten Kranz