深刻学习OpenCV中图像类似度的算法

  最近一段时间学习并作的都是对图像进行处理,其实本身也是新手,各类尝试,因此我这个门外汉想总结一下本身学习的东西,图像处理的流程。可是动起笔来想总结,一下殊不知道本身要写什么,那就把本身作过的类似图片搜索的流程整理一下,想到什么说什么吧。html

  首先在进行图片灰度化处理以前,我以为有必要了解一下为何要进行灰度化处理。python

图像灰度化的目的是什么?

  将彩色图像转化为灰度图像的过程是图像的灰度化处理。彩色图像中的每一个像素的颜色由R,G,B三个份量决定,而每一个份量中可取值0-255,这样一个像素点能够有1600多万(256*256*256=1677256)的颜色的变化范围。而灰度图像是R,G,B三个份量相同的一种特殊的彩色图像,其中一个像素点的变化范围为256种,因此在数字图像处理中通常将各类格式的图像转化为灰度图像以使后续的图像的计算量少一些。灰度图像的描述与彩色图像同样仍然反映了整副图像的总体和局部的色度和高亮等级的分布和特征。算法

一:图像灰度化处理

  灰度化处理就是将一幅色彩图像转化为灰度图像的过程。彩色图像分为R,G,B三个份量,分别显示出红绿蓝等各类颜色,灰度化就是使彩色的R,G,B份量相等的过程。灰度值大的像素点比较亮(像素值最大为255,为白色),反之比较暗(像素最下为0,为黑色)。windows

1.1   图像灰度化的算法:

  1)最大值法:使转化后的R,G,B得值等于转化前3个值中最大的一个,即:R=G=B=max(R,G,B)。这种方法转换的灰度图亮度很高。数组


  2)平均值法:是转化后R,G,B的值为转化前R,G,B的平均值。即:R=G=B=(R+G+B)/3。这种方法产生的灰度图像比较柔和。 网络


  3)加权平均值法:按照必定权值,对R,G,B的值加权平均,即:这里写图片描述分别为R,G,B的权值,取不一样的值造成不一样的灰度图像。因为人眼对绿色最为敏感,红色次之,对蓝色的敏感性最低,所以使将获得较易识别的灰度图像。通常时,获得的灰度图像效果最好。app

 

1.2  图像灰度化的三种方法

  1.2.1,OpenCV直接灰度化

  下面的这种方法,在读取图片的时候,直接将图片转化为灰度化:less

import cv2

img = cv2.imread(photo_file, cv2.IMREAD_GRAYSCALE)

  获得的img是一个函数。ide

  1.2.2,OpenCV先读取再灰度化

  下面的方法,先读取图片,而后再转化为灰度图。函数

import  cv2

img = cv2.imread(photo_file)
# Y = 0.299R + 0.587G + 0.114B
grey_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

  

  1.2.3,使用PIL库中的Image模块

  首先读取图片,而后灰度化,最后转化为数组

import numpy as np
form PIL import Image

# 使用PIL库中的Image模块
# L = 0.299R + 0.587G + 0.114B
img2 = Image.open(photo_file)
grey_img2 = img2.convert('L')
grey_img22 = np.array(grey_img2)
print(type(grey_img22))

  使用python中的图像处理库PIL来实现不一样图像格式的转化,对于彩色图像,无论其图像格式是PNG,仍是BMP,仍是JPG,在PIL中,使用Image模块的open()函数打开后,返回的图像对象的模式都是“RGB”。而对于灰度图像,无论其图像格式是PNG,仍是BMP,或者JPG,打开后,其模式为“L”。

  

1.3   代码实现(灰度化+二值化)

from PIL import Image

#  load a color image
im = Image.open('durant.jpg' )

#  convert to grey level image
Lim = im.convert('L' )
Lim.save('grey.jpg' )

#  setup a converting table with constant threshold
threshold = 185
table = []
for i in range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)

# convert to binary image by the table
bim = Lim.point(table, '1' )

bim.save('durant_grey.jpg' )

原图图片效果展现:

 

灰度化图片效果展现:

二值化图片效果展现:

 1.3 convert() 方法详解

  Convert()会根据传入参数的不一样将图像变成不一样的模式。PIL中有九种不一样模式。分别为1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。

    模式‘1’为二值图像,非黑即白。可是它每一个像素用8个bit表示,
0表示黑,255表示白。

    模式‘L’为灰色图像它的每一个像素用8个bit表示,0表示黑,
255表示白,其余数字表示不一样的灰度。在PIL中,从模式“RGB”转
换为“L”模式是按照下面的公式转换的:
    L = R * 299/1000 + G * 587/1000+ B * 114/1000

    模式“P”为8位彩色图像,它的每一个像素用8个bit表示,其对应的
彩色值是按照调色板查询出来的。

    模式“RGBA”为32位彩色图像,它的每一个像素用32个bit表示,其
中24bit表示红色、绿色和蓝色三个通道,另外8bit表示alpha通道,
即透明通道。

    模式“CMYK”为32位彩色图像,它的每一个像素用32个bit表示。模
式“CMYK”就是印刷四分色模式,它是彩色印刷时采用的一种套色模
式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合
叠加,造成所谓“全彩印刷”。

    模式“YCbCr”为24位彩色图像,它的每一个像素用24个bit表示。
YCbCr其中Y是指亮度份量,Cb指蓝色色度份量,而Cr指红色色度分
量。人的肉眼对视频的Y份量更敏感,所以在经过对色度份量进行子
采样来减小色度份量后,肉眼将察觉不到的图像质量的变化。

    模式“RGB”转换为“YCbCr”的公式以下:
        Y= 0.257R+0.504G+0.098B+16
        Cb = -0.148R-0.291G+0.439B+128
        Cr = 0.439R-0.368G-0.071*B+128

    模式“I”为32位整型灰色图像,它的每一个像素用32个bit表示,0表示黑,
255表示白,(0,255)之间的数字表示不一样的灰度。在PIL中,从模式“RGB”
转换为“I”模式是按照下面的公式转换的:
    I = R * 299/1000 + G * 587/1000 + B * 114/1000

    模式“F”为32位浮点灰色图像,它的每一个像素用32个bit表示,0表示黑,
255表示白,(0,255)之间的数字表示不一样的灰度。在PIL中,从模式“RGB”转
换为“F”模式是按照下面的公式转换的:
    F = R * 299/1000+ G * 587/1000 + B * 114/1000    

 

二:Python图像加强

2.1 图片加强三大类别:点加强,空间加强,频域加强

  图像加强是图像模式识别中很是重要的图像预处理过程。图像加强的目的是经过对图像中的信息进行处理,使得有利于模式识别的信息获得加强,不利于模式识别的信息被抑制,扩大图像中不一样物体特征之间的差异,为图像的信息提取及其识别奠基良好的基础。图像加强按实现方法不一样可分为点加强、空域加强和频域加强。

点加强

  点加强主要指图像灰度变换和几何变换。图像的灰度变换也称为点运算、对比度加强或对比度拉伸,它是图像数字化软件和图像显示软件的重要组成部分。

  灰度变换是一种既简单又重要的技术,它能让用户改变图像数据占据的灰度范围。一幅输入图像通过灰度变换后将产生一幅新的输出图像,由输入像素点的灰度值决定相应的输出像素点的灰度值。灰度变换不会改变图像内的空间关系

  图像的几何变换是图像处理中的另外一种基本变换。它一般包括图像的平移、图像的镜像变换、图像的缩放和图像的旋转。经过图像的几何变换能够实现图像的最基本的坐标变换及缩放功能。

空域加强

  图像的空间信息能够反映图像中物体的位置 、形状、大小等特征,而这些特征能够经过必定的物理模式来描述。例如,物体的边缘轮廓因为灰度值变化剧烈通常出现高频率特征,而一个比较平滑的物体内部因为灰度值比较均一则呈现低频率特征。所以,根据须要能够分别加强图像的高频和低频特征。对图像的高频加强能够突出物体的边缘轮廓,从而起到锐化图像的做用。例如,对于人脸的比对查询,就须要经过高频加强技术来突出五宫的轮廓。相应地,对图像的低频部分进行加强能够对图像进行平滑处理,通常用于图像的噪声消除。

频域加强

  图像的空域加强通常只是对数字图像进行局部加强,而图像的频域加强能够对图像进行全局加强。频域加强技术是在数字图像的频率域空间对图像进行滤波,所以须要将图像从空间域变换到频率域,通常经过傅里叶变换实现。在频率域空间的滤波与空域滤波同样能够经过卷积实现,所以傅里叶变换和和卷积理论是频域滤波技术的基础。

2.2  python图像加强的目的是什么?

  图像加强的主要目的有:改变图像的灰度等级,提升图像对比度,消除边缘和噪声,平滑图像;突出边缘或者线性地物,锐化图像;合成彩色图像;压缩图像数据量,突出主要信息等。

  图像加强的主要内容有:空间域加强、频率域加强、彩色加强、多图像代数运算、多光谱图像加强等。

  在图像分类任务中,图像数据加强通常是大多数人会采用的方法之一,这是因为深度学习对数据集的大小有必定的要求,若原始的数据集比较小,没法很好地知足网络模型的训练,从而影响模型的性能,而图像加强是对原始图像进行必定的处理以扩充数据集,可以在必定程度上提高模型的性能。

 

2.3  亮度,色度,对比度,锐度加强

from PIL import Image
from PIL import ImageEnhance
# 原始图像
image = Image.open('deal_with/A1.jpg')
image.show()

#亮度加强
enh_bri = ImageEnhance.Brightness(image)
brightness = 1.5
image_brightened = enh_bri.enhance(brightness)
image_brightened.show()
image_brightened.save("image_brightened.jpg")

#色度加强
enh_col = ImageEnhance.Color(image)
color = 1.5
image_colored = enh_col.enhance(color)
image_colored.show()
image_colored.save("image_colored.jpg")

#对比度加强
enh_con = ImageEnhance.Contrast(image)
contrast = 1.5
image_contrasted = enh_con.enhance(contrast)
image_contrasted.show()
image_contrasted.save("image_contrasted.jpg")

#锐度加强
enh_sha = ImageEnhance.Sharpness(image)
sharpness = 3.0
image_sharped = enh_sha.enhance(sharpness)
image_sharped.show()
image_sharped.save("image_sharped.jpg")

 原图:

 

亮度加强:

 

色度加强:

 

对比度加强:

 

锐度加强:

 2.4  对图像进行翻转Flipping

  对图像进行翻转是最流行的图像数据加强方法之一,这主要是因为翻转图像操做的代码简单,以及对于大多数问题而言,对图像进行翻转操做可以提高模型的性能。下面的模型能够看到人是朝右而不是朝左边。

 三:图片类似度算法(对像素求方差并比对)的学习

3.1 算法逻辑

3.1.1  缩放图片

  将须要处理的图片所放到指定尺寸,缩放后图片大小由图片的信息量和复杂度决定。譬如,一些简单的图标之类图像包含的信息量少,复杂度低,能够缩放小一点。风景等复杂场景信息量大,复杂度高就不能缩放过小,容易丢失重要信息。根据本身需求,弹性的缩放。在效率和准确度之间维持平衡。

3.1.2  灰度处理

  一般对比图像类似度和颜色关系不是很大,因此处理为灰度图,减小后期计算的复杂度。若是有特殊需求则保留图像色彩。

3.1.3 计算平均值

  此处开始,与传统的哈希算法不一样:分别依次计算图像每行像素点的平均值,记录每行像素点的平均值。每个平均值对应着一行的特征。

3.1.4  计算方差

  对获得的全部平均值进行计算方差,获得的方差就是图像的特征值。方差能够很好的反应每行像素特征的波动,既记录了图片的主要信息。

3.1.5  比较方差

  通过上面的计算以后,每张图都会生成一个特征值(方差)。到此,比较图像类似度就是比较图像生成方差的接近成程度。
  一组数据方差的大小能够判断稳定性,多组数据方差的接近程度能够反应数据波动的接近程度。咱们不关注方差的大小,只关注两个方差的差值的大小。方差差值越小图像越类似!

 

3.2  代码:

import cv2
import matplotlib.pyplot as plt

#计算方差
def getss(list):
    #计算平均值
    avg=sum(list)/len(list)
    #定义方差变量ss,初值为0
    ss=0
    #计算方差
    for l in list:
        ss+=(l-avg)*(l-avg)/len(list)
    #返回方差
    return ss

#获取每行像素平均值
def getdiff(img):
    #定义边长
    Sidelength=30
    #缩放图像
    img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
    #灰度处理
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #avglist列表保存每行像素平均值
    avglist=[]
    #计算每行均值,保存到avglist列表
    for i in range(Sidelength):
        avg=sum(gray[i])/len(gray[i])
        avglist.append(avg)
    #返回avglist平均值
    return avglist

#读取测试图片
img1=cv2.imread("james.jpg")
diff1=getdiff(img1)
print('img1:',getss(diff1))

#读取测试图片
img11=cv2.imread("durant.jpg")
diff11=getdiff(img11)
print('img11:',getss(diff11))

ss1=getss(diff1)
ss2=getss(diff11)
print("两张照片的方差为:%s"%(abs(ss1-ss2)))

x=range(30)

plt.figure("avg")
plt.plot(x,diff1,marker="*",label="$jiames$")
plt.plot(x,diff11,marker="*",label="$durant$")
plt.title("avg")
plt.legend()
plt.show()


cv2.waitKey(0)
cv2.destroyAllWindows()

 两张原图:

 

图像结果以下:

img1: 357.03162469135805
img11: 202.56193703703704
两张照片的方差为:154.469687654321

 

   实验环境开始设置了图片像素值,并且进行灰度化处理,此方法比对图像类似对不一样的图片方差很大,结果很明显,可是对比比较类似,特别类似的图片不适应。

四:图片类似度算法(感知哈希算法)的学习

  "感知哈希算法"(Perceptual hash algorithm),它的做用是对每张图片生成一个"指纹"(fingerprint)字符串,而后比较不一样图片的指纹。结果越接近,就说明图片越类似。

4.1  算法步骤

4.1.1 缩小尺寸

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

4.1.2  简化色彩

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

4.1.3  计算平均值

  计算全部64个像素的灰度平均值

4.1.4  比较像素的灰度平均值

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

4.1.5 计算哈希值

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

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

    此算法参考博客:http://www.ruanyifeng.com/blog/2011/07
    /principle_of_similar_image_search.html
    
可是未实现代码,代码以下:

 

#!/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)

 

五:marking——对OpenCV中waitKey()函数的学习

   函数原型:

C++: int waitKey(int delay=0)       Python: cv2.waitKey([delay]) → retval

C: int cvWaitKey(int delay=0 )       Python: cv.WaitKey(delay=0) → int

  函数功能:

  waitKey() 函数的功能是不断地刷新图像,频率时间为delay,单位为ms。返回值为当前键盘按键值。

   函数做用:

  1,waitKey()  这个函数是在一个给定的时间内(单位ms)等待用户按键触发;若是用户没有按下键,则继续等待(循环)。

  2,若是设置waitKey(0),则表示程序会无限制的等待用户的按键事件。

  3,用OpenCV来显示图像或者视频时,若是后面不加cvWaitKey这个函数,基本上是显示不出来的。

    4,显示图像,通常要在cvShowImage()函数后面加一句cvWaitKey(0);不然图像没法正常显示。

  源代码:

def waitKey(delay=None): # real signature unknown; restored from __doc__
    """
    waitKey([, delay]) -> retval
    .   @brief Waits for a pressed key.
    .   
    .   The function waitKey waits for a key event infinitely (when \f$\texttt{delay}\leq 0\f$ ) or for delay
    .   milliseconds, when it is positive. Since the OS has a minimum time between switching threads, the
    .   function will not wait exactly delay ms, it will wait at least delay ms, depending on what else is
    .   running on your computer at that time. It returns the code of the pressed key or -1 if no key was
    .   pressed before the specified time had elapsed.
    .   
    .   @note
    .   
    .   This function is the only method in HighGUI that can fetch and handle events, so it needs to be
    .   called periodically for normal event processing unless HighGUI is used within an environment that
    .   takes care of event processing.
    .   
    .   @note
    .   
    .   The function only works if there is at least one HighGUI window created and the window is active.
    .   If there are several HighGUI windows, any of them can be active.
    .   
    .   @param delay Delay in milliseconds. 0 is the special value that means "forever".
    """
    pass

 

 

六:marking——图像加强中一阶微分和二阶微分的区别

1,斜坡面上,一阶微分一直不为0 ;二阶微分只有终点和起点不为0

2,一阶微分产生较粗的边缘,二阶微分则细得多

3,一阶微分处理通常对灰度阶梯有较强的响应;二阶微分处理细节有较强的响应

 

七:关于OpenCV的安装

  OpenCV的全称open Sourse Computer Vision Library ,是一个跨平台的计算机视觉库,OpenCV可用于开发实时的图像处理,计算机视觉以及模式识别的程序。

  OpenCV是用C++语言编写,它的主要接口也是C++语言,可是依然保留了大量的C语言接口,该库也有大量的Python,Java和MATLAB的接口,另外,一个使用CUDA的GPU接口也用于2010.9 开始实现。

7.1  为何使用Python+OpenCV

  虽然python很强大,并且也有本身的图像处理库PIL,可是相对于OpenCV来说,它仍是弱小不少。跟不少开源软件同样OpenCV也提供了完善的python接口,很是便于调用。OpenCV 的稳定版是2.4.8,最新版是3.0,包含了超过2500个算法和函数,几乎任何一个能想到的成熟算法均可以经过调用OpenCV的函数来实现,超级方便。

 

 7.2  import cv2发生错误的解决方案

   错误以下:

  1,进入cmd控制台,查看python版本

  2 根据本身用的python版本,下载对应的OpenCV

https://www.lfd.uci.edu/~gohlke/pythonlibs/

 

   3,下载numpy,对应的版本

https://pypi.python.org/pypi/numpy 

 cp36表明着匹配python3.6版本。

win3二、amd64表明着32位、64位系统。

  

  4,安装OpenCV,下载下来是一个whl格式文件,把此文件放在安装的文件名下,直接安装。

 

  就这样安装成功。

 

 

参考文献:https://blog.csdn.net/wsp_1138886114/article/details/81368890

相关文章
相关标签/搜索