【问题标题】:Automatic face detection using Picasa API to extract individual images使用 Picasa API 自动进行人脸检测以提取单个图像
【发布时间】:2011-04-21 18:56:19
【问题描述】:

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

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

扫描文档 Picasa 屏幕截图示例: (来自:google image search multiple sources, fairuse)

例如。在 Picasa 3.8 中,单击“视图”>“人物”时,会显示所有面孔并要求我为它们命名,我可以将这些单独的图片自动保存为不同的图片名称吗?

更新

我要做的就是将上面的图片转换为单独的图片。

在上图中,我展示了 Picasa 3.8 如何检测图像并提示我命名它们。我不需要人脸识别,我只需要人脸检测。 Picasa 会检测单个图像并将其显示在 RHS 上。这些单独的图像是我需要的。 Picasa 会创建一个 .ini 文件,该文件保存包含各个面的坐标的十六进制值。

这些个人脸是我感兴趣的,如果我能得到坐标,我就可以从图片中裁剪出所需的图像。

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 坐标:147.12854003906 156.99691772461 余数 1:62471;结果 1: 0.95323181152344 坐标: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?)提供十六进制代码。如果是这样的话,情况会更好。

所以我们正在接近解决方案。谢谢大家,我希望我能将赏金奖励给每个人(我不能,但不要害怕,并注意你们的代表人数激增!)

【问题讨论】:

  • 你能给出所有四个角的(x,y)格式的最终​​坐标吗?
  • @Nirmal (371,156),(468,156),(468,272),(371,272)

标签: php api picasa face-recognition


【解决方案1】:

我在 .NET 中开发了一个小应用程序,它完全按照您所说的进行,它为面部生成文件。在这里查看:http://ceottaki.com/devprojects/getpicasafaces

源代码也可用。

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

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

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

我希望这会有所帮助。

干杯, 费利佩。

【讨论】:

  • 干得好!没有考虑联系人集成;这是一个额外的好处。不过,依靠 Picasa 来获得 rect hexes 是很痛苦的。希望有一个api!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    对于裁剪部分,我在没有测试的情况下输入代码,但这应该可以:

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

    希望对您有所帮助。

    【讨论】:

    • 谢谢你。我正在探索 php 的图像处理库。竖起大拇指!
    【解决方案4】:

    您对问题的解决方案是矫枉过正。忽略面孔。您所拥有的是纯白色背景和一堆矩形图像。您需要做的就是找到包围每个图像的矩形并裁剪。

    首先对标记所有非背景像素的原始图像运行过滤器。这需要进行一些调整,因为有时背景中会有淡淡的色调(污垢),或者照片会有一些看起来像背景的像素(真正的白牙)。

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

    既然是你做扫描,为什么不把背景设为绿色呢?绿色可能是一种更容易过滤的颜色,尤其是因为护照照片是在白色背景上拍摄的。

    【讨论】:

    • +1 让我从不同的角度看待问题。制作绿色背景将非常简单,我正在开发一个 php webapp,它将在本地服务器上运行,它将扫描的 img 作为上传,然后将单个图片保存在服务器上并使其可用一个 zip 下载。是否有 php 库(gd?)可以让我检测颜色并选择矩形?
    • 不知道有没有库。但是,必须有库来加载图像并处理其中的颜色。从背景过滤器开始,如绿色 > 90%、红色和蓝色 en.wikipedia.org/wiki/Hough_transform。如果您知道矩形与页面的边成直角,那会很有帮助。
    • 我已经更新了这个问题。使用获取(?)图像坐标的 php 脚本。我可以使用它们从图像中裁剪单个图像吗?
    【解决方案5】:

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

    @oedious 写道:- 这将是 有点技术性,所以请稍等。 * rect64() 中包含的数字是 64 位十六进制数。 * 将其分解为四个 16 位数字。 * 将每个除以最大无符号 16 位数 (65535),您将拥有 0 到 1 之间的四个数字。 * 剩下的四个数字为您提供面部的相对坐标 矩形:(左,上,右,下)。 * 如果你想以绝对坐标结束,将左侧和 就在图像宽度和顶部 和底部的图像高度。

    【讨论】:

    • 这是一个宝贵的链接。谢谢你。如果您理解我的问题,我正在尝试将扫描的 img 分解为单独的 img。如果我有坐标,我可以为 Paint.net 编写一个插件来执行此操作(我没有任何桌面编程经验,所以这可能需要我几个月的时间,完成后会发布一个链接:)。)
    • 如何从 64 位的数字中得到 16 位的数字?
    【解决方案6】:

    查看OpenCV - 分发附带的示例之一是用于人脸检测。

    【讨论】:

    • 我一直在寻找这样的库,看起来这会有所帮助。感谢分享。
    【解决方案7】:

    您可以进一步简化问题 :-) 如果扫描的图像始终处于 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
      }
    }
    

    【讨论】:

    • 但是护照照片尺寸变化很大。有些是 5 厘米 × 4 厘米,有些是 4 × 3 厘米,4x4 等,再加上将它们放在扫描仪中通常会产生随意的排列。如果我能检测到图像的标记部分,然后将它们裁剪出来......我可以做一些 php。
    • 我已经更新了原始问题,如果我能得到坐标,你的解决方案似乎是合理的。但是坐标是十六进制的,我对十六进制一无所知,
    猜你喜欢
    • 2019-03-28
    • 2013-11-24
    • 2020-08-27
    • 2012-06-25
    • 1970-01-01
    • 2015-02-07
    • 2013-09-02
    • 2012-02-17
    • 2012-02-06
    相关资源
    最近更新 更多