65.9K
CodeProject 正在变化。 阅读更多。
Home

使用图像分类和 Azure Cognitive Services 构建数字取证工具

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2019 年 6 月 30 日

CPOL

9分钟阅读

viewsIcon

14588

OLAF 是一种数字取证工具,专为面向公众的 PC 或公司桌面设计,可以近实时地对用户浏览时下载的图像进行分类,以帮助执行有关知识产权、不当内容和煽动暴力的计算机使用策略。

引言

OLAFOnline Automated Forensics,在线自动化取证)是一种自动化数字取证工具,它使用计算机视觉和机器学习自动对用户浏览互联网时下载的图像和文档进行分类。

OLAF 监控浏览器和知名用户文件夹的文件系统活动,并使用两阶段检测过程,首先运行图像对象检测算法以确定下载的图像是富文本图像还是可能包含人脸的照片。照片图像被发送到 Azure 认知服务的计算机视觉 API,以分析和分类内容,包括照片是否可能包含性或成人内容。对于非照片图像,OLAF 还会对图像运行 OCR 以提取任何文本,并将其发送到 Azure 认知服务的文本分析 API,以提取有关所提及实体等信息。OLAF 捕获图像伪影在 PC 上创建的精确日期和时间,以及伪影本身和描述图像内容的属性,这些属性可用于为调查违反计算机使用策略的行为提供取证证据。

对于图书馆、学校或网吧等场所的 PC,OLAF 可以帮助执行组织的计算机使用策略,涵盖知识产权和盗版、成人或色情图像、仇恨言论或煽动暴力和恐怖主义以及用户下载的其他不允许内容。对于企业,OLAF 可以检测可能包含竞争对手知识产权的文档的渗透,从而使组织面临法律风险。

在本文中,我将描述在 .NET 中构建一个真实世界的图像分类应用程序的一些步骤和挑战。我将讨论使用两个流行的开源机器学习库——Tesseract OCRAccord.NET,以及使用基于云的机器学习服务——来自 Azure 认知服务计算机视觉 API,来分析和分类图像。我在这里不会过多地讨论图像分类算法或设置 Azure 认知服务帐户,而是将更多地关注将不同的图像分类和机器学习软件组件组合在一起的过程,以及在此过程中出现的设计决策和权衡。设置 Azure 认知服务资源非常简单,可以在五分钟内通过 Azure 门户完成。

与许多 Azure 服务一样,计算机视觉 API 提供了免费使用层,因此任何拥有有效 Azure 订阅(包括免费的 Azure for Students 订阅)的用户都可以试用它或运行像 OLAF 这样的应用程序。

背景

当然,抛开技术问题不谈,OLAF 似乎只是一种监视用户的复杂方式。无论是在公共电脑上还是不在,没有人喜欢一个程序在他们在线浏览时监视他们的想法。但就技术而言,最可靠的立场是,如果某件事有可能做到,那么就一定会有人去做,所以担心你所创造的事物被滥用在很大程度上是没有意义的。最好是了解如何进行用户活动监控,并将其作为开源发布意味着其他人可以研究它并验证至少收集到的有关用户活动的信息是以合法方式使用的。

目前市面上至少有十款商业用户监控应用程序可供购买,并且制作专有用户监控软件的商业公司数量还在不断增长。像 OLAF 这样的开源用户监控软件可以提供一种更为道德和安全的用户监控方式,在这些监控确实具有合法目的和价值的情况下。

概述

OLAF 是一个用 C# 编写的 .NET 应用程序,目标是 .NET Framework 4.5+。尽管设想为桌面 Windows 应用程序,但其核心库中没有任何桌面或 Windows 特定的内容,并且 OLAF 可以在其他桌面平台(如 Linux)或使用 Xamarin 的移动电话上运行。

OLAF 在后台运行,监控用户的浏览器以及他或她下载到特定文件夹的文件。

当检测到图像文件下载时,OLAF 会对该文件运行不同的图像分类算法。首先,它使用 Tesseract OCR 库判断图像是否可能包含文本。然后,它使用 Viola-Jones 对象检测框架判断图像是否可能包含人脸。如果图像可能是一张带人脸的照片,OLAF 会将图像发送到 Azure 计算机视觉 API 进行更高级的分类。通过这种方式,我们可以避免在绝对必要时才调用 Azure API。

上面的视频简要演示了 OLAF 的基本功能。首先,我导航并下载了一张跑车图片到我的下载文件夹。OLAF 的图像分类部分在本地运行,并确定该图片不包含任何人脸,处理流程结束。

05:51:48<03> [DBG] Read 33935 bytes from "C:\\Users\\Allister\\Downloads\\hqdefault.jpg".
05:51:48<03> [DBG] Wrote 33935 bytes to 
"c:\\Projects\\OLAF\\data\\artifacts\\20190628_UserDownloads_636973760617841436\\3_hqdefault.jpg".
05:51:48<08> [DBG] "FileImages" consuming message 3.
05:51:48<08> [INF] Extracting image from artifact 3 started...
05:51:48<08> [DBG] Extracted image from file "3_hqdefault.jpg" 
                   with dimensions: 480x360 pixel format: Format24bppRgb hres: 96 yres: 96.
05:51:48<08> [INF] Extracting image from artifact 3 "completed" in 17.4 ms
05:51:48<08> [INF] "FileImages" added artifact id 4 
                    of type "OLAF.ImageArtifact" from artifact 3.
05:51:48<09> [DBG] "TesseractOCR" consuming message 4.
05:51:48<08> [DBG] Pipeline ending for artifact 3.
05:51:48<09> [DBG] Pix has width: 480 height: 360 depth: 32 xres: 0 yres: 300.
05:51:48<09> [INF] Tesseract OCR (fast) started...
05:51:48<09> [INF] Artifact id 4 is likely a photo or non-text image.
05:51:49<09> [INF] Tesseract OCR (fast) "completed" in 171.4 ms
05:51:49<10> [DBG] "ViolaJonesFaceDetector" consuming message 4.
05:51:49<10> [INF] Viola-Jones face detection on image artifact 4. started...
05:51:49<10> [INF] Found 0 candidate face object(s) in artifact 4.
05:51:49<10> [INF] Viola-Jones face detection on image artifact 4. "completed" in 96.9 ms
05:51:49<11> [DBG] "MSComputerVision" consuming message 4.
05:51:49<11> [DBG] Not calling MS Computer Vision API for image artifact 4 
                   without face object candidates.

当我下载名人 Rashida Jones 的图片时,图像分类算法检测到下载的图片含有人脸,然后将图片发送到 Azure 计算机视觉 API,该 API 分析图片并添加包含图片中检测到的所有对象的标签,包括对图片是否为成人内容的评分。

05:52:13<03> [DBG] Waiting a bit for file to complete write...
05:52:13<03> [DBG] Read 62726 bytes from 
"C:\\Users\\Allister\\Downloads\\rs_1024x759-171120092206-1024.
Rashida-Jones-Must-Do-Monday.jl.112017.jpg".
05:52:13<03> [DBG] Wrote 62726 bytes to 
"c:\\Projects\\OLAF\\data\\artifacts\\20190628_UserDownloads_636973760617841436\\
5_rs_1024x759-171120092206-1024.Rashida-Jones-Must-Do-Monday.jl.112017.jpg".
05:52:13<08> [DBG] "FileImages" consuming message 5.
05:52:13<08> [INF] Extracting image from artifact 5 started...
05:52:13<08> [DBG] Extracted image from file 
"5_rs_1024x759-171120092206-1024.Rashida-Jones-Must-Do-Monday.jl.112017.jpg" 
with dimensions: 1024x759 pixel format: Format24bppRgb hres: 72 yres: 72.
05:52:13<08> [INF] Extracting image from artifact 5 "completed" in 34.4 ms
05:52:14<08> [INF] "FileImages" added artifact id 6 of type 
"OLAF.ImageArtifact" from artifact 5.
05:52:14<08> [DBG] Pipeline ending for artifact 5.
05:52:14<09> [DBG] "TesseractOCR" consuming message 6.
05:52:14<09> [DBG] Pix has width: 1024 height: 759 depth: 32 xres: 0 yres: 300.
05:52:14<09> [INF] Tesseract OCR (fast) started...
05:52:14<09> [INF] Artifact id 6 is likely a photo or non-text image.
05:52:14<09> [INF] Tesseract OCR (fast) "completed" in 99.8 ms
05:52:14<10> [DBG] "ViolaJonesFaceDetector" consuming message 6.
05:52:14<10> [INF] Viola-Jones face detection on image artifact 6. started...
05:52:14<10> [INF] Found 1 candidate face object(s) in artifact 6.
05:52:14<10> [INF] Viola-Jones face detection on image artifact 6. "completed" in 173.6 ms
05:52:14<11> [DBG] "MSComputerVision" consuming message 6.
05:52:14<11> [INF] Artifact 6 is likely a photo with faces detected; 
analyzing using MS Computer Vision API.
05:52:14<11> [INF] Analyze image using MS Computer Vision API. started...
05:52:16<11> [INF] Analyze image using MS Computer Vision API. "completed" in 2058.9 ms
05:52:16<11> [INF] Image categories: ["people_portrait/0.7265625"]
05:52:16<11> [INF] Image properties: Adult: False/0.00276160705834627 
Racy: False/0.00515600480139256 Description:["indoor", "person", "sitting", 
"holding", "woman", "box", "looking", "front", "man", "laptop", "table", "smiling", "shirt", 
"white", "large", "computer", "yellow", "young", "food", "refrigerator", "cat", 
"standing", "sign", "kitchen", "room", "bed"]
05:52:16<12> [DBG] "AzureStorageBlobUpload" consuming message 6.
05:52:16<12> [INF] Artifact id 6 not tagged for preservation.
05:52:16<12> [DBG] Pipeline ending for artifact 6.

Azure 计算机视觉能够检测“露骨”图像和包含裸体的图像。

23:35:11<03> [DBG] Waiting a bit for file to complete write...
23:35:11<03> [DBG] Read 7247 bytes from "C:\\Users\\Allister\\Downloads\\download (1).jpg".
23:35:11<03> [DBG] Wrote 7247 bytes to 
"c:\\Projects\\OLAF\\data\\artifacts\\20190628_UserDownloads_636973760617841436\\
1_download (1).jpg".
23:35:11<08> [DBG] "FileImages" consuming message 1.
23:35:11<08> [INF] Extracting image from artifact 1 started...
23:35:11<08> [DBG] Extracted image from file "1_download (1).jpg" with dimensions: 
194x259 pixel format: Format24bppRgb hres: 96 yres: 96.
23:35:11<08> [INF] Extracting image from artifact 1 "completed" in 14.6 ms
23:35:11<09> [DBG] "TesseractOCR" consuming message 2.
23:35:11<08> [INF] "FileImages" added artifact id 2 of type "OLAF.ImageArtifact" 
from artifact 1.
23:35:11<08> [DBG] Pipeline ending for artifact 1.
23:35:11<09> [DBG] Pix has width: 194 height: 259 depth: 32 xres: 0 yres: 300.
23:35:11<09> [INF] Tesseract OCR (fast) started...
23:35:11<09> [INF] Artifact id 2 is likely a photo or non-text image.
23:35:11<09> [INF] Tesseract OCR (fast) "completed" in 176.5 ms
23:35:11<10> [DBG] "ViolaJonesFaceDetector" consuming message 2.
23:35:11<10> [INF] Viola-Jones face detection on image artifact 2. started...
23:35:11<10> [INF] Found 1 candidate face object(s) in artifact 2.
23:35:11<10> [INF] Viola-Jones face detection on image artifact 2. "completed" in 86.0 ms
23:35:11<11> [DBG] "MSComputerVision" consuming message 2.
23:35:11<11> [INF] Artifact 2 is likely a photo with faces detected; 
analyzing using MS Computer Vision API.
23:35:11<11> [INF] Analyze image using MS Computer Vision API. started...
23:35:14<11> [INF] Analyze image using MS Computer Vision API. "completed" in 2456.2 ms
23:35:14<11> [INF] Image categories: ["people_/0.99609375"]
23:35:14<11> [INF] Image properties: Adult: False/0.0119723649695516 Racy: 
True/0.961882710456848 Description:["clothing", "person", "woman", "posing", 
"young", "smiling", "underwear", "carrying", "holding", "dress", "standing", 
"white", "water", "board", "suitcase", "wedding", "bed"]
23:35:14<12> [DBG] "AzureStorageBlobUpload" consuming message 2.

设计

核心内部设计围绕着一个异步消息队列,应用程序的不同部分通过它高效通信,而不会阻塞特定线程。由于 OLAF 设计为在后台持续运行,并且必须执行一些潜在的计算密集型操作,因此性能是整体设计的关键考虑因素。

该应用程序被构造成一个管道,用户活动生成的工件通过 OCR、图像分类和其他服务进行处理。管道的每个组件都是一个 C# 类,它继承自基类 OLAFApi

    public abstract class OLAFApi<TApi, TMessage> where TMessage : Message

每个组件声明它感兴趣处理或发送的队列消息类型。例如,DirectoryChangesMonitor 组件声明如下:

public class DirectoryChangesMonitor : FileSystemMonitor<FileSystemActivity, 
                                       FileSystemChangeMessage, FileArtifact>

此组件监听 FileSystemChangeMessage 队列消息,并在保留文件工件后,在队列上放置一个 FileArtifact 消息,指示文件工件已准备好供其他管道组件处理。

管道组件基于 OLAF.Base 项目中声明的一组基类构建。组件主要分为 3 大类:活动检测器监视器服务

活动检测器

活动检测器与操作系统交互以检测用户活动,例如文件下载。

    public abstract class ActivityDetector<TMessage>: 
           OLAFApi<ActivityDetector<TMessage>, TMessage>, IActivityDetector
        where TMessage : Message

活动检测器只将消息放入消息队列,不监听队列中的任何消息。例如,FileSystemActivity 检测器声明如下:

    public class FileSystemActivity : ActivityDetector<FileSystemChangeMessage>, IDisposable 

文件系统活动通过标准 .NET FileSystemWatcher 类进行检测。当文件被创建时,会入队一条消息:

private void FileSystemActivity_Created(object sender, FileSystemEventArgs e)
{
    EnqueueMessage(new FileSystemChangeMessage(e.FullPath, e.ChangeType));
}

这允许另一个组件处理实际创建的文件。活动检测器旨在轻量化并快速执行,因为它们代表 OLAF 与操作系统的接触点,并且可能在需要快速无误执行的操作系统钩子内部执行。活动检测器只是将消息放入队列并返回空闲状态,从而能够处理来自操作系统的潜在大量活动通知。消息的实际处理和图像工件的创建由监控器组件处理。

监视器

监视器监听队列中的活动检测器消息,并根据活动检测器提供的信息创建将通过管道处理的初始工件。

    public abstract class Monitor<TDetector, TDetectorMessage, TMonitorMessage> : 
        OLAFApi<Monitor<TDetector, TDetectorMessage, TMonitorMessage>, TMonitorMessage>, 
        IMonitor, IQueueProducer
        where TDetector : ActivityDetector<TDetectorMessage>
        where TDetectorMessage : Message
        where TMonitorMessage : Message

例如,`DirectoryChangesMonitor` 类声明如下:

    public class DirectoryChangesMonitor : 
    FileSystemMonitor<FileSystemActivity, FileSystemChangeMessage, FileArtifact>

此监视器监听指示文件已下载的 FileSystemChange 消息,首先将文件复制到内部 OLAF 数据文件夹,以便即使用户之后将其删除,文件也能得到保留。然后,它将一个 FileArtifact 消息放置在队列上,指示一个工件可供队列图像分类和其他服务进行处理。

服务

服务是对用户活动生成的图像和其他工件进行实际分析的组件。

    public abstract class Service<TClientMessage, TServiceMessage> : 
        OLAFApi<Service<TClientMessage, TServiceMessage>, TServiceMessage>, IService
        where TClientMessage : Message
        where TServiceMessage : Message

例如,`TesseractOCR` 服务声明如下:

public class TesseractOCR : Service<ImageArtifact, Artifact>

此服务消耗一个 ImageArtifact,但由于它根据 OCR 操作的结果可以生成不同的工件,因此它在签名中只使用一个泛型 Artifact,指示输出队列消息类型。BlobDetector 服务消耗图像工件,也生成图像工件。

    public class BlobDetector : Service<ImageArtifact, ImageArtifact>   

每个服务处理在队列中收到的工件,并输出一个通过文本提取或其他机器学习应用程序添加了任何信息的丰富工件。然后,该工件可以由队列中的其他服务进一步处理。

OCR

OLAF 使用流行的 Tesseract OCR 库来检测和提取用户下载图像中的任何文本。我们使用 tesseract.netleptonica.net .NET 库,它们封装了 Tesseract 和 Tesseract 使用的 Leptonica 图像处理库。尽管 Azure 的计算机视觉 API 也具有 OCR 功能,但在本地使用 Tesseract 可以节省每次处理图像工件时调用 Azure 服务的成本。TesseractOCR 服务按如下方式处理图像工件:首先,我们从发布到队列的图像工件创建一个 Leptonica 图像。

        protected override ApiResult ProcessClientQueueMessage(ImageArtifact message)
        {
            BitmapData bData = message.Image.LockBits(
                new Rectangle(0, 0, message.Image.Width, message.Image.Height), 
                              ImageLockMode.ReadOnly, message.Image.PixelFormat);
            int w = bData.Width, h = bData.Height, bpp = 
                              Image.GetPixelFormatSize(bData.PixelFormat) / 8;
            unsafe
            {
                TesseractImage.SetImage(new UIntPtr(bData.Scan0.ToPointer()), 
                               w, h, bpp, bData.Stride);
            }
            Pix = TesseractImage.GetInputImage();
            
            Debug("Pix has width: {0} height: {1} depth: {2} xres: {3} yres: {4}.", 
                                         Pix.Width, Pix.Height, Pix.Depth, 
                Pix.XRes, Pix.YRes);

然后我们在图像上运行识别器

            List<string> text;
            using (var op = Begin("Tesseract OCR (fast)"))
            {
                TesseractImage.Recognize();
                ResultIterator resultIterator = TesseractImage.GetIterator();
                text = new List<string>();
                PageIteratorLevel pageIteratorLevel = PageIteratorLevel.RIL_PARA;
                do
                {
                    string r = resultIterator.GetUTF8Text(pageIteratorLevel);
                    if (r.IsEmpty()) continue;
                    text.Add(r.Trim());
                }
                while (resultIterator.Next(pageIteratorLevel));

如果 Tesseract 识别出少于七个文本部分,则服务认为它可能是照片或非文本图像。服务会自动将它们收到的工件传递给监听队列的其他服务,因此在这种情况下我们无需做任何进一步的操作。如果文本部分多于七个,则服务会创建一个额外的 TextArtifact 并将其发布到队列。

                if (text.Count > 0)
                {
                    string alltext = text.Aggregate((s1, s2) => s1 + " " + s2).Trim();

                    if (text.Count < 7)
                    {
                        Info("Artifact id {0} is likely a photo or non-text image.", 
                              message.Id);
                    }
                    else
                    {
                        message.OCRText = text;
                        Info("OCR Text: {0}", alltext);
                    }
                }
                else
                {
                    Info("No text recognized in artifact id {0}.", message.Id);
                }
                op.Complete();
            }

            message.Image.UnlockBits(bData);
            if (text.Count >= 7)
            {
                TextArtifact artifact = new TextArtifact(message.Name + ".txt", text);
                EnqueueMessage(artifact);
                Info("{0} added artifact id {1} of type {2} from artifact {3}.", 
                     Name, artifact.Id, artifact.GetType(), 
                    message.Id);
            }

            return ApiResult.Success;
        }

人脸识别

ViolaJonesFaceDetector 服务尝试猜测图像工件是否包含人脸。此服务使用 .NET 的 Accord.NET 机器学习框架和 HaarObjectDetector 类,该类实现了用于人脸的 Viola-Jones 对象检测算法。如果检测器在图像工件中检测到人脸,它会将此信息添加到工件中。

        protected override ApiResult ProcessClientQueueMessage(ImageArtifact artifact)
        {
            if (artifact.HasOCRText)
            {
                Info("Not using face detector on text-rich image artifact {0}.", artifact.Id);
                return ApiResult.Success;
            }

            Bitmap image = artifact.Image;
            using (var op = Begin("Viola-Jones face detection on image artifact {0}.", 
                   artifact.Id))
            {
                Rectangle[] objects = Detector.ProcessFrame(image);
                if (objects.Length > 0)
                {
                    if (!artifact.DetectedObjects.ContainsKey(ImageObjectKinds.FaceCandidate))
                    {
                        artifact.DetectedObjects.Add(ImageObjectKinds.FaceCandidate, 
                                                     objects.ToList());
                    }
                    else
                    {
                        artifact.DetectedObjects
                             [ImageObjectKinds.FaceCandidate].AddRange(objects); 
                    }
                }
                Info("Found {0} candidate face object(s) in artifact {1}.", 
                               objects.Length, artifact.Id);
                op.Complete();
            }
            return ApiResult.Success;
        }

有关检测到的人脸信息现在可用于监听队列的其他服务。

计算机视觉 API

MSComputerVision 服务使用 Azure 认知服务提供的 计算机视觉 API SDK,该 SDK 可在 NuGet 上获取。与大多数其他 Azure SDK 一样,从 .NET 设置和使用此 Azure API 非常简单。一旦我们拥有有效的计算机视觉 API 密钥,我们就在服务的 Init() 方法中创建一个 API 客户端。

        public override ApiResult Init()
        {
            try
            {
                ApiKeyServiceClientCredentials c = 
                         new ApiKeyServiceClientCredentials(ApiAccountKey);
                Client = new ComputerVisionClient(c);
                Client.Endpoint = ApiEndpointUrl;
                return SetInitializedStatusAndReturnSucces();
            }
            catch(Exception e)
            {
                Error(e, "Error creating Microsoft Computer Vision API client.");
                Status = ApiStatus.RemoteApiClientError;
                return ApiResult.Failure;
            }
        }

如果正在处理的工件没有任何检测到的人脸对象,那么我们就不调用计算机视觉 API。这会将调用 Azure API 的成本降低到我们认为是人像照片的那些工件。

        protected override ApiResult ProcessClientQueueMessage(ImageArtifact artifact)
        {
            if (!artifact.HasDetectedObjects(ImageObjectKinds.FaceCandidate) || 
                                artifact.HasOCRText)
            {
                Debug("Not calling MS Computer Vision API for image artifact {0} 
                              without face object candidates.", artifact.Id);
            }

            else if (artifact.FileArtifact == null)
            {
                Debug("Not calling MS Computer Vision API for non-file image artifact {0}.", 
                       artifact.Id);
            }

            else
            {

要调用 API,我们打开一个文件流并将其传递给 API 客户端,后者调用 API 并返回一个 Task<ImageAnalysis> 实例,其中包含异步操作的结果。

                Info("Artifact {0} is likely a photo with faces detected; 
                      analyzing using MS Computer Vision API.", artifact.Id);
                ImageAnalysis analysis = null;
                using (var op = Begin("Analyze image using MS Computer Vision API."))
                {
                    try
                    {
                        using (Stream stream = artifact.FileArtifact.HasData ? 
                              (Stream) new MemoryStream(artifact.FileArtifact.Data)
                            : new FileStream(artifact.FileArtifact.Path, FileMode.Open))
                        {
                            Task<ImageAnalysis> t1 = Client.AnalyzeImageInStreamAsync(stream,
                                VisualFeatures, null, null, cancellationToken);
                            analysis = t1.Result;
                            op.Complete();
                        }
                    }
                    catch (Exception e)
                    {
                        Error(e, "An error occurred during image analysis 
                              using the Microsoft Computer Vision API.");
                        return ApiResult.Failure;
                    }
                }

图像分析实例包含计算机视觉 API 将图像分类到的类别

                if (analysis.Categories != null)
                {
                    Info("Image categories: {0}", analysis.Categories.Select
                                 (c => c.Name + "/" + c.Score.ToString()));
                    foreach (Category c in analysis.Categories)
                    {

                        artifact.Categories.Add(new ArtifactCategory(c.Name, null, c.Score));
                    }
                }

以及指示图像是否被归类为露骨或包含成人内容的得分。

                Info("Image properties: Adult: {0}/{1} Racy: {2}/{3} Description:{4}",
                    analysis.Adult.IsAdultContent, analysis.Adult.AdultScore, 
                           analysis.Adult.IsRacyContent,
                    analysis.Adult.RacyScore, analysis.Description.Tags);
                artifact.IsAdultContent = analysis.Adult.IsAdultContent;
                artifact.AdultContentScore = analysis.Adult.AdultScore;
                artifact.IsRacy = analysis.Adult.IsRacyContent;
                artifact.RacyContentScore = analysis.Adult.RacyScore;
                analysis.Description = analysis.Description;
            }
            return ApiResult.Success;
        }

计算机视觉 API 的图像分类器提供的所有信息都添加到工件中,现在可供队列中更下游的其他服务进行进一步处理。

历史

  • 2019 年 7 月 1 日:初始版本
© . All rights reserved.