我的编程空间,编程开发者的网络收藏夹
学习永远不晚

c#中WinForm使用OpencvSharp4实现简易抓边

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

c#中WinForm使用OpencvSharp4实现简易抓边

环境: VS2019 , OpencvSharp4 4.5.5.20211231 , .NET Framework 4.8

界面设计:

图像显示用的是picturebox 控件都是windows基本控件

效果展示:

图像是自己画图画的 所以抓的效果比较好 。其他图片的话可能需要调整一下相关参数,效果可能达不到这么好

实现原理: 在图像中选择ROI,从原图上把对应ROI部分的图像扣下来,然后对扣下来的图像进行边缘处理等操作,得到边缘和拟合线,最后在原图上将边缘和拟合线画出来即可。注意,得到的边缘是相对于ROI区域的坐标,需要转化成相对于原图的坐标才行,只需加上ROI的坐标即可。

主要部分代码:

定义的ROI类 注意一下四个点的相对位置

    public class ROI
    { 
        // 四个点的顺序关系
        //  1---2
        //  |   |
        //  3---4
        public OpenCvSharp.Point FirstPoint { get; set; } = new OpenCvSharp.Point(0, 0);
        public OpenCvSharp.Point SecondPoint { get; set; } = new OpenCvSharp.Point(0, 0);
        public OpenCvSharp.Point ThirdPoint { get; set; } = new OpenCvSharp.Point(0, 0);
        public OpenCvSharp.Point FourthPoint { get; set; } = new OpenCvSharp.Point(0, 0);
 
        public OpenCvSharp.Point2f Center
        {
            get
            {
                OpenCvSharp.Point2f center = new OpenCvSharp.Point2f();
                center.X = (float)((FirstPoint.X + SecondPoint.X + ThirdPoint.X + FourthPoint.X) / 4.0);
                center.Y = (float)((FirstPoint.Y + SecondPoint.Y + ThirdPoint.Y + FourthPoint.Y) / 4.0);
                return center;
            }
        }
 
        public OpenCvSharp.Size2f Size
        {
            get
            {
                return new OpenCvSharp.Size2f(Width, Height);
            }
        }
        public int XLeft
        {
            get { return FirstPoint.X; }
        }
        public int YTop
        {
            get { return FirstPoint.Y; }
        }
        public int XRight
        {
            get { return FourthPoint.X; }
        }
        public int YBottom
        {
            get { return FourthPoint.Y; }
        }
 
        public double Width
        {
            get { return FourthPoint.X - FirstPoint.X; } 
        }
        public double Height
        {
            get { return FourthPoint.Y - FirstPoint.Y; } 
        }
 
        public void Reset()
        {
            FirstPoint = new OpenCvSharp.Point(0, 0);
            SecondPoint = new OpenCvSharp.Point(0, 0);
            ThirdPoint = new OpenCvSharp.Point(0, 0);
            FourthPoint = new OpenCvSharp.Point(0, 0);
        }
 
        // 四个点全为0 则判断为空
        public bool IsNull()
        {
            bool en = true;
            en = en && FirstPoint == new OpenCvSharp.Point(0, 0);
            en = en && SecondPoint == new OpenCvSharp.Point(0, 0);
            en = en && ThirdPoint == new OpenCvSharp.Point(0, 0);
            en = en && FourthPoint == new OpenCvSharp.Point(0, 0);
            return en;
        }
 
        public OpenCvSharp.Point2f[] GetCoutonrs2f()
        {
            OpenCvSharp.Point2f[] coutonrs = new OpenCvSharp.Point2f[4];
            coutonrs[0] = FirstPoint;
            coutonrs[1] = SecondPoint;
            coutonrs[2] = FourthPoint;
            coutonrs[3] = ThirdPoint;
            return coutonrs;
        }
 
        public OpenCvSharp.Point[] GetCoutonrs()
        {
            OpenCvSharp.Point[] coutonrs = new OpenCvSharp.Point[4];
            coutonrs[0] = FirstPoint;
            coutonrs[1] = SecondPoint;
            coutonrs[2] = FourthPoint;
            coutonrs[3] = ThirdPoint;
            return coutonrs;
        } 
    }

相关变量:

    public enum eDirections  // ROI移动方向
    {
        NULL = 0,
        上 = 1,
        下 = 2,
        左 = 3,
        右 = 4
    }
 
    //ROI大小调整方式
    public enum eResizeMode
    {
        All = 0, // 长宽一起调整
        Width = 1, // 只变宽度 即 矩形的长
        Height = 2, //  只变高度 即 矩形的宽
    }
 
 
    public class yVars
    {
        public static string OriImg; // 原图
 
        public static bool IsDrawEdgeOK = false; 
        public static bool pbxMouseDown = false;
        public static bool IsMouseMove = false;
        public static bool IsSelectROIOK = false;
        public static bool IsMouseUp = false;
 
        public static int step; //ROI区域移动步长
        public static eDirections direct = eDirections.NULL;
 
        public static int ROINum = 1; // 操作第一个ROI还是第二个ROI
        public static bool IsSelectingROI = false;
        //  
        public static bool IsSelectROI_1 = false;
        public static bool IsSelectROI_1_OK = false;
 
        public static bool IsSelectROI_2 = false;
        public static bool IsSelectROI_2_OK = false;
 
        public static ROI myROI_1 = new ROI();
        public static ROI myROI_2 = new ROI();
    }

ROI的绘制:

 矩形的ROI ,我们只需要两个点就能确定一个矩形。

我们获取到的位置是鼠标相对于picturebox的位置,需要转化成相对于图像的坐标,我的 picturebox 的 sizemode 是 stretchImage ,所以按比例转化过去就行。

 在 picturebox 的 mousedown 事件中 记录鼠标按下的第一个位置 为ROI的第一个点。

我把绘制ROI的过程写在 mousemove 事件里面,这样就能实现在确定第一个点后鼠标移动时ROI区域一直显示出来

        private void pbxImgShow_MouseMove(object sender, MouseEventArgs e)
        {
            if (yVars.IsSelectROI_1 == false && yVars.IsSelectROI_2 == false)
                return;
            if (yVars.pbxMouseDown == false)
                return;
            if (yVars.IsMouseUp == true)
                return;
            int mx = 0, my = 0;
            Mat mm = new Mat(yVars.OriImg);
            // 鼠标相对于picturebox的位置
            mx = Frm_Main.Instance.pbxImgShow.PointToClient(Control.MousePosition).X;
            my = Frm_Main.Instance.pbxImgShow.PointToClient(Control.MousePosition).Y;
 
            // 鼠标移动时 位置在 picturebox 中就画出对应的ROI形状
            if (mx < pbxImgShow.Width && my < pbxImgShow.Height)
            {
                //转成在图片上的位置
                double xx = mx * mm.Width * 1.0 / Frm_Main.Instance.pbxImgShow.Width;
                double yy = my * mm.Height * 1.0 / Frm_Main.Instance.pbxImgShow.Height;
 
                if (yVars.IsSelectROI_1 == true)
                {
                    yVars.myROI_1.FourthPoint = new OpenCvSharp.Point(xx, yy);
                    yVars.myROI_1.SecondPoint = new OpenCvSharp.Point(xx, yVars.myROI_1.FirstPoint.Y);
                    yVars.myROI_1.ThirdPoint = new OpenCvSharp.Point(yVars.myROI_1.FirstPoint.X, yy);
 
                    mm = yActions.DrawROIMat(mm, yVars.myROI_1);
                    yVars.IsSelectROI_1_OK = true;
                }
                else if (yVars.IsSelectROI_2 == true)
                {
                    yVars.myROI_2.FourthPoint = new OpenCvSharp.Point(xx, yy);
                    yVars.myROI_2.SecondPoint = new OpenCvSharp.Point(xx, yVars.myROI_2.FirstPoint.Y);
                    yVars.myROI_2.ThirdPoint = new OpenCvSharp.Point(yVars.myROI_2.FirstPoint.X, yy);
                    mm = yActions.DrawROIMat(mm, yVars.myROI_2);
                    yVars.IsSelectROI_2_OK = true;
                }
                yVars.IsMouseMove = true;
            }
            else // 释放鼠标时的点位不在picturebox中 将相关变量值清空 
            {
                if (yVars.IsSelectROI_1 == true)
                {
                    yVars.myROI_1.Reset();
 
                    yVars.IsSelectROI_1_OK = false;
                }
                else if (yVars.IsSelectROI_2 == true)
                {
                    yVars.myROI_2.Reset();
                    yVars.IsSelectROI_2_OK = false;
                }
            }
            pbxImgShow.Image = yImgConvert.MatToBitmap(mm);
            mm.Release();
        }

在线程或者循环等过程中定义的 mat 要及时 Release 掉。

在 mouseup 事件中就绘制完成了 注意选择的第一点和第二点,分别是ROI的 FirstPoint 和 FourthPoint  ,两点的相对位置要确定好,要保证 FirstPoint 为左上角的点 FourthPoint 为右下角的点,不是的话 就对 FirstPoint 和 FourthPoint 重新赋值, FirstPoint 为两点的 x , y 最小的点 ,FourthPoint  为两点的 x , y 最大的点。

绘制完ROI后可以对其位置和大小进行相应的调整。

        public static Mat DrawROIMat(Mat class="lazy" data-src, ROI rOI, Scalar? scalar = null, int thickness = 1, LineTypes lineTypes = LineTypes.AntiAlias)
        {
            Scalar sc = scalar ?? Scalar.Red;
            Cv2.Line(class="lazy" data-src, rOI.FirstPoint, rOI.SecondPoint, sc, thickness, lineTypes);
            Cv2.Line(class="lazy" data-src, rOI.SecondPoint, rOI.FourthPoint, sc, thickness, lineTypes);
            Cv2.Line(class="lazy" data-src, rOI.FourthPoint, rOI.ThirdPoint, sc, thickness, lineTypes);
            Cv2.Line(class="lazy" data-src, rOI.ThirdPoint, rOI.FirstPoint, sc, thickness, lineTypes);
            return class="lazy" data-src;
        }

对位置进行调整: 主要思想就是对ROI的四个点的坐标相应方向进行加减即可,主要超限问题即可。

        public static void ImgROIMove(Mat class="lazy" data-src, out Mat dstImg, ref ROI rOI, eDirections eDirections, double step, int gap = 3)
        {
            dstImg = new Mat();
 
            switch (eDirections)
            {
                case eDirections.NULL:
                    break;
                case eDirections.上:
                    if (rOI.YTop - step <= gap)
                    {
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X, rOI.ThirdPoint.Y - rOI.YTop + gap);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X, rOI.FourthPoint.Y - rOI.YTop + gap);
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X, gap);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X, gap);
                    }
                    else
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X, rOI.FirstPoint.Y - step);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X, rOI.SecondPoint.Y - step);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X, rOI.ThirdPoint.Y - step);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X, rOI.FourthPoint.Y - step);
                    }
                    break;
                case eDirections.下:
                    if (rOI.YBottom + step >= class="lazy" data-src.Height - gap)
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X, rOI.FirstPoint.Y + class="lazy" data-src.Height - rOI.YBottom - gap);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X, rOI.SecondPoint.Y + class="lazy" data-src.Height - rOI.YBottom - gap);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X, class="lazy" data-src.Height - gap);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X, class="lazy" data-src.Height - gap);
                    }
                    else
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X, rOI.FirstPoint.Y + step);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X, rOI.SecondPoint.Y + step);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X, rOI.ThirdPoint.Y + step);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X, rOI.FourthPoint.Y + step);
                    }
                    break;
                case eDirections.左:
                    if (rOI.XLeft - step <= gap)
                    {
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X - rOI.XLeft + gap, rOI.SecondPoint.Y);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X - rOI.XLeft + gap, rOI.FourthPoint.Y);
                        rOI.ThirdPoint = new OpenCvSharp.Point(gap, rOI.ThirdPoint.Y);
                        rOI.FirstPoint = new OpenCvSharp.Point(gap, rOI.FirstPoint.Y);
                    }
                    else
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X - step, rOI.FirstPoint.Y);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X - step, rOI.SecondPoint.Y);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X - step, rOI.ThirdPoint.Y);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X - step, rOI.FourthPoint.Y);
                    }
                    break;
                case eDirections.右:
                    if (rOI.XRight + step >= class="lazy" data-src.Width - gap)
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X + class="lazy" data-src.Width - rOI.XRight - gap, rOI.FirstPoint.Y);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X + class="lazy" data-src.Width - rOI.XRight - gap, rOI.ThirdPoint.Y);
                        rOI.FourthPoint = new OpenCvSharp.Point(class="lazy" data-src.Width - gap, rOI.FourthPoint.Y);
                        rOI.SecondPoint = new OpenCvSharp.Point(class="lazy" data-src.Width - gap, rOI.SecondPoint.Y);
                    }
                    else
                    {
                        rOI.FirstPoint = new OpenCvSharp.Point(rOI.FirstPoint.X + step, rOI.FirstPoint.Y);
                        rOI.SecondPoint = new OpenCvSharp.Point(rOI.SecondPoint.X + step, rOI.SecondPoint.Y);
                        rOI.ThirdPoint = new OpenCvSharp.Point(rOI.ThirdPoint.X + step, rOI.ThirdPoint.Y);
                        rOI.FourthPoint = new OpenCvSharp.Point(rOI.FourthPoint.X + step, rOI.FourthPoint.Y);
                    }
                    break;
                default:
                    break;
            }
            dstImg = yActions.DrawROIMat(class="lazy" data-src, rOI);
        }

对大小进行调整: 主要思路是 ROI 大小调整前后,其中心点坐标不变,相应的长度和宽度变了。我们就可以采用 OpenCvSharp.RotatedRect 这个类,根据 中心点坐标,相应size,和倾斜角度(正矩形为0). 最后再把 RotatedRect 的四个顶点重新赋值给 ROI的四个顶点就好,注意一下点的相对位置关系。

        public static void ImgROIResize(Mat class="lazy" data-src, out Mat dstImg, ref ROI rOI, bool IsAdd, double step, eResizeMode eResizeMode)
        {
            dstImg = new Mat();
            double height = rOI.Height, width = rOI.Width; 
            if (IsAdd == true)
            {
                switch (eResizeMode)
                {
                    case eResizeMode.All:
                        height = rOI.Height + step;
                        width = rOI.Width + step;
                        break;
                    case eResizeMode.Width:
                        width = rOI.Width + step;
                        break;
                    case eResizeMode.Height:
                        height = rOI.Height + step;
                        break;
                }
            }
            else
            {
                switch (eResizeMode)
                {
                    case eResizeMode.All:
                        height = rOI.Height - step;
                        width = rOI.Width - step;
                        break;
                    case eResizeMode.Width:
                        width = rOI.Width - step;
                        break;
                    case eResizeMode.Height:
                        height = rOI.Height - step;
                        break;
                }
            }
 
            OpenCvSharp.Size2f size = new Size2f(width, height);
            OpenCvSharp.RotatedRect rotateRect = new RotatedRect(rOI.Center, size, 0);
            Point2f[] points = rotateRect.Points();// 获得矩形四个顶点坐标
            // 大小缩放后需要判断坐标是否超限 
            for (int i = 0; i < points.Length; i++)
            {  
                if (points[i].X <= 0 || points[i].Y <= 0 || points[i].X >= class="lazy" data-src.Width || points[i].Y >= class="lazy" data-src.Height)
                {
                    return;
                }
            }
            rOI.FirstPoint = new OpenCvSharp.Point(points[1].X, points[1].Y);
            rOI.SecondPoint = new OpenCvSharp.Point(points[2].X, points[2].Y);
            rOI.ThirdPoint = new OpenCvSharp.Point(points[0].X, points[0].Y);
            rOI.FourthPoint = new OpenCvSharp.Point(points[3].X, points[3].Y);
            dstImg = yActions.DrawROIMat(class="lazy" data-src, rOI); 
        }

绘制并调整好ROI后,从原图上将对应的ROI图像扣下来,

        public static Mat GetROIMat(Mat mm, ROI rOI)
        {
            Mat mask = Mat.Zeros(mm.Size(), MatType.CV_8UC1);
            List<List<OpenCvSharp.Point>> pp = new List<List<OpenCvSharp.Point>>() {
               rOI.GetCoutonrs().ToList()
            }; 
            Cv2.FillPoly(mask, pp, new Scalar(255, 255, 255));
            OpenCvSharp.Rect rect = Cv2.BoundingRect(rOI.GetCoutonrs2f());
            if (rect.X <= 0) rect.X = 1;
            if (rect.Y <= 0) rect.Y = 0;
            if (rect.X + rect.Width > mm.Width)
                rect.Width = mm.Width - rect.X - 1;
            if (rect.Y + rect.Height > mm.Height)
                rect.Height = mm.Height - rect.Y - 1;
            Mat class="lazy" data-src = new Mat(mm, rect);
            Mat maskROI = new Mat(mask, rect);
            Mat dstImg = new Mat();
            Cv2.BitwiseAnd(class="lazy" data-src, class="lazy" data-src, dstImg, maskROI);
            return dstImg;
        }

然后对每张扣下来的mat进行边缘检测 抓边拟合等操作

部分代码

            coutonrs = yVars.myROI_1.GetCoutonrs2f();
            class="lazy" data-srcROIImg = yActions.GetROIMat(class="lazy" data-src, yVars.myROI_1);
            Cv2.CvtColor(class="lazy" data-srcROIImg, grayImg, ColorConversionCodes.RGB2GRAY);
            Cv2.Blur(grayImg, grayImg, new OpenCvSharp.Size(3, 3));
            Cv2.Canny(grayImg, cannyImg, param1, param2, param3, true);
            //获得轮廓 
            Cv2.FindContours(cannyImg, out contoursROI1, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));
 
            if (contoursROI1.Length == 0)
            {
                YXH._01.yMessagebox.ShowDialogCN("ROI_1未抓到边,请调整迟滞参数,或重新选择ROI区域");
                return;
            }
            // 获取轮廓后需要将点的坐标转换到原图上 此时的坐标是相对于ROI区域的坐标 
            // 即每个坐标需要加上ROI区域的左上角坐标 再将转化后的坐标添加进拟合集合内
            for (int i = 0; i < contoursROI1.Length; i++)
            {
                for (int j = 0; j < contoursROI1[i].Length; j++)
                {
                    contoursROI1[i][j] += yVars.myROI_1.FirstPoint;
                    ROI_1_Points.Add(contoursROI1[i][j]);
                    AllPoints.Add(contoursROI1[i][j]);
                }
            }

操作完成后再根据想要在界面上显示的进行相应的绘制即可。

到此这篇关于c#中WinForm使用OpencvSharp4实现简易抓边的文章就介绍到这了,更多相关c# OpencvSharp4 抓边内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

c#中WinForm使用OpencvSharp4实现简易抓边

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么使用C++实现简易服务器

今天小编给大家分享一下怎么使用C++实现简易服务器的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Server.h#pragm
2023-07-05

使用C#怎么实现一个简易画图板

本篇文章为大家展示了使用C#怎么实现一个简易画图板,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。定义公共变量用于多个窗体之间共同使用数据public class TempData {
2023-06-14

如何使用C语言实现简易扫雷游戏

这篇文章主要介绍了如何使用C语言实现简易扫雷游戏,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、头文件#define _CRT_SECURE_NO_WARNINGS//包含
2023-06-26

C#中怎么用websocket实现简易聊天功能

本篇内容主要讲解“C#中怎么用websocket实现简易聊天功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#中怎么用websocket实现简易聊天功能”吧!前言使用C#语言进行开发,基于.
2023-06-29

Python中怎么使用栈实现简易计算器

这篇文章主要介绍“Python中怎么使用栈实现简易计算器”,在日常操作中,相信很多人在Python中怎么使用栈实现简易计算器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python中怎么使用栈实现简易计算器
2023-06-02

C#中如何使用属性和自动实现属性简化代码

C#中如何使用属性和自动实现属性简化代码,需要具体代码示例在C#编程中,使用属性和自动实现属性可以帮助我们简化代码,提高代码的可读性和可维护性。属性允许我们通过封装字段来访问和更改对象的状态,而自动实现属性则进一步简化了属性的创建过程。属性
2023-10-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录