2012-12-01 13 views
10

Sto provando a creare un'applicazione che risolva un enigma (cercando di sviluppare un algoritmo grafico), e non voglio inserire l'input del campione a mano tutto il tempo.Trovare un'immagine all'interno di un'altra immagine

Modifica: Non sto cercando di creare un gioco. Sto cercando di costruire un agente che gioca il gioco "SpellSeeker"

Dire che ho un'immagine (vedi allegato) sullo schermo con i numeri in esso, e conosco le posizioni delle scatole, e ho l'esatto immagini per questi numeri. Quello che voglio fare è semplicemente dire quale immagine (numero) si trova sulla casella corrispondente.

Numbers http://i46.tinypic.com/3089vyt.jpg

quindi credo che ho bisogno di implementare

bool isImageInsideImage(Bitmap numberImage,Bitmap Portion_Of_ScreenCap) o qualcosa di simile.

Quello che ho provato è (utilizzando AForge librerie)

public static bool Contains(this Bitmap template, Bitmap bmp) 
{ 
    const Int32 divisor = 4; 
    const Int32 epsilon = 10; 

    ExhaustiveTemplateMatching etm = new ExhaustiveTemplateMatching(0.9f); 

    TemplateMatch[] tm = etm.ProcessImage(
     new ResizeNearestNeighbor(template.Width/divisor, template.Height/divisor).Apply(template), 
     new ResizeNearestNeighbor(bmp.Width/divisor, bmp.Height/divisor).Apply(bmp) 
     ); 

    if (tm.Length == 1) 
    { 
     Rectangle tempRect = tm[0].Rectangle; 

     if (Math.Abs(bmp.Width/divisor - tempRect.Width) < epsilon 
      && 
      Math.Abs(bmp.Height/divisor - tempRect.Height) < epsilon) 
     { 
      return true; 
     } 
    } 

    return false; 
} 

ma restituisce falso durante la ricerca di un punto nero in questa immagine.

Come posso implementarlo?

+0

Qualche gioco di sudoku o tic tac toe? – bonCodigo

+0

Hai visto altre domande sul [terreno simile] (http://stackoverflow.com/questions/2472467/how-to-find-one-image-inside-of-another)? – bonCodigo

+0

È un gioco chiamato "spellseeker". Ma non è importante, voglio solo costruire l'algorihm per risolvere un problema del genere. E sì, in realtà ho trovato questa soluzione in altre domande, ma non mi hanno aiutato. E perdonami per la mia pigrizia, ma penso davvero che ci dovrebbe essere un modo più semplice per questo :) – marvin

risposta

5

sto rispondendo la mia domanda da quando ho trovato la soluzione:

this ha funzionato per me:

System.Drawing.Bitmap sourceImage = (Bitmap)Bitmap.FromFile(@"C:\SavedBMPs\1.jpg"); 
      System.Drawing.Bitmap template = (Bitmap)Bitmap.FromFile(@"C:\SavedBMPs\2.jpg"); 
      // create template matching algorithm's instance 
      // (set similarity threshold to 92.5%) 

      ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f); 
       // find all matchings with specified above similarity 

       TemplateMatch[] matchings = tm.ProcessImage(sourceImage, template); 
       // highlight found matchings 

      BitmapData data = sourceImage.LockBits(
       new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), 
       ImageLockMode.ReadWrite, sourceImage.PixelFormat); 
      foreach (TemplateMatch m in matchings) 
      { 

        Drawing.Rectangle(data, m.Rectangle, Color.White); 

       MessageBox.Show(m.Rectangle.Location.ToString()); 
       // do something else with matching 
      } 
      sourceImage.UnlockBits(data); 

l'unico problema era che Stavo cercando tutte le (58) caselle per detto gioco. Ma cambiare il valore di 0.921f a 0,98 reso perfetto, vale a dire si trova solo l'immagine del numero specificato (modello)

Edit: Mi hanno fatto ad entrare diverse soglie di similarità per le diverse immagini.Ho trovato i valori ottimizzati provando, alla fine ho una funzione come

float getSimilarityThreshold(int number) 
1

Un approccio migliore è quello di creare una classe personalizzata che contiene tutte le informazioni necessarie invece di fare affidamento sull'immagine stessa.

Ad esempio:

public class MyTile 
{ 
    public Bitmap TileBitmap; 
    public Location CurrentPosition; 
    public int Value; 
} 

questo modo è possibile "muoversi" la classe di piastrelle e leggere il valore dal campo Value invece di analizzare l'immagine. Basta disegnare qualunque immagine la classe tenga per la posizione che sta attualmente tenendo.

piastrelle che possono essere tenuti in una matrice simile:

private list<MyTile> MyTiles = new list<MyTile>(); 

Allunga la classe in base alle esigenze (e ricordate di smaltire quelle immagini quando non sono più necessari).

se davvero vuole vedere se c'è un'immagine dentro l'immagine, è possibile controllare questa estensione che ho scritto per un altro post (anche se in codice VB):
Vb.Net Check If Image Existing In Another Image

+0

Grazie per questa risposta. Ho già una lezione simile a questa. Ho una classe Node con valori (nelle caselle di testo) e una classe Tile che ha una matrice Node. Ma il problema di inizializzare tutti i nodi rimane ancora. Posso inserirli in caselle di testo, ma significa comunque che devo inserire ~ 60 numeri a mano, per un tempo di esecuzione di 2 secondi. Quindi sto cercando un modo per inizializzarli usando l'immagine dello schermo di stampa. – marvin