Automatic face detection using Picasa API to extract individual images

你离开我真会死。 提交于 2019-11-28 16:55:16

To answer the picasa question, see this response on the picasa forums:
http://www.google.com/support/forum/p/Picasa/thread?tid=36ae553a7b49088e&hl=en

@oedious wrote:- This is going to be somewhat technical, so hang on. * The number encased in rect64() is a 64-bit hexadecimal number. * Break that up into four 16-bit numbers. * Divide each by the maximum unsigned 16-bit number (65535) and you'll have four numbers between 0 and 1. * The four numbers remaining give you relative coordinates for the face rectangle: (left, top, right, bottom). * If you want to end up with absolute coordinates, multiple the left and right by the image width and the top and bottom by the image height.

Look at OpenCV - one of the examples that comes with the distribution is for face detection.

Your solution to the problem is overkill. Ignore the faces. What you have is a solid white background and a bunch of rectangular images on it. All you need to do is find the rectangle that encloses each image and crop.

Start by running a filter over the original image that marks all non-background pixels. This will take some tuning because sometimes the background will have a touch of tint in it (dirt) or the photo will have some pixels that look like the background (really white teeth).

Now you look for large areas with no background color in them. Crop those into rectangles.

Since you are the one doing the scanning, why not make the background green? Green might be an easier color to filter, especially since the passport photos are taken on a white background.

You can simplify the problem even further :-) if the scanned images will always be in a 5x4 grid ... then you can easily just open the image in just about any programming language that offers bitmap manipulation, and save each square. Here's an example of how to do this with C#:

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

All you'd need to do is calculate each rectangle, and then call this method which returns just the area of the image defined by the rectangle. Something like (possibly pseudo code, haven't compiled the code below):

// 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
  }
}
Nirmal

For the cropping part, I am typing the code without testing, but this should work:

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

The above code assumes that your source image is in JPEG format and the coordinates make a perfect rectangle or square.

Hope that helps.

This should get you across the finish line. Here's some code to parse the 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/>";
    }
}

I've developed a little app in .NET that does exactly what you said, it produces the files for the faces. Check it out here: http://ceottaki.com/devprojects/getpicasafaces

The source code is available as well.

While I haven't implemented getting the name of the contacts from their hexadecimal code, it is possible using the Google Contacts API: http://code.google.com/apis/contacts/

With that API it is possible to get contacts by ID, and if your contacts are synced between Picasa and Google Contacts, the hexadecimal ID is the same.

The last part of a full contact link is the hexadecimal used by Picasa.

I hope this helps.

Cheers, Felipe.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!