【发布时间】:2018-09-08 15:20:29
【问题描述】:
我正在尝试将图像哈希添加到数据库中。
我的问题是我有 300 万张图像,其中一些是 99.999+% 相同的。例如 imageA.jpg 和 imageB.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