画像比較アルゴリズムの別のバージョン

この記事は、誰かが最終的に私にカルマをもたらすまで、1ヶ月間私のドラフトにかかっていました。 誰なのかわかりませんが、ありがとう



今日、もう一度ハブに行って、 この興味深い記事に出会いました。 画像ハッシュアルゴリズムについて説明します。 この記事を読んだときに、このアルゴリズムを変更して、明るさなどの大幅に異なる画像を食べるようにする方法を考えました(ただし、画像自体は同じです)。



おそらく、この方法は既に長い間存在しており、誰かによって長い間説明されてきたのかもしれません。



アルゴリズムは、各i番目と(i + 1)番目のピクセルの差を配列に書き込む必要があるということです。 したがって、この配列はイメージのハッシュです(必要に応じて、文字列形式に変換できます)。 つまり、これに基づいて、私たちの画像は特定の色のピクセルのセットではなく、これらのピクセル間の違いの集合であると信じています。



このようなアルゴリズムのテスト結果は非常に面白いことが判明しましたが、コードを解析した後では低くなります。



次に、このアルゴリズムをコードで分析します。

任意の数の画像を比較して、それぞれの違いを示すことができる簡単なクラスを作成しました。

ここにクラス自体があります。必要に応じて停止することもできますし、ここで何が何をしているのかをさらに読むことができます。

class ImagesComparer { const BAD_ARGS = 1, UNSUPPORTED_FILETYPE = 2, ERROR_OPEN = 3; public $Images = array(); private $_types = array('', 'gif', 'jpeg', 'png', '', '', 'wbmp', '', '', '', '', ''); public $CompareWithFirst = false; public function __construct($Image1, $Image2 = null) { if (func_num_args() > 2) $Images = func_get_args(); else if (is_array($Image1)) $Images = $Image1; else $Images = array($Image1, $Image2); foreach ($Images as $Image) { if (is_string($Image)) $this->_openImage($Image); else if (is_resource($Image)) $this->Images[] = array($this->_getPixelsDiff($Image), array()); else throw new Exception('Bad arguments.', self::BAD_ARGS); } } private function _getImageType($Image) { $Type = getimagesize($Image); if (!$Type = $this->_types[$Type[2]]) throw new Exception('Image have an unsupported file type.', self::UNSUPPORTED_FILETYPE); return 'imagecreatefrom' . $Type; } private function _openImage($Image) { $Type = $this->_getImageType($Image); $Image = $Type($Image); if (!$Image) throw new Exception('Error opening image.', self::ERROR_OPEN); $this->Images[] = array($this->_getPixelsDiff($Image), array()); imagedestroy($Image); } private function _getPixelsDiff($Image) { $Sample = imagecreatetruecolor(8, 8); imagecopyresampled($Sample, $Image, 0, 0, 0, 0, 8, 8, imagesx($Image), imagesy($Image)); $Pixels = array(); $Color = array(0, 0, 0); for ($y = 0; $y < 8; $y++) { for ($x = 0; $x < 8; $x++) { $Color1 = imagecolorat($Sample, $x, $y); $Color1 = $this->_scale255To9(array( ($Color1 >> 16) & 0xFF, ($Color1 >> 8) & 0xFF, $Color & 0xFF )); if ($x != 0 || $y != 0) { $Pixels[] = array( $Color1[0] - $Color[0], $Color1[1] - $Color[1], $Color1[2] - $Color[2] ); } $Color = $Color1; } } imagedestroy($Sample); return $Pixels; } private function _scale255To9($NumArr) { return array( round($NumArr[0] / 28.3), round($NumArr[1] / 28.3), round($NumArr[2] / 28.3) ); } private function _getDiff($Img1, $Img2) { $Diff = 0; for ($i = 0; $i < 63; $i++) { $Diff += abs($this->Images[$Img1][0][$i][0] - $this->Images[$Img2][0][$i][0]); $Diff += abs($this->Images[$Img1][0][$i][1] - $this->Images[$Img2][0][$i][1]); $Diff += abs($this->Images[$Img1][0][$i][2] - $this->Images[$Img2][0][$i][2]); } return $Diff; } public function Compare() { $count = count($this->Images); if ($this->CompareWithFirst) { for ($i = 1; $i < $count; $i++) { $this->Images[0][1][$i] = $this->_getDiff(0, $i); } } else { for ($i = 0; $i < $count; $i++) { for ($k = $i + 1; $k < $count; $k++) { //echo "\r\n<br />" . $this->Images[$k][1][$i] = $this->Images[$i][1][$k] = $this->_getDiff($i, $k); } } } } }
      
      







コンストラクターでは、_getPixelsDiff()メソッドが各イメージで呼び出され、その結果がImages配列に入れられます。 このメソッドは、次の操作を実行します。

  1. 画像を8x8に縮小します。
  2. 花の配列を作成します。
  3. 画像の各ピクセルを通過します。

    1. RGBで色を取ります。
    2. 各チャネルは28.3で除算して丸められるため、チャネルの最大値は9に等しくなります。
    3. 各チャネルから前のピクセルの値を減算します。
    4. 結果は配列に入れられて返されます。
それでは、Compare()で_getDiff()メソッドが呼び出され、配列間の違いが検出されます。

ちなみに、このコードに基づいて、画像の最大の差は1701 (63 * 3 * 9、そうでない場合は正しい)になります。



そして今、テスト。



写真の最初のペア: onetwo 。 最初の写真はエアジョーダンのロゴです。 2番目は、ベンダーによって実行される最初のパロディです。 同意して、目はかなり似たような写真です。 そして、私たちのプログラムは、1701のうち68の相違点を与えます。つまり、それらの同一性の確率は約96.1%です。



写真の2番目のペア: 1つと 2つ 。 色はかなり似ていますが、差は266です。 ところで、これらの数字は85%の確率で同一であることがわかります。 そのため、バー(申し訳ありませんが、しきい値)は非常に高く設定する必要があります。



さらに2 あります: 1つと 2つ 。 違い52。



一般的に、この方法は理想的ではないと思いますが、少なくとも生命に対する権利があると思います。



UPD。 この画像とこれの比較。 ご覧のとおり、2番目のコントラストは大きく変更されています。 違いは1701頭のうち70頭です。



All Articles