相似图片_相似图片查找 - CSDN
精华内容
参与话题
  • 图片相似度对比

    千次阅读 2019-05-28 21:49:12
    文章给出了两种方法,可以计算两张图片的相似度 参考文章:https://blog.csdn.net/xundh/article/details/78255037 方法一: from PIL import Image import glob import os class CompareImage(): def calculate...

    文章给出了两种方法,可以计算两张图片的相似度
    参考文章:https://blog.csdn.net/xundh/article/details/78255037

    方法一:

    from PIL import Image
    import glob
    import os
    class CompareImage():
        def calculate(self, image1, image2):
            g = image1.histogram()
            s = image2.histogram()
            assert len(g) == len(s), "error"
    
            data = []
    
            for index in range(0, len(g)):
                if g[index] != s[index]:
                    data.append(1 - abs(g[index] - s[index]) / max(g[index], s[index]))
                else:
                    data.append(1)
    
            return sum(data) / len(g)
    
        def split_image(self, image, part_size):
            pw, ph = part_size
            w, h = image.size
    
            sub_image_list = []
    
            assert w % pw == h % ph == 0, "error"
    
            for i in range(0, w, pw):
                for j in range(0, h, ph):
                    sub_image = image.crop((i, j, i + pw, j + ph)).copy()
                    sub_image_list.append(sub_image)
    
            return sub_image_list
    
    
        def compare_image(self, file_image1, file_image2, size=(256, 256), part_size=(64, 64)):
            '''
            'file_image1''file_image2'是传入的文件路径
             可以通过'Image.open(path)'创建'image1''image2' Image 对象.
             'size' 重新将 image 对象的尺寸进行重置,默认大小为256 * 256 .
             'part_size' 定义了分割图片的大小.默认大小为64*64 .
             返回值是 'image1''image2'对比后的相似度,相似度越高,图片越接近,达到1.0说明图片完全相同。
            '''
    
            image1 = Image.open(file_image1)
            image2 = Image.open(file_image2)
    
            #调用"split_image"函数,把图片切割,并分别放在数组中
            img1 = image1.resize(size).convert("RGB")    
            sub_image1 = self.split_image(img1, part_size)
    
            img2 = image2.resize(size).convert("RGB")
            sub_image2 = self.split_image(img2, part_size)
    
            sub_data = 0
            #把切割好的照片,从数组中一一对应的提出来,传入"calculate"函数,做直方图比较
            for im1, im2 in zip(sub_image1, sub_image2):
                sub_data += self.calculate(im1, im2)
    
            x = size[0] / part_size[0]
            y = size[1] / part_size[1]
    
            pre = round((sub_data / (x * y)), 6)
            # print(str(pre * 100) + '%')
            if pre<0.3:
                os.remove(fp[k])
    
            print('Compare the image result is: ' + str(pre))
            return pre
    
    
    fp = glob.glob('img2/'+'/*jpg')
    for k,i in enumerate(fp):
        # print("对比原图为:",fp[0])
        # print("对比对象为:",fp[k])
        compare_image = CompareImage()
        compare_image.compare_image(fp[0], fp[k])
    
    

    方法二:

    #encoding:utf-8
    import cv2 
    import numpy as np 
    from matplotlib import pyplot as plt 
    
    # 最简单的以灰度直方图作为相似比较的实现 
    def classify_gray_hist(image1,image2,size = (256,256)): 
        # 先计算直方图 
        # 几个参数必须用方括号括起来 
        # 这里直接用灰度图计算直方图,所以是使用第一个通道, 
        # 也可以进行通道分离后,得到多个通道的直方图 
        # bins 取为16 
        image1 = cv2.resize(image1,size) 
        image2 = cv2.resize(image2,size) 
        hist1 = cv2.calcHist([image1],[0],None,[256],[0.0,255.0]) 
        hist2 = cv2.calcHist([image2],[0],None,[256],[0.0,255.0]) 
        # 可以比较下直方图 
        plt.plot(range(256),hist1,'r') 
        plt.plot(range(256),hist2,'b') 
        #plt.show() 
        # 计算直方图的重合度 
        degree = 0
        for i in range(len(hist1)): 
            if hist1[i] != hist2[i]: 
                degree = degree + (1 - abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i])) 
            else: 
                degree = degree + 1
        degree = degree/len(hist1) 
        return degree 
    
    # 计算单通道的直方图的相似值 
    def calculate(image1,image2): 
        hist1 = cv2.calcHist([image1],[0],None,[256],[0.0,255.0]) 
        hist2 = cv2.calcHist([image2],[0],None,[256],[0.0,255.0]) 
        # 计算直方图的重合度 
        degree = 0
        for i in range(len(hist1)): 
            if hist1[i] != hist2[i]: 
                degree = degree + (1 - abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i])) 
            else: 
                degree = degree + 1
        degree = degree/len(hist1) 
        return degree
    
    # 通过得到每个通道的直方图来计算相似度 
    def classify_hist_with_split(image1,image2,size = (256,256)): 
        # 将图像resize后,分离为三个通道,再计算每个通道的相似值 
        image1 = cv2.resize(image1,size) 
        image2 = cv2.resize(image2,size) 
        sub_image1 = cv2.split(image1) 
        sub_image2 = cv2.split(image2) 
        sub_data = 0
        for im1,im2 in zip(sub_image1,sub_image2): 
            sub_data += calculate(im1,im2) 
        sub_data = sub_data/3
        return sub_data 
    
    # 平均哈希算法计算 
    def classify_aHash(image1,image2): 
        image1 = cv2.resize(image1,(8,8)) 
        image2 = cv2.resize(image2,(8,8)) 
        gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY) 
        gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY) 
        hash1 = getHash(gray1) 
        hash2 = getHash(gray2) 
        return Hamming_distance(hash1,hash2) 
    
    def classify_pHash(image1,image2): 
        image1 = cv2.resize(image1,(32,32)) 
        image2 = cv2.resize(image2,(32,32)) 
        gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY) 
        gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY) 
        # 将灰度图转为浮点型,再进行dct变换 
        dct1 = cv2.dct(np.float32(gray1)) 
        dct2 = cv2.dct(np.float32(gray2)) 
        # 取左上角的8*8,这些代表图片的最低频率 
        # 这个操作等价于c++中利用opencv实现的掩码操作 
        # 在python中进行掩码操作,可以直接这样取出图像矩阵的某一部分 
        dct1_roi = dct1[0:8,0:8] 
        dct2_roi = dct2[0:8,0:8] 
        hash1 = getHash(dct1_roi) 
        hash2 = getHash(dct2_roi) 
        return Hamming_distance(hash1,hash2) 
    
    # 输入灰度图,返回hash 
    def getHash(image): 
        avreage = np.mean(image) 
        hash = [] 
        for i in range(image.shape[0]): 
            for j in range(image.shape[1]): 
                if image[i,j] > avreage: 
                    hash.append(1) 
                else: 
                    hash.append(0) 
        return hash
    
    
    # 计算汉明距离 
    def Hamming_distance(hash1,hash2): 
        num = 0
        for index in range(len(hash1)): 
            if hash1[index] != hash2[index]: 
                num += 1
        return num 
    
    
    if __name__ == '__main__': 
        img1 = cv2.imread('img2/t1.jpg')
        #cv2.imshow('img1',img1) 
        img2 = cv2.imread('img2/t5.jpg')
        #cv2.imshow('img2',img2) 
        degree = classify_gray_hist(img1,img2) 
        #degree = classify_hist_with_split(img1,img2) 
        #degree = classify_aHash(img1,img2) 
        #degree = classify_pHash(img1,img2) 
        print( degree) 
        #cv2.waitKey(0)
    
    
    展开全文
  • [图像识别]相似图片搜索的原理

    千次阅读 2013-11-22 16:26:18
    你可以用一张图片,搜索互联网上所有与它相似的图片。... 一个对话框会出现。 你输入网片的网址,或者直接上传图片,Google就会...类似的"相似图片搜索引擎"还有不少,TinEye甚至可以找出照片的拍摄背景。 这种技术

    你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。

    一个对话框会出现。

    你输入网片的网址,或者直接上传图片,Google就会找出与其相似的图片。下面这张图片是美国女演员Alyson Hannigan。

    上传后,Google返回如下结果:

    类似的"相似图片搜索引擎"还有不少,TinEye甚至可以找出照片的拍摄背景。

    这种技术的原理是什么?计算机怎么知道两张图片相似呢?

    根据Neal Krawetz博士的解释,原理非常简单易懂。我们可以用一个快速算法,就达到基本的效果。

    这里的关键技术叫做"感知哈希算法"(Perceptual hash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

    下面是一个最简单的实现:

    第一步,缩小尺寸。

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

    第二步,简化色彩。

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

    第三步,计算平均值。

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

    第四步,比较像素的灰度。

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

    第五步,计算哈希值。

    将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

     = 8f373714acfcf4d0

    得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

    具体的代码实现,可以参见Wote用python语言写的imgHash.py。代码很短,只有53行。使用的时候,第一个参数是基准图片,第二个参数是用来比较的其他图片所在的目录,返回结果是两张图片之间不相同的数据位数量(汉明距离)。

    这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

    实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

    昨天,我在isnowfy的网站看到,还有其他两种方法也很简单,这里做一些笔记。

    一、颜色分布法

    每张图片都可以生成颜色分布的直方图(color histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。

    任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。

    如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。

    任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。

    上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。

    于是,寻找相似图片就变成了找出与其最相似的向量。这可以用皮尔逊相关系数或者余弦相似度算出。

    二、内容特征法

    除了颜色构成,还可以从比较图片内容的相似性入手。

    首先,将原图转成一张较小的灰度图片,假定为50x50像素。然后,确定一个阈值,将灰度图片转成黑白图片。

    如果两张图片很相似,它们的黑白轮廓应该是相近的。于是,问题就变成了,第一步如何确定一个合理的阈值,正确呈现照片中的轮廓?

    显然,前景色与背景色反差越大,轮廓就越明显。这意味着,如果我们找到一个值,可以使得前景色和背景色各自的"类内差异最小"(minimizing the intra-class variance),或者"类间差异最大"(maximizing the inter-class variance),那么这个值就是理想的阈值。

    1979年,日本学者大津展之证明了,"类内差异最小"与"类间差异最大"是同一件事,即对应同一个阈值。他提出一种简单的算法,可以求出这个阈值,这被称为"大津法"(Otsu's method)。下面就是他的计算方法。

    假定一张图片共有n个像素,其中灰度值小于阈值的像素为 n1 个,大于等于阈值的像素为 n2 个( n1 + n2 = n )。w1 和 w2 表示这两种像素各自的比重。

    w1 = n1 / n

    w2 = n2 / n

    再假定,所有灰度值小于阈值的像素的平均值和方差分别为 μ1 和 σ1,所有灰度值大于等于阈值的像素的平均值和方差分别为 μ2 和 σ2。于是,可以得到

    类内差异 = w1(σ1的平方) + w2(σ2的平方)

    类间差异 = w1w2(μ1-μ2)^2

    可以证明,这两个式子是等价的:得到"类内差异"的最小值,等同于得到"类间差异"的最大值。不过,从计算难度看,后者的计算要容易一些。

    下一步用"穷举法",将阈值从灰度的最低值到最高值,依次取一遍,分别代入上面的算式。使得"类内差异最小"或"类间差异最大"的那个值,就是最终的阈值。

    有了50x50像素的黑白缩略图,就等于有了一个50x50的0-1矩阵。矩阵的每个值对应原图的一个像素,0表示黑色,1表示白色。这个矩阵就是一张图片的特征矩阵。

    两个特征矩阵的不同之处越少,就代表两张图片越相似。这可以用"异或运算"实现(即两个值之中只有一个为1,则运算结果为1,否则运算结果为0)。对不同图片的特征矩阵进行"异或运算",结果中的1越少,就是越相似的图片。


    imgHash.py

    #!/usr/bin/python
     
    import glob
    import os
    import sys
     
    from PIL import Image
     
    EXTS = 'jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'
     
    def avhash(im):
    if not isinstance(im, Image.Image):
    im = Image.open(im)
    im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
    avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
    return reduce(lambda x, (y, z): x | (z << y),
    enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())),
    0)
     
    def hamming(h1, h2):
    h, d = 0, h1 ^ h2
    while d:
    h += 1
    d &= d - 1
    return h
     
    if __name__ == '__main__':
    if len(sys.argv) <= 1 or len(sys.argv) > 3:
    print "Usage: %s image.jpg [dir]" % sys.argv[0]
    else:
    im, wd = sys.argv[1], '.' if len(sys.argv) < 3 else sys.argv[2]
    h = avhash(im)
     
    os.chdir(wd)
    images = []
    for ext in EXTS:
    images.extend(glob.glob('*.%s' % ext))
     
    seq = []
    prog = int(len(images) > 50 and sys.stdout.isatty())
    for f in images:
    seq.append((f, hamming(avhash(f), h)))
    if prog:
    perc = 100. * prog / len(images)
    x = int(2 * perc / 5)
    print '\rCalculating... [' + '#' * x + ' ' * (40 - x) + ']',
    print '%.2f%%' % perc, '(%d/%d)' % (prog, len(images)),
    sys.stdout.flush()
    prog += 1
     
    if prog: print
    for f, ham in sorted(seq, key=lambda i: i[1]):
    print "%d\t%s" % (ham, f)

    展开全文
  • 相似图片搜索

    2015-08-09 17:02:56
    前几天在伯乐网上看到有转载相似图片搜索的文章,其实它的方法很简单,就是一篇图片,先做灰度化,resize,01化处理,在判断。出于专业敏感,我想是不是可以利用视频或者图像编码中的DCT变换,利用少量的空间存储大...

      前几天在伯乐网上看到有转载相似图片搜索的文章,其实它的方法很简单,就是一篇图片,先做灰度化,resize,01化处理,在判断。出于专业敏感,我想是不是可以利用视频或者图像编码中的DCT变换,利用少量的空间存储大部分的有效信息,然后再比较,网上搜了搜,果然有这样的算法:phash

      phash算法有很多种,这里介绍一种基于DCT的phash算法。

      图片指纹生成方法:
      图片灰度化
      图片缩放到32x32
      DCT变换处理
      保留最左上部的8x8的DCT系数(图片信息最多部分)
      计算中值
      生成64位指纹,跟中值比较,0表示小于中值,反之为1

      对图片库中的图片按上面方法生成指纹,跟搜寻图片对比,相同指纹比特大于一定阈值,认为相似。

      下面是一个简单的python实现,我这里是将图片缩放到了64x64,DCT为16x16:

    import io
    import os
    from PIL import Image
    import numpy as np
    from scipy import fftpack
    import urllib2
    #import IPython
    import re
    
    #image_url = 'http://imgsrc.baidu.com/forum/w%3D580/sign=bfe6fdf5fddcd100cd9cf829428a47be/1a3a1f30e924b8992d202ec06b061d950a7bf628.jpg'
    base_image_url = 'http://imgsrc.baidu.com/forum/w%3D580/sign=41563ba1053b5bb5bed720f606d2d523/2bdabc3eb13533faebe9a924aed3fd1f41345b5a.jpg'
    
    size = (64,64)
    subsize = 16
    
    def get_image_from_url(image_url):
        image_fd = urllib2.urlopen(image_url)
        image_file = io.BytesIO(image_fd.read())
        image = Image.open(image_file)
        #image.show()
        return image
    
    def preproc_image(image, size=(32, 32)):
        """ 图片预处理
        """
        img_color = image.resize(size, Image.ANTIALIAS) #如果用image.thumbnail() 将保持长宽比
        img_grey = img_color.convert('L')
        #img_grey.show()
        img_grey_array = np.array(img_grey, dtype=np.float)
        return img_grey_array
    
    def get_2d_dct(image_array):
        """ 2D DCT变换
        """
        return fftpack.dct(fftpack.dct(image_array.T, norm='ortho').T, norm='ortho')
    
    def proc_image(image, size=(32, 32), subsize=8):
        #image = get_image_from_url(image_url)
        image_grey_array = preproc_image(image, size)
    
        dct_array = get_2d_dct(image_grey_array)
    
        dct_subarray = dct_array[:subsize,:subsize] 
    
        dct_subarr_fabs = np.fabs(dct_subarray)
        print dct_subarr_fabs
    
        dct_subaverage = np.mean(dct_subarr_fabs)
    
        dct_subfinal = np.greater_equal(dct_subarr_fabs, dct_subaverage*np.ones(dct_subarr_fabs.shape))
        return dct_subfinal
    
    
    base_image = get_image_from_url(base_image_url)
    base_image.save("imageToFind.png",'PNG')
    base_dct_subfinal = proc_image(base_image, size , subsize)
    
    #######################You may change here###############
    #baseurl = 'http://tieba.baidu.com/p/3833419819/'  #请自行添加查找网页地址
    baseurl = 'http://tieba.baidu.com/p/3942417083/'
    format = '(png|bmp|jpg|jpeg|gif|PNG|BMP|JPG|JPEG|GIF)' #图片格式,可自行添加
    #########################################################
    
    #打开页面
    page = urllib2.urlopen(baseurl) 
    
    # 读取包含HTML源码内容的页面信息 
    page_inform = page.read() 
    
    # 获取图片资源列表
    list_of_res = re.findall(r'src="(https?://[^<>]*?\.%s)"' % format, page_inform)
    
    # 去除重复的图片资源
    list_of_res = list(set(list_of_res)) 
    
    imgFindedCount = 0
    imgDoneCount = 0
    
    # 根据图片资源列表逐个搜寻
    for res in list_of_res:
        image_url = res[0]
        if image_url[0:4] != 'http':
            image_url = baseurl+image_url
        #print image_url
    
        image = get_image_from_url(image_url)    
    
        imgDoneCount = imgDoneCount + 1
    
        #image.save("images/image%d.png" % imgDoneCount, "PNG")
    
        if(np.abs(image.size[0]- base_image.size[0])>100 or np.abs(image.size[1]- base_image.size[1])>100):
            print "第%d张图片不匹配" % imgDoneCount
            continue
    
        dct_subfinal = proc_image(image, size, subsize)
        #image.show()
        dct_subfinal = np.logical_xor(base_dct_subfinal, dct_subfinal)
        image_distance = np.count_nonzero(dct_subfinal)
        print image_distance
    
        print image_distance
    
        if(image_distance < 50):
            #image.show()
            imgFindedCount = imgFindedCount + 1
            image.save("imageFinded%d.png" % imgFindedCount, "PNG")
            print "第%d张图片匹配,已找到%d张相似图片~~" % (imgDoneCount,imgFindedCount)
            #break
        else:
            print "第%d张图片不匹配" % imgDoneCount
    
    print "搜索完成^^,共找到%d张相似图片~~" % imgFindedCount     

      包子姐最近上了头条,就用菲吧里的图做个测试吧:
      
      搜索图片

      
      搜索结果(4/52)

    展开全文
  • 相似图片搜索原理和JAVA代码实现

    千次阅读 2019-05-10 17:10:41
    相似图片搜索原理(一) 你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。 一个对话框会出现。 你输入网片的网址,或者直接上传图片,Google就会找出与其相似的图片。下面这张...

    相似图片搜索原理(一)
    你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。

    一个对话框会出现。

    你输入网片的网址,或者直接上传图片,Google就会找出与其相似的图片。下面这张图片是美国女演员Alyson Hannigan。

    上传后,Google返回如下结果:

    类似的"相似图片搜索引擎"还有不少,TinEye甚至可以找出照片的拍摄背景。

    ==========================================================

    这种技术的原理是什么?计算机怎么知道两张图片相似呢?

    根据Neal Krawetz博士的解释,原理非常简单易懂。我们可以用一个快速算法,就达到基本的效果。

    这里的关键技术叫做"感知哈希算法"(Perceptual hash algorithm),它的作用是对每张图片生成一个"指纹"(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

    下面是一个最简单的实现:

    第一步,缩小尺寸。

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

    第二步,简化色彩。

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

    第三步,计算平均值。

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

    第四步,比较像素的灰度。

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

    第五步,计算哈希值。

    将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

     =  = 8f373714acfcf4d0

    得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

    具体的代码实现,可以参见Wote用python语言写的imgHash.py。代码很短,只有53行。使用的时候,第一个参数是基准图片,第二个参数是用来比较的其他图片所在的目录,返回结果是两张图片之间不相同的数据位数量(汉明距离)。

    这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

    实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

    相似图片搜索java代码实现


    预处理:读取图片

    File inputFile = newFile(filename); 
    BufferedImage sourceImage = ImageIO.read(inputFile);//读取图片文件
    


    第一步,缩小尺寸。

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

    int width= 8;
    intheight = 8;
    // targetW,targetH分别表示目标长和宽
    int type= sourceImage.getType();// 图片类型
    BufferedImagethumbImage = null;
    double sx= (double) width / sourceImage.getWidth();
    double sy= (double) height / sourceImage.getHeight();
    // 将图片宽度和高度都设置成一样,以长度短的为准
    if (b) {
          if(sx > sy) {
                sx= sy;
                width= (int) (sx * sourceImage.getWidth());
          }else {
                sy= sx;
                height= (int) (sy * sourceImage.getHeight());
          }
    }
    // 自定义图片
    if (type== BufferedImage.TYPE_CUSTOM) { // handmade
         ColorModelcm = sourceImage.getColorModel();
         WritableRasterraster = cm.createCompatibleWritableRaster(width,height);
         booleanalphaPremultiplied = cm.isAlphaPremultiplied();
         thumbImage= new BufferedImage(cm, raster, alphaPremultiplied, null);
     } else {
         // 已知图片,如jpg,png,gif
         thumbImage= new BufferedImage(width, height, type);
    }
    // 调用画图类画缩小尺寸后的图
    Graphics2Dg = target.createGraphics();
    //smoother than exlax:
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.drawRenderedImage(sourceImage,AffineTransform.getScaleInstance(sx, sy));
    g.dispose();
    

     

    第二步,简化色彩。

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

    int[]pixels = new int[width * height];
    for (inti = 0; i < width; i++) {
          for(int j = 0; j < height; j++) {
                pixels[i* height + j] = rgbToGray(thumbImage.getRGB(i, j));
          }
    }
    /**
     * 灰度值计算
     * @param pixels 彩色RGB值(Red-Green-Blue 红绿蓝)
     * @return int 灰度值
     */
    public static int rgbToGray(int pixels) {
           // int _alpha =(pixels >> 24) & 0xFF;
           int _red = (pixels >> 16) & 0xFF;
           int _green = (pixels >> 8) & 0xFF;
           int _blue = (pixels) & 0xFF;
           return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);
    }
     
    


     

    第三步,计算平均值。

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

    int avgPixel= 0;
    int m = 0;
    for (int i =0; i < pixels.length; ++i) {
          m +=pixels[i];
    }
    m = m /pixels.length;
    avgPixel = m;

    第四步,比较像素的灰度。

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

    int[] comps= new int[width * height];
    for (inti = 0; i < comps.length; i++) {
        if(pixels[i] >= avgPixel) {
            comps[i]= 1;
        }else {
            comps[i]= 0;
        }
    }
    

    第五步,计算哈希值。

    将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

    = = 8f373714acfcf4d0

    StringBufferhashCode = new StringBuffer();
    for (inti = 0; i < comps.length; i+= 4) {
          intresult = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2)+ comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 2];
          hashCode.append(binaryToHex(result));//二进制转为16进制
    }
    StringsourceHashCode = hashCode.toString();
    

    得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算"汉明距离"(Hammingdistance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

    int difference = 0;
    int len =sourceHashCode.length();
           
    for (inti = 0; i < len; i++) {
       if(sourceHashCode.charAt(i) != hashCode.charAt(i)) {
           difference++;
       }
    }
    

    你可以将几张图片放在一起,也计算出他们的汉明距离对比,就可以看看两张图片是否相似。

     

    这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

     

    实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

    提供源码下载,源码下载链接:http://download.csdn.net/detail/luohong722/3965112 


    相似图片搜索原理(二)


    一、颜色分布法

    每张图片都可以生成颜色分布的直方图(color histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。

    任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。

    如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。

    任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。

    上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。

    于是,寻找相似图片就变成了找出与其最相似的向量。这可以用皮尔逊相关系数或者余弦相似度算出。

    二、内容特征法

    除了颜色构成,还可以从比较图片内容的相似性入手。

    首先,将原图转成一张较小的灰度图片,假定为50x50像素。然后,确定一个阈值,将灰度图片转成黑白图片。

      

    如果两张图片很相似,它们的黑白轮廓应该是相近的。于是,问题就变成了,第一步如何确定一个合理的阈值,正确呈现照片中的轮廓?

    显然,前景色与背景色反差越大,轮廓就越明显。这意味着,如果我们找到一个值,可以使得前景色和背景色各自的"类内差异最小"(minimizing the intra-class variance),或者"类间差异最大"(maximizing the inter-class variance),那么这个值就是理想的阈值。

    1979年,日本学者大津展之证明了,"类内差异最小"与"类间差异最大"是同一件事,即对应同一个阈值。他提出一种简单的算法,可以求出这个阈值,这被称为"大津法"(Otsu's method)。下面就是他的计算方法。

    假定一张图片共有n个像素,其中灰度值小于阈值的像素为 n1 个,大于等于阈值的像素为 n2 个( n1 + n2 = n )。w1 和 w2 表示这两种像素各自的比重。  

    w1 = n1 / n
    
    w2 = n2 / n

    再假定,所有灰度值小于阈值的像素的平均值和方差分别为 μ1 和 σ1,所有灰度值大于等于阈值的像素的平均值和方差分别为 μ2 和 σ2。于是,可以得到  

    类内差异 = w1(σ1的平方) + w2(σ2的平方)
    
    类间差异 = w1w2(μ1-μ2)^2

    可以证明,这两个式子是等价的:得到"类内差异"的最小值,等同于得到"类间差异"的最大值。不过,从计算难度看,后者的计算要容易一些。

    下一步用"穷举法",将阈值从灰度的最低值到最高值,依次取一遍,分别代入上面的算式。使得"类内差异最小"或"类间差异最大"的那个值,就是最终的阈值。具体的实例和Java算法,请看这里

    有了50x50像素的黑白缩略图,就等于有了一个50x50的0-1矩阵。矩阵的每个值对应原图的一个像素,0表示黑色,1表示白色。这个矩阵就是一张图片的特征矩阵。

    两个特征矩阵的不同之处越少,就代表两张图片越相似。这可以用"异或运算"实现(即两个值之中只有一个为1,则运算结果为1,否则运算结果为0)。对不同图片的特征矩阵进行"异或运算",结果中的1越少,就是越相似的图片。

    原文链接:

    相似图片搜索的原理

    相似图片搜索的原理(二)

    Google 以图搜图 - 相似图片搜索原理 - Java实现

    参考链接:神奇的图像处理算法, 11款相似图片搜索引擎推荐,以图搜图将不再是难事http://insidesearch.blogspot.com/2011/07/teaching-computers-to-see-image.html

    以上内容大部分直接从阮一峰、依斗罗洪的博客上复制过来,想看原著的童鞋可以去在最上面的链接点击进去看。
    转自:https://blog.csdn.net/YiWangJiuShiXingFu/article/details/89011495 

    展开全文
  • 本文从从图片的dhash,ahash,phash,颜色分布向量到基于语义的sift,surf,gist特征,构建一套分层相似图片检测系统。本文致力于零基础单机快速搭建一个可用的相似图片识别系统。 1 背景 相似图片检测的定义是人...
  • 有了图片想知道这个图片更多的信息,或者类似的图片,怎么搜索呢。
  • 你想凭着一张现有图片找出它...Tineye是典型的以图找图搜索引擎,输入本地硬盘上的图片或者输入图片网址,即可自动帮你搜索相似图片,搜索准确度相对来说还比较令人满意。 TinEye是加拿大Idée公司研发的相似图片搜索
  • 你想凭着一张现有图片找出它的原始图片,或者是凭着一张小...Tineye是典型的以图找图搜索引擎,输入本地硬盘上的图片或者输入图片网址,即可自动帮你搜索相似图片,搜索准确度相对来说还比较令人满意。   TinEye
  • 通过人脸识别查找相似图片

    万次阅读 2017-10-26 21:11:14
    本章内容主要介绍,通过face_recognition工具来识别目标图片对应所对应的相似的已知图片。 实验素材 已知图片 目标图片 名字 23300534014891135650829996334.jpg 1275046_211423046_2.jpg ...
  • 2011年6月,Google把”相似图片搜索”正式放上了首页。你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。 一个对话框会出现。 你输入网片的网址,或者直接上传图片,...
  • Google 以图搜图 - 相似图片搜索原理 - Java实现

    万次阅读 多人点赞 2012-07-11 00:20:15
    前阵子在阮一峰的博客上看到了这篇《相似图片搜索原理》博客,就有一种冲动要将这些原理实现出来了。   Google "相似图片搜索":你可以用一张图片,搜索互联网上所有与它相似的图片。 打开Google图片搜索...
  • 图像相似度主要是对两幅图像内容的相似程度进行打分,根据分数的高低来判断图像的内容的相似程度。图像的相似度在目标检测跟踪、图像内容搜索、特征分析领域有着广泛的应用。常见的图像相似度比较指标有:峰值信噪比...
  • 图像相似性匹配 快速算法

    万次阅读 2018-10-31 15:25:12
    需求是库内存有部分版权图片,现在搜索网上是否有侵权图片。因此从网上跑去大量图片和库内的版权图片比较,由于比较数量大,对效率有一定的要求。 方法1: ...
  •  我的想法是从摄像头采集到的视频, 取出其中的bmp图片, 保存一张静止的图片作为参照物, 这个时候假如有一个移动的物体从摄像头经过, 采集到的bmp图片肯定与参照物不一致,这个时候就会把这张图片保存下来, ...
  • 图像处理之相似图片识别(直方图应用篇)

    万次阅读 多人点赞 2012-07-22 10:38:41
    图像处理之相似图片识别(直方图应用篇) 算法概述: 首先对源图像与要筛选的图像进行直方图数据采集,对采集的各自图像直方图进行归一化再 使用巴氏系数算法对直方图数据进行计算,最终得出图像相似度值,其值...
  • java指纹识别+谷歌图片识别技术

    万次阅读 多人点赞 2012-04-26 13:59:53
    前阵子在阮一峰的博客上看到了这篇《相似图片搜索原理》博客,就有一种冲动要将这些原理实现出来了。 写了图片识别的一个demo 提供源码下载,免费下载地址:...
  • 图像质量评估算法 SSIM(结构相似性)

    万次阅读 多人点赞 2017-04-14 09:20:21
    SSIM的全称为structural similarity index,即为结构相似性,是一种衡量两幅图像相似度的指标。该指标首先由德州大学奥斯丁分校的图像和视频工程实验室(Laboratory for Image and Video Engineering)提出。而如果...
  • 前阵子在阮一峰的博客上看到了这篇《相似图片搜索原理》博客,就有一种冲动要将这些原理实现出来了。 写了图片识别的一个demo 提供源码下载,源码下载链接:[url=...
  • 相似图片搜索算法介绍

    千次阅读 2017-08-22 09:26:55
    相似图片搜索算法介绍
  • 十大相似图片搜索网站(以图搜图)

    千次阅读 2015-09-10 20:33:57
    十大相似图片搜索网站(以图搜图)  2011-04-13 21:07:56| 分类: 默认分类 | 标签:以图搜图 图片搜索 搜图 百度搜图 搜索引擎 |举报|字号 订阅   ...
1 2 3 4 5 ... 20
收藏数 152,199
精华内容 60,879
关键字:

相似图片