利用 OpenVINO™ 工具套件进行智能仪表扫描:AI目标检测和语义分割

查看所有边缘 AI 参考套件

author-image

作者

概述

在本教程中,了解如何按照 Jupyter* Notebook 的指示使用 OpenVINO™ 工具套件来构建智能仪表扫描应用。查看实际基准测试数据,并能够按照自己的设置执行真实世界基准测试。

利用 OpenVINO™ 工具套件,您可以使用目标检测、数字仪表 OCR 和指针类仪表分段,开发基于 AI 的应用以通过数字方式读取工业仪表。OpenVINO™ 工具套件可最大限度地缩短处理输入数据以输出预测所需的时间。决策速度更快,系统交互也更加高效。这有助于利用计算机视觉来读取仪表,最大限度地减少错误,并实现更高精度。

在能源使用等领域,手动检查模拟仪表的结果并不准确,而升级到数字仪表又成本高昂。利用此应用提供的实时数据,公司能够主动识别需要改进和确保安全的区域,甚至通过异常使用模式来检测潜在的设备故障。

此外,该解决方案还可应用于任何需要通过目标检测和语义分割将模拟数据转换为数字数据的情况。

必备条件

第 1 步:克隆存储库

要将智能仪表扫描存储库克隆到您的系统,请使用以下命令:

git clone -b recipes https://github.com/openvinotoolkit/openvino_notebooks.git

这会将该存储库克隆到 openvino_notebooks 文件夹中。接下来,导航到该文件夹:

cd openvino_notebooks/recipes/meter_reader

此应用使用 python 为该项目设置虚拟环境。如果未安装虚拟环境程序包,请运行以下命令:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3-ven

如果采用搭载英特尔® 集成显卡的 CPU,要在此设备上启用推理,请安装英特尔® Graphics Compute Runtime for oneAPI Level Zero and OpenCL™ Driver。用于 Ubuntu* 20.04 的命令如下:

sudo apt-get install intel-opencl-icd

接下来,准备您的虚拟环境。

第 2 步:创建并激活虚拟环境

为避免在系统上造成全局影响,最佳做法是将 Python 项目隔离在它自己的环境中。要设置虚拟环境,请打开终端或命令提示符,然后导航到要建立环境的目录。然后,运行以下命令以创建新的虚拟环境: 

对于基于 UNIX* 的操作系统,例如 Linux* 或 macOS*,请使用:

python3 -m venv venv

对于 Windows*,请使用:

python -m venv venv

这会在当前文件夹中创建新的虚拟环境 venv。下面激活您刚刚创建的环境。所使用的命令因操作系统而异。 

对于基于 UNIX 的操作系统,例如 Linux 或 macOS,请使用:

source venv/bin/activate

对于 Windows,请使用:

 venvScriptsactivate

这会激活虚拟环境,并更改 Shell 提示符,以表明这一点。

第 3 步:安装所需组件

智能仪表扫描应用具有许多依赖项,必须安装这些依赖项才能运行该应用。包含的需求文件中列出了这些依赖项,可以使用 Python 程序包安装程序进行安装。 

要安装所需 Python 库,包括 OpenVINO™ 工具套件,请使用以下命令:

python -m pip install --upgrade pip 

pip install -r requirements.txt

现在已安装所有依赖项和所需组件。接下来,您将准备模型并配置应用。

第 4 步:准备模型

用于仪表读取器解决方案的模型包括检测和分割模型。可以使用 PyTorch* 或 TensorFlow* 等任何 AI 训练框架创建这些模型。在此示例中,要从 PaddlePaddle* 下载预训练模型,请使用以下命令:

cd model

sudo sh ./download_pdmodel.sh

第 5 步:配置智能仪表扫描应用

该项目的测试图像包含不同类型的工业仪表,需要预先定义这些仪表的参数才能计算最终读数。这些参数包括仪表的范围、刻度间隔值和单位,并可以按以下方式进行配置:

"meter_config": [

 {

 "scale_interval_value": 0.5,

 "range": 25.0,

 "unit": "(MPa)"

 },

 {

 "scale_interval_value": 0.05,

 "range": 1.6,

 "unit": "(MPa)"

 }

	],

除仪表上的配置以外,还需要定义模型参数,包括模型文件路径、输入形状、标准化参数和颜色格式。这些参数在每个模型的预处理步骤中实现:

"model_config": {

 "detector": {

 "model_path": "./model/meter_det_model/model.pdmodel",

 "device": "CPU",

 "input_shape": 608,

 "model_shape": {"image": [1, 3, 608, 608], "im_shape": [1, 2], "scale_factor": [1, 2]},

 "scale": 255,

 "color_format": "bgr",

 "mean": [

 0.485,

 0.456,

 0.406

 ],

 "std": [

 0.229,

 0.224,

 0.225

 ]

 },

 "segmenter": {

 "model_path": "./model/meter_seg_model/model.pdmodel",

 "device": "CPU",

 "batch_size": 2,

 "input_shape": 512,

 "model_shape": {"image": [-1, 3, 512, 512]},

 "scale": 255,

 "color_format": "bgr",

  "mean": [

 0.5,

 0.5,

 0.5

 ],

 "std": [

 0.5,

 0.5,

 0.5

 ]

 }

 } 

可以在 config/config.json 文件夹中找到这些参数。对于其他使用不同仪表和模型的场景,需要对这些值做出相应调整。

第 6 步:了解预处理和后处理

模拟仪表读取可以分为预处理(进行图像格式化以检测和分割仪表)和后处理(处理数据以输出最终仪表读数)两部分。

应用首先会对图像进行预处理。该过程包括布局转位、标准化和调整图像大小,以符合模型的输入要求。然后,该图像即准确就绪,可以用于对象检测模型,目标是检测图像中的所有仪表。

def detect(self, input):  

 # Prepare the input data for meter detection model 

 im_shape = np.array([[self.input_shape, self.input_shape]]).astype('float32') 

 scale_factor = np.array([[1, 2]]).astype('float32') 

 input_image = self.det_preprocess(input, self.input_shape) 

 inputs_dict = {'image': input_image, "im_shape": im_shape, "scale_factor": scale_factor} 

 # Run meter detection model 

 det_results = self.det_compiled_model(inputs_dict)[self.det_output_layer] 

 # Filter out the bounding box with low confidence 

 filtered_results = self.filter_bboxes(det_results, self.score_threshold) 

 # Prepare the input data for meter segmentation model 

 scale_x = input.shape[1] / self.input_shape * 2 

 scale_y = input.shape[0] / self.input_shape 

 # Create the individual picture for each detected meter 

 roi_imgs, self.loc = self.roi_crop(input, filtered_results, scale_x, scale_y)  

 roi_imgs, resize_imgs = self.roi_process(roi_imgs, self.METER_SHAPE) 

 # Create the pictures of detection results 

 roi_stack = np.hstack(resize_imgs) 

 cv2.imwrite("./data/detection_results.jpg", roi_stack) 

 return roi_imgs 

此外还会过滤掉置信度较低的检测结果,并返回相关感兴趣区域 (ROI)。然后对这些图像进行裁剪和进一步处理,以便分割。

def roi_crop(image, results, scale_x, scale_y): 

 roi_imgs = [] 

 loc = [] 

 for result in results: 

 bbox = result[2:] 

 xmin, ymin, xmax, ymax = [int(bbox[0] * scale_x), int(bbox[1] * scale_y), int(bbox[2] * scale_x), int(bbox[3] * scale_y)] 

 sub_img = image[ymin:(ymax + 1), xmin:(xmax + 1), :] 

 roi_imgs.append(sub_img) 

 loc.append([xmin, ymin, xmax, ymax]) 

 return roi_imgs, loc 

在此情况下,可能在照片中检测到的仪表数量为任意数目,意味着分割模型的输入形状可能因批次大小而异。这称为动态形状。有一些方法可用于处理任意大小的输入,例如填充、模型重塑和多个预编译模型。 

OpenVINO™ 工具套件具有的优势之一,在于它允许通过动态形状将数据直接加载到 OpenVINO 运行时。如果可以预测图片中仪表的最大数量,强烈建议通过范围维度设置输入数据大小上限,由于内存消耗较低,这提供更好的推理性能。

def segment(self, input):  

 seg_results = list() 

 num_imgs = len(input) 

 image_list = list() 

 # Run meter segmentation model on all detected meters 

 for i in range(0, num_imgs, self.seg_batch_size): 

 batch = input[i : min(num_imgs, i + self.seg_batch_size)] 

 seg_result = self.seg_compiled_model({"image": np.array(batch)})[self.seg_output_layer] 

 seg_results.extend(seg_result) 

 results = [] 

 for i in range(len(seg_results)): 

 results.append(np.argmax(seg_results[i], axis=0))  

 seg_results = self.erode(results, self.erode_kernel) 

 # Create the pictures of segmentation results 

 for i in range(len(seg_results)): 

  image_list.append(self.segmentation_map_to_image( 

	 seg_results[i], self.COLORMAP)) 

 # Create the pictures of segmentation results 

 mask_stack = np.hstack(image_list) 

 cv2.imwrite("./data/segmentation_results.jpg", cv2.cvtColor(mask_stack, cv2.COLOR_RGB2BGR)) 

 return seg_results 

进行分割后,就已经完成预处理,然后会将结果馈送给后处理。检测并分割仪表后,必须处理并返回最终仪表读数。这包括对刻度和指针二值化,以计算指针在刻度图中的位置,从而返回最终仪表读数。

def postprocess(self, input): 

 # Find the pointer location in scale map and calculate the meters reading  

 rectangle_meters = self.circle_to_rectangle(input) 

 line_scales, line_pointers = self.rectangle_to_line(rectangle_meters) 

 binaried_scales = self.mean_binarization(line_scales) 

 binaried_pointers = self.mean_binarization(line_pointers) 

 scale_locations = self.locate_scale(binaried_scales) 

 pointer_locations = self.locate_pointer(binaried_pointers) 

 pointed_scales = self.get_relative_location(scale_locations, pointer_locations) 

 meter_readings = self.calculate_reading(pointed_scales) 

还可以按以下方式显示后处理管道: 

管道流程图

 

 

第 7 步:运行智能仪表扫描应用

了解预处理和后处理之后,现在您可以运行该应用并获取最终仪表读数。

要加载并编译深度学习模型以用于仪表检测和仪表分割,请使用以下代码:

# Loading and compiling for meter detection: 

self.det_model = ie_core.read_model(det_model_path) 

self.det_model.reshape(det_model_shape) 

self.det_compiled_model = ie_core.compile_model( 

model=self.det_model, device_name=self.config["model_config"] 

	["detector"]["device"]) 

self.det_output_layer = self.det_compiled_model.output(0) 

 

# Loading and compiling for meter segmentation: 

 self.seg_model = ie_core.read_model(seg_model_path) 

self.seg_model.reshape(seg_model_shape) 

self.seg_compiled_model = ie_core.compile_model( 

model=self.seg_model, device_name=self.config["model_config"] 

	["segmenter"]["device"]) 

self.seg_output_layer = self.seg_compiled_model.output(0) 

注意:在用于运行推理的 device_name 中,可以指定您的设备首选项或将其设置为 AUTO,以便 OpenVINO™ 工具套件从可用硬件设备中为您选择最佳推理设备。 

要运行该应用,请使用以下命令。确保用配置文件和测试图像的路径替换 config/config.jsondata/test.jpg。结果图像将导出到与测试图像相同的文件夹。

python main.py -i data/test.jpg -c config/config.json -t "analog"

运行该应用所需的输入参数包括: 

  • -i:输入图像(即由实时摄像头捕获的工业仪表图像)的路径 
  • -c:配置文件的路径,其中包括模型推理、预处理和后处理步骤所需的参数。 
  • -t:从 analogdigital 中进行选择,以实现模拟或数字工业仪表的自动仪表读数。 

现在,您已获得了仪表读数。

第 8 步:使用 Benchmark_App 进行性能基准测试

要评估仪表读取器管道中的模型的性能,请使用 OpenVINO™ 工具套件 Benchmark_App。此步骤有助于深入了解模型的真实世界性能,便于您规划部署。

建议使用采用 Ultralytics 框架的全新已训练 YOLOv8l 模型。(GPU 当前不支持 PPYOLOv2。) 可以从 GitHub* 中的同一存储库进行下载。 

要通过 YOLO v8l 管道运行此应用,请使用以下命令将默认配置文件切换为 ./config/yolov8.json

python main.py -i data/test.jpg -c config/yolov8.json 

  -t "analog"

要在英特尔® Developer Cloud 或本地计算机上运行 Benchmark_App,请参阅以下示例:

!python benchmark_app -m ./model/yolov8.onnx  

	 -shape [1, 3, 608, 608]  

            -d $DEVICE  

            -niter 50  

            -hint $PERF_HINT  

            --report_type detailed_counters  

            --report_folder ${SAMPLEPATH}/${OUTPUT_FILE}/${JOB_ID} 

 

!python benchmark_app -m ./model/deeplabv3+.onnx  

	 -shape [1, 3, 512, 512]  

            -d $DEVICE  

            -niter 50  

            -hint $PERF_HINT  

            --report_type detailed_counters  

            --report_folder ${SAMPLEPATH}/${OUTPUT_FILE}/${JOB_ID}

在这里,测试了在 Ultralytics 管道中训练的 YOLO v8l 的仪表检测性能,测试了在 PyTorch 框架中训练的 DeepLabv3+ 的仪表分割性能。

总结

您已了解如何使用 OpenVINO™ 来创建智能仪表扫描应用,该应用将使用计算机视觉进行目标检测和语义分割,以读取模拟工业仪表。这为手动检测提供了可靠、可扩展的替代方案,可提高准确度、时效性和安全性。 

在能源或制造等任何依赖模拟仪表的行业中,都有大量仪表需要持续检查读数,以确保持续运营和安全。这些仪表可能具有多种类型,散布在不同物理位置,并处于恶劣工作条件下。

利用 AI 推理,可以创建智能应用对可视数据执行实时分析,以获取宝贵洞察并改善业务运营。OpenVINO 可确保以较低延迟高效完成该流程。

如有任何问题或想要发表意见,请加入 GitHub英特尔社区支持频道上的讨论。欲了解使用 OpenVINO™ 工具套件进行开发的更多信息,请参阅此文档。 

 

有关性能基准测试的更多详细信息,请访问 GitHub