• OpenCV-Python快速入门(十一):图像矩


    前言

    • 本文是个人快速入门OpenCV-Python的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。
    • 更多精彩内容,可点击进入
      OpenCV-Python快速入门
      专栏或我的个人主页查看

    前提条件

    实验环境

    • Python 3.x (面向对象的高级语言)
    • OpenCV 4.0(python第三方库)pip3 install opencv-python

    图像矩

    • 在了解图像矩之前,先了解一下图像轮廓。
    • 边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。
    • 图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算,比如,用于计算图像矩。
    • 图像轮廓是图像中非常重要的一个特征信息,比如图像的矩特征,通过对图像轮廓的操作,能够获取目标图像的大小、位置、方向等信息。
    • OpenCV 提供了查找图像轮廓的函数 cv2.findContours(),该函数能够查找图像内的轮廓信息,而函数 cv2.drawContours()能够将轮廓绘制出来。

    查找并绘制轮廓

    import cv2
    img = cv2.imread('9.jpg')
    cv2.imshow("origin",img)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    '''
    image, contours, hierarchy = cv2.findContours( image, mode, method)
    参数说明:
        image:与函数参数中的原始图像 image 一致。
        contours:返回的轮廓。
        hierarchy:图像的拓扑信息(轮廓层次)。
        式中的参数为:
        image:原始图像。8 位单通道图像,所有非零值被处理为 1,所有零值保持不变。
                        灰度图像会被自动处理为二值图像。
                        在实际操作时,可以根据需要,预先使用阈值处理等函数将待查找轮廓的图像处理为二值图像。
        mode:轮廓检索模式。
        method:轮廓的近似方法。
                    轮廓的提取方式,具体有如下 4 种:
                        (1)cv2.RETR_EXTERNAL:只检测外轮廓。
                        (2)cv2.RETR_LIST:对检测到的轮廓不建立等级关系。
                        (3)cv2.RETR_CCOMP:检索所有轮廓并将它们组织成两级层次结构。
                                            上面的一层为外边界,下面的一层为内孔的边界。
                                            如果内孔内还有一个连通物体,那么这个物体的边界仍然位于顶层。
                        (4)cv2.RETR_TREE:建立一个等级树结构的轮廓。
    返回值:
        contours:该返回值返回的是一组轮廓信息,每个轮廓都是由若干个点所构成的。
                    例如,contours[i]是第 i 个轮廓(下标从 0 开始),contours[i][j]是第 i 个轮廓内的第 j 个点。
        hierarchy:图像内的轮廓可能位于不同的位置。
                    比如,一个轮廓在另一个轮廓的内部。外部的轮廓称为父轮廓,内部的轮廓称为子轮廓。一幅图像中所有轮廓之间就建立了父子关系。
                根据轮廓之间的关系,就能够确定一个轮廓与其他轮廓是如何连接的。
                    比如,确定一个轮廓是某个轮廓的子轮廓,或者是某个轮廓的父轮廓。称为层次(组织结构),返回值 hierarchy 就包含上述层次关系。 
                每个轮廓 contours[i]对应 4 个元素来说明当前轮廓的层次关系。其形式为:[Next,Previous,First_Child,Parent]
                    其中,Next:后一个轮廓的索引编号。
                        Previous:前一个轮廓的索引编号。
                        First_Child:第 1 个子轮廓的索引编号。
                        Parent:父轮廓的索引编号。
    '''
    image,contours, hierarchy = cv2.findContours(binary,
                                                cv2.RETR_EXTERNAL,
                                                cv2.CHAIN_APPROX_SIMPLE)
    '''
    cv2.drawContours(image, # 待绘制轮廓的图像。
                    contours, # 需要绘制的轮廓。
                    contourIdx, # 需要绘制的边缘索引,一个整数或者为零,则表示绘制对应索引号的轮廓;
                                    如果该值为-1,则表示绘制全部轮廓。
                    color[, # 绘制的颜色。
                    thickness[, # 画笔粗细。-1表示要绘制实心轮廓。
                    lineType[, # 绘制轮廓时所用的线型。
                    hierarchy[, # 对应函数 cv2.findContours()所输出的层次信息。
                    maxLevel[, # 控制所绘制的轮廓层次的深度。如果值为 0,表示仅仅绘制第 0 层的轮廓;
                                    如果值为其他的非零正数,表示绘制最高层及以下的相同数量层级的轮廓。
                    offset]]]]] # 偏移参数。该参数使轮廓偏移到不同的位置展示出来。
                    )
    '''
    img=cv2.drawContours(img,contours,-1,(0,0,255),5)
    cv2.imshow("cv2.drawContours",img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这里插入图片描述

    矩特征

    • 空间矩:
      m j i = ∑ x , y ( i m g ( x , y ) ⋅ x j ⋅ y i ) m_{ji} = \sum_{x,y}(img(x,y)\cdot x^j \cdot y^i) mji=x,y(img(x,y)xjyi)
      其中, i m g ( x , y ) img(x,y) img(x,y)表示图像第x行第y列的像素值
      • 零阶矩:m00
      • 一阶矩:m10, m01
      • 二阶矩:m20, m11, m02
      • 三阶矩:m30, m21, m12, m03
    • 中心矩
      m u j i = ∑ x , y ( i m g ( x , y ) ⋅ ( x − x ˉ ) j ⋅ ( y − y ˉ ) i ) mu_{ji} = \sum_{x,y}(img(x,y)\cdot (x-\bar{x})^j \cdot (y-\bar{y})^i) muji=x,y(img(x,y)(xxˉ)j(yyˉ)i)
      其中, i m g ( x , y ) img(x,y) img(x,y)表示图像第x行第y列的像素值, x ˉ = m 10 m 00 , y ˉ = m 01 m 00 \bar{x}=\frac{m_{10}}{m_{00}},\bar{y}=\frac{m_{01}}{m_{00}} xˉ=m00m10,yˉ=m00m01
      • 二阶中心矩:mu20, mu11, mu02
      • 三阶中心矩:mu30, mu21, mu12, mu03
    • 归一化中心矩
      n u j i = m u j i m 00 ( i + j ) 2 + 1 nu_{ji} = \frac{mu_{ji}}{m_{00}^{\frac{(i+j)}{2}+1}} nuji=m002(i+j)+1muji
      • 二阶 Hu 矩:nu20, nu11, nu02
      • 三阶 Hu 矩:nu30, nu21, nu12, nu03
    • 空间矩、中心矩和归一化中心矩都是根据公式计算得到的,有兴趣的,可自行去深入了解,在此不做过多赘述,大多数矩比较抽象。
    • 如果两个轮廓的矩一致,那么这两个轮廓就是一致的。虽然大多数矩都是通过数学公式计算得到的抽象特征,但是零阶矩m00的含义比较直观,表示一个轮廓的面积。
    • 矩特征函数 cv2.moments()所返回的特征值,能够用来比较两个轮廓是否相似。
    • 例如,有两个轮廓,不管它们出现在图像的哪个位置,我们都可以通过函数 cv2.moments()的 m00 矩判断其面积是否一致。
    • 在位置发生变化时,虽然轮廓的面积、周长等特征不变,但是更高阶的特征会随着位置的变化而发生变化。在很多情况下,我们希望比较不同位置的两个对象的一致性。
    • 解决这一问题的方法是引入中心矩。中心矩通过减去均值而获取平移不变性,因而能够比较不同位置的两个对象是否一致。中心矩具有的平移不变性,能够忽略两个对象的位置关系,比较不同位置上两个对象的一致性。
    • 除了考虑平移不变性外,还会考虑经过缩放后大小不一致的对象的一致性。图像在缩放前后能够拥有一个稳定的特征值。也就是说,让图像在缩放前后具有同样的特征值。显然,中心矩不具有这个属性。
    • 例如,两个形状一致、大小不一的对象,其中心矩是有差异的。
    • 归一化中心矩通过除以物体总尺寸而获得缩放不变性。它通过上述计算提取对象的归一化中心矩属性值,该属性值不仅具有平移不变性,还具有缩放不变性。
    import cv2
    import numpy as np
    img = cv2.imread('10.jpg')
    cv2.imshow("origin",img)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    image,contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    n=len(contours)
    contoursImg=[]
    for i in range(n):
        temp=np.zeros(image.shape,np.uint8)
        contoursImg.append(temp)
        contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,255,3)
        cv2.imshow("contours[" + str(i)+"]",contoursImg[i])
    print("观察各个轮廓的矩(moments):")
    '''
    retval = cv2.moments( array[, binaryImage] )
    参数说明:
        array:可以是点集,也可以是灰度图像或者二值图像。
                当 array 是点集时,函数会把这些点集当成轮廓中的顶点,把整个点集作为一条轮廓,而不是把它们当成独立的点来看待。
        binaryImage:该参数为 True 时,array 内所有的非零值都被处理为 1。该参数仅在参数
        array 为图像时有效。
    返回值:
        retval是矩特征,
    '''
    for i in range(n):
        print("轮廓"+str(i)+"的矩:\n",cv2.moments(contours[i]))
        print("观察各个轮廓的面积:")
    for i in range(n):
        print("轮廓"+str(i)+"的面积:%d" %cv2.moments(contours[i])['m00'])
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    观察各个轮廓的矩(moments):
    轮廓0的矩:
     {'m00': 11529.5, 'm10': 1105743.3333333333, 'm01': 2847787.833333333, 'm20': 120176862.41666666, 'm11': 270349796.125, 'm02': 712630365.9166666, 'm30': 14235866112.7, 'm21': 29152670573.233334, 'm12': 66977238524.066666, 'm03': 180577623654.95, 'mu20': 14129911.619918242, 'mu11': -2768935.0824339986, 'mu02': 9226441.749845982, 'mu30': -39658.30255317688, 'mu21': 84283.91559934616, 'mu12': -132304.25695943832, 'mu03': -23497.28594970703, 'nu20': 0.10629638576745037, 'nu11': -0.020830122622460843, 'nu02': 0.06940860197030822, 'nu30': -2.778484238845095e-06, 'nu21': 5.904981202030144e-06, 'nu12': -9.269314847779921e-06, 'nu03': -1.6462338139499466e-06}
    观察各个轮廓的面积:
    轮廓1的矩:
     {'m00': 8953.5, 'm10': 2733993.6666666665, 'm01': 2274016.833333333, 'm20': 839022387.75, 'm11': 694381324.375, 'm02': 588967940.9166666, 'm30': 258754950659.80002, 'm21': 213146723971.6, 'm12': 179843992765.1, 'm03': 155290097928.05002, 'mu20': 4184461.869233489, 'mu11': -495.0505565404892, 'mu02': 11411392.272744179, 'mu30': -3134.562957763672, 'mu21': 51473359.34176171, 'mu12': 91628.19532775879, 'mu03': -92982228.10702515, 'nu20': 0.05219800910754708, 'nu11': -6.1753827054780176e-06, 'nu02': 0.14234852088438427, 'nu30': -4.132329106022059e-07, 'nu21': 0.006785790040230899, 'nu12': 1.2079446595493111e-05, 'nu03': -0.012257950238254916}
    观察各个轮廓的面积:
    轮廓2的矩:
     {'m00': 9842.5, 'm10': 3005239.333333333, 'm01': 771158.8333333333, 'm20': 925324247.9166666, 'm11': 235467933.04166666, 'm02': 68113586.08333333, 'm30': 287249593438.7, 'm21': 72503694924.4, 'm12': 20798735853.566666, 'm03': 6542331746.450001, 'mu20': 7725726.137263536, 'mu11': 7749.33013227582, 'mu02': 7693373.106139764, 'mu30': -204687.6685180664, 'mu21': -94220.82750475407, 'mu12': 200932.48085737228, 'mu03': 89548.22490978241, 'nu20': 0.07974959059351447, 'nu11': 7.9993245222886e-05, 'nu02': 0.07941562315268903, 'nu30': -2.129747516905527e-05, 'nu21': -9.803549714150096e-06, 'nu12': 2.0906752970020027e-05, 'nu03': 9.317371731559569e-06}
    观察各个轮廓的面积:
    轮廓3的矩:
     {'m00': 14160.5, 'm10': 1550604.3333333333, 'm01': 1111569.6666666665, 'm20': 186503823.5833333, 'm11': 121720951.125, 'm02': 103965306.25, 'm30': 24081987687.2, 'm21': 14640475200.516666, 'm12': 11384761698.816666, 'm03': 10784367997.800001, 'mu20': 16709409.646529496, 'mu11': 1750.395137220621, 'mu02': 16709409.646529496, 'mu30': -1157.9857597351074, 'mu21': -68661.15165162086, 'mu12': 68661.1516456604, 'mu03': 1157.985761642456, 'nu20': 0.08333048885405045, 'nu11': 8.72928999634898e-06, 'nu02': 0.08333048885405045, 'nu30': -4.852960404034913e-08, 'nu21': -2.8774952322123127e-06, 'nu12': 2.8774952319625176e-06, 'nu03': 4.852960412028351e-08}
    观察各个轮廓的面积:
    轮廓0的面积:11529
    轮廓1的面积:8953
    轮廓2的面积:9842
    轮廓3的面积:14160
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    import cv2
    import numpy as np
    img = cv2.imread('10.jpg')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
    image,contours, hierarchy = cv2.findContours(binary,
                                                    cv2.RETR_LIST,
                                                    cv2.CHAIN_APPROX_SIMPLE)
    cv2.imshow("origin",img)
    n=len(contours)
    contoursImg=[]
    '''
    retval =cv2.contourArea(contour [, oriented] ))
    参数说明:
        contour 是轮廓。
        oriented 是布尔型值。当它为 True 时,返回的值包含正/负号,用来表示轮廓是顺时针还是逆时针的。
                            该参数的默认值是 False,表示返回的 retval 是一个绝对值。
    
    retval = cv2.arcLength( curve, closed )
    参数说明:
        curve 是轮廓。
        closed 是布尔型值,用来表示轮廓是否是封闭的。该值为 True 时,表示轮廓是封闭的。
    '''
    for i in range(n):
        print("contours["+str(i)+"]面积=",cv2.contourArea(contours[i]))
        print("contours["+str(i)+"]长度=",cv2.arcLength(contours[i],True))
        temp=np.zeros(img.shape,np.uint8)
        contoursImg.append(temp)
        contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,255,255),3)
        cv2.imshow("contours[" + str(i)+"]",contoursImg[i])
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    contours[0]面积= 11529.5
    contours[0]长度= 455.4385987520218
    contours[1]面积= 8953.5
    contours[1]长度= 413.2964633703232
    contours[2]面积= 9842.5
    contours[2]长度= 371.2619733810425
    contours[3]面积= 14160.5
    contours[3]长度= 475.41421353816986
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Hu 矩

    • Hu 矩是归一化中心矩的线性组合。Hu 矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性,所以经常会使用 Hu 距来识别图像的特征。
    • 在 OpenCV 中,使用函数 cv2.HuMoments()可以得到 Hu 距。该函数使用 cv2.moments()函数的返回值作为参数,返回 7 个 Hu 矩值。
    • Hu 矩是归一化中心矩的线性组合,每一个矩都是通过归一化中心矩的组合运算得到的。
    • 函数 cv2.moments()返回的归一化中心矩中包含:
      • 二阶 Hu 矩:nu20, nu11, nu02
      • 三阶 Hu 矩:nu30, nu21, nu12, nu03
    • 为了表述上的方便,将上述字母“nu”表示为字母“v”,则归一化中心矩为:
      • 二阶 Hu 矩:v20, v11, v02
      • 三阶 Hu 矩:v30, v21, v12, v03
    • 上述 7 个 Hu 矩的计算公式为:
      在这里插入图片描述
    验证 h 0 = n u 20 + n u 02 = v 20 + v 02 h_0=nu_{20}+nu_{02}=v_{20}+v_{02} h0=nu20+nu02=v20+v02
    import cv2
    img = cv2.imread('10.jpg')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    '''
    hu = cv2.HuMoments( m )
    参数:
        m,是由函数 cv2.moments()计算得到矩特征值。
    返回值:
        hu,表示返回的 Hu 矩值。
    '''
    HuM1=cv2.HuMoments(cv2.moments(gray)).reshape(-1,)
    print("cv2.moments(gray)=\n",cv2.moments(gray))
    print("\nHuM1=\n",HuM1)
    print("\ncv2.moments(gray)['nu20']+cv2.moments(gray)['nu02']=%f+%f=%f\n"
            %(cv2.moments(gray)['nu20'],cv2.moments(gray)['nu02'],cv2.moments(gray)['nu20']+cv2.moments(gray)['nu02']))
    print("HuM1[0]=",HuM1[0])
    print("\nHu[0]-(nu02+nu20)=",
            HuM1[0]-(cv2.moments(gray)['nu20']+cv2.moments(gray)['nu02']))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    cv2.moments(gray)=
     {'m00': 10984711.0, 'm10': 2073419806.0, 'm01': 1727047846.0, 'm20': 511135534408.0, 'm11': 331060890119.0, 'm02': 363947136528.0, 'm30': 144117116068876.0, 'm21': 83257440040473.0, 'm12': 70594257720405.0, 'm03': 87457550994094.0, 'mu20': 119767050347.46558, 'mu11': 5071866847.833557, 'mu02': 92415708675.84805, 'mu30': 2424422543738.1875, 'mu21': 980560651950.082, 'mu12': 302566419319.2676, 'mu03': 1177008938055.9062, 'nu20': 0.0009925675733482376, 'nu11': 4.203301788676019e-05, 'nu02': 0.0007658937531944091, 'nu30': 6.062290242573147e-06, 'nu21': 2.4519006754501144e-06, 'nu12': 7.565700361543787e-07, 'nu03': 2.9431213709124163e-06}
    
    HuM1=
     [ 1.75846133e-03  5.84481191e-08  3.38545321e-11  7.56031184e-11    
      1.57210638e-21  1.01272182e-14 -3.48686093e-21]
    
    cv2.moments(gray)['nu20']+cv2.moments(gray)['nu02']=0.000993+0.000766=0.001758
    
    HuM1[0]= 0.0017584613265426467
    
    Hu[0]-(nu02+nu20)= 0.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    Hu矩的应用:形状匹配
    • 通过 Hu 矩来可以判断两个对象的一致性。为了更直观方便地比较 Hu 矩值,OpenCV 提供了函数 cv2.matchShapes(),对两个对象的 Hu 矩进行比较。
    • 函数 cv2.matchShapes()允许我们提供两个对象,对二者的 Hu 矩进行比较。这两个对象可以是轮廓,也可以是灰度图。
    import cv2
    img1 = cv2.imread('11.jpg')
    img2 = cv2.imread('12.jpg')
    img3 = cv2.imread('13.jpg')
    gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
    gray3 = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
    ret, binary1 = cv2.threshold(gray1,127,255,cv2.THRESH_BINARY)
    ret, binary2 = cv2.threshold(gray2,127,255,cv2.THRESH_BINARY)
    ret, binary3 = cv2.threshold(gray3,127,255,cv2.THRESH_BINARY)
    image,contours1, hierarchy = cv2.findContours(binary1,
                                                    cv2.RETR_LIST,
                                                    cv2.CHAIN_APPROX_SIMPLE)
    image,contours2, hierarchy = cv2.findContours(binary2,
                                                    cv2.RETR_LIST,
                                                    cv2.CHAIN_APPROX_SIMPLE)
    image,contours3, hierarchy = cv2.findContours(binary3,
                                                    cv2.RETR_LIST,
                                                    cv2.CHAIN_APPROX_SIMPLE)
    cnt1 = contours1[0]
    cnt2 = contours2[0]
    cnt3 = contours3[0]
    ret0 = cv2.matchShapes(cnt1,cnt1,1,0.0)
    ret1 = cv2.matchShapes(cnt1,cnt2,1,0.0)
    ret2 = cv2.matchShapes(cnt1,cnt3,1,0.0)
    print("相同图像的 matchShape=",ret0)
    print("相似图像的 matchShape=",ret1)
    print("不相似图像的 matchShape=",ret2)
    cv2.imshow("img1",img1)
    cv2.imshow("img2",img2)
    cv2.imshow("img3",img3)
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    相同图像的 matchShape= 0.0
    相似图像的 matchShape= 0.0006734369574569188
    不相似图像的 matchShape= 0.12010013449803147
    
    • 1
    • 2
    • 3
    • 从结果上看:
      • 同一幅图像的 Hu 矩是不变的,二者差值为 0。
      • 相似的图像即使发生了平移、旋转和缩放后,函数 cv2.matchShapes()的返回值仍然比较接近。
        • 例如,图像 img1 和图像 img2,img2 是对 img1 经过缩放、旋转和平移后得到的,但是对二者应用 cv2.matchShapes()函数后,返回值的差较小。
      • 不相似图像 cv2.matchShapes()函数返回值的差较大。
        • 例如,图像 img1 和图像 img3 的差别较大,因此对二者应用 cv2.matchShapes()函数后,返回值的差也较大。

    参考文献

    [1] https://opencv.org/
    [2] 李立宗. OpenCV轻松入门:面向Python. 北京: 电子工业出版社,2019

  • 相关阅读:
    教你用JavaScript实现随机点名
    Python自动化办公(二) —— 查看文件夹中的PDF文件数量
    Vue 官方文档2.x教程学习笔记 1 基础 1.4 模板语法 1.4.2 指令
    植物大战僵尸植物表(二)
    web:[极客大挑战 2019]Havefun
    day53|1143.最长公共子序列、1035.不相交的线、53. 最大子序和
    Flask狼书笔记 | 05_数据库
    aspectj切面织入
    ES 架构及基础 - 1
    Python 导包八种方法
  • 原文地址:https://blog.csdn.net/FriendshipTang/article/details/126394301