Automatyczne wykrywanie twarzy za pomocą Picasa API do wyodrębniania pojedynczych obrazów

(podobne pytanie zadano superużytkownikowi w celu uzyskania odpowiedzi związanych z aplikacjami. Pytanie jest zamieszczane tutaj, aby zebrać programowalne rozwiązania dla tego samego)

W moim miejscu pracy zdjęcia paszportowe są skanowane razem, a następnie pocięte na pojedyncze zdjęcia i zapisywane z unikalnymi numerami plików. Obecnie używamy Paint.net aby ręcznie wybrać, wyciąć i zapisać zdjęcia.

Przykładowy Zeskanowany Dokument Picasa Zrzut Ekranu: (from: google image search wiele źródeł, fairuse)

zrzut ekranu picasa

Dla np. W Picasa 3.8, po kliknięciu Widok > ludzie, wszystkie twarze są wyświetlane i jestem proszony o ich nazwę, Czy Mogę zapisać te pojedyncze zdjęcia automatycznie z nazwami jako różne zdjęcia?

Aktualizacja

wszystko, co chcę zrobić, to przekonwertować powyższe zdjęcie na poszczególne zdjęcia.

Na powyższym obrazku pokazałem, jak Picasa 3.8 wykrywa obrazy i prosi mnie o ich nazwanie. Nie wiem. potrzebuję rozpoznawania twarzy, po prostu potrzebuję wykrywania twarzy. Picasa wykrywa poszczególne obrazy i pokazuje je na RHS. Te pojedyncze obrazy są tym, czego potrzebuję. Picasa tworzy ... plik ini, który zapisuje wartości szesnastkowe, które zawierają współrzędne poszczególnych twarzy.

te poszczególne twarze są tym, co mnie interesuje, jeśli Mogę mieć współrzędne, mogę przyciąć wymagane obrazy ze zdjęcia.

Próbka.jpg

próbka.. jpg

Ini spis treści

 [SAMPLE.jpg]
faces=rect64(c18f4c8ef407851e),d4ff0a020be5c3c0;rect64(534a06d429ae627),dff6163dfd9d4e41;rect64(b9c100fae46b3046),e1059dcf6672a2b3;rect64(7b5105daac3a3cf4),4fc7332c107ffafc;rect64(42a036a27062a6c),ef86c3326c143248;rect64(31f4efe3bd68fd8),90158b3d3b65dc9b;rect64(327904e0614d390d),43cbda6e92fcb63e;rect64(4215507584ae9b8c),15b6a967e857f334;rect64(895d4efeb8b68425),5c4ff70ac70b27d3
backuphash=3660

* Plik ini wydaje się zapisywać współrzędne znaczników twarzy jako rect64(534a06d429ae627),dff6163dfd9d4e41 dla każdego znacznika. Cytując z Picasa Help Site user Technonath says

@ oedious napisał (a): - to będzie trochę techniczne, więc trzymaj się. * Liczba zamknięta w rect64() jest 64-bitową liczbą szesnastkową. * Podziel to na cztery 16-bitowe liczby. * Podziel każdy przez maksymalnie 16-bitowy numer unsigned (65535) a będziesz miał cztery liczby od 0 do 1. * Cztery pozostałe liczby dają względne współrzędne twarzy prostokąt: (lewy, górny, prawy, dolny). * Jeśli chcesz skończyć z współrzędnych bezwzględnych, wielokrotność lewej i tuż przy szerokości obrazu i u góry i na dole o wysokość obrazu.

Powyższy cytat mówi o liczbie zamkniętej w rekt64 () a co z liczbą poza nawiasami po przecinku?

Zadałem podobne pytanie. Odpowiedzi, które mogą Ci pomóc też. uzyskaj cztery 16-bitowe liczby z 64-bitowej wartości szesnastkowej

Uwaga: szczegóły ini są takie same jak picasa generowane dla danego obrazu.

Plus pytanie było wielokrotnie aktualizowane i może nie być wystarczająco jasne.

Są jakieś odpowiedzi na Picasa Help site , gdzie zadałem to samo pytanie Jedna z odpowiedzi z tego wątku, aby uzyskać współrzędne na podstawie wartości hex z pliku ini. Poniższy kod to w C # z esac ze strony pomocy. Czy Mogę zrobić to samo w PHP?

public static RectangleF GetRectangle(string hashstr)
{
    UInt64 hash = UInt64.Parse(hashstr, System.Globalization.NumberStyles.HexNumber);
    byte[] bytes = BitConverter.GetBytes(hash);

    UInt16 l16 = BitConverter.ToUInt16(bytes, 6);
    UInt16 t16 = BitConverter.ToUInt16(bytes, 4);
    UInt16 r16 = BitConverter.ToUInt16(bytes, 2);
    UInt16 b16 = BitConverter.ToUInt16(bytes, 0);

    float left = l16 / 65535.0F;
    float top = t16 / 65535.0F;
    float right = r16 / 65535.0F;
    float bottom = b16 / 65535.0F;

    return new RectangleF(left, top, right - left, bottom - top);
} 

Kod PHP próbuje przekonwertować 64bit na liczby z zakresu od 1 do 0

<?php
$dim = getimagesize("img.jpg");    
$hex64=array();
$b0="c18f4c8ef407851e";
$hex64[]=substr($b0,0,4);
$hex64[]=substr($b0,4,4);
$hex64[]=substr($b0,8,4);
$hex64[]=substr($b0,12,4);
$width=$dim[0];
$height=$dim[1];
foreach($hex64 as $hex16){
$dec=hexdec($hex16);
$divide=65536;
$mod=$dec%$divide;
$result=$dec/$divide;
$cordinate1=$result*$width;
$cordinate2=$result*$height;
echo "Remainder 1 : ".$mod." ; Result 1 :  ".$result."<br/>CO-ORDINATES : <B>".$cordinate1." ".$cordinate2."</B><br/>";
}
?>

Wyjście

Reszta 1: 49551; Wynik 1 : 0.75608825683594 współrzędne: 371.99542236328 396.946334838871: 19598; wynik 1 : 0.29904174804688 współrzędne: 147.12854003906 156.99691772461 reszta 1 : 62471 ; wynik 1 : 0.95323181152344 : 468.99005126953 500.44670104981 : 34078 ; Wynik 1 : 0.51998901367188 WSPÓŁRZĘDNE: 255.83459472656 272.99423217773

Więc ja też mam współrzędne i @Nirmal pokazał jak je przyciąć . Teraz następnym krokiem będzie analiza picasa.ini dla kodów szesnastkowych i nazw plików oraz zintegrować kod. Picasa obecnie nie dostarcza kodów szesnastkowych przez api (lub prawda?). Gdyby tak było, byłoby lepiej.

Więc jesteśmy zbliża się rozwiązanie. Dziękuję wszystkim, chciałbym przyznać nagrodę każdemu (nie mogę, ale nie bój się i uważaj na skok w reputacji!)

Author: abel, 2010-10-06

7 answers

Aby odpowiedzieć na pytanie picasa, zobacz tę odpowiedź na picasa forums:
http://www.google.com/support/forum/p/Picasa/thread?tid=36ae553a7b49088e&hl=en

@oedious napisał (a): - to będzie trochę techniczne, więc trzymaj się. * Liczba zamknięta w rect64() jest 64-bitową liczbą szesnastkową. * Podziel to na cztery 16-bitowe liczby. * Podziel każdy przez maksymalnie 16-bitowy numer unsigned (65535) a będziesz miał cztery liczby od 0 do 1. * The four pozostałe liczby dają względne współrzędne twarzy prostokąt: (lewy, górny, prawy, dolny). * Jeśli chcesz skończyć z współrzędnych bezwzględnych, wielokrotność lewej i tuż przy szerokości obrazu i u góry i na dole o wysokość obrazu.

 3
Author: Joel Martinez,
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
2010-10-08 15:21:29

Spójrz na OpenCV - jednym z przykładów dostarczanych z dystrybucją jest wykrywanie twarzy.

 5
Author: Paul R,
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
2010-10-06 12:18:43

Twoje rozwiązanie problemu to przesada. Zignoruj twarze. To, co masz, to białe tło i kilka prostokątnych obrazów na nim. Wszystko, co musisz zrobić, to znaleźć prostokąt, który otacza każdy obraz i kadr.

Zacznij od uruchomienia filtra nad oryginalnym obrazem, który zaznacza wszystkie piksele niebędące tłem. Wymaga to trochę strojenia, ponieważ czasami tło będzie miało odrobinę odcienia (brudu) lub zdjęcie będzie miało kilka pikseli, które wyglądają jak tło (naprawdę białe zęby).

Teraz szukasz dużych obszarów bez koloru tła w nich. Przyciąć je w prostokąty.

Skoro to ty robisz skanowanie, dlaczego nie zrobić tła na Zielono? Zielony może być łatwiejszym kolorem do filtrowania, zwłaszcza, że zdjęcia paszportowe są robione na białym tle.

 5
Author: Eyal,
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
2010-10-13 10:25:47

Możesz uprościć problem jeszcze bardziej: -) jeśli zeskanowane obrazy będą zawsze w siatce 5x4 ... następnie możesz łatwo po prostu otworzyć obraz w niemal dowolnym języku programowania, który oferuje manipulację bitmapą, i zapisać każdy kwadrat. Oto przykład jak to zrobić z C#:

private Image Crop(Image pics, Rectangle area)
{
   var bitmap = new Bitmap(pics);
   return (Image)bitmap.Clone(area, bitmap.PixelFormat);
}

Wystarczy obliczyć każdy prostokąt, a następnie wywołać tę metodę, która zwraca tylko obszar obrazu zdefiniowany przez prostokąt. Coś w stylu (ewentualnie pseudo kod, nie skompilowałem poniższego kodu):

// assuming that each sub image in the larger is 45x65
int cellwidth=45, cellheight=65;

for(int row=0;row<5;row++)
{
  for(int col=0;col<4;col++)
  {
    var rect = new Rectangle(
      row * cellwidth,
      col * cellheight,
      cellwidth,
      cellheight);
    var picture = Crop(bigPicture, rect);
    // then save the sub image with whatever naming convention you need
  }
}
 2
Author: Joel Martinez,
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
2010-10-06 12:04:16

Dla części kadrującej wpisuję kod bez testowania, ale to powinno zadziałać:

<?php
//source image
$srcImg = "full/path/of/source/image.jpg";
//output image
$outImg = "full/path/to/result/image.jpg";

//coordinates obtained from your calculation
$p1 = array('X'=>371, 'Y'=>156);
$p2 = array('X'=>468, 'Y'=>156);
$p3 = array('X'=>468, 'Y'=>272);
$p4 = array('X'=>371, 'Y'=>272);

//let's calculate the parametres
$srcX = $p1['X'];
$srcY = $p1['Y'];
$width = $p2['X'] - $p1['X'];
$height = $p4['Y'] - $p1['Y'];

//image processing
$srcImg = imagecreatefromjpeg($srcImg);
$dstImg = imagecreatetruecolor($width, $height);
imagecopy($dstImg, $srcImg, 0, 0, $srcX, $srcY, $width, $height);
imagejpeg($dstImg, $outImg, 100); // 100 for highest quality, 0 for lowest quality
imagedestroy($dstImg);
?>

Powyższy kod zakłada, że obraz źródłowy jest w FORMACIE JPEG, a współrzędne tworzą idealny prostokąt lub kwadrat.

Mam nadzieję, że to pomoże.
 1
Author: Nirmal,
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
2010-10-14 10:33:20

To powinno doprowadzić cię do mety. Oto kod do analizy INI.

<?php
$vals = parseIni('picasa.ini');
foreach($vals as $filename => $values) {
    $rects = getRects($values['faces']);
    foreach($rects as $rect) {
        printImageInfo($filename, $rect);
    }
}

/**
 * PHP's own parse_ini_file doesn't like the Picasa format.
 */
function parseIni($file)
{
    $index = 0;
    $vals = array();
    $f = fopen($file, 'r');
    while(!feof($f)) {
        $line = trim(fgets($f));
        if (preg_match('/^\[(.*?)\]$/', $line, $matches)) {
            $index = $matches[1];
            continue;
        }

        $parts = explode('=', $line, 2);
        if (count($parts) < 2) continue;
        $vals[$index][$parts[0]] = $parts[1];
    }

    fclose($f);
    return $vals;
}

function getRects($values)
{
    $values = explode(';', $values);
    $rects = array();
    foreach($values as $rect) {
        if (preg_match('/^rect64\(([^)]+)\)/', $rect, $matches)) {
            $rects[] = $matches[1];
        }
    }

    return $rects;
}

function printImageInfo($filename, $rect)
{
    $dim = getimagesize($filename);    
    $hex64=array();
    $hex64[]=substr($rect,0,4);
    $hex64[]=substr($rect,4,4);
    $hex64[]=substr($rect,8,4);
    $hex64[]=substr($rect,12,4);
    $width=$dim[0];
    $height=$dim[1];
    foreach($hex64 as $hex16){
        $dec=hexdec($hex16);
        $divide=65536;
        $mod=$dec%$divide;
        $result=$dec/$divide;
        $cordinate1=$result*$width;
        $cordinate2=$result*$height;
        echo "Remainder 1 : ".$mod." ; Result 1 :  ".$result."<br/>CO-ORDINATES : <B>".$cordinate1." ".$cordinate2."</B><br/>";
    }
}
 1
Author: mellowsoon,
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
2010-10-18 09:49:53

Opracowałem małą aplikację w. NET, która robi dokładnie to, co powiedziałeś, produkuje pliki dla twarzy. Sprawdź to tutaj: http://ceottaki.com/devprojects/getpicasafaces

Dostępny jest również kod źródłowy.

Chociaż nie zaimplementowałem pobierania nazwy kontaktów z ich kodu szesnastkowego, możliwe jest użycie interfejsu Google Contacts API: http://code.google.com/apis/contacts/

Za pomocą tego API można uzyskać kontakty według ID, a jeśli Twoje kontakty są synchronizowane między kontaktami Picasa i Google, identyfikator szesnastkowy jest taki sam.

Ostatnia część pełnego linku kontaktowego jest szesnastkowa używana przez Picasa.

Mam nadzieję, że to pomoże.

Cheers, Felipe.

 1
Author: Felipe,
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
2011-03-08 16:42:06