Автоматическое распознавание лица с использованием Picasa API для извлечения отдельных изображений - PullRequest
9 голосов
/ 06 октября 2010

(Аналогичный вопрос был задан на суперпользователя для ответов, связанных с приложениями. Вопрос размещен здесь, чтобы собрать программируемые решения для одного и того же)

На моем рабочем месте, размер паспортафотографии сканируются вместе, затем нарезаются на отдельные фотографии и сохраняются с уникальными номерами файлов.В настоящее время мы используем Paint.net для ручного выбора, вырезания и сохранения изображений.

Образец отсканированного документа Снимок экрана Picasa: (из: поиск изображений в Google, несколько источников, fairuse)

picasa screenshot

Например,В Picasa 3.8 при нажатии «Вид»> «Люди» отображаются все лица, и меня просят назвать их имена. Могу ли я автоматически сохранить эти отдельные изображения с именами в виде разных изображений?

Обновлено

Все, что я хочу сделать, - это преобразовать изображение выше в отдельные изображения.

На изображении выше я показал, как Picasa 3.8 обнаруживаетизображения и побуждает меня назвать их.Мне не нужно распознавание лиц, мне просто нужно распознавание лиц.Picasa обнаруживает отдельные изображения и показывает их в RHS.Эти отдельные изображения - то, что мне нужно.Picasa создает INI-файл, в котором сохраняются шестнадцатеричные значения, содержащие координаты отдельных граней.

Эти отдельные лица - то, что меня интересует. Если у меня есть координаты, яможно обрезать необходимые изображения с картинки.

SAMPLE.jpg

sample.jpg

ini содержание

 [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

* Похоже, что в файле ini координаты тегов лица сохраняются как rect64(534a06d429ae627),dff6163dfd9d4e41 для каждого тега.Цитата Справочный сайт Picasa пользователь Technonath говорит

@ oedious пишет: - Это будет несколько техническим, так что подождите.* Число, заключенное в rect64 (), представляет собой шестнадцатеричное 64-разрядное число.* Разбейте это на четыре 16-битных числа.* Разделите каждое на максимальное число без знака 16-разрядное (65535), и у вас будет четыре числа от 0 до 1. * Оставшиеся четыре числа дают вам относительные координаты для прямоугольника лица: (слева, сверху, справа, снизу).* Если вы хотите получить абсолютные координаты, умножьте левую и правую на ширину изображения, а верхнюю и нижнюю на высоту изображения.

Приведенная выше цитата говорит о числе, заключенном в rect64 () как насчет числа вне скобок после запятой?

Я задал связанный вопрос.Ответы на которые могут помочь вам тоже. Получите четыре 16-битных числа из 64-битного шестнадцатеричного значения

Примечание. Сведения ini такие же, как у Picasa для определенного изображения.

Кроме того, вопрос имеетобновлялся несколько раз и может быть недостаточно четким.

На сайте справки Picasa есть несколько ответов, где я задавал один и тот же вопрос Один из ответов в этой теме:получить координаты на основе шестнадцатеричных значений из INI-файла.Следующий код находится на C # из esac с сайта справки.Могу ли я сделать то же самое в 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);
} 

PHP-код , пытаясь преобразовать 64-разрядные числа в числа от 1 до 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/>";
}
?>

Выход

Остаток 1: 49551;Результат 1: 0,75608825683594 КООРДИНАТЫ: 371,99542236328 396,94633483887 Остаток 1: 19598;Результат 1: 0.29904174804688 КООРДИНАТЫ: 147.12854003906 156.99691772461 Остаток 1: 62471;Результат 1: 0,95323181152344 КООРДИНАТЫ: 468,99005126953 500,4467010498 Остаток 1: 34078;Результат 1: 0,51998901367188 КООРДИНАТЫ: 255,83459472656 272,99423217773

Так что у меня тоже есть координаты, и @Nirmal показал , как их обрезать .Теперь следующие шаги будут состоять в том, чтобы проанализировать picasa.ini для шестнадцатеричных кодов и имен файлов и интегрировать код.В настоящее время Picasa не предоставляет шестнадцатеричные коды через API (или Они? ).Если бы это было так, все было бы лучше.

Итак, мы приближаемся к решению.Спасибо всем, я хотел бы вручить награду всем (я не могу, но не бойся и высматривайте всплеск в вашем представительстве!)

Ответы [ 7 ]

5 голосов
/ 13 октября 2010

Ваше решение проблемы - это перебор.Игнорировать лица.У вас есть сплошной белый фон и куча прямоугольных изображений на нем.Все, что вам нужно сделать, это найти прямоугольник, который охватывает каждое изображение и обрезать.

Начните с запуска фильтра поверх исходного изображения, который помечает все пиксели, не являющиеся фоновыми.Это потребует некоторой настройки, потому что иногда фон будет слегка окрашен (грязь), или на фотографии будут пиксели, похожие на фон (действительно белые зубы).

Теперь вы ищите большие областибез цвета фона в них.Обрежьте их в прямоугольники.

Поскольку сканирование выполняется именно вами, почему бы не сделать фон зеленым?Зеленый может быть легче фильтровать, особенно если фотографии для паспорта сделаны на белом фоне.

5 голосов
/ 06 октября 2010

Посмотрите на OpenCV - один из примеров, поставляемых с дистрибутивом, относится к обнаружению лиц.

3 голосов
/ 08 октября 2010

Чтобы ответить на вопрос о Picasa, просмотрите этот ответ на форумах Picasa:
http://www.google.com/support/forum/p/Picasa/thread?tid=36ae553a7b49088e&hl=en

@ oedious писал: - Это будет несколько технический, так что держись. * Число, заключенное в rect64 (), представляет собой шестнадцатеричное 64-разрядное число. * Разбейте это на четыре 16-битных числа. * Разделите каждое на максимальное число без знака 16-разрядное (65535), и вы получите четыре числа от 0 до 1. * Четыре оставшихся числа дают вам относительные координаты лица прямоугольник: (слева, сверху, справа, снизу). * Если вы хотите получить абсолютные координаты, умножьте левую и прямо по ширине изображения и сверху и снизу по высоте изображения.

2 голосов
/ 06 октября 2010

Вы можете еще больше упростить задачу :-), если отсканированные изображения всегда будут в сетке 5x4 ... тогда вы можете легко просто открыть изображение практически на любом языке программирования, который предлагает растровое изображениеманипулирование и сохранение каждого квадрата.Вот пример того, как сделать это с помощью C #:

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

Все, что вам нужно сделать, это вычислить каждый прямоугольник, а затем вызвать этот метод, который возвращает только область изображения, определенную прямоугольником.Что-то вроде (возможно, псевдокод, не скомпилированный код ниже):

// 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
  }
}
1 голос
/ 08 марта 2011

Я разработал небольшое приложение в .NET, которое делает именно то, что вы сказали, оно производит файлы для лиц.Проверьте это здесь: http://ceottaki.com/devprojects/getpicasafaces

Исходный код также доступен.

Хотя я не реализовал получение имени контактов из их шестнадцатеричного кода, это возможно с помощьюAPI контактов Google: http://code.google.com/apis/contacts/

С помощью этого API можно получать контакты по идентификатору, а если ваши контакты синхронизируются между Picasa и контактами Google, шестнадцатеричный идентификатор такой же.

Последняя часть полной контактной ссылки - это шестнадцатеричное число, используемое Picasa.

Надеюсь, это поможет.

Приветствия, Фелипе.

1 голос
/ 18 октября 2010

Это должно пройти через финишную черту. Вот некоторый код для разбора 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 голос
/ 14 октября 2010

Для обрезки я набираю код без тестирования, но это должно работать:

<?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);
?>

Приведенный выше код предполагает, что исходное изображение имеет формат JPEG, а координаты образуют идеальный прямоугольникквадрат.

Надеюсь, что поможет.

...