在这篇文章里面,我们讲解使用Azure+C#+visual studio在Azure上做图像的目标检测系统。
笔者是头一次接触C#。之前以Python Java和Scala为主。感觉C#+.Net是一种挺好用的开发系统。C#和Java非常像。会一个学另一个很快。
首先,目标检测是个什么东西?目标检测是一种计算机视觉技术,用于在图像或视频中识别并定位特定物体的类别和位置。
目标检测,其实分为两个部分。一个是定位,二一个是识别。这有点像我们小时候玩的套圈游戏。也就是说,要首先选出这个框,然后能识别出框里面是啥东西。
目标检测在深度学习曾经在图像处理时代被认为是一个非常难做的问题。在当时目标检测的效果也很差。我记得在我小时候日本进口的照相机能够识别人脸,我们都觉得这是非常牛逼的功能。但是在深度学习时代,这个任务已经做的非常好了。目前最流行,也是最好用的框架便是yolo(可以直接在github,或者ultranalytics的官网上进行查看)。现在,非常好用,非常好训练,也非常容易可以在flask/dijango这样的框架或者嵌入式设备(比如无人机或者照相机)上使用。
一篇很好的目标检测的review是(笔者后续也会更新一篇文章,估计是2万字长文,详细讲解所有的主流目标检测以及图像分割算法):https://www.cvmart.net/community/detail/3056
1,安装VS,以及在Azure上安装C#
这个可以说是最简单的一部分了(请注意visual studio和visual studio code是两个不同的软件,后者是前者的一个简化版):
这里是安装指南。
https://docs.pingcode.com/ask/ask-ask/108294.html
vscode也能搞。但是我个人推荐用vscode的时候尽量用命令行。
2,注册Azure
这个反而是相对麻烦的一部分。我建议大家直接看微软的官方文档(虽然又臭又长,感觉更像是律师而不是程序员看的东西。但是确实能解决问题。ChatGPT之类的可能给你的是旧信息,而且没有图片。问copolit会是个不错的选择。毕竟是微软自家的产品)。
如何创建Azure账号(AWS,GCP,阿里云,腾讯云,华为云和这个是同一个性质的东西)
https://learn.microsoft.com/zh-cn/dotnet/azure/create-azure-account
这里是关于计算机视觉服务的内容。需要先建立一个资源组,然后在这个资源组里加入计算机视觉的服务
https://learn.microsoft.com/zh-cn/azure/ai-services/custom-vision-service/
需要注意的在这里:
创建好资源以后在这里,记录一下你的密钥和终结点(密钥两个选一个即可):
我的建议是绝对不要把这两个以明文的形式写入代码里面。最好的办法是写成一个.json文件:
{
"COMPUTER_VISION_KEY": "",
"COMPUTER_VISION_ENDPOINT": ""
}
然后你就可以开始正式写代码了。
3,正式开搞
在这里,我们用C#写程序来解决问题:
在开搞之前,你需要用Nuget安装需要的package。vs里面,很好用。
using System;
using System.IO;
using System.Text.Json; // 用于处理 JSON 数据
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision; // Azure 计算机视觉服务库
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models; // 计算机视觉相关模型
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
// 存储 Azure 计算机视觉服务的终端点和密钥
private static string endpoint;
private static string key;
// 程序的入口点
static async Task Main(string[] args)
{
// 定义配置文件的路径
var configPath = @"";
// 检查配置文件是否存在
if (!File.Exists(configPath))
{
Console.WriteLine("Configuration file does not exist.");
return;
}
try
{
// 从配置文件中读取并反序列化 JSON 配置
var config = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(configPath));
// 检查是否包含所需的键值
if (config == null || !config.ContainsKey("COMPUTER_VISION_ENDPOINT") || !config.ContainsKey("COMPUTER_VISION_KEY"))
{
Console.WriteLine("Configuration file is missing required keys.");
return;
}
// 设置终端点和密钥
endpoint = config["COMPUTER_VISION_ENDPOINT"];
key = config["COMPUTER_VISION_KEY"];
// 检查终端点或密钥是否为空
if (string.IsNullOrEmpty(endpoint) || string.IsNullOrEmpty(key))
{
Console.WriteLine("Endpoint or key is not set in the configuration file.");
return;
}
}
catch (JsonException ex)
{
// 捕获 JSON 解析错误
Console.WriteLine($"Error reading configuration file: {ex.Message}");
return;
}
// 定义图像的相对路径
string imagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "images", "image.jpg");
Console.WriteLine($"Image Path: {imagePath}");
// 输出当前目录
Console.WriteLine($"Current Directory: {Directory.GetCurrentDirectory()}");
// 列出 images 文件夹中的所有文件
string imagesDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "images");
// 检查 images 目录是否存在
if (Directory.Exists(imagesDirectory))
{
Console.WriteLine("Files in images directory:");
// 输出 images 文件夹中的所有文件
foreach (var file in Directory.GetFiles(imagesDirectory))
{
Console.WriteLine(file);
}
}
else
{
Console.WriteLine("Images directory does not exist.");
return;
}
// 检查图像文件是否存在
if (!File.Exists(imagePath))
{
Console.WriteLine("File does not exist.");
return;
}
try
{
// 创建 Azure 计算机视觉服务客户端
ComputerVisionClient client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{
Endpoint = endpoint
};
// 读取图像文件流并分析图像中的物体
using (var imageStream = new FileStream(imagePath, FileMode.Open))
{
// 调用 Azure 计算机视觉服务的 API 以检测图像中的物体
var result = await client.AnalyzeImageInStreamAsync(imageStream, new List<VisualFeatureTypes?> { VisualFeatureTypes.Objects });
// 遍历检测结果并输出物体的名称、置信度和位置
foreach (var obj in result.Objects)
{
Console.WriteLine($"Object: {obj.ObjectProperty}, Confidence: {obj.Confidence}, Location: {obj.Rectangle.X}, {obj.Rectangle.Y}, {obj.Rectangle.W}, {obj.Rectangle.H}");
}
}
}
catch (UriFormatException ex)
{
// 捕获 URI 格式错误
Console.WriteLine($"Invalid URI: {ex.Message}");
}
catch (Exception ex)
{
// 捕获其他异常
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
我们做开发的时候还需要注意文件的路径问题。这是我开发路径的截图: