5-10
Saturday
标签
梦涛笔记

Imghash:相似图片搜索的php实现

PHP 发布时间:2025-03-13 20:00:52

前几天看到阮一峰的博客里写到关于相似图片搜索的原理, 里面介绍了Google相似图片搜索的大致原理,主要是从Neal Krawetz博士的LOOKS LIKE IT翻译而来。文章详细的介绍了相似图片搜索处理的相关步骤,并且给出了一个python的实现,由于我对PHP比较熟,所以写了个PHP的版本。
图片相似搜索的简单原理
根据文章里的描述,其实原理比较简单,大致有如下几个步骤:

1、缩小尺寸。将图片缩小到8×8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

2、简化色彩。将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

3、计算平均值。计算所有64个像素的灰度平均值。

4、比较像素的灰度。将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

5、计算哈希值。将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。

图片相似搜索的PHP实现
原文中给出了一个python版本的实现,代码只有53行。我写了个对应的PHP版本,由于直接是用类写的,所以代码有100行,具体如下:

class Imghash{
	
	private static $_instance = null;
	
	public $rate = 2;
	
	public static function getInstance(){
		if (self::$_instance === null){
			self::$_instance = new self();
		}
		return self::$_instance;
	}
	public function run($file){
		if (!function_exists('imagecreatetruecolor')){
			throw new Exception('must load gd lib', 1);
		}
		$isString = false;
		if (is_string($file)){
			$file = array($file);
			$isString = true;
		}
		$result = array();
		foreach ($file as $f){
			$result[] = $this->hash($f);
		}
		return $isString ? $result[0] : $result;
	}
	public function checkIsSimilarImg($imgHash, $otherImgHash){
		if (file_exists($imgHash) && file_exists($otherImgHash)){
			$imgHash = $this->run($imgHash);
			$otherImgHash = $this->run($otherImgHash);
		}
		if (strlen($imgHash) !== strlen($otherImgHash)) return false;
		$count = 0;
		$len = strlen($imgHash);
		for($i=0;$i<$len;$i++){
			if ($imgHash{$i} !== $otherImgHash{$i}){
				$count++;
			}
		}
		return $count <= (5 * $rate * $rate) ? true : false;
	}
	public function hash($file){
		if (!file_exists($file)){
			return false;
		}
		$height = 8 * $this->rate;
		$width = 8 * $this->rate;
		$img = imagecreatetruecolor($width, $height);
		list($w, $h) = getimagesize($file);
		$source = $this->createImg($file);
		imagecopyresampled($img, $source, 0, 0, 0, 0, $width, $height, $w, $h);
		$value = $this->getHashValue($img);
		imagedestroy($img);
		return $value;
	}
	public function getHashValue($img){
		$width = imagesx($img);
		$height = imagesy($img);
		$total = 0;
		$array = array();
		for ($y=0;$y<$height;$y++){
			for ($x=0;$x<$width;$x++){
				$gray = ( imagecolorat($img, $x, $y) >> 8 ) & 0xFF;
				if (!is_array($array[$y])){
					$array[$y] = array();
				}
				$array[$y][$x] = $gray;
				$total += $gray;
			}
		}
		$average = intval($total / (64 * $this->rate * $this->rate));
		$result = '';
		for ($y=0;$y<$height;$y++){
			for ($x=0;$x<$width;$x++){
				if ($array[$y][$x] >= $average){
					$result .= '1';
				}else{
					$result .= '0';
				}
			}
		}
		return $result;
	}
	public function createImg($file){
		$ext = $this->getFileExt($file);
		if ($ext === 'jpeg') $ext = 'jpg';
		$img = null;
		switch ($ext){
			case 'png' : $img = imagecreatefrompng($file);break;
			case 'jpg' : $img = imagecreatefromjpeg($file);break;
			case 'gif' : $img = imagecreatefromgif($file);
		}
		return $img;
	}
	public function getFileExt($file){
		$infos = explode('.', $file);
		$ext = strtolower($infos[count($infos) - 1]);
		return $ext;
	}
}
require_once “Imghash.class.php”;
$instance = ImgHash::getInstance();
$result = $instance->checkIsSimilarImg(‘chenyin/IMG_3214.png’, ‘chenyin/IMG_3212.JPG’);

如果$result值为true, 则表明2个图片相似,否则不相似。

在实际的相似图片搜索中,算图片的指纹并不是难点,难点而是在怎么从海量的图片指纹里找出与之相似的指纹。


POST调试工具

HTML PHP 发布时间:2025-03-13 19:34:08

实际开发工作中,很多时候需要用到POST提交值,每次都需要针对写出相对的POST环境,

所以写出这个POST调试工具公共库,方便调试使用。

程序运行环境需要php 及 extension=php_curl.dll

调试时填写的内容:

提交的网址:填写需要调试的网址

提交的变量:分别填写变量名及变量值,可以添加多个变量,及多行(TEXT)变量

提交执行提供了正常执行,返回原码,解析JSON,解析XML 多种操作

可以将返回直接显示,也可以解析后直观显示

在线运行: https://www.zhisg.com/dev/post.php

验证URL字符串的正则

PHP JavaScript 发布时间:2025-03-13 19:31:17

验证URL字符串的正则

^(((file|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(\w+\.))*(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[\d]+)?(/[\w\&%_\./-~-\W]*)?$

在PHP中的写法为:

if(preg_match("@^(((file|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(\w+\.))*(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[\d]+)?(/[\w\&%_\./-~-\W]*)?$@i", $_url))


cURL超时设置

HTML PHP 发布时间:2025-03-13 19:28:34

一般我们访问HTTP方式很多,主要是:curl, socket, file_get_contents() 等方法。

如果碰到对方服务器一直没有响应的时候,我们就悲剧了,很容易把整个服务器搞死,所以在访问http的时候也需要考虑超时的问题。

CURL 是我们常用的一种比较靠谱的访问HTTP协议接口的lib库,性能高,还有一些并发支持的功能等。


curl_setopt($ch, opt) 可以设置一些超时的设置,主要包括:

*(重要) CURLOPT_TIMEOUT 设置cURL允许执行的最长秒数。

*(重要) CURLOPT_TIMEOUT_MS 设置cURL允许执行的最长毫秒数。

(在cURL 7.16.2中被加入。从PHP 5.2.3起可使用)


CURLOPT_CONNECTTIMEOUT 在发起连接前等待的时间,如果设置为0,则无限等待。

CURLOPT_CONNECTTIMEOUT_MS 尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。

(在cURL 7.16.2中被加入。从PHP 5.2.3开始可用)


CURLOPT_DNS_CACHE_TIMEOUT 设置在内存中保存DNS信息的时间,默认为120秒。


curl普通秒级超时:

$ch = curl_init();  
curl_setopt($ch, CURLOPT_URL,$url);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);  
curl_setopt($ch, CURLOPT_TIMEOUT,60);   //只需要设置一个秒的数量就可以  
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);  
curl_setopt($ch, CURLOPT_USERAGENT, $defined_vars['HTTP_USER_AGENT']);  

curl如果需要进行毫秒超时,需要增加:

curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1L);  
//或者是:  
curl_setopt ( $ch,  CURLOPT_NOSIGNAL,true);//是可以支持毫秒级别超时设置的  

curl一个毫秒级超时的例子:

if(!isset($_GET['foo'])){  
        // Client  
        $ch = curl_init('http://example.com/');  
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);  
        curl_setopt($ch, CURLOPT_NOSIGNAL,1);    //注意,毫秒超时一定要设置这个  
        curl_setopt($ch, CURLOPT_TIMEOUT_MS,200);  //超时毫秒,cURL 7.16.2中被加入。从PHP 5.2.3起可使用  
        $data = curl_exec($ch);  
        $curl_errno = curl_errno($ch);  
        $curl_error = curl_error($ch);  
        curl_close($ch);  
   
        if($curl_errno >0){  
                echo "cURL Error ($curl_errno): $curl_error\n";  
        }else{  
                echo "Data received: $data\n";  
        }  
}else{  
        // Server  
        sleep(10);  
        echo "Done.";  
}  

其他一些技巧:

1. 按照经验总结是:cURL 版本 >= libcurl/7.21.0 版本,毫秒级超时是一定生效的,切记。

2. curl_multi的毫秒级超时也有问题。。单次访问是支持ms级超时的,curl_multi并行调多个会不准


XmlHttpRequest error: Origin null is not allowed by Access-Control-Allow-Origin

HTML PHP 发布时间:2025-03-13 19:16:28

解决办法:

1.恳求的url是PHP的,须要PHP中

echo header("Access-Control-Allow-Origin: *");

2.html的,须要在head头加

<meta http-equiv="Access-Control-Allow-Origin" content="*">

这样就可以解决Ajax跨域访问问题。

PHP PECL 扩展库安装

PHP CentOS 发布时间:2025-03-13 14:41:46

https://pecl.php.net/

PECL is a repository for PHP Extensions, providing a directory of all known extensions

搜索下载对应的PHP扩展库原码
#如果不安装php-devel就不会有phpize和php-config

/usr/bin/phpize              # php安装后的路径(不知道位置的可以whereis phpize 查看位置)
./configure --with-php-config=/usr/bin/php-config
make && make install

修改php.ini文件 , 增加如下内容:

extension=XXX.so  #增加对应的扩展库名

重启php-fpm: 或httpd

systemctl restart php-fpm
OR
systemctl restart httpd


Centos8 用dnf安装php7.4

PHP CentOS 发布时间:2025-03-13 14:19:25
#查看PHP模块列表
dnf module list php

#重置PHP模块
dnf module reset php

#设置对应该的模块版本
dnf module enable php:7.4

#安装PHP
dnf install php

#查看安装的版本
php -v


My-Images 图片管理, FTP相册

FTP PHP 发布时间:2025-04-20 22:06:11

对于经常写Blog,发BBS,以及开网店的朋友都经常要用到贴图的功能。但很多地方都没有上传插图的功能,所以就只好用到相册。
但有很多人自己都有空间,只是因为不易操作,而放弃使用,还 要花钱去租相册。
本程序就是专门应用于自己的空间,把图片FTP上传到空间里,本程序就可以进行浏览,方便用户贴图等使用。
本程序不需要安装,也不需要数据支持,只需把程序上传到空间就行了。

  • pic 目录为图片存放目录,图片用FTP上传也要上传到这个目录下。可以建多级子目录。
  • FTP上传工具可以使用FlashFxp,下载地址
  • 如果是LINUX空间的话,需要把 piccache 目录权限设为 777
  • 目录名和图片名都不要用中文,否则会读不到,或兼容性很差。
  • inc/config.php 为配置文件,配置内容如下:
  • $WebName : 网页标题
  • $PicDir : 图片存储目录
  • $SmallPicCache : 缩略图缓存目录
  • $WebURL : 系统网址URL
  • $LockRoot :是否锁定根目录为 $PicDir下


示例: https://www.zhisg.com/myimg/