OpenCV 图像处理学习手册:1~5 您所在的位置:网站首页 qt按钮立体效果 OpenCV 图像处理学习手册:1~5

OpenCV 图像处理学习手册:1~5

2023-04-30 11:56| 来源: 网络整理| 查看: 265

一、处理图像和视频文件

本章旨在与 OpenCV,其安装和第一个基本程序进行首次接触。 我们将涵盖以下主题:

面向新手的 OpenCV 简介,然后是简单的分步安装库指南在用户本地磁盘中安装后快速浏览 OpenCV 的结构使用带有一些常见编程框架的库创建项目的快速秘籍如何使用函数读取和写入图像和视频最后,我们描述了用于向软件项目添加丰富的用户界面的库函数,包括鼠标交互,绘图基元和 Qt 支持OpenCV 简介

OpenCV(开源计算机视觉)最初是由英特尔开发的,它是一个免费跨平台库,用于实时图像处理,实际上已经成为用于与计算机视觉相关的所有事物的标准工具。 第一个版本于 2000 年以 BSD 许可证发行,此后,其功能得到了科学界的极大丰富。 2012 年,非营利组织 OpenCV.org 承担了为开发人员和用户维护支持网站的任务。

注意

在撰写本书时,OpenCV 的新主要版本(版本 3.0)可用,但仍处于 beta 状态。 在整本书中,我们将介绍此新版本带来的最相关的更改。

OpenCV 适用于最流行的操作系统,例如 GNU/Linux,OSX,Windows,Android,iOS 等。 第一个实现是在C编程语言中实现的; 但是,随着版本 2.0 的 C++ 实现,它的受欢迎程度随之增加。 新功能使用 C++ 编程。 但是,如今,该库具有其他编程语言(例如 Java,Python 和 MATLAB/Octave)的完整接口。 另外,还开发了用于其他语言(例如 C#,Ruby 和 Perl)的包装程序,以鼓励程序员采用。

为了最大程度地提高计算密集型视觉任务的性能,OpenCV 包括对以下内容的支持:

使用线程构建模块(TBB)在多核计算机上进行多线程处理-由 Intel 开发的模板库。英特尔处理器上的集成性能基元(IPP)的子集,以提高性能。 多亏了 Intel,这些原语可从 3.0 beta 版开始免费获得。使用计算统一设备架构(CUDA)和开放计算语言(OpenCL)。

OpenCV 的应用涵盖以下领域:分段和识别,2D 和 3D 功能工具包,对象识别,人脸识别,运动跟踪,手势识别,图像拼接,高动态范围(HDR)成像,增强现实等等。 此外,为了支持某些先前的应用领域,还包括具有统计机器学习功能的模块。

下载并安装 OpenCV

OpenCV 可从这里免费下载。 该站点提供了发行的最新版本(当前为 3.0 beta)和较旧的版本。

注意

如果下载的版本是不稳定版本,例如当前的 3.0 beta 版本,则应格外小心,以免出现错误。

在这个页面上,可以找到适用于每个平台的 OpenCV 版本。 可以根据最终目的从不同的存储库中获取代码和库信息:

主存储库(位于这个页面),专用于最终用户。 它包含库的二进制版本和目标平台的可编译源。 测试数据存储库(位于这个页面),其中包含用于测试某些库模块目的的数据集。 贡献者仓库位于这个页面)带有源代码,与贡献者提供的额外功能和最先进的功能相对应。 与主干相比,此代码更容易出错,并且测试较少。 提示 在最新版本的 OpenCV 3.0 beta 中,额外的贡献模块未包含在主包中。 它们应单独下载,并通过适当的选项明确包含在编译过程中。 如果包括其中一些贡献的模块,请务必谨慎,因为其中一些模块依赖于 OpenCV 不附带的第三方软件。 每个模块的文档站点(位于这个页面),包括提供的模块。 开发库(位于这个页面),带有库的当前开发版本。 它适用于库主要功能的开发人员以及希望在发布最新版本之前仍使用最新更新的“急躁”用户。

而不是 GNU/Linux 和 OSX,其中 OpenCV 仅作为源代码分发,在 Windows 发行版中,可以找到预编译的(使用 Microsoft Visual C++ v10,v11 和 v12)的版本。 每个预编译的版本都可以与 Microsoft 编译器一起使用。 但是,如果主要目的是使用不同的编译器框架开发项目,则需要为该特定编译器(例如 GNU GCC)编译库。

提示

使用 OpenCV 最快的方法是使用发行版随附的预编译版本之一。 然后,更好的选择是使用用于软件开发的本地平台的最佳设置来构建库的微调版本。 本章提供在 Windows 上构建和安装 OpenCV 的信息。 在这个页面和这个页面上可以找到在 Linux 上设置库的更多信息。

获取编译器并设置 CMake

使用 OpenCV 开发跨平台的一个不错的选择是使用 GNU 工具包(包括 gmake,g++ 和 gdb)。 对于大多数流行的操作系统,可以轻松获得 GNU 工具包。 对于开发环境,我们的首选选择包括 GNU 工具包和跨平台 Qt 框架,其中包括 Qt 库和 Qt Creator 集成开发环境(IDE)。 Qt 框架可从这个页面免费获得。

注意

在 Windows 上安装编译器之后,请记住正确设置Path环境变量,为编译器的可执行文件添加路径,例如 Qt 框架随附的 GNU /编译器的C:\Qt\Qt5.2.1\5.2.1\mingw48_32\bin。 在 Windows 上,免费的快速环境编辑器工具(可从这个页面获得)提供了一种方便的方式来更改Path和其他环境变量 。

要以与编译器无关的方式管理 OpenCV 库的生成过程,推荐使用 CMake 工具。 CMake 是可从这个页面上获得的免费且开源的跨平台工具。

使用 CMake 配置 OpenCV

将库的源代码下载到本地磁盘后,需要为该库的编译过程配置 Makefile。 CMake 是轻松配置 OpenCV 安装过程的关键工具。 它可以从命令行使用,也可以通过图形用户界面(GUI)版本以更加用户友好的方式使用。

使用 CMake 配置 OpenCV 的步骤总结如下:

选择源目录(在下面将其命名为OPENCV_SRC)和目标目录[OPENCV_BUILD)。 目标目录是编译后的二进制文件所在的位置。选中分组和高级复选框,然后单击配置按钮。选择所需的编译器(例如,GNU 默认编译器,MSVC 等)。设置首选选项,然后取消设置不需要的选项。单击配置按钮并重复步骤 4 和 5,直到没有错误为止。单击生成按钮并关闭 CMake。

以下屏幕截图显示了 CMake 的主窗口,其中包含源目录和目标目录以及将所有可用选项分组的复选框:

预先配置步骤后的 CMake 主窗口

注意

为简便起见,本文中使用OPENCV_BUILD和OPENCV_SRC分别表示 OpenCV 本地设置的目标目录和源目录。 请记住,所有目录都应与您当前的本地配置相匹配。

在预配置过程中,CMake 会检测到存在的编译器和许多其他本地属性,以设置 OpenCV 的生成过程。 上一个屏幕截图显示了预配置过程后的 CMake 主窗口,并以红色显示了分组的选项。

可以保留默认选项不变,然后继续配置过程。 但是,可以设置一些方便的选项:

BUILD_EXAMPLES:设置为使用 OpenCV 构建一些示例。BUILD_opencv_:设置为在构建过程中包括模块(module_name)。OPENCV_EXTRA_MODULES_PATH:当您需要一些额外的模块时使用; 在此处设置附加模块的源代码的路径(例如C:/opencv_contrib-master/modules)。WITH_QT:启用此功能可将 Qt 功能包括在库中。WITH_IPP:此选项默认为打开。 当前的 OpenCV 3.0 版本包括英特尔集成性能基元(IPP)的子集,这些子集可加快库的执行时间。提示

如果编译新的 OpenCV 3.0(测试版),请小心,因为已报告一些与 IPP 包含有关的意外错误(即,使用此选项的默认值)。 我们建议您取消设置WITH_IPP选项。

如果配置与 CMake 一起执行(循环执行步骤 4 和 5)没有产生任何其他错误,则可以为构建过程生成最终的 Makefile。 以下屏幕截图显示了生成步骤后没有错误的 CMake 主窗口:

编译和安装库

使用 CMake 生成 Makefile 的过程之后的下一步是使用适当的make工具进行的编译。 通常在目标目录(在 CMake 配置步骤中设置的目录)的命令行(控制台)上执行此工具。 例如,在 Windows 中,应从命令行启动编译,如下所示:

OPENCV_BUILD>mingw32-make

此命令使用 CMake 生成的 Makefile 启动构建过程。 整个编译通常需要几分钟。 如果编译没有错误结束,则安装将继续执行以下命令:

OPENCV_BUILD>mingw32-make install

此命令将 OpenCV 二进制文件复制到OPENCV_BUILD\install目录。

如果在编译过程中出现问题,我们应该再次运行 CMake 来更改在配置过程中选择的选项。 然后,我们应该重新生成 Makefile。

通过将库二进制文件的位置(例如,在 Windows 中,生成的 DLL 文件位于OPENCV_BUILD\install\x64\mingw\bin)添加到Path,安装环境变量的末尾。 如果Path字段中没有此目录,则每个 OpenCV 可执行文件的执行都会出错,因为找不到库二进制文件。

要检查安装过程是否成功,可以运行随库一起编译的一些示例(如果使用 CMake 设置了BUILD_EXAMPLES选项)。 代码示例(用 C++ 编写)可以在OPENCV_BUILD\install\x64\mingw\samples\cpp找到。

注意

安装 OpenCV 的简短说明适用于 Windows。 可以在这个页面上阅读有关 Linux 前提条件的详细说明。 尽管本教程适用于 OpenCV 2.0,但几乎所有信息对于版本 3.0 仍然有效。

OpenCV 的结构

一旦安装 OpenCV ,OPENCV_BUILD\install目录将填充三种类型的文件:

头文件:它们位于OPENCV_BUILD\install\include子目录中的,用于通过 OpenCV 开发新项目。库二进制文件:这些是静态或动态库(取决于 CMake 选择的选项),具有每个 OpenCV 模块的功能。 它们位于bin子目录中(例如,当使用 GNU 编译器时,为x64\mingw\bin)。示例二进制文件:这些是可执行文件,并带有使用库的示例。 这些样本的来源可以在源包中找到(例如OPENCV_SRC\sources\samples)。

OpenCV 具有模块化的结构,这意味着该包为每个模块都包含一个静态或动态(DLL)库。 每个模块的正式文档可以在这个页面中找到。 包中包含的主要模块是:

core:这定义了所有其他模块使用的基本功能以及包括重要多维数组Mat在内的基本数据结构。 highgui:这提供了简单的用户界面(UI)功能。 使用 Qt 支持(WITH_QT CMake 选项)构建库可以使 UI 与此类框架兼容。 imgproc:这些是图像处理功能,包括滤波(线性和非线性),几何变换,颜色空间转换,直方图等。 imgcodecs: 这是一个易于使用的界面,用于读取和写入图像。 注意 自从 OpenCV 3.0 以来,请注意模块中的更改,因为某些功能已移至新模块(例如,读取和写入图像功能已从highgui移至imgcodecs)。 photo:这包括计算摄影,包括修补,去噪,High 动态范围(HDR)成像等。 stitching:用于图像拼接。 videoio:这是一个易于使用的界面,用于视频捕获和视频编解码器。 video:它为提供视频分析功能(运动估计,背景提取和对象跟踪)。 features2d:这些是功能,用于特征检测(角和平面对象),特征描述,特征匹配等。 objdetect:这些是功能,用于对象检测和预定义检测器实例(例如脸部,眼睛,微笑,人,汽车等)。

其他一些模块是calib3d(相机校准),flann(聚类和搜索),ml(机器学习),shape(形状距离和匹配),superres(超分辨率),video (视频分析)和videostab(视频稳定)。

注意

从 3.0 beta 版开始,新的贡献模块以单独的包(opencv_contrib-master.zip)分发,可以从这个页面下载。 这些模块提供了的附加功能,在使用它们之前,应充分了解它们。 有关新版 OpenCV(版本 3.0)中新功能的快速概述,请参考位于这个页面的文档。

使用 OpenCV 创建用户项目

在本书中,我们假定 C++ 是用于编程图像处理应用的主要语言,尽管实际上提供了其他编程语言的接口和包装器(例如 Python,Java,MATLAB/Octave 等)。

在本节中,我们将说明如何使用易于使用的跨平台框架使用 OpenCV 的 C++ API 开发应用。

库的一般用法

要使用 C++ 开发 OpenCV 应用,我们需要我们的代码:

包括带有定义的 OpenCV 头文件链接 OpenCV 库(二进制文件)以获取最终的可执行文件

OpenCV 标头文件位于OPENCV_BUILD\install\include\opencv2目录中,每个模块都有一个文件(*.hpp)。 头文件的包含是通过#include伪指令完成的,如下所示:

#include // Including the header file for each module used in the code

使用此伪指令,可以包含用户程序所需的每个头文件。 另一方面,如果包含opencv.hpp头文件,则将自动包括所有头文件,如下所示:

#include // Including all the OpenCV's header files in the code注意

请记住,本地安装的所有模块都在OPENCV_BUILD\install\include\opencv2\opencv_modules.hpp头文件中定义,该头文件在 OpenCV 的构建过程中自动生成。

#include指令的使用并不总是保证正确包含头文件,因为有必要告诉编译器在哪里可以找到包含文件。 这可以通过在文件的位置传递一个特殊的参数来实现(例如,对于 GNU 编译器为I\)。

链接过程要求您为链接器提供库(动态或静态),可以在其中找到所需的 OpenCV 功能。 通常使用链接器的两种类型的参数来完成:库的位置(例如,对于 GNU 编译器为‑L)和库的名称(例如-l)。

注意

您可以在这个页面和这个页面中找到 GNU GCC 和make可用在线文档的完整列表。

开发新项目的工具

开发我们自己的 OpenCV C++ 应用的主要先决条件是:

OpenCV 头文件和库二进制文件:当然,我们需要编译 OpenCV,辅助库是进行此类编译的前提条件。 该包应使用与生成用户应用相同的编译器进行编译。C++ 编译器:一些辅助工具可以方便地用作代码编辑器,调试器,项目管理器和流程管理器(例如 CMake),版本控制系统(例如 Git,Mercurial,SVN 等)以及类检查器等。 通常,这些工具一起部署在所谓的集成开发环境(IDE)中。任何其他辅助库:可选地,将需要对最终应用进行编程的任何其他辅助库,例如图形,统计等。

用于编程 OpenCV C++ 应用的最受欢迎的编译器套件是:

Microsoft Visual C(MSVC):Windows 仅支持,它与 IDE Visual Studio 集成得很好,尽管它也可以与其他跨平台 IDE(例如 Qt Creator 或 Eclipse)集成。 当前与最新的 OpenCV 版本兼容的 MSVC 版本是 VC 10,VC 11 和 VC 12(Visual Studio 2010、2012 和 2013)。GNU 编译器集合 GNU GCC:这是由 GNU 项目开发的跨平台编译器系统。 对于 Windows,此套件称为 MinGW(最小 GNU GCC)。 与当前 OpenCV 发行版兼容的版本是 GNU GCC 4.8。 该套件可与多个 IDE 一起使用,例如 Qt Creator,Code :: Blocks,Eclipse 等。

对于本书介绍的示例,我们使用了 Windows 的 MinGW 4.8 编译器套件以及 Qt 5.2.1 库和 Qt Creator IDE(3.0.1)。 跨平台 Qt 库需要使用此类库提供的新 UI 功能来编译 OpenCV。

注意

对于 Windows,可以从这个页面下载 Qt 捆绑包(包括 Qt 库,Qt Creator 和 MinGW 套件)。 捆绑包约为 700 MB。

Qt Creator 是用于 C++ 的跨平台 IDE,它集成了我们编码应用所需的工具。 在 Windows 中,它可以与 MinGW 或 MSVC 一起使用。 以下屏幕截图显示了 Qt Creator 主窗口,其中包含 OpenCV C++ 项目的不同面板和视图:

Qt Creator 的主窗口带有 OpenCV C++ 项目的一些视图

使用 Qt Creator 创建 OpenCV C++ 程序

接下来,我们说明如何使用 Qt Creator IDE 创建代码项目。 特别是,我们将此描述应用于 OpenCV 示例。

我们可以通过导航到文件 | Qt Creator | 新文件或文件 | 项目…,然后导航到非 Qt 项目 | 普通 C++ 项目为任何 OpenCV 应用创建一个项目。 然后,我们必须选择一个项目名称及其存储位置。 下一步是为项目(在我们的情况下为 Desktop Qt 5.2.1 MinGW 32 位)选择一个工具包(即编译器),并确定生成二进制文件的位置。 通常,使用两种可能的构建配置(配置文件):debug和release。 这些配置文件设置适当的标志来构建和运行二进制文件。

使用 Qt Creator 创建项目时,将生成两个特殊文件(扩展名为.pro和.pro.user)来配置生成和运行过程。 构建过程由在项目创建期间选择的工具包确定。 使用 Desktop Qt 5.2.1 MinGW 32 位套件,此过程依赖于qmake和 mingw32make 工具。 使用*.pro文件作为输入,qmake生成用于驱动每个配置文件(即release和debug)构建过程的 Makefile。 Qt Creator IDE 使用qmake工具作为 CMake 的替代品,以简化软件项目的构建过程。 它可以自动从几行信息中生成 Makefile。

以下各行代表*.pro文件(例如showImage.pro)的示例:

TARGET: showImage TEMPLATE = app CONFIG += console CONFIG -= app_bundle CONFIG -= qt SOURCES += \ showImage.cpp INCLUDEPATH += C:/opencv300-buildQt/install/include LIBS += -LC:/opencv300-buildQt/install/x64/mingw/lib \ -lopencv_core300.dll \ -lopencv_imgcodecs300.dll\ -lopencv_highgui300.dll\ -lopencv_imgproc300.dll

上一个文件说明了qmake生成适当的 Makefile 来构建项目二进制文件所需的选项。 每行以一个标记(表示TARGET,CONFIG,SOURCES,INCLUDEPATH和LIBS)的标签开头,后跟一个标记以添加(+=)或删除(-=)可选值。 在此示例项目中,我们使用非 Qt 控制台应用。 可执行文件为showImage.exe(TARGET),源文件为showImage.cpp(SOURCES)。 由于此项目是基于 OpenCV 的应用,因此最后两个标签指示此特定项目(core,imgcodecs,highgui和imgproc)。 注意,在行末尾的反斜杠表示在下一行继续。

注意

有关在 Qt 项目中开发的工具(包括 Qt Creator 和qmake)的详细说明,请访问这个页面。

读写图像文件

图像处理依赖于获得图像(例如照片或视频名望)并通过在其上应用信号处理技术来“播放”图像以获得所需的结果。 在本节中,我们向您展示如何使用 OpenCV 提供的功能从文件读取图像。

基本 API 概念

Mat类是在 OpenCV 中存储和处理图像的主要数据结构。 此类在core模块中定义。 OpenCV 已实现了为这些数据结构自动分配和释放内存的机制。 但是,当数据结构共享相同的缓冲存储器时,程序员仍应格外小心。 例如,赋值运算符不将内存内容从对象(Mat A)复制到另一个对象(Mat B); 它仅复制引用(内容的内存地址)。 然后,一个对象(A或B)的更改会影响两个对象。 要复制Mat对象的内存内容,应使用Mat::clone()成员函数。

注意

OpenCV 中的许多函数通常使用Mat类来处理密集的单通道或多通道数组。 但是,在某些情况下,可以使用其他数据类型,例如std::vector,Matx,Vec或Scalar。 为此,OpenCV 提供了代理类InputArray和OutputArray,它们允许将任何先前的类型用作函数的参数。

Mat类用于密集的 n 维单通道或多通道数组。 它实际上可以存储实数或复数值向量和矩阵,彩色或灰度图像,直方图,点云等。

创建Mat对象的方法有很多,最流行的是构造器,其中指定数组的大小和类型如下:

Mat(nrows, ncols, type, fillValue)

数组元素的初始值可以由Scalar类设置为典型的四元素向量(针对数组中存储的图像的每个 RGB 和透明度分量)。 接下来,我们向您展示Mat的用法示例,如下所示:

Mat img_A(4, 4, CV_8U, Scalar(255)); // White image: // 4 x 4 single-channel array with 8 bits of unsigned integers // (up to 255 values, valid for a grayscale image, for example, // 255=white)

DataType类定义了 OpenCV 的原始数据类型。 基本数据类型可以是bool,unsigned char,signed char,unsigned short,signed short,int,float,double或这些原始类型之一的值的元组。 任何原始类型都可以由标识符以以下形式定义:

CV_{U|S|F}C()

在前面的代码U中,S和F分别代表unsigned,signed和float。 对于单通道数组,将应用以下枚举,以描述数据类型:

enum {CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3,CV_32S=4, CV_32F=5, CV_64F=6};注意

在此,应注意,这三个声明是等效的:CV_8U,CV_8UC1和CV_8UC(1)。 单通道声明非常适合用于灰度图像的整数数组,而数组的三通道声明更适合具有三个分量(例如 RGB,BRG,HSV 等)的图像。 对于线性代数运算,可以使用float(F)类型的数组。

我们可以为多通道数组(最多 512 个通道)定义所有上述数据类型。 以下屏幕截图说明了一个通道(CV_8U,grayscale)的图像内部表示以及三个通道(CV_8UC3,RGB)表示的同一图像。 这些屏幕截图是通过放大 OpenCV 可执行文件窗口中显示的图像(showImage示例)而获得的:

RGB 颜色和灰度的图像的 8 位表示

注意

的注意很重要,要使用 OpenCV 功能正确保存 RGB 图像,必须将图像存储在内存中,其通道按 BGR 顺序排列。 以相同的方式,当从文件中读取 RGB 图像时,它以 BGR 顺序以其通道存储在内存中。 而且,它需要一个辅助的第四通道(alpha)来操作具有 RGB 和透明性三个通道的图像。 对于 RGB 图像,较大的整数值表示 alpha 通道的像素更亮或更透明。

所有 OpenCV 类和函数都在cv命名空间中,因此,我们在源代码中将具有以下两个选项:

包括头文件之后,添加using namespace cv声明(这是本书所有代码示例中使用的选项)。将cv::前缀附加到我们使用的所有 OpenCV 类,函数和数据结构。 如果 OpenCV 提供的外部名称与常用的标准模板库(STL)或其他库冲突,则建议使用此选项。图像文件支持的格式

OpenCV 支持最常见的图像格式。 但是,其中一些需要(免费提供)第三方库。 OpenCV 支持的主要格式为:

Windows 位图(*.bmp和*dib)便携式图像格式(*.pbm,*.pgm,*.ppm)太阳栅格(*.sr,*.ras)

需要辅助库的格式为:

JPEG(*.jpeg,*.jpg,*.jpe)JPEG 2000(*.jp2)便携式网络图形(*.png)TI​​FF(*.tiff,*.tif)WebP(*.webp)。

除上述列出的格式外,对于 OpenCV 3.0 版本,它还包括支持以下格式的驱动程序(NITF,DTED,SRTM 等) 由地理数据抽象库(GDAL)设置,并带有 CMake 选项WITH_GDAL。 请注意,尚未在 Windows 操作系统上对 GDAL 支持进行广泛的测试。 在 Windows 和 OSX 中,默认情况下使用 OpenCV 附带的编解码器(libjpeg,libjasper,libpng和libtiff)。 然后,在这些 OS 中,可以读取 JPEG,PNG 和 TIFF 格式。 Linux(和其他类似 Unix 的开源操作系统)正在寻找系统中安装的编解码器。 可以在 OpenCV 之前安装编解码器,也可以通过在 CMake 中设置适当的选项(例如BUILD_JASPER,BUILD_JPEG,BUILD_PNG和BUILD_TIFF)从 OpenCV 包中构建库。

示例代码

为了说明如何使用 OpenCV 读取和写入图像文件,我们现在将描述showImage示例。 从命令行使用相应的输出窗口执行示例,如下所示:

\showImage.exe fruits.jpg fruits_bw.jpg

showImage示例的输出窗口

在此示例中,给出了两个文件名作为参数。 第一个是要读取的输入图像文件。 第二个是要与输入图像的灰度副本一起写入的图像文件。 接下来,我们向您显示源代码及其说明:

#include #include using namespace std; using namespace cv; int main(int, char *argv[]) { Mat in_image, out_image; // Usage: // Read original image in_image = imread(argv[1], IMREAD_UNCHANGED); if (in_image.empty()) { // Check whether the image is read or not cout >(Mat& image):抓取,解码并返回下一帧。 此方法具有等效的bool VideoCapture::read(OutputArray image)函数。 可以使用它而不是使用VideoCapture::grab()函数,然后使用VideoCapture::retrieve()。 VideoWriter& VideoWriter::operator


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有