2010-10-10 8 views
7

Come posso rilevare la differenza tra 2 immagini, creando una maschera dell'area diversa per elaborare l'area che è comune ad entrambe le immagini (sfocatura gaussiana per esempio)?Creare una maschera dalla differenza tra due immagini (iPhone)

sketch

EDIT: Attualmente sto usando questo codice per ottenere il valore RGBA di pixel:

+ (NSArray*)getRGBAsFromImage:(UIImage*)image atX:(int)xx andY:(int)yy count:(int)count 
{ 
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:count]; 

    // First get the image into your data buffer 
    CGImageRef imageRef = [image CGImage]; 
    NSUInteger width = CGImageGetWidth(imageRef); 
    NSUInteger height = CGImageGetHeight(imageRef); 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    unsigned char *rawData = malloc(height * width * 4); 
    NSUInteger bytesPerPixel = 4; 
    NSUInteger bytesPerRow = bytesPerPixel * width; 
    NSUInteger bitsPerComponent = 8; 
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, 
        bitsPerComponent, bytesPerRow, colorSpace, 
        kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
    CGColorSpaceRelease(colorSpace); 

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 
    CGContextRelease(context); 

    // Now your rawData contains the image data in the RGBA8888 pixel format. 
    int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel; 
    for (int ii = 0 ; ii < count ; ++ii) 
    { 
     CGFloat red = (rawData[byteIndex]  * 1.0)/255.0; 
     CGFloat green = (rawData[byteIndex + 1] * 1.0)/255.0; 
     CGFloat blue = (rawData[byteIndex + 2] * 1.0)/255.0; 
     CGFloat alpha = (rawData[byteIndex + 3] * 1.0)/255.0; 
     byteIndex += 4; 

     UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; 
     [result addObject:acolor]; 
    } 

    free(rawData); 

    return result; 
} 

Il problema è che le immagini vengono catturate dalla fotocamera di iPhone in modo da non sono esattamente nella stessa posizione. Devo creare aree di un paio di pixel ed estrarre il colore generale dell'area (magari sommando i valori RGBA e dividendo per il numero di pixel?). Come potrei farlo e poi tradurlo in un CGMask?

So che questa è una domanda complessa, quindi qualsiasi aiuto è apprezzato.

Grazie.

risposta

6

Penso che il modo più semplice per farlo sarebbe utilizzare una modalità di fusione delle differenze. Il seguente codice è basato sul codice che uso in CKImageAdditions.

+ (UIImage *) differenceOfImage:(UIImage *)top withImage:(UIImage *)bottom { 
    CGImageRef topRef = [top CGImage]; 
    CGImageRef bottomRef = [bottom CGImage]; 

    // Dimensions 
    CGRect bottomFrame = CGRectMake(0, 0, CGImageGetWidth(bottomRef), CGImageGetHeight(bottomRef)); 
    CGRect topFrame = CGRectMake(0, 0, CGImageGetWidth(topRef), CGImageGetHeight(topRef)); 
    CGRect renderFrame = CGRectIntegral(CGRectUnion(bottomFrame, topFrame)); 

    // Create context 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if(colorSpace == NULL) { 
     printf("Error allocating color space.\n"); 
     return NULL; 
    } 

    CGContextRef context = CGBitmapContextCreate(NULL, 
               renderFrame.size.width, 
               renderFrame.size.height, 
               8, 
               renderFrame.size.width * 4, 
               colorSpace, 
               kCGImageAlphaPremultipliedLast); 
    CGColorSpaceRelease(colorSpace); 

    if(context == NULL) { 
     printf("Context not created!\n"); 
     return NULL; 
    } 

    // Draw images 
    CGContextSetBlendMode(context, kCGBlendModeNormal); 
    CGContextDrawImage(context, CGRectOffset(bottomFrame, -renderFrame.origin.x, -renderFrame.origin.y), bottomRef); 
    CGContextSetBlendMode(context, kCGBlendModeDifference); 
    CGContextDrawImage(context, CGRectOffset(topFrame, -renderFrame.origin.x, -renderFrame.origin.y), topRef); 

    // Create image from context 
    CGImageRef imageRef = CGBitmapContextCreateImage(context); 
    UIImage * image = [UIImage imageWithCGImage:imageRef]; 
    CGImageRelease(imageRef); 

    CGContextRelease(context); 

    return image; 
} 
+1

Ciao Cory, il codice è molto utile, è riuscito a produrre gli elementi che non sono presenti in nessuna delle due foto. Tuttavia, sembra anche produrre uno sfondo nero, a differenza di uno sfondo trasparente. C'è un modo per rimuovere lo sfondo nero? – wahkiz

0

Non puoi semplicemente sottrarre i valori dei pixel dalle immagini ed elaborare i pixel dove la differenza è 0?

+0

@ Ross, grazie per la risposta. Il mio problema è che non so come creare la maschera dei pixel in cui i valori RGBA sono diversi. –

0

Passare attraverso i pixel, copiare quelli diversi nell'immagine inferiore in uno nuovo (non opaco).

Sfocare completamente la parte superiore, quindi mostrare la nuova sopra.

+0

In che modo esattamente posso copiare i pixel su una nuova immagine? –

0

Ogni pixel che non ha un pixel adeguatamente simile nell'altra immagine entro un certo raggio può essere considerato parte della maschera. È lento, (anche se non c'è molto che sarebbe più veloce) ma funziona abbastanza semplicemente.

2

Ci sono tre ragioni pixel cambierà da un iPhone foto a quella successiva, il soggetto è cambiato, l'iPhone si mosse, e il rumore casuale. Presumo per questa domanda, sei più interessato alle modifiche del soggetto e desideri elaborare gli effetti delle altre due modifiche. Suppongo inoltre che l'app intenda che l'utente mantenga l'iPhone ragionevolmente fermo, quindi i cambiamenti di movimento dell'iPhone sono meno significativi dei cambiamenti di soggetto.

Per ridurre gli effetti del rumore casuale, è sufficiente sfocare leggermente l'immagine. Una semplice sfocatura media, in cui ogni pixel dell'immagine risultante è una media del pixel originale con i suoi vicini più vicini dovrebbe essere sufficiente per appianare qualsiasi rumore in un'immagine di iPhone ragionevolmente ben illuminata.

Per indirizzare il movimento dell'iPhone, è possibile eseguire un algoritmo di rilevamento delle funzioni su ciascuna immagine (per prima cosa cercare il rilevamento delle funzioni su Wikipedia). Quindi calcolare le trasformazioni necessarie per allineare le funzionalità rilevate meno modificate.

Applicare quella trasformazione alle immagini sfocate e trovare la differenza tra le immagini. Qualsiasi pixel con una differenza sufficiente diventerà la tua maschera. È quindi possibile elaborare la maschera per eliminare eventuali isole di pixel modificati. Ad esempio, un soggetto può indossare una maglietta in tinta unita. Il soggetto può spostarsi da un'immagine all'altra, ma l'area della maglietta in tinta unita potrebbe sovrapporsi risultando in una maschera con un foro nel mezzo.

In altre parole, si tratta di un problema di elaborazione dell'immagine significativo e difficile.Non troverai la risposta in un post StackOverflow.com. Troverai la risposta in un manuale di elaborazione delle immagini digitali.

+0

Grazie per la risposta, signor Berna. So che questa è una domanda complessa e apprezzo i tuoi consigli. Farò sicuramente qualche ricerca sull'elaborazione delle immagini per affrontare questo problema. –