0

ソース PNG 画像は、ユーザー入力に基づいて Imagick を使用して PHP によってトリミングされます。結果は、透明なピクセルがある場合とない場合があるトリミングされた画像になります。トリミングされた画像に透過性があるかどうかを検出する方法を探しているので、不透明な PNG を JPG に変換できます。

これは、画像をロードするための私のコードです:

// Get user input
$src = $_POST['src'];
$resize = json_decode($_POST['selection_data']);

// Load image (source image has transparency)
$dst = new Imagick($src);

// Crop image (the part that will be cropped is fully opaque)
$dst->cropImage($resize->selW, $resize->selH, $resize->selX, $resize->selY);
$dst->resizeImage($resize->dstW, $resize->dstH, imagick::FILTER_CATROM, 0.9, false);

この後、 を使用してアルファチャンネルを確認でき$dst->getImageAlphaChannel()ます。ただし、trueソース イメージ (透過性を持つ) の読み込み中に設定されるため、トリミングされたイメージに透明なピクセルが含まれているかどうかに関係なく返されます。

透明なピクセルをチェックするもう 1 つの方法は、すべてのピクセルで 1* より小さいアルファ値を探すことです。

$alpha = false;
for ($x = 0; $x < $resize->dstW; $x++)
{
    for ($y = 0; $y < $resize->dstH; $y++)
    {               
        if ($dst->getImagePixelColor($x, $y)->getColorValue(Imagick::COLOR_ALPHA) < 1)
        {
            $alpha = true;
            break 2;
        }
    }
}

しかし、大きな画像 (1000x1000) の場合、これを実行するのに 30 秒以上かかるため、理想的ではありません。

画像に透明なピクセルがあるかどうかを検出する最速の方法は何ですか?

*: 現在テスト中の Debian Wheezy では、不透明なピクセルは実際には 0.99999999976717 (32 ビット浮動小数点数) のアルファ値を返します。

4

1 に答える 1

1

1つの解決策は次のとおりです。

  1. テストするイメージと同じサイズの色付きの背景を持つ新しいイメージを作成します。

  2. と を使用して、その新しいキャンバスの上に画像を描画しcompositeImageますCOMPOSITE_ATOP

  3. すべてのカラー チャネルのイメージ統計を取得します。

透明度がまったくない画像の場合、2 つの画像は、すべてのカラー チャネルについてまったく同じ画像統計値を持つ必要があります。

コードでは、これは次のようになります。

$imagick = new Imagick(realpath("../images/fnord.png"));

$newCanvas = new Imagick();
$newCanvas->newImage($imagick->getImageWidth(), $imagick->getImageHeight(), 'rgba(255, 255, 0, 1)', 'png');
$newCanvas->compositeimage($imagick, Imagick::COMPOSITE_ATOP, 0, 0);

function dumpInfo(Imagick $imagick) {

    $identifyInfo = $imagick->getImageChannelStatistics();

    foreach ($identifyInfo as $key => $value) {

        echo "$key :";

        if (is_array($value) == true) {
            var_dump($value);
        }
        else {
            echo $value;
        }

        echo "<br/>";
    }
}

dumpInfo($imagick);
echo "<br/><br/>";
dumpInfo($newCanvas);

透明な画像の場合、出力は次のようになります。

0 :array(5) { ["mean"]=> float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation "]=> float(0) ["depth"]=> int(1) } 1 :array(5) { ["mean"]=> float(5764.6123956044) ["minima"]=> float(0) [ "maxima"]=> float(53619) ["standardDeviation"]=> float(11888.331707876) ["depth"]=> int(15) } 2 :array(5) { ["mean"]=> float(2058.7978021978) ) ["最小"]=> float(0) ["最大"]=> float(34951) ["標準偏差"]=> float(5059.2862080476) ["深さ"]=> int(15) } 4 :array( 5) { ["平均"]=> float(6324.2305054945) ["最小"]=> float(0) ["最大"]=> float(46773) ["標準偏差"]=> float(11356.366371237) ["深さ"]=> int(15) } 8 :array(5) { ["平均"]=> float(46867.721934066) ["最小値"]=> float(0) [" maxima"]=> float(65535) ["standardDeviation"]=> float(26491.889090216) ["depth"]=> int(15) } 32 :array(5) { ["mean"]=> float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation"]=> float(0) ["depth"]=> int(1 ) }float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation"]=> float(0) ["depth"]= > int(1) }float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation"]=> float(0) ["depth"]= > int(1) }

0 :array(5) { ["mean"]=> float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation "]=> float(0) ["深さ"]=> int(1) } 1 :array(5) { ["平均値"]=> float(51766.576175824) ["最小値"]=> float(0) [ "maxima"]=> float(65535) ["standardDeviation"]=> float(19889.498582657) ["depth"]=> int(16) } 2 :array(5) { ["mean"]=> float(48461.548131868) ) ["最小"]=> float(0) ["最大"]=> float(65535) ["標準偏差"]=> float(24228.543381351) ["深さ"]=> int(16) } 4 :array( 5) { ["平均"]=> float(5353.375032967) ["最小"]=> float(0) ["最大"]=> float(43081) ["標準偏差"]=> float(10139.362164338) ["深さ"]=> int(16) } 8 :array(5) { ["平均"]=> float(0) ["最小値"]=> float(0) [" maxima"]=> float(0) ["standardDeviation"]=> float(0) ["depth"]=> int(1) } 32 :array(5) { ["mean"]=> float(0) ["minima"]=> float(1.0E+37) ["maxima"]=> float(-1.0E-37) ["standardDeviation"]=> float(0) ["depth"]=> int(1 ) }]=> float(-1.0E-37) ["標準偏差"]=> float(0) ["深さ"]=> int(1) }]=> float(-1.0E-37) ["標準偏差"]=> float(0) ["深さ"]=> int(1) }

明らかでない場合、これらの 2 つの配列は明らかに同じではありません。

1 :array(5) { ["平均"]=> float(5764.6123956044) 1 :array(5) { ["平均"]=> float(51766.576175824)

理論的にはgetImageChannelStatistics、値が実際に何を意味するかを理解できれば、実際の値を調べるだけで済みますが、比較メソッドの方がおそらく安全です。

于 2013-11-13T15:36:08.453 に答える