根据上一篇博客可知,单纯的通过求取最大面积而进行定位的局限性,因此我们接下来将通过cv2.moments()和cv2.HuMoments()这两个方法来在更复杂的环境中去找到我们的目标区域。

cv2.moments():

参数:

  • array:表示输入图像的单通道数组。通常是灰度图像,可以是8位或浮点型。
  • binaryImage:一个可选参数,如果设置为 True,则将 array 视为二进制图像。默认为 False。

返回值:

  • moments:一个包含图像矩特征信息的字典对象。这些矩包括图像的原始矩、中心矩以及一些其他相关的信息。您可以使用这些矩特征来描述图像的几何形状和分布情况。

cv2.HuMoments():

参数:

  • moments:一个字典对象,包含通过cv2.moments()函数计算得到的图像矩特征。

返回值:

  • huMoments:一个包含7个不变矩特征值的一维数组。这些特征值对图像的形状、轮廓和几何特征进行了描述。通常用于图像识别和匹配。

  简易的介绍一下moments(矩)这个东西,它是用来描述一个形状的特性,比如说正方形,我们能分辨出来是因为知道其四个边是相等的,这便是在我们的认知中所知的正方形的轮廓特性,

而在计算机中呈现的就是一组数据,通过和这组数据进行比对,我们就可以较为准确的去寻找我们的目标区域。

  但是相较于上一篇博客的直接在输入图像中查找,使用矩我们需要事先获取目标的完整轮廓,并保存其矩特性数据。

图像准备,一张没有完整的只有barcode的图像

Code:

 1 import cv2 2 import numpy 3  4 img = cv2.imread('../images/barcode.jpg') 5 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 kernel_x = numpy.array( 7     [ 8         [-1, 0, 1], 9         [-2, 0, 2],10         [-1, 0, 1]11     ]12 )13 sobel_x = cv2.filter2D(gray, -1, kernel_x)14 _, thresh = cv2.threshold(sobel_x, 127, 255, cv2.THRESH_BINARY)15 kernel_ed = numpy.ones((3, 3), dtype=numpy.uint8)16 img_d = cv2.dilate(thresh, kernel_ed, iterations=6)17 contours, hir = cv2.findContours(img_d, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)18 print(cv2.HuMoments(cv2.moments(contours[0])))19 cv2.drawContours(img, contours, -1, (0, 255, 0), 3)20 cv2.imshow('', img)21 cv2.waitKey()22 cv2.destroyAllWindows()

Result:

我就直接和上一篇博客的barcode的轮廓矩特性进行对比:

    只有barcode图       包含其他图形的barcode图

通过对比数据我们可以发现,在第1不变矩中,数据是最接近的,这个时候就可以利用这个特性数据来进行轮廓特征比对寻找目标区域。

当然因为OpenCV提供了一个方法为我们减免了比较的操作cv2.matchShapes()方法。

cv2.matchShapes()

参数:

  • contour1:第一个轮廓,通常是一个包含点集的 NumPy 数组。
  • contour2:第二个轮廓,也是一个包含点集的 NumPy 数组。
  • method:表示相似性度量方法的整数值。可以是 1、2 或 3,分别代表不同的计算方法。

返回值:

  • match:一个表示两个轮廓之间相似性的浮点数值。该值越小表示两个轮廓形状越相似。

至此,当我们所得到的图像源包含了其他复杂的图形时,我们则可以使用矩特性来进一步提高我们的检测能力,但是还有其他更为复杂的场景,所以还需要优化我们的解决思路。