C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码+编号 检测,后续裁剪出图片并摆正显示

news2024/10/10 10:27:45

C# Onnx Yolov8-OBB 旋转目标检测 行驶证副页条码+编号 检测,后续裁剪出图片并摆正显示

目录

效果

模型信息

项目

代码 

下载


效果

模型信息

Model Properties
-------------------------
date:2024-06-25T10:59:15.206586
description:Ultralytics YOLOv8n-obb model trained on C:\Work\yolov8\config\dl-obb.yaml
author:Ultralytics
version:8.1.29
task:obb
license:AGPL-3.0 License (https://ultralytics.com/license)
docs:https://docs.ultralytics.com
stride:32
batch:1
imgsz:[1024, 1024]
names:{0: 'code'}
---------------------------------------------------------------

Inputs
-------------------------
name:images
tensor:Float[1, 3, 1024, 1024]
---------------------------------------------------------------

Outputs
-------------------------
name:output0
tensor:Float[1, 6, 21504]
---------------------------------------------------------------

项目

代码 

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using OpenCvSharp;
using OpenCvSharp.Dnn;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace Onnx_Yolov8_Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";
        string classer_path;
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;
        string model_path;
        Mat image;
        Mat result_image;
        public string[] class_lables;
        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<float> input_tensor;
        List<NamedOnnxValue> input_container;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;

        Tensor<float> result_tensors;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pictureBox1.Image = null;
            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            textBox1.Text = "";
            image = new Mat(image_path);
            pictureBox2.Image = null;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }

            button2.Enabled = false;

            pictureBox2.Image = null;
            pictureBox3.Image = null;
            textBox1.Text = "";
            Application.DoEvents();

            //图片缩放
            image = new Mat(image_path);
            int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
            Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
            Rect roi = new Rect(0, 0, image.Cols, image.Rows);
            image.CopyTo(new Mat(max_image, roi));

            float[] result_array;
            float factor = (float)(max_image_length / 1024.0);

            // 将图片转为RGB通道
            Mat image_rgb = new Mat();
            Cv2.CvtColor(max_image, image_rgb, ColorConversionCodes.BGR2RGB);
            Mat resize_image = new Mat();
            Cv2.Resize(image_rgb, resize_image, new OpenCvSharp.Size(1024, 1024));

           // Cv2.ImShow("resize_image",resize_image);

            // 输入Tensor
            for (int y = 0; y < resize_image.Height; y++)
            {
                for (int x = 0; x < resize_image.Width; x++)
                {
                    input_tensor[0, 0, y, x] = resize_image.At<Vec3b>(y, x)[0] / 255f;
                    input_tensor[0, 1, y, x] = resize_image.At<Vec3b>(y, x)[1] / 255f;
                    input_tensor[0, 2, y, x] = resize_image.At<Vec3b>(y, x)[2] / 255f;
                }
            }

            //将 input_tensor 放入一个输入参数的容器,并指定名称
            input_container.Add(NamedOnnxValue.CreateFromTensor("images", input_tensor));

            dt1 = DateTime.Now;
            //运行 Inference 并获取结果
            result_infer = onnx_session.Run(input_container);
            dt2 = DateTime.Now;

            // 将输出结果转为DisposableNamedOnnxValue数组
            results_onnxvalue = result_infer.ToArray();

            // 读取第一个节点输出并转为Tensor数据
            result_tensors = results_onnxvalue[0].AsTensor<float>();

            result_array = result_tensors.ToArray();

            Mat result_data = new Mat(6, 21504, MatType.CV_32F, result_array);
            result_data = result_data.T();
            string s = result_data.Dump();
            List<Rect2d> position_boxes = new List<Rect2d>();
            List<int> class_ids = new List<int>();
            List<float> confidences = new List<float>();
            List<float> rotations = new List<float>();
            // Preprocessing output results
            for (int i = 0; i < result_data.Rows; i++)
            {
                Mat classes_scores = new Mat(result_data, new Rect(4, i, 1, 1));
                string s2 = classes_scores.Dump();
                OpenCvSharp.Point max_classId_point, min_classId_point;
                double max_score, min_score;
                // Obtain the maximum value and its position in a set of data
                Cv2.MinMaxLoc(classes_scores, out min_score, out max_score,
                    out min_classId_point, out max_classId_point);
                // Confidence level between 0 ~ 1
                // Obtain identification box information
                if (max_score > 0.5)
                {
                    float cx = result_data.At<float>(i, 0);
                    float cy = result_data.At<float>(i, 1);
                    float ow = result_data.At<float>(i, 2);
                    float oh = result_data.At<float>(i, 3);
                    double x = (cx - 0.5 * ow) * factor;
                    double y = (cy - 0.5 * oh) * factor;
                    double width = ow * factor;
                    double height = oh * factor;
                    Rect2d box = new Rect2d();
                    box.X = x;
                    box.Y = y;
                    box.Width = width;
                    box.Height = height;
                    position_boxes.Add(box);
                    class_ids.Add(max_classId_point.X);
                    confidences.Add((float)max_score);
                    rotations.Add(result_data.At<float>(i, 5));
                }
            }

            // NMS 
            int[] indexes = new int[position_boxes.Count];
            CvDnn.NMSBoxes(position_boxes, confidences, 0.5f, 0.5f, out indexes);
            List<RotatedRect> rotated_rects = new List<RotatedRect>();
            for (int i = 0; i < indexes.Length; i++)
            {
                int index = indexes[i];
                float w = (float)position_boxes[index].Width;
                float h = (float)position_boxes[index].Height;
                float x = (float)position_boxes[index].X + w / 2;
                float y = (float)position_boxes[index].Y + h / 2;
                float r = rotations[index];
                float w_ = w > h ? w : h;
                float h_ = w > h ? h : w;
                r = (float)((w > h ? r : (float)(r + Math.PI / 2)) % Math.PI);
                RotatedRect rotate = new RotatedRect(new Point2f(x, y), new Size2f(w_, h_), (float)(r * 180.0 / Math.PI));

                if (rotate.Angle>90)
                {
                    rotate.Angle =  rotate.Angle-180;
                }
                rotated_rects.Add(rotate);
            }

            result_image = image.Clone();

            for (int i = 0; i < indexes.Length; i++)
            {
                int index = indexes[i];

                if (confidences[index]<0.7)
                {
                    continue;
                }

                Point2f[] points = rotated_rects[i].Points();

                //裁剪出需要的图片
                Mat codeMat = GetRotateCropImage(image, rotated_rects[i]);
                pictureBox3.Image = new Bitmap(codeMat.ToMemoryStream());

                for (int j = 0; j < 4; j++)
                {
                    Cv2.Line(result_image, (OpenCvSharp.Point)points[j], (OpenCvSharp.Point)points[(j + 1) % 4], new Scalar(0, 255, 0), 2, LineTypes.Link8);
                }

                Cv2.PutText(result_image, class_lables[class_ids[index]] + "-" + confidences[index].ToString("0.00"),
                    (OpenCvSharp.Point)points[0], HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 255), 2);

                pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());

            }

            


            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";

            button2.Enabled = true;
        }

        private Mat GetRotateCropImage(Mat src, RotatedRect rect)
        {
            bool wider = rect.Size.Width > rect.Size.Height;
            float angle = rect.Angle;
            OpenCvSharp.Size srcSize = src.Size();
            Rect boundingRect = rect.BoundingRect();

            int expTop = Math.Max(0, 0 - boundingRect.Top);
            int expBottom = Math.Max(0, boundingRect.Bottom - srcSize.Height);
            int expLeft = Math.Max(0, 0 - boundingRect.Left);
            int expRight = Math.Max(0, boundingRect.Right - srcSize.Width);

            Rect rectToExp = boundingRect + new OpenCvSharp.Point(expTop, expLeft);
            Rect roiRect = Rect.FromLTRB(
                boundingRect.Left + expLeft,
                boundingRect.Top + expTop,
                boundingRect.Right - expRight,
                boundingRect.Bottom - expBottom);
            Mat boundingMat = src[roiRect];


            Mat expanded = boundingMat.CopyMakeBorder(expTop, expBottom, expLeft, expRight, BorderTypes.Replicate);
            Point2f[] rp = rect.Points()
                .Select(v => new Point2f(v.X - rectToExp.X, v.Y - rectToExp.Y))
                .ToArray();


            Point2f[] srcPoints = new[] { rp[0], rp[3], rp[2], rp[1] };

            if (wider == true && angle >= 0 && angle < 45)
            {
                srcPoints = new[] { rp[1], rp[2], rp[3], rp[0] };
            }

            var ptsDst0 = new Point2f(0, 0);
            var ptsDst1 = new Point2f(rect.Size.Width, 0);
            var ptsDst2 = new Point2f(rect.Size.Width, rect.Size.Height);
            var ptsDst3 = new Point2f(0, rect.Size.Height);

            Mat matrix = Cv2.GetPerspectiveTransform(srcPoints, new[] { ptsDst0, ptsDst1, ptsDst2, ptsDst3 });

            Mat dest = expanded.WarpPerspective(matrix, new OpenCvSharp.Size(rect.Size.Width, rect.Size.Height), InterpolationFlags.Nearest, BorderTypes.Replicate);

            if (rect.Angle<0)
            {
                Cv2.Flip(dest, dest, FlipMode.X);
            }

            boundingMat.Dispose();
            expanded.Dispose();
            matrix.Dispose();

            return dest;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            model_path = "model/best.onnx";
            classer_path = "model/lable.txt";

            // 创建输出会话,用于输出模型读取信息
            options = new SessionOptions();
            options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
            options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行

            // 创建推理模型类,读取本地模型文件
            onnx_session = new InferenceSession(model_path, options);//model_path 为onnx模型文件的路径

            // 输入Tensor
            input_tensor = new DenseTensor<float>(new[] { 1, 3, 1024, 1024 });
            // 创建输入容器
            input_container = new List<NamedOnnxValue>();

            List<string> str = new List<string>();
            StreamReader sr = new StreamReader(classer_path);
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                str.Add(line);
            }
            class_lables = str.ToArray();

            image_path = "test_img/1.jpg";
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        SaveFileDialog sdf = new SaveFileDialog();
        private void button3_Click(object sender, EventArgs e)
        {
            if (pictureBox3.Image == null)
            {
                return;
            }
            Bitmap output = new Bitmap(pictureBox3.Image);
            sdf.Title = "保存";
            sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
            if (sdf.ShowDialog() == DialogResult.OK)
            {
                switch (sdf.FilterIndex)
                {
                    case 1:
                        {
                            output.Save(sdf.FileName, ImageFormat.Jpeg);
                            break;
                        }
                    case 2:
                        {
                            output.Save(sdf.FileName, ImageFormat.Png);
                            break;
                        }
                    case 3:
                        {
                            output.Save(sdf.FileName, ImageFormat.Bmp);
                            break;
                        }
                }
                MessageBox.Show("保存成功,位置:" + sdf.FileName);
            }
        }
    }
}

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using OpenCvSharp;
using OpenCvSharp.Dnn;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace Onnx_Yolov8_Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";
        string classer_path;
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;
        string model_path;
        Mat image;
        Mat result_image;
        public string[] class_lables;
        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<float> input_tensor;
        List<NamedOnnxValue> input_container;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;

        Tensor<float> result_tensors;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pictureBox1.Image = null;
            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            textBox1.Text = "";
            image = new Mat(image_path);
            pictureBox2.Image = null;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }

            button2.Enabled = false;

            pictureBox2.Image = null;
            pictureBox3.Image = null;
            textBox1.Text = "";
            Application.DoEvents();

            //图片缩放
            image = new Mat(image_path);
            int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
            Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
            Rect roi = new Rect(0, 0, image.Cols, image.Rows);
            image.CopyTo(new Mat(max_image, roi));

            float[] result_array;
            float factor = (float)(max_image_length / 1024.0);

            // 将图片转为RGB通道
            Mat image_rgb = new Mat();
            Cv2.CvtColor(max_image, image_rgb, ColorConversionCodes.BGR2RGB);
            Mat resize_image = new Mat();
            Cv2.Resize(image_rgb, resize_image, new OpenCvSharp.Size(1024, 1024));

           // Cv2.ImShow("resize_image",resize_image);

            // 输入Tensor
            for (int y = 0; y < resize_image.Height; y++)
            {
                for (int x = 0; x < resize_image.Width; x++)
                {
                    input_tensor[0, 0, y, x] = resize_image.At<Vec3b>(y, x)[0] / 255f;
                    input_tensor[0, 1, y, x] = resize_image.At<Vec3b>(y, x)[1] / 255f;
                    input_tensor[0, 2, y, x] = resize_image.At<Vec3b>(y, x)[2] / 255f;
                }
            }

            //将 input_tensor 放入一个输入参数的容器,并指定名称
            input_container.Add(NamedOnnxValue.CreateFromTensor("images", input_tensor));

            dt1 = DateTime.Now;
            //运行 Inference 并获取结果
            result_infer = onnx_session.Run(input_container);
            dt2 = DateTime.Now;

            // 将输出结果转为DisposableNamedOnnxValue数组
            results_onnxvalue = result_infer.ToArray();

            // 读取第一个节点输出并转为Tensor数据
            result_tensors = results_onnxvalue[0].AsTensor<float>();

            result_array = result_tensors.ToArray();

            Mat result_data = new Mat(6, 21504, MatType.CV_32F, result_array);
            result_data = result_data.T();
            string s = result_data.Dump();
            List<Rect2d> position_boxes = new List<Rect2d>();
            List<int> class_ids = new List<int>();
            List<float> confidences = new List<float>();
            List<float> rotations = new List<float>();
            // Preprocessing output results
            for (int i = 0; i < result_data.Rows; i++)
            {
                Mat classes_scores = new Mat(result_data, new Rect(4, i, 1, 1));
                string s2 = classes_scores.Dump();
                OpenCvSharp.Point max_classId_point, min_classId_point;
                double max_score, min_score;
                // Obtain the maximum value and its position in a set of data
                Cv2.MinMaxLoc(classes_scores, out min_score, out max_score,
                    out min_classId_point, out max_classId_point);
                // Confidence level between 0 ~ 1
                // Obtain identification box information
                if (max_score > 0.5)
                {
                    float cx = result_data.At<float>(i, 0);
                    float cy = result_data.At<float>(i, 1);
                    float ow = result_data.At<float>(i, 2);
                    float oh = result_data.At<float>(i, 3);
                    double x = (cx - 0.5 * ow) * factor;
                    double y = (cy - 0.5 * oh) * factor;
                    double width = ow * factor;
                    double height = oh * factor;
                    Rect2d box = new Rect2d();
                    box.X = x;
                    box.Y = y;
                    box.Width = width;
                    box.Height = height;
                    position_boxes.Add(box);
                    class_ids.Add(max_classId_point.X);
                    confidences.Add((float)max_score);
                    rotations.Add(result_data.At<float>(i, 5));
                }
            }



            // NMS 
            int[] indexes = new int[position_boxes.Count];
            CvDnn.NMSBoxes(position_boxes, confidences, 0.5f, 0.5f, out indexes);
            List<RotatedRect> rotated_rects = new List<RotatedRect>();
            for (int i = 0; i < indexes.Length; i++)
            {
                int index = indexes[i];
                float w = (float)position_boxes[index].Width;
                float h = (float)position_boxes[index].Height;
                float x = (float)position_boxes[index].X + w / 2;
                float y = (float)position_boxes[index].Y + h / 2;
                float r = rotations[index];
                float w_ = w > h ? w : h;
                float h_ = w > h ? h : w;
                r = (float)((w > h ? r : (float)(r + Math.PI / 2)) % Math.PI);
                RotatedRect rotate = new RotatedRect(new Point2f(x, y), new Size2f(w_, h_), (float)(r * 180.0 / Math.PI));

                if (rotate.Angle>90)
                {
                    rotate.Angle =  rotate.Angle-180;
                }
                rotated_rects.Add(rotate);
            }

            result_image = image.Clone();

            for (int i = 0; i < indexes.Length; i++)
            {
                int index = indexes[i];

                if (confidences[index]<0.7)
                {
                    continue;
                }

                Point2f[] points = rotated_rects[i].Points();

                //裁剪出需要的图片
                Mat codeMat = GetRotateCropImage(image, rotated_rects[i]);
                pictureBox3.Image = new Bitmap(codeMat.ToMemoryStream());

                for (int j = 0; j < 4; j++)
                {
                    Cv2.Line(result_image, (OpenCvSharp.Point)points[j], (OpenCvSharp.Point)points[(j + 1) % 4], new Scalar(0, 255, 0), 2, LineTypes.Link8);
                }

                Cv2.PutText(result_image, class_lables[class_ids[index]] + "-" + confidences[index].ToString("0.00"),
                    (OpenCvSharp.Point)points[0], HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 255), 2);

                pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());

            }

          
            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";

            button2.Enabled = true;
        }

        private Mat GetRotateCropImage(Mat src, RotatedRect rect)
        {
            bool wider = rect.Size.Width > rect.Size.Height;
            float angle = rect.Angle;
            OpenCvSharp.Size srcSize = src.Size();
            Rect boundingRect = rect.BoundingRect();

            int expTop = Math.Max(0, 0 - boundingRect.Top);
            int expBottom = Math.Max(0, boundingRect.Bottom - srcSize.Height);
            int expLeft = Math.Max(0, 0 - boundingRect.Left);
            int expRight = Math.Max(0, boundingRect.Right - srcSize.Width);

            Rect rectToExp = boundingRect + new OpenCvSharp.Point(expTop, expLeft);
            Rect roiRect = Rect.FromLTRB(
                boundingRect.Left + expLeft,
                boundingRect.Top + expTop,
                boundingRect.Right - expRight,
                boundingRect.Bottom - expBottom);
            Mat boundingMat = src[roiRect];


            Mat expanded = boundingMat.CopyMakeBorder(expTop, expBottom, expLeft, expRight, BorderTypes.Replicate);
            Point2f[] rp = rect.Points()
                .Select(v => new Point2f(v.X - rectToExp.X, v.Y - rectToExp.Y))
                .ToArray();


            Point2f[] srcPoints = new[] { rp[0], rp[3], rp[2], rp[1] };

            if (wider == true && angle >= 0 && angle < 45)
            {
                srcPoints = new[] { rp[1], rp[2], rp[3], rp[0] };
            }

            var ptsDst0 = new Point2f(0, 0);
            var ptsDst1 = new Point2f(rect.Size.Width, 0);
            var ptsDst2 = new Point2f(rect.Size.Width, rect.Size.Height);
            var ptsDst3 = new Point2f(0, rect.Size.Height);

            Mat matrix = Cv2.GetPerspectiveTransform(srcPoints, new[] { ptsDst0, ptsDst1, ptsDst2, ptsDst3 });

            Mat dest = expanded.WarpPerspective(matrix, new OpenCvSharp.Size(rect.Size.Width, rect.Size.Height), InterpolationFlags.Nearest, BorderTypes.Replicate);

            if (rect.Angle<0)
            {
                Cv2.Flip(dest, dest, FlipMode.X);
            }

            boundingMat.Dispose();
            expanded.Dispose();
            matrix.Dispose();

            return dest;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            model_path = "model/best.onnx";
            classer_path = "model/lable.txt";

            // 创建输出会话,用于输出模型读取信息
            options = new SessionOptions();
            options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
            options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行

            // 创建推理模型类,读取本地模型文件
            onnx_session = new InferenceSession(model_path, options);//model_path 为onnx模型文件的路径

            // 输入Tensor
            input_tensor = new DenseTensor<float>(new[] { 1, 3, 1024, 1024 });
            // 创建输入容器
            input_container = new List<NamedOnnxValue>();

            List<string> str = new List<string>();
            StreamReader sr = new StreamReader(classer_path);
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                str.Add(line);
            }
            class_lables = str.ToArray();

            image_path = "test_img/1.jpg";
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        SaveFileDialog sdf = new SaveFileDialog();
        private void button3_Click(object sender, EventArgs e)
        {
            if (pictureBox3.Image == null)
            {
                return;
            }
            Bitmap output = new Bitmap(pictureBox3.Image);
            sdf.Title = "保存";
            sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
            if (sdf.ShowDialog() == DialogResult.OK)
            {
                switch (sdf.FilterIndex)
                {
                    case 1:
                        {
                            output.Save(sdf.FileName, ImageFormat.Jpeg);
                            break;
                        }
                    case 2:
                        {
                            output.Save(sdf.FileName, ImageFormat.Png);
                            break;
                        }
                    case 3:
                        {
                            output.Save(sdf.FileName, ImageFormat.Bmp);
                            break;
                        }
                }
                MessageBox.Show("保存成功,位置:" + sdf.FileName);
            }
        }
    }
}

下载

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1862956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第一课:SSH协议、SSHD守护进程、Openssh软件包

第一节课 6月12日 ssh协议 关键问题 一、ssh、sshd、openssh的概念和区别&#xff1f; 二、ssh是基于什么架构&#xff1f;B/S还是C/S&#xff1f; 三、用户远程连接服务器经历哪些过程&#xff1f; 四、如何查看openssh软件包是否安装&#xff1f; 五、rpm和yum的区别&#xf…

node带参数命令

不带参数命令示例&#xff1a; node /www/wwwroot/server 带参数命令示例&#xff1a; node /www/wwwroot/server arg1 arg2 arg3 在启动页进行参数处理&#xff1a; // 获取启动参数(除去前2个默认参数&#xff0c;示例&#xff1a;node /www/wwwroot/server arg1 arg2 …

SAP ABAP 之容器

文章目录 前言一、案例介绍/笔者需求二、自定义容器 a.实例化对象 b.自定义容器效果演示 c.Copy Code 三、自适应容器 a.常用 必须 参数理解 b.METRIC 度量单位 c.RATIO 百分比尺寸 d.STYLE 容器…

WMV 视频格式怎么转换?WMV 视频为什么不流行了?

目前有越来越多的视频格式类型&#xff0c;如常见的 MP4、FLV、AVI 等等&#xff0c;而技术的演变也逐渐让一些常见的视频格式变的越来越少了。 今天我们一起来聊下 WMV 这个视频格式&#xff0c;让我们看看它的发展以及为什么现在越来越少人使用了。 什么是 WMV 视频格式&…

微信营销自动化(朋友圈自动点赞工具):UIAutomation的解决方案

文章不用看, 是AI生成的, 请直接查看下载地址 http://www.aisisoft.top . 微信朋友圈自动点赞工具, 自动群发工具 在当今的数字化营销领域&#xff0c;自动化工具成为了提升工作效率、增强客户互动的关键。本文将详细介绍一款基于UIAutomation框架与Python语言构建的微信营销自…

数据容器(四)

目录 一、dict&#xff08;字典、映射&#xff09; 1.字典的定义 2.字典数据的获取 3.字典的嵌套 一、dict&#xff08;字典、映射&#xff09; 1.字典的定义 使用{}&#xff0c;不过存储的元素是一个个的&#xff1a;键值对。 2.字典数据的获取 字典同集合一样&#xff…

PointCloudLib-滤波模块(Filtering)-使用统计异常值移除过滤器移除异常值

在本教程中,我们将学习如何消除噪声测量值,例如异常值, 使用统计分析技术的点云数据集。 背景 激光扫描通常会生成不同点密度的点云数据集。 此外,测量误差会导致稀疏异常值,从而破坏 结果更多。这使得本地点云的估计变得复杂 表面法线或曲率变化等特征,导致 错误的值,…

【WEB】关于react的WEB应用中使用React Developer Tools便捷快速查看元素数据

1、往扩展工具中添加React Developer Tools的扩展包 2、检查是否生效&#xff0c;如下图&#xff1a; 可以看到右上角多出来一个Components的tab选项&#xff0c;就是成功了

转运机器人:智能物流的得力助手

在物流行业&#xff0c;转运机器人已经成为提高转运效率、降低成本的重要工具。而富唯智能转运机器人凭借其出色的性能和智能化的设计&#xff0c;成为了众多企业的得力助手。 富唯智能转运机器人采用了先进的AMR控制系统&#xff0c;可以一体化控制移动机器人并实现与产线设备…

美国众议院通过ENFORCE ACT草案:AI领域的潜在冷战?

近日&#xff0c;美国众议院通过了“增强关键出口海外限制国家框架法案”&#xff08;ENFORCE ACT&#xff09;&#xff0c;该法案旨在限制AI/ML技术和人才向中国的流动。这一举动引发了广泛讨论和担忧&#xff0c;许多人认为这将对在美从事AI相关工作的中国人造成重大影响。本…

【力扣】重排链表

&#x1f525;博客主页&#xff1a; 我要成为C领域大神 &#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于分享知识&#xff0c;欢迎大家共同学习和交流。 给定一个单链表…

传媒行业采购堡垒机的必要性你知道吗?

随着互联网的快速发展&#xff0c;传媒行业也是发展速度。特别是近年来&#xff0c;自媒体行业的火热&#xff0c;如何保障网络安全&#xff0c;如何保障大家信息安全至关重要。虽然国家严格要求执行等保政策&#xff0c;但大家对于为什么传媒行业要采购堡垒机不是很了解。你知…

JDK16特性

JDK16特性 一、JAVA16概述 2021年3月16日正式发布,一共更新了17JEP https://openjdk.java.net/projects/jdk/16/ 二、语法层面变化 1.JEP 397:密封类(第二次预览) sealed class 第二次预览通过密封的类和接口来增强Java编程语言,这是新的预览特性,用于限制超类的使用密封…

Nuxt 3组件开发与管理

title: Nuxt 3组件开发与管理 date: 2024/6/20 updated: 2024/6/20 author: cmdragon excerpt: 摘要&#xff1a;本文深入探讨了Nuxt 3的组件开发与管理&#xff0c;从基础概念、安装配置、目录结构、组件分类与开发实践、生命周期与优化&#xff0c;到测试与维护策略。详细…

小程序注册

【 一 】小程序注册 微信公众平台 https://mp.weixin.qq.com/ https://mp.weixin.qq.com/注册 邮箱激活 小程序账户注册 微信小程序配置 微信小程序开发流程 添加项目成员 【 二 】云服务 lass 基础设施服务&#xff08;组装机&#xff09; 你买了一大堆的电脑配件&#x…

【AI编译器】triton学习:矩阵乘优化

Matrix Multiplication 主要内容&#xff1a; 块级矩阵乘法 多维指针算术 重新编排程序以提升L2缓存命 自动性能调整 Motivations 矩阵乘法是当今高性能计算系统的一个关键组件&#xff0c;在大多数情况下被用于构建硬件。由于该操作特别复杂&#xff0c;因此通常由软件提…

鸿蒙开发报错 -cppcrash happened

报错信息&#xff1a; cppcrash happened in ‘设备名’ 现象&#xff1a;打开应用就闪退&#xff0c;无论是模拟器还是真机都会闪退&#xff0c;预览器没有问题 报错原因&#xff0c;在入口页面添加了export&#xff0c; 页面是不需要导出的&#xff0c;只有组件需要导出&…

三,SSM整合-前后端分离(实现增删改查)

实现增删改查 实现功能03-添加家居信息需求分析/图解思路分析代码实现注意事项和细节 实现功能04-显示家居信息需求分析/图解思路分析代码实现 实现功能05-修改家居信息需求分析/图解思路分析代码实现注意事项和细节 实现功能06-删除家居信息需求分析/图解思路分析代码实现课后…

数据接入开放协议-术语表

数据与元数据 - 数据 传感器采样生成的 具有物理含义的一个或一系列值 - 实时数据 包含 时间、数据质量指示的一个或一系列数据 - 位号元数据 对于传感器采样得到的数据的物理描述 包括但不限于 时间、单位、数据范围、数据质量指示 上位机与下位机 - 上位机supOS 系统 - 下位…

信息学奥赛初赛天天练-32-CSP-J2021阅读程序-冒泡排序、数组去重、二分查找、坐标确定矩形应用

PDF文档公众号回复关键字:20240625 2021 CSP-J 完善程序3 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) (矩形计数)平面上有n个关键点&#xff0c;求有多少个四条边都和x轴或者y轴平行的矩形&#xff0c;满足四个顶点都是关键点。给出的关键点可能有重复&am…