基于.NET 后端实现图片搜索图片库的方案,核心是计算上传图片与库中图片的特征向量相似度并排序展示结果。
整体思路
- 图像特征提取:使用深度学习模型(如 ResNet)提取图片的特征向量。
- 特征向量存储:将图片的特征向量存储在数据库中。
- 相似度计算:使用余弦相似度算法计算上传图片与库中图片的特征向量相似度。
- 结果排序与展示:按相似度从高到低排序,并将相似图像展示给用户。
实现步骤
1. 项目搭建
创建一个新的 .NET Web API 项目,安装必要的 NuGet 包:
Microsoft.EntityFrameworkCore.SqlServer
:用于与 SQL Server 数据库交互。ML.NET
:用于特征提取和相似度计算。ImageSharp
:用于图像处理。
2. 图像特征提取
使用 ResNet 模型提取图片的特征向量。以下是一个示例代码:
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using Microsoft.ML;
using Microsoft.ML.Data;
using Microsoft.ML.Vision;
public class ImageData
{
[LoadColumn(0)]
public string ImagePath;
}
public class ImagePrediction
{
[ColumnName("Score")]
public float[] Score;
}
public class FeatureExtractor
{
private readonly MLContext _mlContext;
private readonly ITransformer _model;
public FeatureExtractor()
{
_mlContext = new MLContext();
var data = _mlContext.Data.LoadFromEnumerable(new List<ImageData>());
var pipeline = _mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: "", inputColumnName: nameof(ImageData.ImagePath))
.Append(_mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: 224, imageHeight: 224, inputColumnName: "input"))
.Append(_mlContext.Transforms.ExtractPixels(outputColumnName: "input"))
.Append(_mlContext.Model.LoadTensorFlowModel("resnet50.pb")
.ScoreTensorFlowModel(outputColumnNames: new[] { "output" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true));
_model = pipeline.Fit(data);
}
public float[] ExtractFeatures(string imagePath)
{
var imageData = new ImageData { ImagePath = imagePath };
var predictionEngine = _mlContext.Model.CreatePredictionEngine<ImageData, ImagePrediction>(_model);
var prediction = predictionEngine.Predict(imageData);
return prediction.Score;
}
}
3. 数据库设计与存储
创建一个 SQL Server 数据库,包含一个表用于存储图片的路径和特征向量。以下是一个示例表结构:
CREATE TABLE Images (
Id INT PRIMARY KEY IDENTITY(1,1),
ImagePath NVARCHAR(255) NOT NULL,
FeatureVector NVARCHAR(MAX) NOT NULL
);
使用 Entity Framework Core 进行数据库操作:
using Microsoft.EntityFrameworkCore;
public class ImageDbContext : DbContext
{
public DbSet<ImageEntity> Images { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("YourConnectionString");
}
}
public class ImageEntity
{
public int Id { get; set; }
public string ImagePath { get; set; }
public string FeatureVector { get; set; }
}
4. 相似度计算
使用余弦相似度算法计算两个特征向量的相似度:
public static double CosineSimilarity(float[] vectorA, float[] vectorB)
{
double dotProduct = 0;
double normA = 0;
double normB = 0;
for (int i = 0; i < vectorA.Length; i++)
{
dotProduct += vectorA[i] * vectorB[i];
normA += Math.Pow(vectorA[i], 2);
normB += Math.Pow(vectorB[i], 2);
}
normA = Math.Sqrt(normA);
normB = Math.Sqrt(normB);
if (normA == 0 || normB == 0)
{
return 0;
}
return dotProduct / (normA * normB);
}
5. 图片搜索 API
创建一个 Web API 接口,用于接收上传的图片并返回相似图片列表:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
[ApiController]
[Route("[controller]")]
public class ImageSearchController : ControllerBase
{
private readonly ImageDbContext _dbContext;
private readonly FeatureExtractor _featureExtractor;
public ImageSearchController(ImageDbContext dbContext, FeatureExtractor featureExtractor)
{
_dbContext = dbContext;
_featureExtractor = featureExtractor;
}
[HttpPost]
public IActionResult Search([FromForm] IFormFile image)
{
// 保存上传的图片
var uploadPath = "uploads/" + image.FileName;
using (var stream = new FileStream(uploadPath, FileMode.Create))
{
image.CopyTo(stream);
}
// 提取上传图片的特征向量
var uploadFeatures = _featureExtractor.ExtractFeatures(uploadPath);
// 从数据库中获取所有图片的特征向量
var allImages = _dbContext.Images.ToList();
// 计算相似度并排序
var similarities = new List<(ImageEntity Image, double Similarity)>();
foreach (var imageEntity in allImages)
{
var features = imageEntity.FeatureVector.Split(',').Select(float.Parse).ToArray();
var similarity = CosineSimilarity(uploadFeatures, features);
similarities.Add((imageEntity, similarity));
}
similarities = similarities.OrderByDescending(s => s.Similarity).ToList();
// 返回相似图片列表
var result = similarities.Select(s => s.Image.ImagePath).ToList();
return Ok(result);
}
}
总结
通过以上步骤,你可以实现一个基于 .NET 后端的图片搜索图片库功能。用户上传图片后,系统会提取其特征向量,计算与库中图片的相似度,并按相似度从高到低排序展示相似图片。