使用 OpenCV 测量物体尺寸
你是否曾经遇到过这样的问题:想要知道计算器的精确尺寸,但手头又没有专业的测量工具?别担心,今天我们就来教大家一个简单又实用的方法,通过一张A4纸就能估算出计算器的宽度和高度,精确到毫米哦!
该算法的主要思想其实非常简单。请看下面图 1 中我们要处理的样本图像。
图 1.本教程中使用的示例图像。
本教程的目的是估算计算器的宽度和高度(以毫米为单位)。为此,我们需要一个已知尺寸的物体作为参考长度。这基本上就是我们使用白纸作为对象背景的原因。纸张尺寸为 A4,这意味着它的宽度和高度分别为 210 毫米和 297 毫米。然后,我们可以借助这些数字获得估计的计算器尺寸。
在开始之前,我们这篇文章分为几个章节:
-
导入模块和参数初始化
-
图像加载和预处理
-
寻找纸张轮廓
-
透视变换
-
寻找物体轮廓
-
边长计算
-
将所有内容放在一个函数中
现在,我们从第一个开始。
1. 导入模块及参数初始化
和其他 Python 项目一样,我要做的第一件事就是导入所有必需的模块。在本例中,我们的大部分工作将使用 和 来完成cv2
,numpy
而matplotlib
仅用于显示图像。
# Codeblock 1``import cv2``import numpy as np``import matplotlib.pyplot as plt
由于模块已导入,我们将初始化一些参数,这些参数是未来计算所需的,您可以在下面的 Codeblock 2 中看到。变量SCALE
主要用于我们不希望生成的图像太小。同时,和PAPER_W
表示PAPER_H
纸张宽度和高度(以毫米为单位)。
# Codeblock 2``SCALE = 3``PAPER_W = 210 * SCALE``PAPER_H = 297 * SCALE
就这样。第一章到此结束,因为这部分没有什么可说的了。
2.图像加载和预处理
之后,我们将创建一个名为和的函数load_image()
,show_image()
我认为这两个函数的名称是不言自明的。它们的详细信息可以在 Codeblock 3 中看到。您可以在下面看到我定义了参数scale
(小写),其中我的目的是使输入图像变得有点小,因为原始图像分辨率非常高。但是,从技术上讲,您也可以通过传递大于 1 的值来使其更大。
show_image()
另一方面,该函数实现cv2.cvtColor()
了将颜色通道从 BGR 转换为 RGB 的功能。这种转换是必要的,因为 Matplotlib 在颜色通道顺序方面与 OpenCV 的工作方式不同。
# Codeblock 3``def load_image(path, scale=0.7):
img = cv2.imread(path)
img_resized = cv2.resize(img, (0,0), None, scale, scale)``return img_resized`` ``def show_image(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(6,8))
plt.xticks([])
plt.yticks([])
plt.imshow(img)
plt.show()
由于上面的两个函数已经初始化,现在我们可以使用它来实际加载图像。这里我决定将参数保留scale
为其默认值(0.7),这将导致加载的图像大小为 1120×840 px(原始大小为 1600×1200 px)。
# Codeblock 4``img_original = load_image(path='images/1.jpeg')``show_image(img_original)``print(img_original.shape)
图 2. 要处理的图像尺寸为 1120 x 840 像素。
我上面显示的图像存储在 中img_original
。接下来要做的步骤是使用一系列图像处理技术对该图像进行预处理,即灰度转换(#1
)、模糊(#2
)、Canny 边缘检测(#3
)、扩张(#5
)和闭合(#6
)。所有这些步骤都包含在preprocess_image()
Codeblock 5 中的函数中。
# Codeblock 5``def preprocess_image(img, thresh_1=57, thresh_2=232):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #1
img_blur = cv2.GaussianBlur(img_gray, (5,5), 1) #2
img_canny = cv2.Canny(img_blur, thresh_1, thresh_2) #3``
kernel = np.ones((3,3)) #4
img_dilated = cv2.dilate(img_canny, kernel, iterations=1) #5
img_closed = cv2.morphologyEx(img_dilated, cv2.MORPH_CLOSE,`` kernel, iterations=4) #6``
img_preprocessed = img_closed.copy()``
img_each_step = {'img_dilated': img_dilated,
'img_canny' : img_canny,
'img_blur' : img_blur,