使用 OpenCV 测量物体尺寸

使用 OpenCV 测量物体尺寸

你是否曾经遇到过这样的问题:想要知道计算器的精确尺寸,但手头又没有专业的测量工具?别担心,今天我们就来教大家一个简单又实用的方法,通过一张A4纸就能估算出计算器的宽度和高度,精确到毫米哦!

该算法的主要思想其实非常简单。请看下面图 1 中我们要处理的样本图像。

图 1.本教程中使用的示例图像。

本教程的目的是估算计算器的宽度和高度(以毫米为单位)。为此,我们需要一个已知尺寸的物体作为参考长度。这基本上就是我们使用白纸作为对象背景的原因。纸张尺寸为 A4,这意味着它的宽度和高度分别为 210 毫米和 297 毫米。然后,我们可以借助这些数字获得估计的计算器尺寸。

在开始之前,我们这篇文章分为几个章节:

  1. 导入模块和参数初始化

  2. 图像加载和预处理

  3. 寻找纸张轮廓

  4. 透视变换

  5. 寻找物体轮廓

  6. 边长计算

  7. 将所有内容放在一个函数中

现在,我们从第一个开始。

1. 导入模块及参数初始化

和其他 Python 项目一样,我要做的第一件事就是导入所有必需的模块。在本例中,我们的大部分工作将使用 和 来完成cv2numpymatplotlib仅用于显示图像。

# 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_c

<think>好的,我现在需要帮用户解决如何使用C#和OpenCV测量图像中物体尺寸的问题。首先,我得仔细看看用户提供的引用内容,特别是引用[1]和[2],里面提到了Python的示例,而用户需要的是C#的实现。还有引用[3]是关于C#和OpenCVSharp运动检测的,可能相关。 用户的问题是要在C#中用OpenCV实现物体尺寸测量,所以首先我需要确定OpenCV的C#库是什么。通常,OpenCVSharp是常用的,所以应该用这个库。接着,参考Python代码的逻辑,转换成C#。 根据引用[1],步骤包括检测物体轮廓,计算像素与真实尺寸的比例,然后测量物体尺寸。引用[2]中的convert_to_mm函数通过缩放比例将像素转换为毫米,这可能在C#中也需要类似处理。 首先,用户需要加载图像,预处理(比如灰度化、二值化),然后找轮廓。在C#中,使用OpenCVSharp的话,可以用Cv2.FindContours方法。找到最大轮廓后,计算最小外接矩形,得到像素宽度和高度。 然后确定参考物体的实际尺寸,比如用户可能使用A4纸作为参照,引用[2]中的PAPER_H和PAPER_W可能就是A4的尺寸(比如297mm和210mm)。通过已知的参照物在图像中的像素尺寸计算出每个像素对应的实际长度(pixelsPerMetric)。 之后,对于检测到的物体,用像素尺寸乘以这个比例,得到实际尺寸。显示的时候,用Cv2.PutText将尺寸标注在图像上。 需要注意的是,C#的语法和OpenCVSharp的方法可能与Python不同,比如轮廓处理需要用到轮廓数组,而C#中返回值可能是一个数组。此外,绘制轮廓和矩形的函数参数也可能稍有不同。 可能遇到的难点包括正确找到物体的轮廓,处理图像预处理步骤(如高斯模糊、阈值处理)的参数调整,以及确保参考物体的比例计算准确。此外,图像可能存在透视变形,引用[2]中的img_warped可能进行了透视校正,所以用户是否需要先进行透视校正?如果用户拍摄的物体不在同一平面上,可能需要先做这一步,但问题中没有提到,可能暂时忽略,先处理简单情况。 另外,代码示例需要测试,可能用户在实际运行时需要调整参数,比如高斯模糊的核大小,阈值处理的参数,以及轮廓筛选的条件(比如面积大小)。 最后,生成相关问题时要考虑用户可能的后续疑问,比如如何处理多个物体,如何提高精度,或者如何处理非矩形物体等。</think>以下是使用C#和OpenCVSharp实现物体尺寸测量的完整步骤和代码示例: ### 实现原理 1. **图像预处理**:通过边缘检测和轮廓分析定位物体 2. **比例计算**:使用已知尺寸的参照物建立像素-实际尺寸比例关系$ \text{pixelsPerMetric} = \frac{\text{参照物像素宽度}}{\text{实际宽度}} $ 3. **尺寸转换**:根据检测到的物体像素尺寸计算实际物理尺寸 ### 完整代码实现 ```csharp using OpenCvSharp; using System.Linq; public class SizeMeasurement { public static void MeasureObject(string imagePath) { // 读取图像 using var src = new Mat(imagePath); // 预处理流程 var gray = new Mat(); Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); Cv2.GaussianBlur(gray, gray, new Size(7, 7), 0); Cv2.Threshold(gray, gray, 60, 255, ThresholdTypes.Binary); // 查找轮廓 Cv2.FindContours(gray, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); // 选择最大轮廓 var maxContour = contours.OrderByDescending(c => Cv2.ContourArea(c)).First(); // 获取最小外接矩形 var rect = Cv2.MinAreaRect(maxContour); var boxPoints = Cv2.BoxPoints(rect).Select(p => new Point((int)p.X, (int)p.Y)).ToArray(); // 计算像素尺寸 double pixelWidth = rect.Size.Width; double pixelHeight = rect.Size.Height; // 建立比例关系(假设已知参照物实际尺寸) const double refWidthMm = 210; // A4纸宽度 double pixelsPerMetric = pixelWidth / refWidthMm; // 转换实际尺寸 double actualWidth = pixelWidth / pixelsPerMetric; double actualHeight = pixelHeight / pixelsPerMetric; // 绘制测量结果 Cv2.DrawContours(src, new[] { boxPoints }, -1, new Scalar(0, 255, 0), 2); Cv2.PutText(src, $"{actualWidth:0.0}mm", new Point((int)boxPoints[0].X, (int)boxPoints[0].Y - 10), HersheyFonts.HersheySimplex, 0.6, new Scalar(255, 0, 0), 1); Cv2.PutText(src, $"{actualHeight:0.0}mm", new Point((int)boxPoints[1].X + 10, (int)boxPoints[1].Y), HersheyFonts.HersheySimplex, 0.6, new Scalar(255, 0, 0), 1); Cv2.ImShow("Measurement Result", src); Cv2.WaitKey(0); } } ``` ### 关键步骤说明 1. **图像预处理**:通过高斯模糊(GaussianBlur)和阈值处理(Threshold)增强边缘特征[^3] 2. **轮廓分析**:使用FindContours获取物体轮廓,通过MinAreaRect获取物体最小包围矩形[^1] 3. **比例计算**:基于参照物建立像素到实际尺寸的转换关系,如A4纸的已知尺寸[^2] 4. **尺寸转换**:根据检测到的像素尺寸和比例系数计算实际物理尺寸 ### 使用建议 1. 拍摄时需要保证相机与物体平面平行 2. 在画面中放置已知尺寸的参照物(如信用卡、A4纸) 3. 调整高斯模糊参数(Size(7,7))适应不同图像分辨率 4. 通过修改阈值参数(60)优化二值化效果
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack_pirate

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值