【问题标题】:PHP Image hashing accuracy suggestionPHP 图像哈希精度建议
【发布时间】:2018-09-08 15:20:29
【问题描述】:

我正在尝试将图像哈希添加到数据库中。

我的问题是我有 300 万张图像,其中一些是 99.999+% 相同的。例如 imageA.jpgimageB.jpg 都具有相同的 800x600 分辨率,但假设 imageB.jpg 有 10 个不同的像素:

800x600 = 480000 总像素;

(480000 - 10 像素差异)/ 48000 总像素 = 0.9999791666666667 相似度

为了减少重复,我编写了 PHP 类原型。一切正常,不是完美,但很好。主要问题是,即使我设置了最高质量,->recreateFile() 函数每次都会创建一些不同的图像。

我正在寻找稳定所有像素的解决方案,即使我会重新创建图像 100 次。

还有其他更好的解决方案/想法来减少我的重复图像吗?

我的 PHP 类代码:

<?php

/**
 * Class HashImage
 * @package App\Cryptography
 */
class HashImage
{
    /**
     *
     */
    const IMAGE_PIXELS = 32;
    /**
     *
     */
    const IMAGE_QUALITY = 100;
    /**
     *
     */
    const IMAGE_FORMAT = 'jpg';
    /**
     *
     */
    const IMAGE_ALGORITHM = 'sha256';
    /**
     * @var string
     */
    private $file;
    /**
     * @var
     */
    private $hash;

    /**
     * HashImage constructor.
     * @param string $file
     */
    public function __construct(string $file)
    {
        $this->file = $file;
    }

    /**
     * @return string
     * @throws \ImagickException
     */
    public function getHash(): string
    {
        $this
            ->recreateFile()
            ->setHash(1)
            ->setHash(2)
            ->setHash(0);
        return hash(self::IMAGE_ALGORITHM, $this->hash);
    }


    /**
     * @param int $type
     * @return self
     * @throws \ImagickException
     */
    private function setHash(int $type): self
    {
        $image = new \Imagick($this->file);
        $image->setImageDepth(8);
        $image->setGravity(\Imagick::GRAVITY_CENTER);
        $image->quantizeImage(15, \Imagick::COLORSPACE_RGB, 255, false, false);
        $image->setImageFormat('PNG');
        if ($type === 1) {
            $width = self::IMAGE_PIXELS;
            $height = self::IMAGE_PIXELS / 2;
        } elseif ($type === 2) {
            $width = self::IMAGE_PIXELS / 2;
            $height = self::IMAGE_PIXELS;
        } else {
            $width = self::IMAGE_PIXELS;
            $height = self::IMAGE_PIXELS;
        }
        $image->cropThumbnailImage($width, $height);
        $img = imagecreatefromstring($image->getImageBlob());
        for ($x = 0; $x < $width; $x++) {
            for ($y = 0; $y < $height; $y++) {
                $colors = imagecolorsforindex($img, imagecolorat($img, $x, $y));
                $this->hash .= round((round((round((round(($colors['red'] + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN)
                    . round((round((round((round(($colors['green'] + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN)
                    . round((round((round((round(($colors['blue'] + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN) + 1) / 2, 0, PHP_ROUND_HALF_DOWN);
            }
        }
        return $this;
    }

    /**
     * @return self
     */
    private function optimizeFile(): self
    {
        exec('/usr/bin/jpegoptim --strip-all --all-progressive ' . $this->file);
        return $this;
    }

    /**
     * @return self
     * @throws \ImagickException
     */
    private function recreateFile(): self
    {
        $image = new \Imagick($this->file);
        $image->setImageFormat(self::IMAGE_FORMAT);
        $image->setCompression(\Imagick::COMPRESSION_JPEG);
        $image->setCompressionQuality(self::IMAGE_QUALITY);
        $image->writeImage($this->file);
        return $this;
    }
}

【问题讨论】:

  • 如果您希望绝对 100% 无损地重新创建或散列图像,您不能使用 JPEG!不同版本的库,不同的实现,不同的质量参数会导致不同的像素。
  • 我同意库的区别,但是如果库相同,源文件相同,为什么调整大小后两张图的随机像素不同?
  • 您的 setHash 方法调用 ImageMagick + GD 库之间的编码和解码,以及量化和舍入。如此多的数据被丢弃,正如@MarkSetchell 指出的那样,在使用无损格式时,您已经存在准确性劣势。另请注意; Imagick 已经用 getImageSignature 计算了这个哈希值。
  • getImageSignature 方式比我的方法更准确,我想将一些图像标记为重复,即使总共有

标签: php image hash duplicates imagick


【解决方案1】:

花了很多时间在这上面, 当前解决方案代码:

<?php declare(strict_types=1);

namespace App\Cryptography;
/**
 * Class HashImage
 * @package App\Cryptography
 */
class HashImage
{
    /**
     * Hashing accuracy
     */
    const HASHING_PIXELS = 64;
    /**
     * Return encryption algorithm
     */
    const HASHING_ALGORITHM = 'sha256';
    /**
     * @var string
     */
    private $file;
    /**
     * @var string
     */
    private $hash;

    /**
     * HashImage constructor.
     * @param string $file
     */
    public function __construct(string $file)
    {
        $this->file = $file;
    }

    /**
     * @return string
     * @throws \ImagickException
     */
    public function getHash(): string
    {
        $this
            ->setHash(1)
            ->setHash(2)
            ->setHash(0);
        return hash(self::HASHING_ALGORITHM, $this->hash);
    }

    /**
     * @param int $type
     * @return self
     * @throws \ImagickException
     */
    private function setHash(int $type): self
    {
        $image = new \Imagick($this->file);
        $image->setImageFormat('PNG');
        $image->setImageDepth(8);
        $image->setGravity(\Imagick::GRAVITY_CENTER);
        $width = $height = self::HASHING_PIXELS;
        if ($type === 1) {
            $height = self::HASHING_PIXELS / 2;
        } elseif ($type === 2) {
            $width = self::HASHING_PIXELS / 2;
        }
        $image->cropThumbnailImage($width, $height);
        $img = imagecreatefromstring($image->getImageBlob());
        for ($x = 0; $x < $width; $x++) {
            for ($y = 0; $y < $height; $y++) {
                $colors = imagecolorsforindex($img, imagecolorat($img, $x, $y));
                $this->hash .= $colors['red'] . $colors['green'] . $colors['blue'];
            }
        }
        return $this;
    }
}

【讨论】:

    猜你喜欢
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    相关资源
    最近更新 更多