C3031
2026-01-30 22ff831583da8c6f1c015c1e294f0bc1ef70ac85
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithm.cs
@@ -41,7 +41,7 @@
        /// <summary>
        /// 读写锁
        /// </summary>
        public readonly object lockObj = new object();
        public static readonly object lockObj = new object();
        /// <summary>
        /// 裁切图片为hoDomainImage(保留原坐标系,其余填充为空)
@@ -64,7 +64,7 @@
                {
                    if (InputImage is Bitmap)
                    {
                        Bitmap2Mat((Bitmap)InputImage, out Mat src);
                        TAlgorithm.Bitmap2Mat((Bitmap)InputImage, out Mat src);
                        if (Params.Fixture == null)
                            Params.Fixture = new Fixture();
@@ -96,7 +96,7 @@
                                // 4. 创建与原图大小相同的Mat,并初始化无效值
                                image = new Mat(src.Size(), src.Type());
                                ((Mat)image).SetTo(GetInvalidValueForMat(src)); // 全部初始化为无效值
                                ((Mat)image).SetTo(TAlgorithm.GetInvalidValueForMat(src)); // 全部初始化为无效值
                                // 5. 创建遮罩:在result上绘制旋转矩形(白色填充)
                                using (Mat cropped = new Mat(src, boundingRect))
@@ -113,7 +113,7 @@
                                // 2. 创建与原图大小相同的Mat,并初始化无效值
                                image = new Mat(src.Size(), src.Type());
                                ((Mat)image).SetTo(GetInvalidValueForMat(src)); // 全部初始化为无效值
                                ((Mat)image).SetTo(TAlgorithm.GetInvalidValueForMat(src)); // 全部初始化为无效值
                                // 3. 创建圆形遮罩
                                using (Mat mask = Mat.Zeros(src.Rows, src.Cols, MatType.CV_8UC1))
@@ -127,8 +127,39 @@
                                image = ((Bitmap)InputImage)?.Clone();
                                return true;
                        }
                        Mat2Bitmap((Mat)image, out Bitmap bmp);
                        TAlgorithm.Mat2Bitmap((Mat)image, out Bitmap bmp);
                        image = bmp;
                        return true;
                    }
                    else if (InputImage is HObject ho_image)
                    {
                        if (!ho_image.IsInitialized())
                            return false;
                        if (Params.Fixture == null)
                            Params.Fixture = new Fixture();
                        HObject hoDomainImage = null;
                        switch (Params.ROI?.GetType().Name)
                        {
                            case "HRectangle2":
                                HOperatorSet.GenRectangle2(out HObject hRectangle2, (HTuple)(Params.ROI.Row + Params.Fixture.Row), (HTuple)(Params.ROI.Column + Params.Fixture.Column)
                                    , (HTuple)(Params.ROI.Phi + Params.Fixture.Phi), (HTuple)((HRectangle2)Params.ROI).SemiLength1, (HTuple)((HRectangle2)Params.ROI).SemiLength2);
                                HOperatorSet.ReduceDomain(ho_image, hRectangle2, out hoDomainImage);
                                break;
                            case "HCircle":
                                HOperatorSet.GenCircle(out HObject hCircle, (HTuple)(Params.ROI.Row + Params.Fixture.Row), (HTuple)(Params.ROI.Column + Params.Fixture.Column)
                                    , (HTuple)((HCircle)Params.ROI).Radius);
                                HOperatorSet.ReduceDomain(ho_image, hCircle, out hoDomainImage);
                                break;
                            case "ROI":
                            default:
                                image = ho_image.CopyObj(1, -1);
                                return true;
                        }
                        image = hoDomainImage;
                        return true;
                    }
                    else if (InputImage is Mat)
@@ -162,7 +193,7 @@
                                // 4. 创建与原图大小相同的Mat,并初始化无效值
                                image = new Mat(src.Size(), src.Type());
                                ((Mat)image).SetTo(GetInvalidValueForMat(src)); // 全部初始化为无效值
                                ((Mat)image).SetTo(TAlgorithm.GetInvalidValueForMat(src)); // 全部初始化为无效值
                                // 5. 创建遮罩:在result上绘制旋转矩形(白色填充)
                                using (Mat cropped = new Mat(src, boundingRect))
@@ -179,7 +210,7 @@
                                // 2. 创建与原图大小相同的Mat,并初始化无效值
                                image = new Mat(src.Size(), src.Type());
                                ((Mat)image).SetTo(GetInvalidValueForMat(src)); // 全部初始化为无效值
                                ((Mat)image).SetTo(TAlgorithm.GetInvalidValueForMat(src)); // 全部初始化为无效值
                                // 3. 创建圆形遮罩
                                using (Mat mask = Mat.Zeros(src.Rows, src.Cols, MatType.CV_8UC1))
@@ -213,112 +244,32 @@
            }
        }
        public virtual bool ReduceDomainImage(object InputImage, ref HImage image)
        {
            image = null;
            if (InputImage == null)
            {
                image = null;
                Msg = "输入图片为空";
                Result = false;
                return false;
            }
            lock (InputImage)
            {
                try
                {
                    if (InputImage is HImage ho_image)
                    {
                        if (!ho_image.IsInitialized())
                            return false;
                        if (Params.Fixture == null)
                            Params.Fixture = new Fixture();
                        HImage hoDomainImage = null;
                        switch (Params.ROI?.GetType().Name)
                        {
                            case "HRectangle2":
                                using (HRegion hRectangle2 = new HRegion())
                                {
                                    hRectangle2.GenRectangle2((HTuple)(Params.ROI.Row + Params.Fixture.Row), (HTuple)(Params.ROI.Column + Params.Fixture.Column)
                                        , (HTuple)(Params.ROI.Phi + Params.Fixture.Phi), (HTuple)((HRectangle2)Params.ROI).SemiLength1, (HTuple)((HRectangle2)Params.ROI).SemiLength2);
                                    hoDomainImage = ho_image.ReduceDomain(hRectangle2);
                                }
                                break;
                            case "HCircle":
                                using (HRegion hCircle = new HRegion())
                                {
                                    hCircle.GenCircle((HTuple)(Params.ROI.Row + Params.Fixture.Row), (HTuple)(Params.ROI.Column + Params.Fixture.Column)
                                    , (HTuple)((HCircle)Params.ROI).Radius);
                                    hoDomainImage = ho_image.ReduceDomain(hCircle);
                                }
                                break;
                            case "ROI":
                            default:
                                image = ho_image.CopyObj(1, -1);
                                return true;
                        }
                        image = hoDomainImage;
                        return true;
                    }
                    else
                    {
                        image = null;
                        Msg = $"输入格式不正确{InputImage.GetType()}";
                        Result = false;
                        return false;
                    }
                }
                catch (Exception ex)
                {
                    image = null;
                    Msg = $"裁剪区域失败,原因是:{ex.ToString()}";
                    Result = false;
                    return false;
                }
            }
        }
        public override void Dispose()
        {
            if (InputImage != null)
            {
                if (InputImage is HObject)
                {
                    ((HObject)InputImage).Dispose();
                }
                else if (InputImage is Mat)
                {
                    ((Mat)InputImage).Dispose();
                }
                else if (InputImage is Bitmap)
                {
                    ((Bitmap)InputImage).Dispose();
                }
                InputImage = null;
            }
            if (OutputImage != null)
            {
                if (OutputImage is HObject)
                {
                    ((HObject)OutputImage).Dispose();
                }
                else if (OutputImage is Mat)
                {
                    ((Mat)OutputImage).Dispose();
                }
                else if (OutputImage is Bitmap)
                {
                    ((Bitmap)OutputImage).Dispose();
                }
                OutputImage = null;
            }
            if (Record != null)
            {
                Record.Dispose();
@@ -336,18 +287,13 @@
                if (InputImage != null)
                {
                    if (InputImage is HObject ho_image && ho_image.IsInitialized())
                    {
                        obj.InputImage = ho_image.CopyObj(1, -1);
                    }
                    else if (InputImage is Mat mat && !mat.Empty())
                    {
                        obj.InputImage = mat.Clone();
                    }
                    else if (InputImage is Bitmap bitmap)
                    {
                        obj.InputImage = bitmap.Clone();
                    }
                }
                return obj;
            }
            catch { return (TAlgorithm)MemberwiseClone(); }
@@ -357,32 +303,26 @@
        {
            Result = true;
            bCompleted = false;
            Msg = string.Empty;
            //if (InputImage != null)
            //{
            //    if (InputImage is HObject)
            //    {
            //        ((HObject)InputImage).Dispose();
            //    }
            //    else if (InputImage is Mat)
            //    {
            //        ((Mat)InputImage).Dispose();
            //    }
            //    else if (InputImage is Bitmap)
            //    {
            //        ((Bitmap)InputImage).Dispose();
            //    }
            //    InputImage = null;
            //}
            if (Record != null)
            Msg = "";
            if (OutputImage != null)
            {
                Record.Dispose();
                if (OutputImage is HObject)
                    ((HObject)OutputImage).Dispose();
                else if (OutputImage is Mat)
                    ((Mat)OutputImage).Dispose();
                else if (OutputImage is Bitmap)
                    ((Bitmap)OutputImage).Dispose();
                OutputImage = null;
            }
            if (Record != null)
                Record.Dispose();
        }
        public override bool Run()
        {
            DateTime StartTime = DateTime.Now;
            InitRunParams();
            HOperatorSet.GenEmptyObj(out HObject EmptyObj);
            OutputImage = EmptyObj;
@@ -400,6 +340,7 @@
                Thread.Sleep(30);
            }
            Msg = "运行超时";
            Result = false;
            RunTime = (DateTime.Now - StartTime).TotalMilliseconds;
@@ -425,9 +366,8 @@
            try
            {
                if (string.IsNullOrEmpty(fullPath))
                {
                    return false;
                }
                if (!fullPath.Contains(".json"))
                {
                    Debug.WriteLine("文件路径不完整");
@@ -438,6 +378,7 @@
                    Debug.WriteLine("文件路径不完整");
                    return false;
                }
                // 获取不带文件名的目录路径
                string directoryPath = Path.GetDirectoryName(fullPath);
                strProcessName = Path.GetFileNameWithoutExtension(fullPath);
@@ -448,6 +389,7 @@
                    Save(directoryPath);
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(fullPath, Encoding.UTF8))
                {
@@ -456,9 +398,8 @@
                }
                Params = JsonConvert.DeserializeObject<ProcessParams>(strJson);
                if (Params == null)
                {
                    return false;
                }
                Params.FixDeserializedData();
                return true;
            }
@@ -521,20 +462,20 @@
                return value;
        }
        public static HImage Bitmap2HImage(Bitmap bmp)
        public static void Bitmap2HObject(Bitmap bmp, out HObject image)
        {
            BitmapData srcBmpData;
            HImage image = null;
            try
            {
                if (bmp.Tag == null || bmp == null || bmp.Width == 0 || bmp.Height == 0)
                if (bmp == null || bmp.Width == 0 || bmp.Height == 0)
                {
                    image = null;
                    return image;
                    return;
                }
                lock (bmp)
                {
                    image = new HImage();
                    switch (bmp.PixelFormat)
                    {
                        case PixelFormat.Format24bppRgb:
@@ -543,41 +484,35 @@
                            int width = bmp.Width;
                            int height = bmp.Height;
                            int stride = srcBmpData.Stride;
                            if (stride == width * 3)
                            {
                                image.GenImageInterleaved(srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
                            }
                                HOperatorSet.GenImageInterleaved(out image, srcBmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", 0, 0, 0, 0, -1, 0);
                            else
                            {
                                image = HandleStrideAlignmentBest(srcBmpData.Scan0, width, height, stride);
                            }
                            bmp.UnlockBits(srcBmpData);
                            break;
                        default:
                            srcBmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
                            image.GenImage1("byte", bmp.Width, bmp.Height, srcBmpData.Scan0);
                            HOperatorSet.GenImage1(out image, "byte", bmp.Width, bmp.Height, srcBmpData.Scan0);
                            bmp.UnlockBits(srcBmpData);
                            break;
                    }
                }
                return image;
                return;
            }
            catch
            {
                if (image != null)
                {
                    image.Dispose();
                }
                image = null;
                return image;
                return;
            }
        }
        private static HImage HandleStrideAlignmentBest(IntPtr scan0, int width, int height, int stride)
        private static HObject HandleStrideAlignmentBest(IntPtr scan0, int width, int height, int stride)
        {
            int expectedStride = width * 3;
            byte[] alignedData = new byte[width * height * 3];
            HImage image = new HImage();
            unsafe
            {
                byte* srcPtr = (byte*)scan0;
@@ -595,31 +530,31 @@
                            expectedStride
                        );
                    }
                    image.GenImageInterleaved(new IntPtr(dstPtr), "bgr", width, height, 0, "byte", width, height, 0, 0, -1, 0);
                    return image;
                    HOperatorSet.GenImageInterleaved(out HObject ho_img, new IntPtr(dstPtr), "bgr", width, height, 0, "byte", width, height, 0, 0, -1, 0);
                    return ho_img;
                }
            }
        }
        public static unsafe void HImage2Bitmap(HImage hImage, out Bitmap bmp)
        public static unsafe void HObject2Bitmap(HObject hObject, out Bitmap bmp)
        {
            try
            {
                if (hImage == null || !hImage.IsInitialized())
                if (hObject == null || !hObject.IsInitialized())
                {
                    bmp = null;
                    return;
                }
                // 获取图像信息
                hImage.GetImageSize(out HTuple width, out HTuple height);
                HTuple channels = hImage.CountChannels();
                HOperatorSet.GetImageSize(hObject, out HTuple width, out HTuple height);
                HOperatorSet.CountChannels(hObject, out HTuple channels);
                if (channels.I == 1)
                {
                    // 灰度图处理
                    HTuple ptr, type;
                    ptr = hImage.GetImagePointer1(out type, out width, out height);
                    HOperatorSet.GetImagePointer1(hObject, out ptr, out type, out width, out height);
                    bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
@@ -648,7 +583,7 @@
                {
                    // 彩色图处理(BGR顺序)
                    HTuple ptrR, ptrG, ptrB, type;
                    hImage.GetImagePointer3(out ptrR, out ptrG, out ptrB, out type, out width, out height);
                    HOperatorSet.GetImagePointer3(hObject, out ptrR, out ptrG, out ptrB, out type, out width, out height);
                    bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
                    BitmapData bmpData = bmp.LockBits(
@@ -685,20 +620,20 @@
            }
        }
        public static HImage Mat2HImage(Mat mat)
        public static void Mat2HObject(Mat mat, out HObject image)
        {
            HImage image = null;
            try
            {
                if (mat == null || mat.Empty())
                {
                    return image;
                    image = null;
                    return;
                }
                if (mat.Type() == MatType.CV_8UC3) // 彩色图像 (BGR)
                {
                    image = new HImage();
                    image.GenImageInterleaved(
                    HOperatorSet.GenImageInterleaved(
                        out image,
                        mat.Data,
                        "bgr",
                        mat.Width,
@@ -709,8 +644,8 @@
                }
                else if (mat.Type() == MatType.CV_8UC1) // 灰度图像
                {
                    image = new HImage();
                    image.GenImage1(
                    HOperatorSet.GenImage1(
                        out image,
                        "byte",
                        mat.Width,
                        mat.Height,
@@ -719,13 +654,14 @@
                else
                {
                    throw new ArgumentException($"Mat2HObject不支持的图像格式:{mat.Type()}");
                    return;
                }
                return image;
                return;
            }
            catch
            {
                image = null;
                return image;
                return;
            }
        }
@@ -1311,10 +1247,10 @@
                HOperatorSet.GenImageConst(out image, "real", hv_xMax + 1, hv_yMax + 1);
                HOperatorSet.SetGrayval(image, hv_y, hv_x, hv_z);
                //hoperatorset.getimagesize(ho_image, out htuple hv_width, out htuple hv_height);
                //hoperatorset.genrectangle1(out hobject ho_rectangle, 0, 0, hv_height - 1, hv_width - 1);
                //hoperatorset.getregionpoints(ho_rectangle, out htuple hv_rows, out htuple hv_columns);
                //hoperatorset.getgrayval(ho_image, hv_rows, hv_columns, out htuple hv_z);
                //HOperatorSet.GetImageSize(ho_Image, out HTuple hv_Width, out HTuple hv_Height);
                //HOperatorSet.GenRectangle1(out HObject ho_Rectangle, 0, 0, hv_Height - 1, hv_Width - 1);
                //HOperatorSet.GetRegionPoints(ho_Rectangle, out HTuple hv_Rows, out HTuple hv_Columns);
                //HOperatorSet.GetGrayval(ho_Image, hv_Rows, hv_Columns, out HTuple hv_Z);
            }
            catch { image = null; }
        }
@@ -1325,7 +1261,7 @@
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public double GetDistanceP2P(HPoint startPoint, HPoint endPoint)
        public static double GetDistanceP2P(HPoint startPoint, HPoint endPoint)
        {
            try
            {
@@ -1334,12 +1270,12 @@
            catch { return 9994; }
        }
        public double GetDistanceP2P(Point startPoint, Point endPoint)
        public static double GetDistanceP2P(Point startPoint, Point endPoint)
        {
            return GetDistanceP2P(new HPoint(startPoint), new HPoint(endPoint));
        }
        public double DistanceP2P(double startX, double startY, double endX, double endY)
        public static double DistanceP2P(double startX, double startY, double endX, double endY)
        {
            return GetDistanceP2P(new HPoint(startX, startY), new HPoint(endX, endY));
        }
@@ -1350,17 +1286,17 @@
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public HPoint GetMidPoint(HPoint startPoint, HPoint endPoint)
        public static HPoint GetMidPoint(HPoint startPoint, HPoint endPoint)
        {
            return new HPoint((startPoint.X + endPoint.X) / 2, (startPoint.Y + endPoint.Y) / 2);
        }
        public Point GetMidPoint(Point startPoint, Point endPoint)
        public static Point GetMidPoint(Point startPoint, Point endPoint)
        {
            return new Point((startPoint.X + endPoint.X) / 2, (startPoint.Y + endPoint.Y) / 2);
        }
        public System.Drawing.Point GetMidPoint(System.Drawing.Point startPoint, System.Drawing.Point endPoint)
        public static System.Drawing.Point GetMidPoint(System.Drawing.Point startPoint, System.Drawing.Point endPoint)
        {
            return new System.Drawing.Point((startPoint.X + endPoint.X) / 2, (startPoint.Y + endPoint.Y) / 2);
        }
@@ -1371,7 +1307,7 @@
        /// <param name="point"></param>
        /// <param name="segment"></param>
        /// <returns></returns>
        public bool IsPointOnSegment(HPoint pt, HSegment segment, double tolerance = 1e-3)
        public static bool IsPointOnSegment(HPoint pt, HSegment segment, double tolerance = 1e-3)
        {
            // 计算直线方程的系数
            double A = segment.EndY - segment.StartX;
@@ -1394,7 +1330,7 @@
            return false;
        }
        public bool IsPointOnSegment(double px, double py, double x1, double y1, double x2, double y2)
        public static bool IsPointOnSegment(double px, double py, double x1, double y1, double x2, double y2)
        {
            return IsPointOnSegment(new HPoint(px, py), new HSegment(x1, y1, x2, y2));
        }
@@ -1419,7 +1355,7 @@
            catch { return false; }
        }
        public bool IsPointNearRectangleSilde(HPoint pt, HRectangle2 rect, double tolerance = 100)
        public static bool IsPointNearRectangleSilde(HPoint pt, HRectangle2 rect, double tolerance = 100)
        {
            return IsPointNearRectangleSilde(new System.Drawing.Point((int)pt.X, (int)pt.Y), new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), tolerance);
        }
@@ -1431,21 +1367,21 @@
        /// <param name="pt2"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public bool IsPointNearPoint(HPoint pt1, HPoint pt2, double tolerance = 100)
        public static bool IsPointNearPoint(HPoint pt1, HPoint pt2, double tolerance = 100)
        {
            if (GetDistanceP2P(pt1, pt2) <= tolerance)
                return true;
            return false;
        }
        public bool IsPointNearPoint(Point pt1, Point pt2, double tolerance = 100)
        public static bool IsPointNearPoint(Point pt1, Point pt2, double tolerance = 100)
        {
            if (GetDistanceP2P(pt1, pt2) <= tolerance)
                return true;
            return false;
        }
        public bool IsPointNearPoint(double x1, double y1, double x2, double y2, int tolerance = 100)
        public static bool IsPointNearPoint(double x1, double y1, double x2, double y2, int tolerance = 100)
        {
            return IsPointNearPoint(new HPoint(x1, y1), new HPoint(x2, y2), tolerance);
        }
@@ -1458,7 +1394,7 @@
        /// <param name="corner"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public bool IsPointNearRectangleCorner(Point pt, Rectangle rect, out string corner, double tolerance = 10)
        public static bool IsPointNearRectangleCorner(Point pt, Rectangle rect, out string corner, double tolerance = 10)
        {
            try
            {
@@ -1497,7 +1433,7 @@
            catch { corner = ""; return false; }
        }
        public bool IsPointNearRectangleCorner(HPoint pt, HRectangle2 rect, out string corner, double tolerance = 10)
        public static bool IsPointNearRectangleCorner(HPoint pt, HRectangle2 rect, out string corner, double tolerance = 10)
        {
            try
            {
@@ -1545,7 +1481,7 @@
        /// <param name="p3">线2起始点</param>
        /// <param name="p4"></param>
        /// <returns></returns>
        public Point2d? GetLineIntersection(Point2d p1, Point2d p2, Point2d p3, Point2d p4, bool bOnSegment = false)
        public static Point2d? GetLineIntersection(Point2d p1, Point2d p2, Point2d p3, Point2d p4, bool bOnSegment = false)
        {
            // 直线1的向量
            double x1 = p1.X, y1 = p1.Y;
@@ -1582,7 +1518,7 @@
        #region Halcon
        // Chapter: Graphics / Output
        // Short Description: Display 3D object models 
        public void visualize_object_model_3d(HTuple hv_WindowHandle, HTuple hv_ObjectModel3D,
        public static void visualize_object_model_3d(HTuple hv_WindowHandle, HTuple hv_ObjectModel3D,
            HTuple hv_CamParam, HTuple hv_PoseIn, HTuple hv_GenParamName, HTuple hv_GenParamValue,
            HTuple hv_Title, HTuple hv_Label, HTuple hv_Information, out HTuple hv_PoseOut)
        {
@@ -3310,7 +3246,7 @@
        // Chapter: Calibration / Camera Parameters
        // Short Description: Set the value of a specified camera parameter in the camera parameter tuple. 
        public void set_cam_par_data(HTuple hv_CameraParamIn, HTuple hv_ParamName, HTuple hv_ParamValue,
        public static void set_cam_par_data(HTuple hv_CameraParamIn, HTuple hv_ParamName, HTuple hv_ParamValue,
            out HTuple hv_CameraParamOut)
        {
            // Local iconic variables 
@@ -3414,7 +3350,7 @@
            }
        }
        public void gen_arrow_contour_xld(out HObject ho_Arrow, HTuple hv_Row1, HTuple hv_Column1,
        public static void gen_arrow_contour_xld(out HObject ho_Arrow, HTuple hv_Row1, HTuple hv_Column1,
            HTuple hv_Row2, HTuple hv_Column2, HTuple hv_HeadLength, HTuple hv_HeadWidth)
        {
            // Stack for temporary objects 
@@ -3588,7 +3524,7 @@
            }
        }
        public void get_rect2_vertex(HTuple hv_Row, HTuple hv_Column, HTuple hv_Phi, HTuple hv_Length1,
        public static void get_rect2_vertex(HTuple hv_Row, HTuple hv_Column, HTuple hv_Phi, HTuple hv_Length1,
            HTuple hv_Length2, out HTuple hv_TopLeft_Row, out HTuple hv_TopLeft_Col, out HTuple hv_TopRight_Row,
            out HTuple hv_TopRight_Col, out HTuple hv_LowLeft_Row, out HTuple hv_LowLeft_Col,
            out HTuple hv_LowRight_Row, out HTuple hv_LowRight_Col)
@@ -3795,7 +3731,7 @@
            }
        }
        public void pts_to_best_line(out HObject ho_LineXld, HTuple hv_Rows, HTuple hv_Columns,
        public static void pts_to_best_line(out HObject ho_LineXld, HTuple hv_Rows, HTuple hv_Columns,
            HTuple hv_IgnoreNum, out HTuple hv_Row1, out HTuple hv_Column1, out HTuple hv_Row2,
            out HTuple hv_Column2)
        {
@@ -3881,7 +3817,7 @@
            }
        }
        public (double, double) CalculateTailValues(HTuple minValue, HTuple maxValue, HTuple mean, HTuple deviation, double tailPercentage = 0.3)
        public static (double, double) CalculateTailValues(HTuple minValue, HTuple maxValue, HTuple mean, HTuple deviation, double tailPercentage = 0.3)
        {
            // 计算低尾灰度值
            double lowTailValue = minValue.TupleReal() + (mean.TupleReal() - minValue.TupleReal()) * tailPercentage;
@@ -3896,6 +3832,61 @@
            return (highTailValue, lowTailValue);
        }
        /// <summary>
        /// 图像增强算法-边缘增强
        /// </summary>
        /// <param name="ho_Image">待测图片</param>
        /// <param name="hv_Wid">掩膜宽</param>
        /// <param name="hv_High">掩膜高</param>
        /// <param name="hv_Fac">增强因子</param>
        /// <param name="hv_Row1">起始纵坐标</param>
        /// <param name="hv_Column1">起始横坐标</param>
        /// <param name="hv_Row2">结束纵坐标</param>
        /// <param name="hv_Column2">结束横坐标</param>
        public static void ImageEnhancement(HObject ho_Image, out HObject ho_OutImage, HTuple hv_ImageEnhancementType, HTuple hv_Wid, HTuple hv_High, HTuple hv_Fac)
        {
            HOperatorSet.GenEmptyObj(out ho_OutImage);
            try
            {
                HTuple hv_ImageEnhancementTypeOut = new HTuple();
                hv_ImageEnhancementTypeOut.Dispose();
                hv_ImageEnhancementTypeOut = new HTuple(hv_ImageEnhancementType);
                hv_Wid.Dispose();
                hv_High.Dispose();
                ho_OutImage.Dispose();
                //设置图像增强算法
                if ((int)(new HTuple(hv_ImageEnhancementTypeOut.TupleEqual("emphasize"))) != 0)
                {
                    hv_ImageEnhancementTypeOut.Dispose();
                    hv_ImageEnhancementTypeOut = "emphasize";
                    HOperatorSet.Emphasize(ho_Image, out ho_OutImage, hv_Wid, hv_High, hv_Fac);
                }
                else if ((int)(new HTuple(hv_ImageEnhancementTypeOut.TupleEqual("equHisto"))) != 0)
                {
                    hv_ImageEnhancementTypeOut.Dispose();
                    hv_ImageEnhancementTypeOut = "equHisto";
                    HOperatorSet.ScaleImageMax(ho_Image, out ho_OutImage);
                }
                else
                {
                    hv_ImageEnhancementTypeOut.Dispose();
                    hv_ImageEnhancementTypeOut = "scaleMax";
                    HOperatorSet.EquHistoImage(ho_Image, out ho_OutImage);
                }
                return;
            }
            catch (HalconException HDevExpDefaultException)
            {
                hv_Wid.Dispose();
                hv_High.Dispose();
                throw HDevExpDefaultException;
            }
        }
        /// <summary>
        /// 卡尺算法
        /// </summary>
@@ -3914,7 +3905,7 @@
        /// <param name="hv_Column2">结束横坐标</param>
        /// <param name="hv_ResultRow">结果点集合纵坐标</param>
        /// <param name="hv_ResultColumn">结果点集合横坐标</param>
        public void Rake(HObject ho_Image, out HObject ho_Regions, HTuple hv_Elements,
        public static void Rake(HObject ho_Image, out HObject ho_Regions, HTuple hv_Elements,
            HTuple hv_DetectHeight, HTuple hv_DetectWidth, HTuple hv_Sigma, HTuple hv_Threshold,
            HTuple hv_Transition, HTuple hv_Select, HTuple hv_Row1, HTuple hv_Column1, HTuple hv_Row2,
            HTuple hv_Column2, out HTuple hv_ResultRow, out HTuple hv_ResultColumn)
@@ -5110,7 +5101,7 @@
            catch { }
        }
        public void scale_gray_map(HObject ho_Image, out HObject ho_Image1, HTuple hv_Min, HTuple hv_Max)
        public static void scale_gray_map(HObject ho_Image, out HObject ho_Image1, HTuple hv_Min, HTuple hv_Max)
        {
            HTuple hv_Mult = new HTuple(), hv_Add = new HTuple();
            HOperatorSet.GenEmptyObj(out ho_Image1);
@@ -5197,7 +5188,7 @@
        #region OpenCVSharp
        // 根据Mat类型返回对应的无效值
        public Scalar GetInvalidValueForMat(Mat mat)
        public static Scalar GetInvalidValueForMat(Mat mat)
        {
            MatType type = mat.Type();
            if (type == MatType.CV_8UC1 || type == MatType.CV_8UC3)
@@ -5210,7 +5201,7 @@
                return new Scalar(0); // 对于8位无符号类型,0是安全的无效值
        }
        public void RGB2XYZ(double sR, double sG, double sB, out double X, out double Y, out double Z)
        public static void RGB2XYZ(double sR, double sG, double sB, out double X, out double Y, out double Z)
        {
            // 输入的颜色值 (sR, sG, sB) 应为 0 到 255 之间的值
@@ -5241,7 +5232,7 @@
            Z = Math.Round(var_Z / (var_X + var_Y + var_Z), 3);
        }
        public void ExtractFrames(string videoPath, string outputDir)
        public static void ExtractFrames(string videoPath, string outputDir)
        {
            // 检查视频文件是否存在
            if (!File.Exists(videoPath))