• 在C#中使用PaddleInference插件实现图片旋转角度的检测功能
  • 发布于 2个月前
  • 204 热度
    0 评论
效果

项目

VS2022+.net4.8+ OpenCvSharp4+Sdcb.PaddleInference


代码
using OpenCvSharp;
using Sdcb.PaddleInference;
using Sdcb.PaddleInference.Native;
using System;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
 
namespace PaddleInference_图片旋转角度检测
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        Bitmap bmp;
        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string img = "";
        string startupPath = "";
 
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;
 
        PaddlePredictor predictor;
        float rotateThreshold = 0.50f;
        InputShape defaultShape = new InputShape(3, 224, 224);
 
        private unsafe void Form1_Load(object sender, EventArgs e)
        {
            startupPath = Application.StartupPath;
            // 堆代码 duidaima.com
            IntPtr _ptr = PaddleNative.PD_ConfigCreate();
 
            Encoding PaddleEncoding = Environment.OSVersion.Platform == PlatformID.Win32NT ? Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.ANSICodePage) : Encoding.UTF8;
 
            //设置推理模型路径
            String programPath = Application.StartupPath + "\\models\\inference.pdmodel";
            String paramsPath = Application.StartupPath + "\\models\\inference.pdiparams";
 
            byte[] programBytes = PaddleEncoding.GetBytes(programPath);
            byte[] paramsBytes = PaddleEncoding.GetBytes(paramsPath);
            fixed (byte* programPtr = programBytes)
            fixed (byte* paramsPtr = paramsBytes)
 
            PaddleNative.PD_ConfigSetModel(_ptr, (IntPtr)programPtr, (IntPtr)paramsPtr);
            PaddleNative.PD_ConfigEnableMKLDNN(_ptr);
 
            predictor = new PaddlePredictor(PaddleNative.PD_PredictorCreate(_ptr));
        }
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;
 
            pictureBox1.Image = null;
 
            img = ofd.FileName;
            bmp = new Bitmap(img);
            pictureBox1.Image = new Bitmap(img);
            textBox1.Text = "";
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            if (img == "") { return; }
            Mat src = OpenCvSharp.Extensions.BitmapConverter.ToMat(new Bitmap(pictureBox1.Image));
            Cv2.CvtColor(src, src, ColorConversionCodes.RGBA2RGB);//mat转三通道mat
            dt1 = DateTime.Now;
 
            Mat resized = ResizePadding(src, defaultShape);
            Mat normalized = Normalize(resized);
 
            using (PaddleTensor input = predictor.GetInputTensor(predictor.InputNames[0]))
            {
                input.Shape = new[] { 1, 3, normalized.Rows, normalized.Cols };
                float[] data = ExtractMat(normalized);
                input.SetData(data);
            }
 
            normalized.Dispose();
            resized.Dispose();
 
            if (!predictor.Run())
            {
                throw new Exception("PaddlePredictor(Classifier) run failed.");
            }
 
            RotationDegree r = RotationDegree._0;
 
            using (PaddleTensor output = predictor.GetOutputTensor(predictor.OutputNames[0]))
            {
                float[] softmax = output.GetData<float>();
                float max = softmax.Max();
                int maxIndex = Array.IndexOf(softmax, max);
                if (max > rotateThreshold)
                {
                    r = (RotationDegree)maxIndex;
                }
            }
 
            dt2 = DateTime.Now;
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("图片旋转角度:" + r.ToString());
            sb.AppendLine("--------------------");
            sb.AppendLine("耗时:" + (dt2 - dt1).TotalMilliseconds + "ms");
            textBox1.Text = sb.ToString();
        }
 
        private float[] ExtractMat(Mat src)
        {
            int rows = src.Rows;
            int cols = src.Cols;
            float[] result = new float[rows * cols * 3];
            GCHandle resultHandle = default;
            try
            {
                resultHandle = GCHandle.Alloc(result, GCHandleType.Pinned);
                IntPtr resultPtr = resultHandle.AddrOfPinnedObject();
                for (int i = 0; i < src.Channels(); ++i)
                {
                    Mat dest = new Mat(rows, cols, MatType.CV_32FC1, resultPtr + i * rows * cols * sizeof(float));
                    Cv2.ExtractChannel(src, dest, i);
                    dest.Dispose();
                }
            }
            finally
            {
                resultHandle.Free();
            }
            return result;
        }
 
        private Mat ResizePadding(Mat src, InputShape shape)
        {
            OpenCvSharp.Size srcSize = src.Size();
            Mat roi = srcSize.Width / srcSize.Height > shape.Width / shape.Height ?
                src[0, srcSize.Height, 0, (int)Math.Floor(1.0 * srcSize.Height * shape.Width / shape.Height)] :
                src.Clone();
            double scaleRate = 1.0 * shape.Height / srcSize.Height;
            Mat resized = roi.Resize(new OpenCvSharp.Size(Math.Floor(roi.Width * scaleRate), shape.Height));
            if (resized.Width < shape.Width)
            {
                Cv2.CopyMakeBorder(resized, resized, 0, 0, 0, shape.Width - resized.Width, BorderTypes.Constant, Scalar.Black);
            }
            roi.Dispose();
            return resized;
        }
 
        private Mat Normalize(Mat src)
        {
            Mat normalized = new Mat();
            src.ConvertTo(normalized, MatType.CV_32FC3, 1.0 / 255);
            Mat[] bgr = normalized.Split();
            float[] scales = new[] { 2.0f, 2.0f, 2.0f };
            float[] means = new[] { 0.5f, 0.5f, 0.5f };
            for (int i = 0; i < bgr.Length; ++i)
            {
                bgr[i].ConvertTo(bgr[i], MatType.CV_32FC1, 1.0 * scales[i], (0.0 - means[i]) * scales[i]);
            }
 
            normalized.Dispose();
 
            Mat dest = new Mat();
            Cv2.Merge(bgr, dest);
 
            foreach (Mat channel in bgr)
            {
                channel.Dispose();
            }
 
            return dest;
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            if (bmp == null)
            {
                return;
            }
 
            var mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
            Cv2.CvtColor(mat, mat, ColorConversionCodes.RGBA2RGB);
            Cv2.Rotate(mat, mat, RotateFlags.Rotate90Clockwise);
            var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
            pictureBox1.Image = bitmap;
        }
 
        private void button4_Click(object sender, EventArgs e)
        {
            if (bmp == null)
            {
                return;
            }
 
            var mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
            Cv2.CvtColor(mat, mat, ColorConversionCodes.RGBA2RGB);
            Cv2.Rotate(mat, mat, RotateFlags.Rotate180);
            var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
            pictureBox1.Image = bitmap;
        }
 
        private void button5_Click(object sender, EventArgs e)
        {
            if (bmp == null)
            {
                return;
            }
 
            var mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
            Cv2.CvtColor(mat, mat, ColorConversionCodes.RGBA2RGB);
            Cv2.Rotate(mat, mat, RotateFlags.Rotate90Counterclockwise);
            var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
            pictureBox1.Image = bitmap;
        }
 
    }
 
    /// <summary>
    /// Represents the shape of input data for a rotation detection model.
    /// </summary>
    public readonly struct InputShape
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InputShape"/> struct.
        /// </summary>
        /// <param name="channel">The number of color channels in the input image.</param>
        /// <param name="width">The width of the input image in pixels.</param>
        /// <param name="height">The height of the input image in pixels.</param>
        public InputShape(int channel, int width, int height)
        {
            Channel = channel;
            Height = height;
            Width = width;
        }
 
        /// <summary>
        /// Gets the number of color channels in the input image.
        /// </summary>
        public int Channel { get; }
 
        /// <summary>
        /// Gets the height of the input image in pixels.
        /// </summary>
        public int Height { get; }
 
        /// <summary>
        /// Gets the width of the input image in pixels.
        /// </summary>
        public int Width { get; }
    }
 
    /// <summary>
    /// Enum representing the degrees of rotation.
    /// </summary>
    public enum RotationDegree
    {
        /// <summary>
        /// Represents the 0-degree rotation angle.
        /// </summary>
        _0,
        /// <summary>
        /// Represents the 90-degree rotation angle.
        /// </summary>
        _90,
        /// <summary>
        /// Represents the 180-degree rotation angle.
        /// </summary>
        _180,
        /// <summary>
        /// Represents the 270-degree rotation angle.
        /// </summary>
        _270,
    }
 
}
参考:https://github.com/sdcb/PaddleSharp
用户评论