微软计算机视觉 API 精粹(全)
一、微软认知服务简介
毫无疑问,人工智能(AI)是当今信息技术的重要组成部分。它在未来肯定会变得越来越重要,但是它已经在许多方面得到了应用,所以作为开发人员,您应该了解有哪些工具和服务可以用来构建下一代应用。
世界上大多数软件巨头都提供人工智能解决方案,微软有一系列有趣的服务和工具,可以简化您构建和实施基于人工智能的解决方案的方式。本章提供了微软为人工智能提供的高层次概述,并详细描述了认知服务 API。这是下一章的基础,在下一章中,您将学习计算机视觉 API。
微软人工智能平台简介
微软提供 AI 平台( www.microsoft.com/en-us/AI/ai-platform
),一套应用可以跨平台消费的服务和工具。人工智能平台包括创建机器人的服务;机器学习和深度学习的服务;以及用于分析图片、实时视频和语音的服务。
更具体地说,微软人工智能平台包括以下内容:
- 机器人框架,允许你建立和连接对话机器人,并创建与用户的自然交互(
http://dev.botframework.com/
)。 - 认知服务(Cognitive Services),一套 RESTful 服务,能够识别、理解和解释图片、演讲、直播视频、书面文本等内容,并带有自然语言描述(
http://azure.microsoft.com/en-us/services/cognitive-services/
)。 - Azure Machine Learning,一个强大的云平台,帮助开发人员构建自己的定制 AI 解决方案(
http://azure.microsoft.com/en-us/services/machine-learning-services/
)。
在下一节中,您将了解认知服务的概况;然后,在第二章,你将开始使用计算机视觉 API,这是本书真正的重点。
微软认知服务简介
微软认知服务是 RESTful 服务,允许用户在任何设备的任何平台上进行自然交互。
认知服务 API 通过提供一组丰富的 API 来处理人类语言、情感、情绪、身体特征、音频等,完美地体现了微软坚信的对话即平台愿景。在更高的层次上,认知服务 API 被分组到表 1-1 中的类别中。
表 1-1。
Categories of Microsoft Cognitive Services
| 服务类别 | 描述 | | --- | --- | | 视力 | 这些 API 提供了图像处理算法,有助于用自然语言描述( [`http://azure.microsoft.com/en-us/services/cognitive-services/directory/vision/`](http://azure.microsoft.com/en-us/services/cognitive-services/directory/vision/) )来识别、说明、调节、理解和描述图片和视频。 | | 知识 | 这些 API 通过查找活动、地点、学术论文和根据客户需求定制的建议( [`http://azure.microsoft.com/en-us/services/cognitive-services/directory/know/`](http://azure.microsoft.com/en-us/services/cognitive-services/directory/know/) )来帮助您实现客户的知识。 | | 语言 | 这些 API 能够处理自然语言,评估情感,理解客户的需求( [`http://azure.microsoft.com/en-us/services/cognitive-services/directory/lang/`](http://azure.microsoft.com/en-us/services/cognitive-services/directory/lang/) )。 | | 演讲 | 这些 API 支持音频处理,包括说话者识别、语音验证和音频到文本的转换( [`http://azure.microsoft.com/en-us/services/cognitive-services/directory/speech/`](http://azure.microsoft.com/en-us/services/cognitive-services/directory/speech/) )。 | | 搜索 | 基于必应搜索引擎服务,这些 API 允许你实现图片搜索、新闻搜索、视频搜索、自动建议( [`http://azure.microsoft.com/en-us/services/cognitive-services/directory/search/`](http://azure.microsoft.com/en-us/services/cognitive-services/directory/search/) )。 |每个类别都包含许多专门的 API 集。描述所有这些集合超出了本书的范围;因此,您可以通过访问每个类别的相关网页来了解更多信息。值得一提的是视觉类别中的可用 API,因为这本书重点介绍了计算机视觉 API,包含在该类别中,以便您对这些 API 可以做什么有一个概述。表 1-2 总结了视觉类别中可用的专用 API。
表 1-2。
The Vision APIs
| 应用接口 | 描述 | | --- | --- | | 计算机视觉 API | 提供图像处理算法,帮助您理解、分析和描述具有自然语言响应的图像。包括光学字符识别(OCR)和名人识别(`http://azure.microsoft.com/en-us/services/cognitive-services/computer-vision/`)。 | | 内容版主 | 为图像、视频和文本提供自动内容审核(`http://azure.microsoft.com/en-us/services/cognitive-services/content-moderator/`)。 | | 视频 API | 提供强大的 API,能够提高视频质量以及检测和识别视频中的人脸和其他元素( [`http://azure.microsoft.com/en-us/services/cognitive-services/video-api/`](http://azure.microsoft.com/en-us/services/cognitive-services/video-api/) )。这是目前的预览服务。 | | 视频索引器 | 允许您最大化视频互动和洞察力,帮助使视频内容更容易被发现( [`http://azure.microsoft.com/en-us/services/cognitive-services/video-indexer/`](http://azure.microsoft.com/en-us/services/cognitive-services/video-indexer/) )。这是目前的预览服务。 | | Face API | 检测、识别、分析和组织图像中的人脸( [`http://azure.microsoft.com/en-us/services/cognitive-services/face/`](http://azure.microsoft.com/en-us/services/cognitive-services/face/) )。 | | 情感 API | 检测图像中人的情绪,基于人脸检测( [`http://azure.microsoft.com/en-us/services/cognitive-services/emotion/`](http://azure.microsoft.com/en-us/services/cognitive-services/emotion/) )。 | | 定制视觉服务 | 启用基于标记和标签的自定义图像处理( [`http://azure.microsoft.com/en-us/services/cognitive-services/custom-vision-service/`](http://azure.microsoft.com/en-us/services/cognitive-services/custom-vision-service/) )。该服务目前处于预览阶段。 |认知服务 API 是通过微软 Azure 云平台提供的,包括本书中讨论的计算机视觉 API。这意味着,你需要一个有效的 Azure 订阅来使用这些服务。您可以在 http://azure.microsoft.com/en-us/free/
申请免费的 Azure 试用。这也是完成下一章的代码示例所必需的,所以在第二章,我将解释如何配置你的 Azure 订阅来获得你的个人访问密钥。
介绍开发工具和平台
基于 REST 方法和 JSON 标准数据交换格式,任何应用、任何设备、任何操作系统,以及任何支持 REST 和 JSON 的开发平台和编程语言都可以使用认知服务。
作为一名使用。NET 技术,您可以在任何类型的。NET 应用和所有的。NET 语言,如 C#、F#和 Visual Basic。说到这里,你有三个主要的选择。
- 在 Windows 上,您可以使用 Visual Studio 2017 作为开发环境,以全面支持所有。NET 项目类型。如果您没有 MSDN 订阅,您可以免费下载社区版(
www.visualstudio.com/downloads/
)。 - 在 macOS 上,您可以使用 Visual Studio for Mac 作为支持跨平台开发的开发环境。NET 核心和移动应用开发。可以免费下载社区版(
www.visualstudio.com/vs/visual-studio-mac/
)。 - 在 Linux(及其最流行的发行版)、macOS 和 Windows 上,您可以使用 Visual Studio 代码(
http://code.visualstudio.com
)进行 C#开发。网芯。
在本书中,我将展示两个基于 Xamarin 和。NET Core,所以我鼓励大家在 Windows 上使用 Visual Studio 2017,或者在 macOS 上使用 Visual Studio for Mac。如果您在 Linux 上工作,不用担心:您将能够理解所有与。NET 核心,通过使用 Visual Studio 代码。在所有情况下,您将能够在第三章中学习如何使用控制台应用在 C#中查询计算机视觉服务。
摘要
多年来,微软提供了许多高质量和强大的人工智能服务和工具,人工智能平台代表了微软的艺术水平。本章简要介绍了人工智能平台,描述了它包含的工具和服务。
还提供了对认知服务的介绍,以及对视觉类别中提供的服务的提及,以便您可以更好地理解计算机视觉 API 如何融入 Microsoft 产品中。最后,您了解了在应用中使用认知服务需要什么工具和平台。在下一章,你将学习计算机视觉 API 是如何工作的,你将学习如何配置你的 Azure 订阅来获得你的访问密钥。
二、计算机视觉 API 入门
想象一下,你想开发一些应用来帮助残疾人理解他们周围的事情,并代表他们阅读报纸。
现在想象一下,你想开发一些应用,帮助孩子们从图片中了解世界,确保成人内容被排除在外。然后,假设你想开发一些应用,通过提供描述图像的自然语言句子来帮助人们学习外语。最后,假设您在一个警察部门工作,想要构建一个自定义解决方案来帮助您的部门基于图像识别罪犯。
这些只是人工智能如何帮助解决许多问题的几个例子,但它们足以让你理解计算机视觉 API 的目的。结合其他认知服务 API,你有无限的机会。本章首先描述了计算机视觉 API 的工作原理,然后描述了如何配置您的 Azure 订阅并公开一个可由任何应用使用的计算机视觉 API 端点。
了解计算机视觉 API
和其他认知服务一样,计算机视觉 API 也有自己的门户;可以在 http://azure.microsoft.com/en-us/services/cognitive-services/computer-vision/
到达。在这里你可以找到文档和例子的快捷方式,但是我想把重点放在 http://bit.ly/2sBtryy
可用的 API 参考上。当您打开此页面时,您将看到可以对图像执行的可用操作列表。
从技术上讲,使用 Computer Vision API,您可以通过上传图像或指向现有的图像 URL 并根据您想要对图像执行的分析类型发送 GET 和 POST HTTP 请求来调用 RESTful 服务。
计算机视觉服务将返回一个包含分析结果的 JSON 响应。服务 URL 因您最近的地区而异,需要一个有效的 Azure 订阅来激活您将在 HTTP 请求中使用的密钥。您将在下一部分配置您的 Azure 订阅;现在,请关注您可以对图像及其相应的 HTTP 请求执行的可用分析类型,如表 2-1 中所述。
表 2-1。
Available Analysis Types with the Computer Vision API
| 类型 | 描述 | HTTP 动词 | 端点 | | --- | --- | --- | --- | | 分析图像 | 分析图像的成人和种族内容、人脸检测、标签和主色 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/analyze[?visualFeatures][&details][&language]` | | 描述图像 | 用人类可读的语言和完整的句子生成图像描述 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/describe[?maxCandidates]` | | 获取缩略图 | 从指定的图像生成缩略图 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/generateThumbnail[?width][&height][&smartCropping` | | 列出特定领域的模型 | 获取当前支持的特定于域的模型的列表,如名人和地标识别器 | 得到 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/models` | | 光学字符识别 | 对图像执行光学字符识别,并将检测到的文本存储为机器可用的字符 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/ocr[?language][&detectOrientation ]` | | 识别特定领域的内容 | 分析图片以检索特定领域的内容,如名人或地标 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/models/{model}/analyze` | | 识别手写文本 | 执行手写文本识别 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/recognizeText[?handwriting` `]` | | 标签图像 | 生成与指定图像内容相关的单词列表 | 邮政 | `https://[location].api.cognitive.microsoft.com/vision/v1.0/tag` |在 2-1 中列出的每个操作都作为一个特定的端点被调用。每次您想要调用计算机视觉服务时,您都需要将 URL 中的[ location].api.cognitive.microsoft.com
文字替换为以下文字之一,具体取决于最近的 Azure 区域:
westus.api.cognitive.microsoft.com
美国西部地区westus2.api.cognitive.microsoft.com
针对美国西部 2 个地区eastus.api.cognitive.microsoft.com
针对美国东部地区eastus2.api.cognitive.microsoft.com
针对美国东部 2 个地区westcentralus.api.cognitive.microsoft.com
美国中西部地区southcentralus.api.cognitive.microsoft.com
美国中南部地区westeurope.api.cognitive.microsoft.com
西欧地区northeurope.api.cognitive.microsoft.com
针对北欧地区southeastasia.api.cognitive.microsoft.com
针对东南亚地区eastasia.api.cognitive.microsoft.com
针对东亚地区australiaeast.api.cognitive.microsoft.com
澳大利亚东部地区brazilsouth.api.cognitive.microsoft.com
巴西南部地区
如果地区数量增加或重组,可用 URL 的列表将来可能会有所不同。你可以查看 Azure regions ( http://azure.microsoft.com/en-us/regions/
)的完整列表,但请记住,并非所有微软产品在所有地区都可用,认知服务也是如此。
执行 HTTP 请求
一般来说,要使用 2-1 中列出的操作之一来分析图像,您需要向相关端点发送一个 HTTP 请求。例如,假设您想要生成一个与图像内容相关的标签列表。您将使用以下端点(用 Azure 区域的域名替换[location]
):
https://[location].api.cognitive.microsoft.com/vision/v1.0/tag
每个请求将包含以下标题:
Content-Type
,可选字符串,描述发送给 API 的主体的媒体类型,如application/JSON
或application/octet-stream
Ocp-Apim-Subscription-Key
,包含有效订阅密钥的强制字符串,提供对 API 的访问,您将通过 Azure 门户获得
请求体通常与 POST 请求一起传递,可以是原始图像二进制文件,也可以是通过 JSON 语法提供的图像 URL。例如,如果您想要传递现有图像的 URL,您的请求主体将如下所示:
{"url":"http://onewebsite.com/image1.jpg"}
此正文的 MIME 类型是application/JSON
。在现实世界的开发中,您将使用允许通过网络进行数据交换的类,如 C#和 Java 中的HttpClient
,或 web 调试应用(如 Postman)来发送您的请求,因此您将无需担心如何手动创建头和请求体。例如,你可以用 Postman 发送一个请求,并期待一个 JSON 响应,如图 2-1 所示,其中你还可以看到在哪里以及如何提供内容类型和订阅密钥(出于隐私原因,后者被部分混淆)。
图 2-1。
Sending an HTTP request to the Computer Vision API with Postman
在这个特殊的例子中,您将得到一个 JSON 响应,其中包含一个标记数组,每个标记都有一个名称和置信度百分比。您还可以获得额外的信息,比如请求的惟一标识符和图像大小。计算机视觉 API 提供的其他操作可以以类似的方式调用,更改端点并提供所需的参数。
无论您是使用像 Postman 这样的调试工具,还是使用您喜欢的编程语言中的专用类,您都需要提供前面描述的信息。在下一章中,你将看到如何用HttpClient
类执行 C#中所有可用的操作,以及如何用代码解析 JSON 响应。在此期间,您可以尝试计算机视觉 API 门户中包含的 API 测试控制台(在 http://bit.ly/2sBtryy
可用)。为此,在左侧选择一个操作,然后单击“打开 API 测试控制台”框附近代表您的 Azure 区域的按钮。此时,将会出现一系列文本框,您将会看到如何填写这些文本框并向服务创建 POST 请求的指导。如果操作成功,您将能够看到 JSON 响应,如果操作失败,您将看到一条错误消息。
处理 HTTP 响应
像任何其他 RESTful 服务一样,Computer Vision 返回一个 HTTP 代码和一个描述,允许您了解操作是否成功以及原因。表 2-2 总结了使用计算机视觉时最常见的 HTTP 状态代码。
表 2-2。
Computer Vision Status Codes
| HTTP 状态代码 | 描述 | | --- | --- | | 200(成功) | 请求的操作成功完成,分析结果作为 JSON 返回。 | | 400(错误请求) | 请求的操作失败,出现以下一个不言自明的错误:`InvalidImageUrl`、`InvalidImageFormat`、`InvalidImageSize`、`NotSupportedImage`。 | | 415(不支持的媒体类型) | 请求的操作失败,因为提供的`Content-Type`标题与图像内容不匹配。 | | 500(内部服务器错误) | 请求的操作失败,出现以下一个不言自明的错误:`FailedToProcess`、`Timeout`、`InternalServerError`。 | | 401(未经授权) | 无法执行请求的操作,因为提供了无效的订阅密钥。 |值得一提的是,如果您提供的图像不满足这些最低要求,您可能会收到错误 400(错误请求):
- 图像必须是 PNG、JPG、BMP 或 GIF。
- 图像必须大于 50 × 50。
- 文件大小必须小于 4Mb。
因此,作为最佳实践,请确保您的应用在请求计算机视觉分析操作之前检查图像是否满足最低要求。
配置您的 Azure 订阅
在尝试计算机视觉 API 之前,您需要在 Microsoft Azure 管理门户中激活订阅密钥。假设您已经拥有一个有效的 Azure 订阅,您可以通过 http://portal.azure.com
登录门户。
登录后,点击新建,然后点击 AI +认知服务(见图 2-2 ),最后点击计算机视觉 API。
图 2-2。
Creating a new Computer Vision API subscription
此时,您需要为新的 Computer Vision API 服务指定名称、位置、定价层和资源组。您可以输入自己选择的名称,或者像当前示例中一样输入 MyVisionService,如图 2-3 所示。请注意,作为位置,您需要选择离您最近的 Azure 区域。对于定价层,我建议您使用免费的 F0 计划(单击“查看完整定价详情”了解更多信息)。对于资源组,您可以创建一个新组或选择一个现有组。在当前示例中,为了方便起见,我创建了一个新的资源组。如果你是 Azure 的新手,值得一提的是,顾名思义,资源组是一组云资源,可以包括服务、应用、移动后端、SQL 数据库、AI 服务等等。您基本上使用资源组来组织您的云资源。
图 2-3。
Supplying information for the new Computer Vision API
单击“创建”时,将提供服务。在图 2-4 中,您可以看到一个名为“显示访问密钥”的快捷方式,您需要单击它来生成订阅密钥,这是访问计算机视觉 API 所必需的。
图 2-4。
The service details and the “Show access keys” shortcut
当您点按“显示访问密钥”时,您将看到两个自动生成的密钥。您将能够在您的 HTTP 请求中交替使用它们,并且您可以使用工具栏中的重新生成 Key1 和重新生成 Key2 按钮来重新生成这些密钥(参见图 2-5 )。
图 2-5。
Displaying access keys
您可以将这些密钥复制到剪贴板,供以后重复使用。显然,这些包括敏感信息,所以你应该始终保持他们的安全。使用计算机视觉 API 不需要任何其他配置,因为您将简单地调用服务 URL,传递订阅密钥。
摘要
计算机视觉 API 允许您对图像执行许多分析操作。为了实现这一点,您调用一个端点,该端点的 URL 根据您想要使用的 Azure 区域而变化。一般来说,创建一个 HTTP 请求,其头部包含订阅密钥和内容类型,而主体包含要分析的图像,可以是 URL 或二进制数据。
无论您请求的操作是什么,如果操作成功,您都会收到一个包含分析结果的 JSON 响应。如果失败,服务将返回适当的 HTTP 状态代码和描述。调用计算机视觉 API 所需的订阅密钥可以在 Azure 管理门户中生成,在那里您可以获得两个密钥,您可以将其复制到剪贴板或随时重新生成。在下一章中,您将开始用 C#对 Computer Vision API 服务执行真正的 HTTP 请求,执行所有可用的分析操作,并学习如何解析和解释 JSON 结果。
三、从 C# 调用计算机视觉 API
作为 RESTful 服务,所有的认知服务 API,包括计算机视觉 API,都可以被任何支持 HTTP 请求和 JSON 格式的编程语言查询。这一章是关于 C#的,并解释了如何用可以跨平台使用的 C#代码来分析图像。您将学习如何使用微软的所有主要 ide 来执行计算机视觉提供的所有分析操作。
第一步是设置您的工具箱,然后您将能够编写一些代码。
Note
永远小心你如何使用认知服务和你上传的图片。微软有严格的条款,在使用 API 之前必须阅读,可在 http://azure.microsoft.com/en-us/support/legal/cognitive-services-terms
获得。
获取样本图像
很明显,你可以完全自由地使用你自己的图像进行分析,我也鼓励你这样做,但是如果你没有任何有用的图像文件,我在我的博客上为你准备了三个。
- 一幅海边风景:
http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_SeasideLandscape.jpg
- 一张自己的照片,将用来演示人脸检测:
http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_AleDelSole.png
- 一张带有一些印刷文字的图片,将用来演示光学字符识别:
http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_OcrSample.jpg
在将任何应用投入生产之前,请记住查看认知服务使用条款。
创建 C#控制台应用
因为本章的目的是解释如何在 C#中针对计算机视觉服务进行编码,所以使用控制台应用是一个好主意,它是一个独立于平台的项目类型。在接下来的两章中,您将分别看到如何创建移动应用和 web 应用。
我现在将解释如何使用 Visual Studio 2017、Visual Studio for Mac 和 Visual Studio 代码创建控制台应用。
Note
C#中有很多方法可以解析 JSON 标记。NET 对象,具有内置类型和第三方库。在本书中,我将使用流行的 Newtonsoft。Json 库( https://www.newtonsoft.com/json
),这是以一种方便的方式使用 JSON 的事实上的标准。
在 Visual Studio 2017 中创建控制台应用
Visual Studio 2017 允许您同时使用。NET 框架和。NET 核心运行时。我将创建一个基于。NET Framework,但是请记住,相同的步骤也适用于。NET Core,如果你已经安装了的话。请记住,认知服务可以在任何平台上使用,这意味着基于。NET 框架(如 Windows Presentation Foundation、Windows 窗体和 ASP.NET)也可以利用认知服务。
在 Visual Studio 2017 中,选择文件➤新➤项目。在新建项目对话框中,选择位于 Windows Classic Desktop 下的控制台应用模板(见图 3-1 )。
图 3-1。
The Console App template in Visual Studio 2017
将新项目命名为 ComputerVisionDemo,然后单击 OK。计算机视觉 API 以 JSON 格式返回分析结果;因此,您需要一种方法来解析 JSON 响应,并以 C#对象的形式使用结果。要做到这一点,您可以使用流行的 Newtonsoft。可以从 NuGet 安装的 Json 库。在解决方案资源管理器中右击项目名称,然后选择“管理 NuGet 包”。在 NuGet 用户界面中,您应该已经在包列表中看到了这个库(如果没有看到,只需在搜索框中键入它的名称)。选择库,然后点击右边的安装按钮,如图 3-2 所示。
图 3-2。
Installing the Newtonsoft.Json NuGet package
安装完软件包后,在您的Program.cs
文件中添加以下using
指令:
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
这些指令对于缩短调用 RESTful 服务和使用 JSON 标记所需的对象调用非常有用。现在一切都在 Visual Studio 2017 中设置好了,让我们转移到 Visual Studio for Mac 环境。
在 Visual Studio for Mac 中创建控制台应用
Visual Studio for Mac 允许您构建。NET 核心应用,并提供一个控制台应用模板。要在 macOS 上创建和配置控制台应用,请按照下列步骤操作:
图 3-5。
Installing the Newtonsoft.Json NuGet package
图 3-4。
Assigning a name to the new project
图 3-3。
Creating a console app in Visual Studio for Mac
- 单击文件➤新解决方案。
- 在“新建项目”对话框中,选择下的应用项目。NET Core,然后选择控制台应用项目模板,确保 C#是所选的语言(参见图 3-3 )。
- 单击下一步,如果需要,指定。您选择的 NET Core 版本。我建议你使用最新的版本。
- 输入一个项目名称(见图 3-4 ),如 ComputerVisionDemo 最后,单击创建。
- 当项目准备就绪时,在解决方案面板中右键单击项目名称,然后选择添加➤ NuGet 包。在添加包对话框中(见图 3-5 ,搜索 Json.NET 包,然后点击添加包。请注意,这是之前在 Visual Studio 2017 中讨论过的同一个库,但在这里它以一个替代的显示名称出现。
在您的Program.cs
文件的顶部,添加下面的using
指令,其目的是简化对。您将用来调用 RESTful 服务和使用 JSON 标记的. NET 对象:
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
用 Visual Studio 代码创建控制台应用
Visual Studio 代码是一个流行的跨平台工具,它允许开发人员在多个系统上用多种语言编写代码,包括 Windows、macOS 和 Linux(及其最流行的发行版)。特别是对于基于 Linux 的系统,Visual Studio 代码是编写基于。NET 核心运行时。我现在将演示如何在 Ubuntu 机器上设置控制台应用,但是如果您决定在 Windows 和 macOS 上使用 Visual Studio 代码,同样的步骤也适用于这些系统。
Ubuntu 可能是 Linux 最流行的桌面客户端发行版;因此,出于演示目的,这是一个不错的选择。如果还没有安装,您需要下载并安装 Visual Studio 代码( http://code.visualstudio.com
)和。网芯 SDK ( www.microsoft.com/net/download/core
)。
Note
如果您在 Windows 或 macOS 上工作,并希望在 Ubuntu 上尝试 Visual Studio 代码,您可以使用该操作系统创建一个虚拟机。你可以从 Ubuntu.com 下载 Ubuntu 的 ISO 镜像。
假设您已经安装了 Visual Studio 代码和。NET Core 2.0,要创建 C#控制台应用,请遵循以下步骤:
-
在 Files 程序的帮助下,找到你的个人文件夹(通常是
/Home/YourName
)。 -
右键单击文件夹,然后选择在终端中打开。这将打开一个文件夹的终端窗口。
-
使用以下命令创建一个包含新项目的新目录:
> mkdir ComputerVisionDemo
-
使用以下命令将新创建的目录设置为当前目录:
> cd ComputerVisionDemo
-
使用以下命令搭建一个新的 C#控制台项目:
> dotnet new console
-
使用以下命令打开 Visual Studio 代码:
> code.
Visual Studio 代码启动时,会打开之前创建的 C#项目(见图 3-6 )。
图 3-6。
The new project opened in Visual Studio Code
Visual Studio 代码没有内置的 NuGet 包管理器,所以需要手动编辑项目文件(.csproj
)来添加对 Newtonsoft 的引用。Json 包,这是将计算机视觉 API 返回的 JSON 服务解析为 C#对象所必需的。为此,在浏览器栏中,单击ComputerVisionDemo.csproj
文件,并将以下 XML 标记添加到该文件中:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
如果您现在选择“文件”“➤”“全部保存”, Visual Studio 代码将询问您是否允许还原丢失的依赖项,以便 Newtonsoft。Json 包已安装。一旦你完成了这些,打开Program.cs
文件并添加下面的using
指令:
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
它们有助于缩短对用于调用 RESTful 服务和使用 JSON 标记的对象的调用。
描述和分析图像
计算机视觉 API 允许你描述和分析图像。区别很简单:描述图像意味着检索图像内容的自然语言描述,加上一系列相关标签和关于图像文件的细节,比如大小和格式;分析图像包括描述图像,但它也允许检索进一步的细节,如成人和色情内容以及主色。先来描述一个形象。
描述图像
你用来描述一个图像的端点是https://[location].api.cognitive.microsoft.com/vision/v1.0/describe[?maxCandidates]
,其中[location]
必须替换为你最近的 Azure 区域的域名(见第二章),maxCandidates
表示一个查询字符串参数,确定应该返回多少描述。如果未指定此参数,默认值为 1。现在假设你想用计算机视觉 API 来描述我提供的风景图片。这可以通过下面的代码来完成(参见注释):
async static Task DescribeImageAsync()
{
var client = new HttpClient();
// Return two natural language sentences
string requestParameters = "maxCandidates=2";
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"YOUR-KEY-GOES-HERE");
// Define the API endpoint including the query string parameters
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/describe?" +
requestParameters;
HttpResponseMessage response;
// Construct a well-formed JSON key/value pair that
// represents the image URL
JObject imageUrl = new JObject(
new JProperty("url",
"http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_SeasideLandscape.jpg"));
// You pass the JSON object above as the request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
// Add headers
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Call the endpoint
response = await client.PostAsync(uri, content);
// If successful...
if (response.StatusCode == HttpStatusCode.OK)
{
// Read the resulting HTTP content as a string
string jsonResponse = await response.Content.ReadAsStringAsync();
// Generate fully indented JSON markup from the original response
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
}
Console.ReadLine();
}
对于所有请求,您将使用HttpClient
类,提供适当的头,然后调用它的PostAsync
方法,传递端点 URL 和请求体。注意请求体是如何通过JObject
类构造的,它允许您生成格式良好的 JSON 对象。JProperty
类允许您指定一个键/值对,在本例中是一个表示图像 URL 的键/值对。在这种情况下,代码还提供了maxCandidates
参数来检索多个描述。PostAsync
向计算机视觉 API 发送 HTTP POST 请求;并且,如果操作成功完成,来自Content
对象(类型为HttpContent
)的ReadAsStringAsync
方法将返回一个 JSON 字符串,其中包含服务能够返回的所有细节。为了清楚起见,调用JObject.Parse
来获得一个完全缩进的 JSON 字符串,它将出现在控制台窗口中。必须从Program
类的Main
方法中调用前面的方法,如下所示:
static void Main(string[] args)
{
DescribeImageAsync().Wait();
}
因为您不能在Main
方法中使用async
和await
,除非您使用 C# 7.1,否则调用实际上是使用Wait
方法同步完成的。
Note
C# 7.1 引入了在Main
方法中使用async
和await
的选项,需要 Visual Studio 2017 版本 15.3 及更高版本。我在本书中没有使用这种语言版本,这样你就可以毫无问题地运行示例代码。
例如,我从这个 RESTful 调用中得到的响应如下:
{
"description": {
"tags": [
"outdoor",
"boat",
"scene",
"water",
"harbor",
"filled",
"ship",
"dock",
"carrying",
"large",
"small",
"people",
"man",
"docked",
"many",
"bunch",
"group",
"air",
"truck",
"ocean",
"white",
"airplane",
"plane",
"body",
"parked",
"standing",
"ramp",
"board"
],
"captions": [
{
"text": "a group of people on a boat in a harbor",
"confidence": 0.74378581874407157
},
{
"text": "a boat is docked next to a body of water"
,
"confidence": 0.74278581874407157
}
]
},
"requestId": "aed5709e-c6c6-43c7-b583-94a2fe0930ad",
"metadata": {
"width": 3840,
"height": 2160,
"format": "Jpeg"
}
}
名为description
的第一个 JSON 元素公开了一个tags
数组,该数组包含服务能够基于图片内容生成的标签列表。description
中的第二个数组叫做captions
,包含由服务生成的自然语言句子列表和置信度。级别越高,关于生成的句子的准确度的置信度越高。requestId
元素是唯一标识请求的 GUID,而metadata
元素包含图像大小和格式,具有不言自明的属性。在 C#中,你有很多选择来访问和迭代数组。然而,您也可以利用JObject
实例上的索引器来检索特定的信息。例如,下面一行检索数组中第二个标题的自然语言句子:
//Return "a boat is docked next to a body of water"
string description = parsedJson["description"]["captions"][1]["text"].ToString();
作为另一个示例,您可以迭代标签列表,如下所示:
foreach(var item in parsedJson["description"]["tags"])
{
Console.WriteLine(item.ToString());
}
正如你所看到的,计算机视觉 API 能够用自然语言语句描述图像内容以及它如何返回标签和元数据是非常出色的。
分析图像
分析图像的工作方式基本上类似于描述图像,但区别在于您可以检索更多的细节,因此您可以创建更复杂的查询字符串。分析一张图片的终点是https://[location].api.cognitive.microsoft.com/vision/v1.0/analyze[?visualFeatures][&details][&language]
,其中[location]
必须替换为最接近 Azure 区域的域名。您还可以提供许多可选的查询字符串参数:
visualFeatures
允许您指定应该返回哪些视觉特征。支持的功能列表将很快提供。details
允许您包含特定领域的详细信息,如名人和地标名称。支持的值有Celebrities
和Landmarks
。language
提供一个选项来指定服务应该使用什么语言来描述图像。在撰写本文时,支持的语言是en
(英语)和zh
(简体中文)。如果没有指定语言,则默认为英语。
以下是您可以为更深入的图像分析指定的视觉特征列表:
Categories
:该服务将为图像生成一个可能的类别列表。Tags
:该服务将生成与图像内容相关的单词列表。- 该服务将检索图像中的任何人脸,如果有的话,将生成坐标、年龄和性别。
ImageType
:该服务检测图像是剪贴画还是线条画。Color
:该服务检测强调色、主色,以及图像是否为黑白。Adult
:该服务检测图片是否包含露骨的色情内容。
您可以通过用逗号分隔来组合多个视觉特征。例如,下面的代码演示了如何在包含人脸的图像上检索视觉特征:
async static Task AnalyzeImageAsync()
{
var client = new HttpClient();
// Request parameters. Visual features are comma-separated
string requestParameters = "visualFeatures=Categories,Description,Color,Faces,Adult";
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"YOUR-KEY-GOES-HERE");
string uri =
"https://westus.api.cognitive.microsoft.com/vision/v1.0/analyze?"
+ requestParameters;
HttpResponseMessage response;
JObject imageUrl = new JObject(
new JProperty("url",
"http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_AleDelSole.png"));
// Request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response = await client.PostAsync(uri, content);
if(response.StatusCode == HttpStatusCode.OK)
{
string jsonResponse = await response.Content.ReadAsStringAsync();
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
}
Console.ReadLine();
}
前面的代码用于分析我提供的照片,将返回以下 JSON:
{
"categories": [
{
"name": "people_portrait",
"score": 0.91015625
}
],
"adult": {
"isAdultContent": false,
"isRacyContent": false,
"adultScore": 0.0095219314098358154,
"racyScore": 0.0099660586565732956
},
"description": {
"tags": [
"person",
"man",
"outdoor",
"building",
"camera",
"smiling",
"standing",
"holding",
"car",
"street",
"bus",
"sitting",
"wearing",
"city",
"black",
"glasses",
"large",
"woman",
"dog",
"phone",
"white"
],
"captions": [
{
"text": "a man smiling for the camera",
"confidence": 0.96098232754013913
}
]
},
"requestId": "591dac9c-4729-4964-96f4-726c2c292210",
"metadata": {
"width": 234,
"height": 234,
"format": "Png"
},
"faces": [
{
"age": 37,
"gender": "Male",
"faceRectangle": {
"left": 53,
"top": 68,
"width": 134,
"height": 134
}
}
],
"color": {
"dominantColorForeground": "White",
"dominantColorBackground": "Black",
"dominantColors": [
"White",
"Grey"
],
"accentColor": "8D6B3E",
"isBWImg": false
}
}
JSON 标记非常容易理解。除了通过描述图像已经获得的信息之外,您还可以获得关于检测到的人脸、性别、年龄和人脸位置坐标的物理细节。还要注意adult
元素的结果,您可以正确地看到该图像不包含成人或色情内容。为了给你更准确的概念,我写这篇文章的时候已经 40 岁了,但是这张照片是我 35 岁的时候拍的。该服务检测到一名 37 岁的男子,这是一个很好的近似水平。您可以使用前面描述的相同技术将 JSON 元素和子元素解析成JObject
实例,以便更容易地访问 JSON 数组及其属性/值对。
生成缩略图
计算机视觉 API 使得生成图像缩略图变得容易。端点是https://[location].api.cognitive.microsoft.com/vision/v1.0/generateThumbnail[?width][&height][&smartCropping]
,其中[location]
是你最近的 Azure 区域的域名。width
、height
和smartCropping
查询字符串参数表示缩略图的宽度和高度以及用于启用智能裁剪的布尔标志。
如您所料,在这种情况下,计算机视觉服务不会返回纯文本 JSON 响应。返回的对象实际上是二进制数据,C#允许您将这些数据包装到一个MemoryStream
中,然后您可以根据自己的需要对其进行处理,比如将流内容直接显示为图像,或者使用一个FileStream
从流中创建一个文件。下面的代码演示了如何生成缩略图:
async static Task GenerateThumbnailAsync()
{
var client = new HttpClient();
// Return two natural language sentences
string requestParameters = "width=320&height=240";
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"YOUR-KEY-GOES-HERE");
// Define the API endpoint
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/GenerateThumbnail?" +
requestParameters;
HttpResponseMessage response;
// Construct a well-formed JSON key/value pair that
// represents the image URL
JObject imageUrl = new JObject(
new JProperty("url",
"http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_SeasideLandscape.jpg"));
// You pass the JSON object above as the request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
// Add headers
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Call the endpoint
response = await client.PostAsync(uri, content);
// If successful,
if (response.StatusCode == HttpStatusCode.OK)
{
// Get the thumbnail as a MemoryStream
var binaryResponse = await response.Content.ReadAsStreamAsync();
}
}
Console.ReadLine();
}
注意这次您是如何调用ReadAsStreamAsync
将响应解析成 C#可以使用的流对象的。
标记图像
计算机视觉 API 还允许您根据图像内容快速生成图像标签,而无需执行更详细的分析。用于标记的端点在https://[location].api.cognitive.microsoft.com/vision/v1.0/tag
可用,并且没有查询字符串参数可用。您可以编写以下代码:
async static Task TagImageAsync()
{
var client = new HttpClient();
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"YOUR-KEY-GOES-HERE");
// Define the API endpoint
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/tag";
HttpResponseMessage response;
// Construct a well-formed JSON key/value pair that
// represents the image URL
JObject imageUrl = new JObject(
new JProperty("url",
"http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_SeasideLandscape.jpg"));
// You pass the JSON object above as the request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
// Add headers
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Call the endpoint
response = await client.PostAsync(uri, content);
// If successful,
if (response.StatusCode == HttpStatusCode.OK)
{
// Read the resulting HTTP content as a string
string jsonResponse = await response.Content.ReadAsStringAsync();
// Generate fully indented JSON markup from the original response
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
}
Console.ReadLine();
}
您将得到的结果类似于下面的 JSON:
{
"tags": [
{
"name": "sky",
"confidence": 0.99912935495376587
},
{
"name": "outdoor",
"confidence": 0.97800672054290771
},
{
"name": "boat",
"confidence": 0.94631272554397583
},
{
"name": "scene",
"confidence": 0.89682495594024658
},
{
"name": "harbor",
"confidence": 0.77457839250564575
}
],
"requestId": "37a85e3b-3008-4166-ba36-7da2c2a78cd7",
"metadata": {
"width": 3840,
"height": 2160,
"format": "Jpeg"
}
}
如您所见,这个简化的 JSON 响应包含一个tags
数组,其中每个元素包含单词和置信度。您仍然可以使用JObject
类和前面描述的技术来访问数组中的单个元素。
使用光学字符识别
计算机视觉 API 提供光学字符识别(OCR)。OCR 功能强大:计算机视觉可以检测文本,它可以检测语言、单词的位置、文本方向以及检测到的文本相对于最近的水平或垂直方向的角度(以度为单位)。您可以通过将所需的图像以二进制流或 URL 的形式传递到以下端点来利用 OCR:https://[location].api.cognitive.microsoft.com/vision/v1.0/ocr[?language][&detectOrientation]
。
与其他端点一样,您将使用最近的 Azure 区域的域名替换[location]
,并且您可以传递language
和detectOrientation
查询字符串参数。第一个参数允许您为想要分析的文本指定语言,而第二个参数指定您还想要检索文本方向。请注意,提供语言完全是可选的,因为计算机视觉算法会自动检测语言。值得一提的是,这个服务足够强大,可以检索图像中其他元素内的文本。在 C#中,调用服务的方式类似于前面的例子。
async static Task RecognizeTextAsync()
{
var client = new HttpClient();
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"YOUR-KEY-GOES-HERE");
// Define the API endpoint
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/ocr";
HttpResponseMessage response;
// Construct a well-formed JSON key/value pair that
// represents the image URL
JObject imageUrl = new JObject(
new JProperty("url",
"http://community.visual-basic.img/community_visual-basic_it/Alessandro/184/o_OcrSample.jpg"));
// You pass the JSON object above as the request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
// Add headers
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Call the endpoint
response = await client.PostAsync(uri, content);
// If successful,
if (response.StatusCode == HttpStatusCode.OK)
{
// Read the resulting HTTP content as a string
string jsonResponse = await response.Content.ReadAsStringAsync();
// Generate fully indented JSON markup from the original response
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
}
Console.ReadLine();
}
对于指定的图像,您从计算机视觉的 OCR 服务获得的响应类似于以下 JSON:
{
"language": "en",
"textAngle": -2.0000000000000338,
"orientation": "Up",
"regions": [
{
"boundingBox": "92,165,467,136",
"lines": [
{
"boundingBox": "97,165,451,57",
"words": [
{
"boundingBox": "97,165,8,42",
"text": "I"
},
{
"boundingBox": "126,167,106,44",
"text": "CAN"
},
{
"boundingBox": "255,171,293,51",
"text": "RECOGNIZE"
}
]
},
{
"boundingBox": "92,243,467,58",
"words": [
{
"boundingBox": "92,243,159,46",
"text": "WHAT"
},
{
"boundingBox": "265,249,108,45",
"text": "YOU"
},
{
"boundingBox": "393,253,166,48",
"text": "WRITE"
}
]
}
]
}
]
}
JSON 响应由以下核心元素组成:
regions
:一个对象数组,其中每个对象代表一个检测到的文本区域lines
:一个对象数组,每个对象代表一个区域中的一行文本words
:一个对象数组,每个对象代表一行中的一个单词
当您想用 OCR 解析检测到的文本时,您需要记住这个更复杂的层次结构。当然,您仍然可以使用JObject
类来解析 JSON 响应的内容,就像您之前看到的那样。
检索手写文本
计算机视觉 API 还提供了一项有趣的服务,允许您从图像中检索手写文本。它的行为类似于 OCR 服务,但是您调用下面的端点:https://[location].api.cognitive.microsoft.com/vision/v1.0/recognizeText[?handwriting]
。这里您需要做的是提供handwriting=true
查询字符串参数来启用手写文本识别。如果不指定此参数,服务将通过 OCR 搜索打印文本。
使用领域特定的模型
通过特定领域的模型,计算机视觉算法可以对特定类别的图像进行专门的分析。在撰写本文时,计算机视觉 API 提供了两个现成的特定领域模型:名人识别和地标识别。特定领域模型的列表将来肯定会增加,并且您可以选择创建自己的模型。
假设您想要检测照片中的名人。首先,您需要检索特定领域模型的列表,并获得名人识别的引用。这是通过针对https://[location].api.cognitive.microsoft.com/vision/v1.0/models
端点的 HTTP GET 请求来完成的,如下面的代码所示:
async static Task ListModelsAsync()
{
var client = new HttpClient();
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "YOUR-KEY-GOES-HERE");
// Define the API endpoint
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/models";
HttpResponseMessage response;
// Call the endpoint
response = await client.GetAsync(uri);
// If successful,
if (response.StatusCode == HttpStatusCode.OK)
{
// Read the resulting HTTP content as a string
string jsonResponse = await response.Content.ReadAsStringAsync();
// Generate fully indented JSON markup from the original response
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
Console.ReadLine();
}
前面的调用将返回以下 JSON(将来可能会有所不同):
{
"models": [
{
"name": "celebrities",
"categories": [
"people_"
]
},
{
"name": "landmarks",
"categories": [
"outdoor_",
"building_"
]
}
],
"requestId": "d7a81873-fdf9-4e48-8247-26b1ec0725b4"
}
可以看到,有一个数组叫做models
。对于数组中的每一项,您将需要检查name
属性的值,比如celebrities
或landmarks
。这必须传递给对图像执行实际识别的端点。用于识别特定领域内容的端点的 URL 如下:https://[location].api.cognitive.microsoft.com/vision/v1.0/models/{model}/analyze
。这里你需要用最近的 Azure 区域的域名替换[location]
,用celebrities
或landmarks
替换{model}
。出于版权原因,我不会显示名人的图片,也不会指向关于名人的现有图像 URL,但是您可以使用以下代码来检索名人识别图像的结果:
async static Task RecognizeCelebrityAsync()
{
var client = new HttpClient();
// Add the subscription key to the header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "YOUR-KEY-GOES-HERE");
// Define the API endpoint
string uri = "https://westus.api.cognitive.microsoft.com/vision/v1.0/models/celebrities/analyze";
HttpResponseMessage response;
// Construct a well-formed JSON key/value pair that
// represents the image URL
JObject imageUrl = new JObject(
new JProperty("url",
"IMAGE-URL-GOES-HERE"));
// You pass the JSON object above as the request body
using (var content =
new StringContent(imageUrl.ToString(), Encoding.UTF8, "application/json"))
{
// Add headers
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Call the endpoint
response = await client.PostAsync(uri, content);
// If successful,
if (response.StatusCode == HttpStatusCode.OK)
{
// Read the resulting HTTP content as a string
string jsonResponse = await response.Content.ReadAsStringAsync();
// Generate fully indented JSON markup from the original response
var parsedJson = JObject.Parse(jsonResponse);
Console.WriteLine(parsedJson.ToString());
}
}
Console.ReadLine();
}
您得到的 JSON 响应如下所示:
{
"requestId": "ab594260-2d70-4919-b997-425cddd9758d",
"metadata": {
"width": 960,
"height": 540,
"format": "Jpeg"
},
"result": {
"celebrities": [
{
"name": "Celebrity name",
"faceRectangle": {
"left": 346,
"top": 74,
"width": 75,
"height": 75
},
"confidence": 0.9925701
}
]
}
}
JSON 响应包含metadata
项中的图像信息和一个名为celebrities
的数组。这包含了一个在图像中检测到的所有名人名字的列表,对于每个名人,你可以看到他们的脸的坐标。至于其他端点,您可以使用JObject
类来解析 JSON 结果。NET 对象。地标识别以同样的方式工作,但是你有一个名为landmarks
的阵列来代替celebrities
阵列。
摘要
计算机视觉 API 提供了强大而复杂的算法,允许您使用自然语言描述来描述和分析图像。为了查询服务,您向各个端点发送 HTTP POST 和 GET 请求。在 C#中,更常见的是在。NET 中,这可以用System.Net.Http.HttpClient
类来完成,它可以跨平台移植,因此可以在所有。NET 平台和所有的微软 ide,如 Visual Studio 2017、Visual Studio for Mac 和 Visual Studio Code。
在 Windows、macOS 和 Ubuntu 上创建和配置了控制台应用之后,您通过首先学习如何用自然语言、机器生成的描述来描述图像,从而了解了计算机视觉 API 的功能。然后,您看到了如何使用图像分析检索更复杂的结果。然后讨论转移到如何使用简单的 API 调用生成缩略图和标签。继续,您看到了 OCR 引擎如何强大到足以识别图像中的印刷文本和手写文本。最后,您从特定于领域的模型开始,学习如何获得可用模型的列表,然后学习如何执行名人识别。在所有代码示例中,您都使用了JObject
类来构造和解析 JSON 对象。
到目前为止,您已经看到了如何调用计算机视觉 API,并且学习了如何发送请求和解析字符串形式的 JSON 响应。在下一章中,您将开始在使用 Xamarin 的移动应用中使用计算机视觉 API。表单和基于计算机视觉客户端库的不同方法。
四、基于 Xamarin 的移动应用的计算机视觉
如果人工智能随处可用,它会给用户带来巨大的好处。有了移动设备和移动应用,这当然是可能的。出于这个原因,作为一名开发人员,理解如何在移动应用中使用认知服务是非常重要的。
从 C#开发的角度来看,Xamarin 无疑是您在移动应用开发中需要考虑的技术。使用 Xamarin,您可以用 C#为 Android、iOS、macOS 和 tvOS 构建本机应用。此外,使用 Xamarin。表单,您可以使用一个共享的 C#代码库为 Android、iOS 和 Windows 10 编写本机应用,从而创建跨平台的解决方案。本章向您介绍了 Xamarin 在移动设备上的计算机视觉的奇妙世界。形式,我相信你会立即察觉到人工智能给移动开发者带来的不可思议的机会。
Note
在本章中,您将使用模拟器运行示例项目的 iOS、Android 和 Windows 10 版本。然而,对于现实世界的移动开发,我强烈建议您在物理设备上工作。
创造一个 Xamarin。表单解决方案
本章的目标之一是解释如何在多种移动平台上使用计算机视觉 API(以及更一般的微软认知服务)。在手机 app 开发方面,Xamarin。Forms 当然是最合适的选择,因为它允许你从一个 C#代码库创建 iOS、Android 和 Windows 10 的应用。更具体地说,您将看到如何创建一个用户界面由三个选项卡组成的应用,允许描述图像、识别文本和识别名人。
建造一个 Xamarin。表单解决方案,需要 Windows 上的 Visual Studio 2017 或者 macOS 上的 Visual Studio for Mac。两种 ide 免费社区版都完全支持 Xamarin。表单开发。我现在将描述创建和配置一个新的示例 Xamarin 的步骤。在两个系统上形成解决方案。
Note
因为本章的目标不是介绍 Xamarin。表单,而是描述如何从 Xamarin 调用计算机视觉 API。表单解决方案,Xamarin 的基本知识。强烈建议使用表单来完成本章。如果你没有经验,你可以免费使用我的 Xamarin。形式简洁的电子书,可在 http://bit.ly/2gegT9l
买到。我假设您知道如何创建页面,以及如何使用可扩展应用标记语言(XAML)来设计基本的用户界面。
为 Xamarin 配置 Visual Studio 2017
Note
如果您已经随 Visual Studio 2017 一起安装了 Xamarin 开发工具,则可以跳过这一部分。假设您在安装时选择了 Xamarin 组件,那么您不需要在 Visual Studio for Mac 上进行任何额外的配置,Visual Studio for Mac 已经包含了所有必需的工具。
在 Visual Studio 2017 中开始 Xamarin 开发之前,必须安装适当的工具。为此,首先需要启动 Visual Studio Installer 工具,然后选择“Mobile development with”。NET”工作量,如图 4-1 所示。
图 4-1。
Installing the Xamarin development tools
此时,单击“Individual components”选项卡,找到模拟器组,并确保至少选择了以下组件:
- 谷歌安卓模拟器
- 英特尔硬件加速执行管理器
- Windows 10 移动模拟器(尽可能选择最高的 Windows 版本)
准备就绪后,单击修改。Visual Studio 安装程序将需要几分钟时间来安装选定的组件。安装完成后,您可以关闭 Visual Studio 安装程序并启动 Visual Studio 2017。
介绍计算机视觉客户端库
在前一章中,您看到了如何使用System.Net.HttpClient
类对计算机视觉 API 服务执行 HTTP 请求,然后您使用了 Newtonsoft。Json 名称空间来解析 JSON 响应。这种方法是最通用的,因为它可以很容易地跨平台重用,但它要求您实现自己的方法。NET 对象来表示对图像的分析结果,当您创建一个HttpClient
实例和调用它的方法(通常是PostAsync
和GetAsync
)时,它需要您手动指定头、内容类型、端点和查询字符串参数。
Microsoft 还开发了一个客户端可移植库,它将 HTTP 请求封装到特定的方法中,并公开一些类,您可以使用这些类轻松地将分析结果反序列化到。NET 强类型对象。这个库叫做Microsoft.ProjectOxford.Vision.dll
,作为一个 NuGet 包提供。
Note
牛津项目是微软认知服务发布前的项目名称。
在使用可移植库的解决方案中,该库可以极大地简化您与计算机视觉 API 的交互方式。因此,它非常适合 Xamarin。表单解决方案,在本章中,您将学习如何使用这个库而不是其他方法,以便您完全了解查询计算机视觉服务的所有方法。表 4-1 列出了该库提供的最重要的类型和成员。
表 4-1。
Most Important Types and Members in the Microsoft.ProjectOxford.Vision Library
| 名字 | 类型 | 描述 | | --- | --- | --- | | `VisionServiceClient` | 班级 | 提供对计算机视觉 API 的托管访问,并允许您指定订阅密钥 | | `AnalyzeImageAsync` | 方法 | 允许您分析和描述图像 | | `RecognizeTextAsync` | 方法 | 对包含文本的图像执行 OCR | | `AnalyzeImageInDomainAsync` | 方法 | 允许您基于特定领域的模型(如名人和地标)分析图像 | | `AnalysisResult` | 班级 | 表示对图像分析结果的响应 | | `AnalysisInDomainResult` | 班级 | 表示基于特定领域模型的图像分析的响应 | | `VisualFeature` | 列举型别 | 表示查询计算机视觉服务必须返回的信息 |这些类型和成员将在创建示例应用页面时详细讨论。
在创建 Xamarin 之前提到这个库。Forms 解决方案是必要的,以便您在安装所有必要的 NuGet 包时知道它是什么。
创造一个 Xamarin。Visual Studio 2017 中的表单解决方案
在 Visual Studio 2017 中,选择文件➤新➤项目。在新建项目对话框中,定位跨平台节点,然后选择跨平台 App (Xamarin)项目模板,如图 4-2 所示。输入 ComputerVisionDemo 作为项目名称,然后单击确定。
在下一个对话框中,Visual Studio 将要求您指定 UI 技术和代码共享策略。选择 Xamarin。表单和可移植类库(PCL)(见图 4-3 )。
图 4-3。
Configuring a Xamarin.Forms solution
图 4-2。
Creating a Xamarin.Forms solution
准备就绪后,单击确定。出现提示时,选择您想要的最高版本的 Windows 10。几秒钟后,Visual Studio 将生成一个由以下内容组成的解决方案:
- 一个包含所有跨平台共享代码的可移植类库(PCL)项目
- 一个 Xamarin。面向 Android 设备的 Android 项目
- 针对 iOS 设备的 Xamarin.iOS 项目
- 面向 Windows 10 设备和机器的通用 Windows 平台(UWP)项目
PCL 项目是您编写可以跨平台共享的所有代码的地方,这些代码包括用户界面和所有不特定于平台的代码。您现在需要几个 NuGet 包,通过在解决方案资源管理器中右键单击解决方案名称,然后选择 Manage NuGet Packages 来安装这些包。当 NuGet 用户界面出现时,您需要安装以下软件包:
- 微软。ProjectOxford.Vision,前面描述的客户端库。此库依赖于 Newtonsoft。Json 包,它也将被安装。
- Xam。Plugin.Media 是一个库,可以很容易地使用跨平台代码访问媒体文件。
- Xam。Plugin.Connectivity,一个允许你用跨平台代码检查互联网连接可用性的库。
解决方案现在已经建立。现在将提供关于 Visual Studio for Mac 的指南,然后您将开始编写代码。
创造一个 Xamarin。Visual Studio for Mac 中的窗体解决方案
在 Visual Studio for Mac 中,选择“文件”>“新建解决方案”。当新项目对话框出现时,找到多平台下的应用节点,并选择空白表单应用模板(参见图 4-4 )。不要选择 Forms 应用模板,因为它包含对本例没有用的样板代码。
图 4-4。
Creating a Xamarin.Forms solution on the Mac
点击下一步时,系统会要求您输入项目名称(参见图 4-5 )。进入 ComputerVisionDemo 并确保“使用可移植类库”和“对用户界面文件使用 XAML”都被选中。
图 4-5。
Configuring a Xamarin.Forms solution on the Mac
请记住 Xamarin。用 Visual Studio for Mac 创建的窗体解决方案不支持通用 Windows 平台项目类型。单击下一步,等待解决方案创建完成。现在你需要安装一些 NuGet 包。与 Windows 上的 Visual Studio 2017 不同,在 Visual Studio for Mac 中,您不能直接在解决方案级别安装软件包。这意味着您需要在每个单独的项目中安装相同的 NuGet 包。要将一个或多个 NuGet 包安装到项目中,您需要在解决方案面板中右键单击项目名称,然后选择添加➤添加 Nuget 包。当“添加包”对话框出现时,您可以搜索并选择要安装到同一个项目中的多个包。您需要的软件包如下:
- 微软。ProjectOxford.Vision,前面描述的客户端库。此包仅在您的解决方案的 PCL 项目中是必需的,并且依赖于 Newtonsoft。Json 包,它也将被安装。
- Xam。Plugin.Media 是一个库,可以很容易地使用跨平台代码访问媒体文件。此包必须安装到解决方案中的所有项目中。
- Xam。Plugin.Connectivity,一个允许你用跨平台代码检查互联网连接可用性的库。此包必须安装到解决方案中的所有项目中。
完成 NuGet 包的安装后,您就可以使用 Xamarin 解决方案中的计算机视觉 API 了。
实例化服务客户端
计算机视觉客户端库提供了一个名为VisionServiceClient
的类,来自微软。ProjectOxford.Vision 命名空间,它允许您以完全。面向网络的时尚。因此,您需要这个类的一个实例,创建它的一个好地方是在App
类和App.xaml.cs
文件中。
这样,您将有一个单独的实例来服务不同应用页面中的多个请求。下面的代码演示了如何声明和创建VisionServiceClient
类的共享实例:
using Microsoft.ProjectOxford.Vision;
using Xamarin.Forms;
namespace ComputerVisionDemo
{
public partial class App : Application
{
internal static VisionServiceClient visionClient;
public App()
{
InitializeComponent();
visionClient = new VisionServiceClient("YOUR-KEY-GOES-HERE",
"https://YourAzureRegion.api.cognitive.microsoft.com/vision/v1.0");
MainPage = new ComputerVisionDemo.MainPage();
}
}
请注意构造函数是如何接受两个字符串参数的:第一个参数代表您的订阅密钥,第二个参数是根服务 URL,您需要用第二章中总结的 URL 之一替换关于 Azure 区域的部分。
实施图像分析
您要实现的第一个功能是利用计算机视觉客户端库来分析和描述图像。这将通过一个特定的页面提供,该页面稍后将嵌入到应用的主页中。
首先,向 PCL 项目添加一个新的 XAML 内容页面。在 Visual Studio 2017 中,您可以通过右击项目名称,然后选择“添加➤新项”来完成此操作。在 Visual Studio for Mac 中,可以通过右击项目名,然后选择“添加➤新文件”来完成此操作。在这两种情况下,选择 ContentPage XAML 项模板并调用新页面ImageAnalysisPage.xaml
。当您添加页面时,Visual Studio 还会生成一个 C#代码隐藏文件,在本例中为ImageAnalysisPage.xaml.cs
。您将在这里编写代码,将图像上传到计算机视觉服务进行分析并获得响应。这可以通过调用VisionServiceClient
类的AnalyzeImageAsync
方法来完成,封装逻辑如下:
private async Task<AnalysisResult> AnalyzePictureAsync(Stream inputFile)
{
// Use the connectivity plugin to detect
// if a network connection is available
// Remember a using Plugin.Connectivity; directive
if (!CrossConnectivity.Current.IsConnected)
{
await DisplayAlert("Network error",
"Please check your network connection and retry.", "OK");
return null;
}
VisualFeature[] visualFeatures = new VisualFeature[] { VisualFeature.Adult,
VisualFeature.Categories, VisualFeature.Color, VisualFeature.Description,
VisualFeature.Faces, VisualFeature.ImageType, VisualFeature.Tags };
AnalysisResult analysisResult =
await App.visionClient.AnalyzeImageAsync(inputFile,
visualFeatures);
return analysisResult;
}
这段代码首先通过利用Xam.Plugin.Connectivity
库中的CrossConnectivity
类来检查互联网连接的可用性。然后它创建了一个由VisualFeature
对象组成的数组,每个对象代表一条您想要从图像中检索的信息。VisualFeature
实际上是一个枚举,数组组合了多个成员。这就是VisualFeature
是如何在幕后实现的:
namespace Microsoft.ProjectOxford.Vision
{
public enum VisualFeature
{
ImageType = 0,
Color = 1,
Faces = 2,
Adult = 3,
Categories = 4,
Tags = 5,
Description = 6
}
}
AnalyzeImageAsync
方法接收两个参数:输入文件,它是一个流,以及VisualFeature
对象的数组。结果被封装到一个类型为AnalysisResult
的对象中,定义如下:
namespace Microsoft.ProjectOxford.Vision.Contract
{
public class AnalysisResult
{
public AnalysisResult();
public Guid RequestId { get; set; }
public Metadata Metadata { get; set; }
public ImageType ImageType { get; set; }
public Color Color { get; set; }
public Adult Adult { get; set; }
public Category[] Categories { get; set; }
public Face[] Faces { get; set; }
public Tag[] Tags { get; set; }
public Description Description { get; set; }
}
}
这个类的每个属性都是一个专用类型。看看它们是如何定义的是一个好主意;您需要知道您需要的信息实际存储在哪里,因为您可能希望从用户界面到这些对象执行数据绑定。在当前的示例应用中,您将考虑Color
、Adult
、Category
、Face
、Tags
和Description
类型。顺便说一下,示例应用将只使用这些类型中的一些属性,因此表 4-2 总结了将被使用的属性。如果您想查看完整的类型定义,只需在代码编辑器中右击类型名称,然后选择“转到定义”。
表 4-2。
Most Common Properties for Image Analysis
| 财产 | 班级 | 描述 | 类型 | | --- | --- | --- | --- | | `AccentColor` | `Color` | 返回图片中的主色 | `string` | | `IsAdultContent` | `Adult` | 如果图像包含明确的内容,则返回 true | `bool` | | `IsRacyContent` | `Adult` | 如果图像包含色情内容,则返回 true | `bool` | | `Captions` | `Description` | 由一个`Text`字符串属性和一个`Confidence`双精度属性组成的`Caption`类型的数组,表示图像的人类语言描述 | `Caption[]` |然后,您需要一些代码,允许用户从设备中选取现有图像,或者从内置相机中拍摄新照片。为了实现这一点,您可以利用Xam.Plugin.Media
库并编写以下代码,这些代码与即将在用户界面中声明的两个按钮相关(还要注意,Indicator1
是一个ActivityIndicator
控件,稍后将放入用户界面中):
private async void TakePictureButton_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", "No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = "test.jpg"
});
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
this.BindingContext = await AnalyzePictureAsync(file.GetStream());
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
private async void UploadPictureButton_Clicked(object sender, EventArgs e)
{
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("No upload", "Picking a photo is not supported.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
try
{
this.BindingContext = await AnalyzePictureAsync(file.GetStream());
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.Message, "OK");
return;
}
finally
{
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
}
Note
在前面的代码中,AnalyzePictureAsync
方法的结果被直接赋给了BindingContext
属性,只是为了演示的目的。在真实世界的代码中,您将希望创建一个合适的视图模型,该模型还将作为用户界面的数据源。
以下是前面代码中的一些有趣之处:
- Xam 中的
CrossMedia
类。Plugin.Media library 允许你分别用PickPhotoAsync
和TakePhotoAsync
方法从相机中选择一个现有的图像或拍摄一个。 TakePhotoAsync
允许您指定文件名以及是否将文件保存到相机胶卷中。- 选中的图片被分配给一个名为
Image1
的Image
控件的Source
属性,并且必须作为一个开放流传递给之前定义的AnalyzePictureAsync
方法。 - 从
AnalyzePictureAsync
返回的AnalysisResult
类的实例被分配给页面的BindingContext
属性,作为用户界面的数据源。这允许将控件数据绑定到AnalysisResult
实例中的属性,稍后您将在 XAML 代码中看到这一点。
现在让我们看看如何允许用户选择图像,以及如何在当前页面的用户界面中显示分析结果。
设计用户界面
当前页面的用户界面的 XAML 代码很简单。根StackLayout
包含一个Image
控件,其中将显示所选图像;一个ActivityIndicator
控件,用于显示进度指示器;一个ScrollView
,其内容是一组绑定到AnalysisResult
对象属性的Label
控件;以及一个ListView
控件,将通过数据绑定显示检测到的标签列表。XAML 代码如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage Title="Analysis"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ComputerVisionDemo.ImageAnalysisPage">
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
Text="Take from camera"/>
<Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
Text="Pick a photo"/>
<ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
<Image x:Name="Image1" HeightRequest="240" WidthRequest="320" />
<ScrollView Padding="10">
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Adult content: "/>
<Label Text="{Binding Adult.IsAdultContent}"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Racy content: "/>
<Label Text="{Binding Adult.IsRacyContent}"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Description: "/>
<Label Text="{Binding Description.Captions[0].Text}"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Accent color: "/>
<Label Text="{Binding Color.AccentColor}"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Tags: "/>
<ListView ItemsSource="{Binding Tags}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
前面的 XAML 代码中的关注点由Binding
表达式表示,每个表达式指向AnalysisResult
类的属性及其子属性。有趣的是,Description.Captions
数组中的第一个元素(索引为零)包含图像的自然语言描述。现在您将看到如何实现光学字符识别。
实现光学字符识别
计算机视觉客户端库还简化了图像的光学字符识别,其方法类似于图像分析,即从VisionServiceClient
类中调用一个名为RecognizeTextAsync
的方法,传递您想要分析的图像并获得一个类型为OcrResults
的对象作为响应。也就是说,在 PCL 项目中添加一个新的 XAML 内容页面,名为OcrRecognitionPage.xaml
。在 C#代码隐藏文件中,您可以编写以下方法来对作为流传递的图像文件实现 OCR 识别:
private async Task<OcrResults> AnalyzePictureAsync(Stream inputFile)
{
if (!CrossConnectivity.Current.IsConnected)
{
await DisplayAlert("Network error", "Please check your network connection and retry.", "OK");
return null;
}
OcrResults ocrResult = await App.visionClient.RecognizeTextAsync(inputFile);
return ocrResult;
}
正如您之前所做的,您可以使用CrossConnectivity
类来检测互联网连接的可用性。OcrResults
类比AnalysisResult
更复杂。在其他特性中,它公开了一个类型为Region[]
的Regions
属性。数组中的每个Region
代表服务能够识别的文本区域,并公开类型Line[]
的Lines
属性。数组中的每一行代表区域中的一行,并公开一个类型为Word[]
的Words
属性。数组中的每个Word
代表该行中的一个单词,它的Text
属性包含实际的单词。由于这种更复杂的结构,检索已识别文本的一种可能方式是迭代区域,然后是行,然后是单词。例如,您可以创建多个StackLayout
容器,这些容器带有多个代表检测到的文本的标签,如下所示:
private void PopulateUIWithRegions(OcrResults ocrResult)
{
// Iterate the regions
foreach (var region in ocrResult.Regions)
{
// Iterate lines per region
foreach (var line in region.Lines)
{
// For each line, add a panel
// to present words horizontally
var lineStack = new StackLayout
{ Orientation = StackOrientation.Horizontal };
// Iterate words per line and add the word
// to the StackLayout
foreach (var word in line.Words)
{
var textLabel = new Label { Text = word.Text };
lineStack.Children.Add(textLabel);
}
// Add the StackLayout to the UI
this.DetectedText.Children.Add(lineStack);
}
}
}
DetectedText
是 UI 中的根StackLayout
容器,用AnalyzePictureAsync
检索 OCR 结果后会调用PopulateUIWithRegions
方法。现在,正如您对图像分析所做的那样,您可以实现两个Button.Clicked
事件处理程序,一个用于从设备的磁盘中选取图像,一个用于从相机中拍摄照片:
private async void UploadPictureButton_Clicked(object sender, EventArgs e)
{
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("No upload", "Picking a photo is not supported.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
var ocrResult = await AnalyzePictureAsync(file.GetStream());
this.BindingContext = ocrResult;
PopulateUIWithRegions(ocrResult);
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
private async void TakePictureButton_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", "No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = "test.jpg"
});
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
var ocrResult = await AnalyzePictureAsync(file.GetStream());
this.BindingContext = null;
this.BindingContext = ocrResult;
PopulateUIWithRegions(ocrResult);
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
注意 OCR 的结果是如何分配给页面的BindingContext
属性的。原因是用户界面会将一个标签数据绑定到OcrResults
类的Language
属性,该属性包含识别文本的语言。然后注意对PopulateUIWithRegions
的调用如何用所有单独的文本行填充 UI。
设计用户界面
这个页面的用户界面甚至更简单,因为它包含显示所选图像的Image
控件、两个按钮、一个显示进度指示器的ActivityIndicator
、一个显示语言的数据绑定的Label
,以及一个在运行时用PopulateUIWithRegions
方法填充的可滚动的StackLayout
。XAML 标记如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage Title="OCR"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ComputerVisionDemo.OcrRecognitionPage">
<StackLayout Orientation="Vertical">
<Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
Text="Take from camera"/>
<Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
Text="Pick a photo"/>
<ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
<Image x:Name="Image1" HeightRequest="240" />
<StackLayout Orientation="Horizontal">
<Label Text="Language: "/>
<Label Text="{Binding Language}"/>
</StackLayout>
<ScrollView>
<StackLayout x:Name="DetectedText"/>
</ScrollView>
</StackLayout>
</ContentPage>
你差不多完成了。下一步是实施名人认可,然后你将能够在行动中看到你的工作成果。
实施名人认可
名人识别是计算机视觉 API 中可用的领域特定模型的一部分。在撰写本文时,该服务支持将名人和地标识别为特定于领域的模型。关于特定于领域的模型,计算机视觉客户端库提供了VisionServiceClient.AnalyzeImageInDomainAsync
方法,该方法返回一个类型为AnalysisInDomainResult
的对象。
为了理解它是如何工作的,向 PCL 项目添加一个名为CelebrityRecognitionPage.xaml
的新页面。在 C#代码隐藏中,添加以下方法:
private async Task<AnalysisInDomainResult> AnalyzePictureAsync(Stream inputFile)
{
if (!CrossConnectivity.Current.IsConnected)
{
await DisplayAlert("Network error", "Please check your network connection and retry.", "OK");
return null;
}
AnalysisInDomainResult analysisResult =
await App.visionClient.AnalyzeImageInDomainAsync(inputFile, await GetDomainModel());
return analysisResult;
}
如您所见,AnalyzeImageInDomainAsync
方法需要输入文件作为参数,还需要一个类型为Model
的对象,该对象表示特定于领域的模型,图像必须根据该模型进行分析。在本例中,这个对象由一个名为GetDomainModel
的方法返回,其代码如下:
private async Task<Model> GetDomainModel()
{
ModelResult modelResult = await App.visionClient.ListModelsAsync();
// At this writing, only celebrity recognition
// is available. It is the first model in the list
return modelResult.Models.First();
}
ListModelsAsync
方法返回可用的特定领域模型的列表。列表中的第一个模型是关于名人的,但是您可以选择不同的模型。解析分析结束时返回的AnalysisInDomainResult
对象更加复杂,因为它的Result
属性是object
类型,因此您必须进行一些手动解析。结果实际上是 JSON 标记,其中包含一个名为celebrities
的元素,该元素包含一个名人姓名数组,每个姓名由name
属性标识。简单地说,您可以使用Newtonsoft.Json.Linq.JObject
类将 JSON 内容解析成字符串内容,如下所示:
private string ParseCelebrityName(object analysisResult)
{
JObject parsedJSONresult = JObject.Parse(analysisResult.ToString());
var celebrities = from celebrity in parsedJSONresult["celebrities"]
select (string)celebrity["name"];
return celebrities.FirstOrDefault();
}
注意,为了保持 UI 简单,前面的代码只返回一个名人的名字。如果您想处理多个名人的名字,可以修改代码来删除FirstOrDefault
并返回一个IEnumerable<string>
。正如您之前所做的,您现在可以处理两个Button.Clicked
事件,如下所示:
private async void TakePictureButton_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", "No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = "test.jpg"
});
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
var analysisResult = await AnalyzePictureAsync(file.GetStream());
this.CelebrityName.Text = ParseCelebrityName(analysisResult.Result);
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
private async void UploadPictureButton_Clicked(object sender, EventArgs e)
{
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("No upload", "Picking a photo is not supported.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
this.Indicator1.IsVisible = true;
this.Indicator1.IsRunning = true;
Image1.Source = ImageSource.FromStream(() => file.GetStream());
AnalysisInDomainResult analysisResult = await AnalyzePictureAsync(file.GetStream());
this.CelebrityName.Text = ParseCelebrityName(analysisResult.Result);
this.Indicator1.IsRunning = false;
this.Indicator1.IsVisible = false;
}
在这种特殊情况下,没有数据绑定。只有一个名为CelebrityName
的标签,其Text
属性被赋予了ParseCelebrityName
的结果。如果您更改代码来处理多个名人的名字,显然您将需要多个标签或一个ListView
控件。
设计用户界面
这个页面的用户界面的 XAML 代码非常简单。在核心部分,您需要一个Image
控件来显示选中的图像,一个Label
控件来显示名人的名字:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage Title="Celebrity"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ComputerVisionDemo.CelebrityRecognitionPage">
<StackLayout Orientation="Vertical">
<Button x:Name="TakePictureButton" Clicked="TakePictureButton_Clicked"
Text="Take from camera"/>
<Button x:Name="UploadPictureButton" Clicked="UploadPictureButton_Clicked"
Text="Pick a photo"/>
<ActivityIndicator x:Name="Indicator1" IsVisible="False" IsRunning="False" />
<Image x:Name="Image1" HeightRequest="240" />
<Label x:Name="CelebrityName"/>
</StackLayout>
</ContentPage>
现在是时候把所有的页面放在一起,看看应用是如何工作的。
把所有的放在一起
示例 Xamarin 的最后一步。表单解决方案是创建一个包含以前创建的内容页面的选项卡式页面。为此,您可以将MainPage.xaml
页面的内容从一个ContentPage
对象更改为一个TabbedPage
对象,其 XAML 标记如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ComputerVisionDemo"
x:Class="ComputerVisionDemo.MainPage">
<TabbedPage.Children>
<local:ImageAnalysisPage />
<local:OcrRecognitionPage />
<local:CelebrityRecognitionPage />
</TabbedPage.Children>
</TabbedPage>
请注意如何将ContentPage
对象添加到TabbedPage.Children
属性和 Xamarin 中。表单将根据应用运行的系统解析适当的布局。在 C#代码隐藏中,您需要将MainPage
对象的继承从ContentPage
更改为TabbedPage
,如下所示:
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
}
}
现在,您已经准备好测试您的示例应用,但是还有最后一步您必须完成,那就是在所需的平台上启用访问相机和图片库的权限。对于 UWP 项目,您不需要更改应用清单,因为已经设置了所有必需的权限。对于 Android 项目,需要在应用清单中选择以下权限:CAMERA
、INTERNET
、READ_EXTERNAL_STORAGE
。对于 iOS 项目,在Info.plist
文件中,您需要包含带有字符串描述的NSCameraUsageDescription
和NSPhotoLibraryUsageDescription
属性,以支持 iOS 10 和更高版本中的隐私限制。此时,选择您的目标平台,并使用系统上可用的工具栏或键盘快捷键开始调试。图 4-6 显示了 Windows 平板电脑模拟器上的图像描述示例,而图 4-7 显示了基于 iOS 模拟器的 OCR 示例。出于版权原因,我不会展示名人识别的结果,但您可以亲自尝试。
图 4-7。
The sample app performing OCR on the iPhone
图 4-6。
The sample app running on a Windows 10 tablet
正如你所见,根据图像质量,你的应用将能够对图像进行复杂的分析。在您的移动应用中实现计算机视觉会带来无限的场景,并将帮助您构建下一代智能应用。
摘要
人工智能在移动应用上非常有用,因为用户可以在口袋里装上由智能算法支持的应用,无论他们去哪里。基于此,本章介绍了如何在使用 Xamarin.Forms 开发的移动应用上使用计算机视觉 API。
您了解了如何创建 Xamarin。Visual Studio 2017 和 Visual Studio for Mac 上的窗体解决方案,以及如何使用正确的 NuGet 包配置该解决方案。然后,您了解了查询计算机视觉 API 的另一种方法,这种方法基于计算机视觉客户端库,由 Microsoft。Vision 包,它公开了允许执行操作和检索结果的类型和成员。面向网络的时尚。然后讨论转移到分析操作的实际实现,包括描述图像、执行 OCR 和识别名人,同时利用有用的 Xamarin 插件。使用客户端库的最大好处是您不需要执行复杂的 JSON 解析,因为您得到的是强类型。NET 对象来表示服务返回的响应。通过实现,您看到了如何设计基本的用户界面,以及如何在模拟器中测试示例应用。相反,下一章将向您概述另一个有趣的机会,那就是使用 ASP.NET web 应用的计算机视觉 API。
五、基于 ASP.NET MVC 核心的 Web 应用中的计算机视觉
正如你在第四章中看到的,将人工智能引入移动应用非常有趣,原因有很多,不仅是从你作为开发人员所拥有的机会的角度来看,还因为你让用户能够用他们口袋里的设备做更多的事情。
然而,像在其他开发场景中一样,您永远不应该忘记在办公室工作站或家庭办公室中使用 PC 工作的人。例如,想象一下医疗保健行业的人工智能如何帮助医生识别患者的症状或情绪,并生成适当的报告。这可以通过移动设备来完成,但医生可能会在办公桌前的电脑上工作,环境可能是一个私有的内部网,带有可以连接到网络摄像头的自定义 web 应用。
因为认知服务可以由任何平台上的任何应用使用,所以它们也可以在 ASP.NET web 应用中使用。我说的 ASP.NET,是指场上的 ASP.NET MVC。NET 框架,ASP.NET MVC 核心上。NET 核心和 Web API 服务。NET 框架和。网芯。在本章中,我将演示如何在 Windows、macOS 和 Ubuntu 上的 ASP.NET MVC 核心应用中使用计算机视觉 API。请记住,同样的概念也适用于 ASP.NET。NET 框架。本章的重点不是解释 ASP.NET MVC 核心,所以你可以看看官方文档( http://docs.microsoft.com/en-us/aspnet/core
)了解更多细节。
Note
本章假设您已经使用 Visual Studio 2017、Visual Studio for Mac 或 Visual Studio 代码配置了开发环境,具体取决于您的操作系统。查看第三章,了解关于配置开发环境的更多信息。
创建 ASP.NET MVC 核心应用
ASP.NET MVC 核心是一个轻量级的、开源的、跨平台的框架,它允许你使用 C#和。NET 核心运行时。如果你有 ASP.NET MVC 的经验。NET 框架,你会熟悉它的。净核心对应方。本章的目的是解释如何创建一个将图像文件上传到计算机视觉 API 的 web 应用,并在网页上显示分析结果。
我先解释一下如何在第三章介绍的三个操作系统上生成一个新的 ASP.NET MVC 核心应用;然后我将解释可以用来发送图像进行分析、解析和显示响应的 C#代码。
使用 Visual Studio 2017 创建 Web 应用
在 Visual Studio 2017 中,选择文件➤新➤项目。在“新建项目”对话框中,找到。网芯类。然后选择 ASP.NET 核心 Web 应用模板,如图 5-1 所示。调用新项目 WebComputerVision,然后单击确定。
图 5-1。
The project template for an ASP.NET Core web application
在下一个对话框中,将要求您指定想要创建哪种应用。选择 Web 应用(模型-视图-控制器)模板(见图 5-2 )然后点击确定。
图 5-2。
Creating an MVC project Note
注意如何配置身份验证机制,以及如何支持将应用打包到 Docker 容器中。关于身份验证,您可以选择个人身份验证(用户名和密码)、Office 365 身份验证、intranets 的 Windows 身份验证和匿名身份验证(默认)。这是一个不错的选择,因为 Visual Studio 将生成必要的基础结构来支持身份验证。
创建项目后,下一步是添加一个新的网页,该网页将用于显示上传图像和显示分析结果所需的控件。为了简单起见,这个页面可以添加到Views\Home
文件夹中。因此,在解决方案资源管理器中右击该文件夹,然后选择“添加➤新项”。在添加新项对话框中,选择 MVC 视图页面项,如图 5-3 所示。
图 5-3。
Adding an MVC page
确保页面名称为Vision.cshtml
,然后点击添加。为了避免额外的复杂性,在这种情况下,不需要添加专用的控制器类;将使用HomeController
类。这将在后面演示。现在,让我们继续通过安装 Newtonsoft 来配置项目。Json NuGet 包。正如你在第三章中所做的,在解决方案浏览器中右击项目名称,然后选择管理 NuGet 包。当 NuGet 窗口出现时,搜索 Newtonsoft。Json 包,然后单击 Install。这个包将用于反序列化和解析由计算机视觉服务返回的 JSON 响应。
用 Visual Studio for Mac 创建 Web 应用
在 Visual Studio for Mac 中,选择文件➤新解决方案。在“新建项目”对话框中,在下找到 ASP.NET 核心 Web App 项目模板。NET Core ➤ App,如图 5-4 所示。准备就绪后,单击下一步。
图 5-4。
Creating a new ASP.NET MVC Core project in Visual Studio for Mac Note
如果看到两个 ASP.NET 核心 Web App 模板,选择列表中的第一个,如图 5-4 所示。第二个项目模板基于 Razor 视图生成一个 web 项目,但是我在本书中并没有讨论 Razor。
如果您有多个版本的。NET Core,您将被要求选择运行时版本。选择。NET Core 2.0,然后单击下一步。最后会要求你提供项目名称,如图 5-5 所示,所以进入 WebComputerVision,点击创建。
图 5-5。
Providing a project name
对于 Windows 上的 Visual Studio 2017,您需要添加一个新的网页,该网页将显示上传图像和显示分析结果所需的用户控件。为此,右键单击解决方案面板中的Views\Home
文件夹,然后选择添加➤新文件。在新建文件对话框中,选择 MVC 视图页面模板,输入 Vision 作为页面名称,如图 5-6 所示;然后单击新建。
图 5-6。
Adding a new MVC page
最后一步是从 NuGet 安装一个可以用来解析和反序列化 JSON 内容的库。正如您在第三章中所做的,在解决方案面板中右键单击项目名称,然后选择添加➤添加 NuGet 包。当 NuGet 对话框出现时,搜索 Json.NET 包,然后点击添加包(参见图 5-7 )。
图 5-7。
Installing the Json.NET package Note
记得 Json.NET 和牛顿软件公司。Json 是一回事,但是 Visual Studio 2017 显示的是包 ID (Newtonsoft。Json)和 Visual Studio for Mac 显示包名。
现在项目已经配置好了,所以您可以继续使用 Visual Studio 代码在 Ubuntu 上创建一个 ASP.NET MVC 核心应用。
使用 Visual Studio 代码创建 Web 应用
正如你在第三章中学到的,你可以创造。NET 应用及其更流行的发行版,使用 C#和 Visual Studio 代码。但是,后者没有创建新项目的内置选项,所以您必须使用dotnet
命令行工具。这将在 Ubuntu 上演示。请遵循以下步骤:
-
使用 Files 程序,打开
Home
文件夹并新建一个名为WebComputerVision
的子文件夹。 -
输入新文件夹,右键单击,然后选择在终端中打开。
-
当终端的实例启动时,键入以下命令行,这将搭建一个新的空 ASP.NET MVC 项目,该项目具有您在 Visual Studio 2017 和 Visual Studio for Mac 中看到的相同结构:
> dotnet new mvc
-
使用以下命令行在 Visual Studio 代码中打开新项目:
> code.
当 Visual Studio 代码启动,新项目打开时,接受提示生成所需资产;然后在浏览器栏中,找到Views\Home
文件夹。右键单击,选择新建文件,将新文件重命名为Vision.cshtml
。该文件表示一个新的网页,该网页将用于显示将图像文件上传到计算机视觉 API 和分析结果所需的控件。
下一步是添加 Newtonsoft。Json NuGet 包到项目中。您可能还记得第三章中的,为了完成这个任务,您需要在浏览器栏中选择.csproj
项目文件,然后添加一个PackageReference
元素,如下所示:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
现在单击“文件”“➤”“全部保存”,这样 Visual Studio 代码将能够恢复所有包并刷新引用。此时,您已经在所有三个主要平台上配置了一个 ASP.NET MVC 核心项目,并且您可以开始在您选择的编辑器中编写代码。
实现控制器
在 MVC 应用中,URL 被映射到控制器,控制器是处理传入请求、处理用户输入和执行应用逻辑的 C#类。当您使用。这个项目包含一个名为HomeController
的控制器类,在HomeController.cs
文件中定义。该类公开了当用户单击用户界面中的超链接时调用的方法(技术上的操作),因此这些方法通过 HTML 标记映射到页面的内容,您将在下一节中看到。
对于当前示例,有必要在控制器内部实现一个方法(动作),该方法将被映射到之前添加到项目中的Vision.cshtml
页面。尽管这是现实应用中的常见做法,但在这种特殊情况下,为了简单起见,没有必要创建单独的控制器,因此可以根据我们的目的扩展HomeController
类。目前,HomeController
控制器包含四种动作方法:Index
,映射到Index.cshtml
页面;About
,映射到About.cshtml
页面;Contact
,映射到Contact.cshtml
页面;和Error
,映射到一般错误页面。名为Vision
的新动作将被添加到控制器中。该操作的代码很简单,如下所示:
public IActionResult Vision()
{
ViewData["Message"] = "Picture analysis";
return View();
}
这个方法返回到同名的页面,给动态对象ViewData
分配一个将在页面中显示的字符串。然后,您需要实现真正的操作,该操作将负责向计算机视觉服务发送 HTTP 请求,包括图像文件。在计算机视觉、面部和情感 API 的情况下,图像文件必须作为一个Stream
对象读取,它必须序列化为 base-64 字符串,然后包装成一个字节数组。因此,在实现该操作之前,您需要一些代码来读取图像文件并将其序列化为一个字节数组。这是通过以下代码完成的:
private string BytesToSrcString(byte[] bytes) => "data:img/jpg;base64," + Convert.ToBase64String(bytes);
// IFormFile represents a file that can be sent
// with HTTP requests
private string FileToImgSrcString(IFormFile file)
{
byte[] fileBytes;
using (var stream = file.OpenReadStream())
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
fileBytes = memoryStream.ToArray();
}
}
return BytesToSrcString(fileBytes);
}
既然您已经有了将图像文件作为流读取并将其序列化为字节数组的方法,那么您可以如下实现Vision
动作(参见代码中的注释):
private const string apiKey = "YOUR-KEY-GOES-HERE";
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Vision(IFormFile file)
{
//put the original file in the view data
ViewData["originalImage"] = FileToImgSrcString(file);
string result = null;
using (var httpClient = new HttpClient())
{
// Request parameters (Replace [location] with the domain name of your Azure region)
string baseUri = "https://[location].api.cognitive.microsoft.com/vision/v1.0/describe";
//set up HttpClient
httpClient.BaseAddress = new Uri(baseUri);
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
//set up data object
HttpContent content = new StreamContent(file.OpenReadStream());
content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/octet-stream");
//make request
var response = await httpClient.PostAsync(baseUri, content);
// get the string for the JSON response
string jsonResponse = await response.Content.ReadAsStringAsync();
// You can replace the following code with customized or
// more precise JSON deserialization
var jresult = JObject.Parse(jsonResponse);
result = jresult["description"]["captions"][0]["text"].ToString();
}
ViewData["result"] = result;
return View();
}
这里的代码调用允许描述图像的端点,但是当然您可以使用不同的端点。另外,注意这里的代码是如何使用你在第三章中使用的JObject
类的反序列化技术的。当然,根据您调用的端点和您期望的响应,您可以实现不同的反序列化技术。在这个特殊的例子中,服务返回的第一个自然语言描述被检索并返回到调用者页面,这是您之前添加的Vision.cshtml
页面,将在下一节中设计。
设计视图
用于选择和上传图像文件以及显示分析结果的Vision.cshtml
页面的用户界面非常简单。一个Form
对象包含用于显示一些文本的Label
控件,一个Input
控件允许用户选择一个文件,另一个Input
控件启动上传操作;此外,一个Img
控件用于显示选择的图像,另一个Label
用于显示调用计算机视觉服务的结果。页面的完整标记如下所示:
@{
ViewData["Title"] = "Vision";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<div class="row">
<div class="col-md-12">
<form asp-action="Vision" enctype="multipart/form-data">
<div class="form-horizontal">
<div class="form-group">
<label for="file">Image</label>
<input type="file" name="file" id="file" class="form-control">
<p class="help-block">Images must be up to 4 megabytes and greater than 50x50</p>
</div>
<div class="form-group">
<input type="submit" value="Upload" class="btn btn-primary" />
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h4>Original Image</h4>
<img src="@ViewData["originalImage"]" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<h4>Result</h4>
<label>@ViewData["result"]</label>
</div>
</div>
注意页面如何通过使用ViewData
对象从相关动作接收数据(在 ASP.NET MVC 中,@
符号允许您在标记中包含 C#代码)。设计好页面后,您必须将它添加到应用可用的页面列表中。为此,打开位于Views\Shared
下的_Layout.cshtml
文件,并在对可用页面进行分组的代码块中添加下面以粗体突出显示的行:
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Vision">Vision</a></li>
</ul>
</div>
注意asp-controller
是如何指定关联的控制器类的(省略了Controller
的字面意思)以及asp-action
是如何允许你在控制器中指定与页面关联的动作的。现在页面已经准备好了,您可以测试应用了。
测试应用
不管您使用的是什么开发环境和操作系统,您都可以使用您已经知道的调试工具来启动应用。比如,你可以在 Visual Studio 2017 中按 F5,在 Visual Studio for Mac 中按 Command+Enter,或者在 Visual Studio 代码中点击调试窗格中的“开始调试”按钮。
要知道,对于本地调试,ASP.NET MVC 核心使用一个名为 Kestrel ( http://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel
)的 web 服务器。Kestrel 是一个开源的跨平台开发服务器,可用于在调试时托管 web 应用,Visual Studio for Mac 和 Visual Studio 代码都会在您开始调试时自动使用 Kestrel。Windows 上的 Visual Studio 2017 不仅限于使用 Kestrel,还允许选择 IIS Express 作为主机。为了跨平台的一致性,对于这个例子,请确保选择 Kestrel 作为 Visual Studio 2017 中的开发服务器。为此,展开开始按钮的菜单并选择您的项目名称,如图 5-8 所示。
图 5-8。
In Visual Studio 2017, selecting the project name enables the Kestrel debugger.
当应用以调试模式启动时。NET 核心执行环境还在控制台应用中启动 Kestrel 服务。默认情况下,Kestrel 使用http://localhost:5000
地址。但是,Visual Studio 2017 允许您在项目属性中更改端口。当应用在你的浏览器中启动时,它将如图 5-9 所示。
图 5-9。
The sample application running
如您所见,右上角有一个名为 Vision 的超链接。如果您点击此超链接,将出现愿景页面,看起来如图 5-10 所示。
图 5-10。
The user interface designed to select and upload an image file
在这里,您可以单击浏览按钮,选择一个图像文件,准备好后,单击上传按钮。如果所选图像有效,计算机视觉 API 将返回一个描述,该描述将与所选图像一起显示在页面中,如图 5-11 所示。
图 5-11。
The result of the analysis returned by the Computer Vision API and displayed in the web page
现在让我们通过使用 OCR 而不是图像描述来看看应用的行为。首先,在HomeController.cs
文件中,用下面的声明更改baseUri
变量:
string baseUri = "https://[location].api.cognitive.microsoft.com/vision/v1.0/ocr";
其中[location]
必须替换为您的 Azure 区域的域名。然后,替换以下行:
result = jresult["description"]["captions"][0]["text"].ToString();
使用下面的循环来解析区域、行和单词(参见第章第三部分来回顾 OCR 响应):
foreach(var region in jresult["regions"])
{
foreach(var line in region["lines"])
{
foreach(var word in line["words"])
{
result = result + " " + word["text"].ToString();
}
}
}
如果您现在重新启动应用并选择一个包含文本的图像,您将看到如果操作成功,页面如何正确显示 OCR 识别的结果。图 5-12 显示了一个例子。
图 5-12。
The result of optical character recognition on an image
相反,最后一个例子是基于特定领域的模型,特别是基于地标识别。在 C#代码中,用以下内容替换baseUri
变量的值:
string baseUri = "https://[location].api.cognitive.microsoft.com/vision/v1.0/models/landmarks/analyze";
按照惯例,[location]
必须替换为您的 Azure 地区的名称。
Note
在前面的章节中,您看到了如何执行一个 HTTP GET 请求来检索您可以与前面的端点一起使用的特定于域的模型的列表。显然,如果您预先知道域模型的确切名称,就像在当前的例子中一样,您可以避免 GET 请求。
现在,将解析 JSON 响应的方式更改如下:
result = jresult["result"]["landmarks"][0]["name"].ToString();
其中,JSON 响应包含一个名为result
的数组,数组的数量与图片中检测到的地标一样多;每个的name
属性返回地标名称。如果您现在重启应用并尝试上传带有地标的图像,您将看到计算机视觉服务将如何检测到正确的信息,如图 5-13 所示。
图 5-13。
Landmarks recognition
计算机视觉 API 可以真正增强企业和消费者世界的 web 应用,其强大的图像分析算法可以帮助您创建下一代应用。此外,随着。NET Core,所有这些功能也可用于 macOS 和 Linux 系统。
摘要
在本章中,您看到了如何在用 ASP.NET MVC 核心构建的 web 应用中利用计算机视觉 API 的强大功能。一开始,您看到了如何使用 Visual Studio 2017、Visual Studio for Mac 和 Visual Studio 代码在三个不同的系统上创建相同的示例项目。
然后,您看到了如何在控制器中实现一个动作,从磁盘中读取一个图像文件,并将其发送到计算机视觉服务以描述其内容。接下来,您看到了如何设计一个包含选择和上传图像以及显示分析结果的控件的 web 页面。最后,您看到了如何在本地测试应用,展示了利用人工智能的 web 应用有多么强大。
标签:精粹,微软,Visual,API,Studio,图像,com,microsoft From: https://www.cnblogs.com/apachecn/p/18448121