c#中 在webapi中 使用opencvSharp4以及ssim算法 完成人脸检测 以此实现以图搜图

c#中 在webapi中 使用opencvSharp4以及ssim算法 完成人脸检测 以此实现以图搜图

通过把上传的图片中的人物人脸剪切出来跟图库作比较 
最终跟相似度做比较 把符合的筛选出来
优化
1.ssim算法消耗进程内存过多
2.opencvsharp可以考虑替换成开源框架FaceRecognitionDotNet

整体代码如下

using Emgu.CV;
using Emgu.CV.Structure;
using Microsoft.AspNetCore.Mvc;
using OpenCvSharp;
using System.Drawing;
using CascadeClassifier = Emgu.CV.CascadeClassifier;
using Mat = OpenCvSharp.Mat;
using Size = System.Drawing.Size;

namespace WebApplication5.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }

        /// <summary>
        /// 剪切图片中的人脸并保存
        /// </summary>
        [HttpGet(Name = "Getface")]
        public void GetFace()
        {
            var face = new CascadeClassifier(@"C:\Users\2023\Desktop\haarcascade_frontalface_alt.xml");
            //加载要识别的图片
            var img = new Image<Bgr, byte>(@"C:\Users\2023\Desktop\test\38.png");

            //在这一步就已经识别出来了,返回的是人脸所在的位置和大小
            var facesDetected = face.DetectMultiScale(img, 1.2, 10, new Size(60, 60));

            //循环把人脸部分切出来并保存
            int count = 0;
            var b = img.ToBitmap();

            foreach (var item in facesDetected)
            {
                count++;
                var bmpOut = new Bitmap(item.Width, item.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                var g = Graphics.FromImage(bmpOut);
                g.DrawImage(b, new Rectangle(0, 0, item.Width, item.Height), new Rectangle(item.X, item.Y, item.Width, item.Height), GraphicsUnit.Pixel);
                g.Dispose();
                
                bmpOut.Save($"{count}.png", System.Drawing.Imaging.ImageFormat.Png);
                bmpOut.Dispose();
            }

            //释放资源退出
            b.Dispose();
            img.Dispose();
            face.Dispose();
        }


        /// <summary>
        /// 根据生成的人脸进行比对并输出符合条件的图片
        /// </summary>
        [HttpGet(Name = "GetResultImage")]
        public void getResultImage()
        {
            
            var localImages = Directory.GetFiles(@"C:\Users\2023\Desktop\test", "*.png");
            String generatedImage = @"C:\Users\2023\Desktop\6.png";
            double Minshold = 0.38731;
            double Maxhold = 0.4401;

            Parallel.ForEach(localImages, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
                (i) =>
                {
                    // 进行比对的代码
                    double ssim = (double)CompareImagesSSIM(i, generatedImage);

                    if (ssim >= Minshold && ssim <= Maxhold)
                    {
                        var outputDirectory = @"C:\Users\2023\Desktop\testPro\newDir";
                        if (!Directory.Exists(outputDirectory))
                        {
                            Directory.CreateDirectory(outputDirectory);
                        }
                        var outputFilePath = Path.Combine(outputDirectory, Path.GetFileName(i));

                        using (var sourceStream = new FileStream(i, FileMode.Open))
                        using (var destinationStream = new FileStream(outputFilePath, FileMode.Create))
                        {
                            sourceStream.CopyTo(destinationStream);
                        }
                    }
                }
            );
        }








        /// <summary>
        /// 计算ssim精确度
        /// </summary>
        /// <param name="imgFile1"></param>
        /// <param name="imgFile2"></param>
        /// <returns></returns>
        [HttpPost(Name = "GetSsim")]
        public Scalar CompareImagesSSIM(string imgFile1, string imgFile2)
        {
            using (var image1 = Cv2.ImRead(imgFile1))
            using (var image2Tmp = Cv2.ImRead(imgFile2))
            {
                // 将两个图片处理成同样大小,否则会有错误: 
                var image2 = new Mat();
                Cv2.Resize(image2Tmp, image2, new OpenCvSharp.Size(image1.Size().Width, image1.Size().Height));
                double C1 = 6.5025, C2 = 58.5225;
                var validImage1 = new Mat();
                var validImage2 = new Mat();
                Parallel.Invoke(
                    () =>{  image1.ConvertTo(validImage1, MatType.CV_32F); },
                   () => { image2.ConvertTo(validImage2, MatType.CV_32F); }

                );
                //image1.ConvertTo(validImage1, MatType.CV_32F); //数据类型转换为 float,防止后续计算出现错误
                //image2.ConvertTo(validImage2, MatType.CV_32F);

                Mat image1_1 = validImage1.Mul(validImage1); //图像乘积
                Mat image2_2 = validImage2.Mul(validImage2);
                Mat image1_2 = validImage1.Mul(validImage2);

               
               Mat gausBlur1 = new Mat(), gausBlur2 = new Mat(), gausBlur12 = new Mat();
                Cv2.GaussianBlur(validImage1, gausBlur1, new OpenCvSharp.Size(11, 11), 1.5); //高斯卷积核计算图像均值
                Cv2.GaussianBlur(validImage2, gausBlur2, new OpenCvSharp.Size(11, 11), 1.5);
                Cv2.GaussianBlur(image1_2, gausBlur12, new OpenCvSharp.Size(11, 11), 1.5);

                Parallel.Invoke(
                   () => { }
                   );

                Mat imageAvgProduct = gausBlur1.Mul(gausBlur2); //均值乘积
                Mat u1Squre = gausBlur1.Mul(gausBlur1); //各自均值的平方
                Mat u2Squre = gausBlur2.Mul(gausBlur2);

                Mat imageConvariance = new Mat(), imageVariance1 = new Mat(), imageVariance2 = new Mat();
                Mat squreAvg1 = new Mat(), squreAvg2 = new Mat();
                Cv2.GaussianBlur(image1_1, squreAvg1, new OpenCvSharp.Size(11, 11), 1.5); //图像平方的均值
                Cv2.GaussianBlur(image2_2, squreAvg2, new OpenCvSharp.Size(11, 11), 1.5);

                imageConvariance = gausBlur12 - gausBlur1.Mul(gausBlur2);// 计算协方差
                imageVariance1 = squreAvg1 - gausBlur1.Mul(gausBlur1); //计算方差
                imageVariance2 = squreAvg2 - gausBlur2.Mul(gausBlur2);

                var member = ((2 * gausBlur1.Mul(gausBlur2) + C1).Mul(2 * imageConvariance + C2));
                var denominator = ((u1Squre + u2Squre + C1).Mul(imageVariance1 + imageVariance2 + C2));
                Mat ssim = new Mat();
                Cv2.Divide(member, denominator, ssim);
                var sclar = Cv2.Mean(ssim);

                validImage1.Dispose();
                validImage2.Dispose();
                image1_1.Dispose();
                image2_2.Dispose();
                image1_2.Dispose();
                gausBlur1.Dispose();
                gausBlur2.Dispose();
                gausBlur12.Dispose();
                imageAvgProduct.Dispose();
                u1Squre.Dispose();
                u2Squre.Dispose();
                imageConvariance.Dispose();
                imageVariance1.Dispose();
                imageVariance2.Dispose();
                squreAvg1.Dispose();
                squreAvg2.Dispose();
                ssim.Dispose();

                GC.Collect();
                return sclar;  // 变化率,即差异
            }

        }

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SSIM(结构相似性)是评估两张图片相似度的一种指标。Java实现2张图片的SSIM算法,需要用到以下步骤: 1. 将两张图片读入内存,可以使用BufferedImage类。 2. 将图片转换为灰度图像,可以使用ColorConvertOp类。 3. 将灰度图像按照一定的窗口大小划分为多个子窗口。 4. 计算每个子窗口的像素值均值、标准差和协方差。 5. 根据子窗口的像素值均值、标准差和协方差计算SSIM指数。 下面是Java代码实现: ```java import java.awt.image.BufferedImage; import java.awt.image.ColorConvertOp; public class SSIM { public static double getSSIM(BufferedImage img1, BufferedImage img2) { int width = img1.getWidth(); int height = img1.getHeight(); // Convert images to grayscale ColorConvertOp op = new ColorConvertOp(null); BufferedImage grayImg1 = op.filter(img1, null); BufferedImage grayImg2 = op.filter(img2, null); // Set window size int windowSize = 8; // Set constants double K1 = 0.01; double K2 = 0.03; double L = 255; double C1 = Math.pow(K1 * L, 2); double C2 = Math.pow(K2 * L, 2); double ssim = 0.0; // Loop through each window for (int i = 0; i < height; i += windowSize) { for (int j = 0; j < width; j += windowSize) { double sum1 = 0.0; double sum2 = 0.0; double sum3 = 0.0; // Loop through each pixel in window for (int k = i; k < i + windowSize && k < height; k++) { for (int l = j; l < j + windowSize && l < width; l++) { double pixel1 = grayImg1.getRGB(l, k) & 0xff; double pixel2 = grayImg2.getRGB(l, k) & 0xff; sum1 += pixel1; sum2 += pixel2; sum3 += pixel1 * pixel2; } } // Calculate mean and covariance double n = windowSize * windowSize; double mean1 = sum1 / n; double mean2 = sum2 / n; double cov = (sum3 / n) - (mean1 * mean2); // Calculate SSIM for this window double numerator = (2 * mean1 * mean2 + C1) * (2 * cov + C2); double denominator = (Math.pow(mean1, 2) + Math.pow(mean2, 2) + C1) * (Math.pow(Math.sqrt(Math.pow(cov, 2) + C2), 2)); ssim += numerator / denominator; } } // Average SSIM for all windows ssim /= (height / windowSize) * (width / windowSize); return ssim; } } ``` 调用方法: ```java BufferedImage img1 = ImageIO.read(new File("img1.jpg")); BufferedImage img2 = ImageIO.read(new File("img2.jpg")); double ssim = SSIM.getSSIM(img1, img2); System.out.println("SSIM: " + ssim); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值