使用Picasa API自动进行面部检测以提取单个图像

时间:2010-10-06 11:52:21

标签: php api picasa face-recognition

(超级用户已经向类似的问题询问了与应用程序相关的答案。此问题已发布在此处以收集相同的可编程解决方案)

在我的工作场所,护照大小的照片会一起扫描,然后剪切成单独的照片并以唯一的文件编号保存。目前我们使用Paint.net手动选择,剪切和保存图片。

示例扫描文档Picasa屏幕截图 (来自:谷歌图片搜索多个来源,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 Help Site用户Technonath

   @oedious写道: - 这将是   有点技术,所以坚持下去。   * rect64()中包含的数字是64位十六进制数。   *将其分成四个16位数字。   *将每个除以最大无符号16位数(65535)并且你将得到   0到1之间的四个数字。   *剩下的四个数字为您提供面部的相对坐标   矩形:(左,上,右,下)。   *如果你想以绝对坐标结束,那么左边和后面有多个   右边是图像宽度和顶部   和图像高度的底部。

上面的引言谈到了在rect64()中包含的数字,逗号后括号外的数字怎么样?

我问了一个相关的问题。答案也可能对你有所帮助。 Get four 16bit numbers from a 64bit hex value

  

注意:   ini细节与picasa相同   为特定图像生成。

     

此外,问题已多次更新,可能不够清晰。

Picasa Help site有一些回复,我在那里问了同样的问题 该线程的答案之一是根据ini文件中的十六进制值得到坐标。以下代码位于帮助网站的esac的C#中。我可以用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 CO-ORDINATES:147.12854003906 156.99691772461剩余1:62471;结果1:   0.95323181152344 CO-ORDINATES:468.99005126953 500.4467010498剩余1:34078;结果1:   0.51998901367188协议:255.83459472656 272.99423217773

所以我也有坐标,@ Nirmal有shown how to crop them。现在接下来的步骤是解析picasa.ini以获取十六进制代码和文件名并集成代码。 Picasa目前不通过api(或Do they?)提供十六进制代码。如果是这样的话,事情本来会更好。

所以我们即将解决问题。谢谢大家,我希望我可以奖励每个人(我不能,但不要害怕,并留意你的代表中的尖峰!)

7 个答案:

答案 0 :(得分:5)

查看OpenCV - 分发附带的一个示例是面部检测。

答案 1 :(得分:5)

您解决问题的方法有点过头了。忽略面孔。你拥有的是纯白色背景和一堆矩形图像。您需要做的就是找到包围每个图像和裁剪的矩形。

首先在标记所有非背景像素的原始图像上运行滤镜。这将需要一些调整,因为有时背景会有一点色调(污垢)或照片会有一些看起来像背景的像素(真的是白牙)。

现在您要查找没有背景颜色的大区域。将它们裁剪成矩形。

由于您是进行扫描的人,为什么不将背景设为绿色?绿色可能是一种更容易过滤的颜色,特别是因为护照照片是在白色背景上拍摄的。

答案 2 :(得分:3)

要回答picasa问题,请在picasa论坛上查看此回复:
http://www.google.com/support/forum/p/Picasa/thread?tid=36ae553a7b49088e&hl=en

   @oedious写道: - 这将是   有点技术,所以坚持下去。   * rect64()中包含的数字是64位十六进制数。   *将其分成四个16位数字。   *将每个除以最大无符号16位数(65535)并且你将得到   0到1之间的四个数字。   *剩下的四个数字为您提供面部的相对坐标   矩形:(左,上,右,下)。   *如果你想以绝对坐标结束,那么左边和后面有多个   右边是图像宽度和顶部   和图像高度的底部。

答案 3 :(得分:2)

你可以进一步简化问题:-)如果扫描的图像总是在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
  }
}

答案 4 :(得分:1)

对于裁剪部分,我正在键入代码而不进行测试,但这应该有效:

<?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格式,坐标是一个完美的矩形或正方形。

希望有所帮助。

答案 5 :(得分:1)

这会让你越过终点线。这是解析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/>";
    }
}

答案 6 :(得分:1)

我在.NET中开发了一个小应用程序,它完全按照你所说,它生成面部文件。请在此处查看:http://ceottaki.com/devprojects/getpicasafaces

源代码也可用。

虽然我没有实现从十六进制代码中获取联系人的姓名,但可以使用Google通讯录API:http://code.google.com/apis/contacts/

使用该API可以按ID获取联系人,如果您的联系人在Picasa和Google通讯录之间同步,则十六进制ID也相同。

完整联系人链接的最后一部分是Picasa使用的十六进制。

我希望这会有所帮助。

干杯, 菲利普。