从PHP中的照片裁剪暗区

时间:2011-12-14 05:22:33

标签: php image-processing gd

这篇文章是几年前问的一个问题的延伸: Crop whitespace from image in PHP

这篇文章解释了如何使用php从图像周围裁剪纯白色空间。这里的问题是它希望图像周围有“纯白色”。这是我想要做的以及它有何不同:

我使用手机作为“扫描仪”来拍摄文件,然后将它们上传到我的服务器(别担心......这里没有“秘密特工”的东西......这是实际上主要是午餐和有时候的名片收据)。在我的情况下,我总是尝试使用深色背景与浅色纸张进行对比。然而,图像从未出现“纯”黑/白色。我的图片始终采用JPG格式。我正在尝试上面引用的代码(但交换测试黑/黑边框)并想知道是否有一种方法来推广该函数以更广泛地应用?我可以安装ImageMagick并使用trimImage和其他一些东西,但宁愿坚持使用GD,因为这对更多StackOverflow用户更有用。这是我到目前为止所想到的:

IDEA#1:将图像转换为灰度并将对比度设置得非常高......在那里进行比较(在该点可能与纯黑色相比)...然后使用原始上找到的坐标(非灰度)图片。你觉得怎么样......好方法?会有用吗? 我会使用imagefilter($ img,IMG_FILTER_GRAYSCALE);然后是imagefilter($ img,IMG_FILTER_CONTRAST,-90);

IDEA#2:去通用。这是我需要最多帮助的想法。如果我可以自动检测边界的大致颜色范围,那将是非常酷的。我们的想法是从四个角中的每个角采样一个像素(或几个),然后“平均”它们以找出背景。这意味着有一天,如果我想拍照棕色背景,红色背景或绿色背景......没问题。我认为朝这个方向迈出的第一步将涉及使用imagecolorclosest(),但坦率地说,如何选择,比较,平均,然后重新比较颜色。理想情况下,有一种方法可以将一些逻辑插入到原始函数中(来自上面的链接),然后无论图像中的背景颜色是什么(假设它是合理一致的),它都能够一般地工作,并且会使用照片(因此背景颜色不是绝对相同的颜色值的图像)。

所以...两部分问题:我的IDEA#1是最好的方法,我应该注意哪些问题或改进/实施的建议?并且......有没有人想在IDEA#2上放弃,至少给我足够的代码以便朝着正确的方向前进?

1 个答案:

答案 0 :(得分:0)

所以我继续前进并使用IDEA#1,它的效果非常好。我已经准备好了,现在不需要进一步的帮助......虽然仍然认为IDEA#2是一个更好的全能解决方案,所以如果有人想提供它的一些指示,我会玩弄这些想法并尝试在这里发布其他代码示例。现在,这是我上面描述的IDEA#1的工作版本,并在几个手机图像上进行了测试:

//MANY THANKS TO: http://stackoverflow.com/questions/1669683/crop-whitespace-from-image-in-php    

$OriginalImageFileLocation = 'sampleimage.jpg';

    //load the image into a variable (and throw an error if image does not exist)
    if( !$img = imagecreatefromjpeg("$OriginalImageFileLocation") )
    { exit("Could not use image $OriginalImageFileLocation"); } 

    // This function only can detect the background if it is "pure black"...so convert to greyscale then crank the contrast
    imagefilter($img, IMG_FILTER_GRAYSCALE);
    imagefilter($img, IMG_FILTER_CONTRAST, -100);


    //find the size of the borders
    $b_top = 0;
    $b_btm = 0;
    $b_lft = 0;
    $b_rt = 0;

    //top
    for(; $b_top < imagesy($img); ++$b_top) {
      for($x = 0; $x < imagesx($img); ++$x) {
        if(imagecolorat($img, $x, $b_top) != 0x000000) {
           break 2; //out of the 'top' loop
        }
      }
    }

    //bottom
    for(; $b_btm < imagesy($img); ++$b_btm) {
      for($x = 0; $x < imagesx($img); ++$x) {
        if(imagecolorat($img, $x, imagesy($img) - $b_btm-1) != 0x000000) {
           break 2; //out of the 'bottom' loop
        }
      }
    }

    //left
    for(; $b_lft < imagesx($img); ++$b_lft) {
      for($y = 0; $y < imagesy($img); ++$y) {
        if(imagecolorat($img, $b_lft, $y) != 0x000000) {
           break 2; //out of the 'left' loop
        }
      }
    }

    //right
    for(; $b_rt < imagesx($img); ++$b_rt) {
      for($y = 0; $y < imagesy($img); ++$y) {
        if(imagecolorat($img, imagesx($img) - $b_rt-1, $y) != 0x000000) {
           break 2; //out of the 'right' loop
        }
      }
    }

    //now re-initialize the original image since the greyscaled version was just for gathering cordinates
    $img = imagecreatefromjpeg("$OriginalImageFileLocation");

    // OPTIONAL: make the final image a bit prettier (and greyscale for long-term consistency)
    imagefilter($img, IMG_FILTER_GRAYSCALE);
    imagefilter($img, IMG_FILTER_BRIGHTNESS, +15);
    imagefilter($img, IMG_FILTER_CONTRAST, -20);


    //copy the contents, excluding the border
    $newimg = imagecreatetruecolor( imagesx($img)-($b_lft+$b_rt), imagesy($img)-($b_top+$b_btm) );
    imagecopy($newimg, $img, 0, 0, $b_lft, $b_top, imagesx($newimg), imagesy($newimg));

    //finally, output the image
    header("Content-Type: image/jpeg");
    imagejpeg($newimg);