c#实现halcon的rle编码blob分析

效果展示

实现功能

  • connection
  • 膨胀
  • 腐蚀
  • 开运算
  • 闭运算
  • 特征计算

膨胀
连接
腐蚀

核心代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace view3d
{

    // 基础对象类,类似于 Halcon 的 HObject
    public abstract class HObject
    {
        public abstract HObjectType Type { get; }

        public enum HObjectType
        {
            Region,
            XLD,
            Image
        }
    }
    // 使用 RLE (Run-Length Encoding) 编码的 HRegion 实现
    public class HRegion : HObject
    {
        public override HObjectType Type => HObjectType.Region;

        // RLE 编码数据结构: 每行存储起始列和结束列的列表
        private Dictionary<int, List<Interval>> _rleData = new Dictionary<int, List<Interval>>();

        // 边界框缓存
        private Rectangle _boundingBox;
        private bool _boundingBoxValid = false;

        // 用于表示一行中的连续区间
        private struct Interval
        {
            public int Start;
            public int End;

            public Interval(int start, int end)
            {
                Start = start;
                End = end;
            }

            public int Length => End - Start + 1;
        }

        // 构造函数
        public HRegion() { }

        // 从位图创建区域
        public HRegion(Bitmap bitmap, byte threshold = 128)
        {
            FromBitmap(bitmap, threshold);
        }

        // 从位图二值化并创建区域
        public void FromBitmap(Bitmap bitmap, byte threshold = 128,byte maxThreshold=255)
        {
            _rleData.Clear();
            _boundingBoxValid = false;

            for (int y = 0; y < bitmap.Height; y++)
            {
                List<Interval> intervals = new List<Interval>();
                bool inRegion = false;
                int startX = 0;

                for (int x = 0; x < bitmap.Width; x++)
                {
                    Color pixel = bitmap.GetPixel(x, y);
                    byte intensity = (byte)((pixel.R + pixel.G + pixel.B) / 3);
                    bool isForeground = intensity >= threshold && intensity<=maxThreshold;

                    if (isForeground && !inRegion)
                    {
                        // 进入区域
                        inRegion = true;
                        startX = x;
                    }
                    else if (!isForeground && inRegion)
                    {
                        // 离开区域
                        intervals.Add(new Interval(startX, x - 1));
                        inRegion = false;
                    }
                }

                // 处理行末尾仍在区域中的情况
                if (inRegion)
                {
                    intervals.Add(new Interval(startX, bitmap.Width - 1));
                }

                if (intervals.Count > 0)
                {
                    _rleData[y] = intervals;
                }
            }

            UpdateBoundingBox();
        }

        // 更新边界框
        private void UpdateBoundingBox()
        {
            if (_rleData.Count == 0)
            {
                _boundingBox = Rectangle.Empty;
                _boundingBoxValid = true;
                return;
            }

            int minX = int.MaxValue;
            int maxX = int.MinValue;
            int minY = _rleData.Keys.Min();
            int maxY = _rleData.Keys.Max();

            foreach (var kvp in _rleData)
            {
                foreach (var interval in kvp.Value)
                {
                    if (interval.Start < minX) minX = interval.Start;
                    if (interval.End > maxX) maxX = interval.End;
                }
            }

            _boundingBox = new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
            _boundingBoxValid = true;
        }

        // 获取边界框
        public Rectangle BoundingBox
        {
            get
            {
                if (!_boundingBoxValid) UpdateBoundingBox();
                return _boundingBox;
            }
        }

        // 计算区域面积
        public double Area()
        {
            double area = 0;
            foreach (var intervals in _rleData.Values)
            {
                foreach (var interval in intervals)
                {
                    area += interval.Length;
                }
            }
            return area;
        }

        // 计算重心
        public PointF CenterOfGravity()
        {
            if (_rleData.Count == 0) return PointF.Empty;

            double sumX = 0, sumY = 0;
            double totalPixels = 0;

            foreach (var kvp in _rleData)
            {
                int y = kvp.Key;
                foreach (var interval in kvp.Value)
                {
                    int length = interval.Length;
                    double centerX = (interval.Start + interval.End) / 2.0;

                    sumX += centerX * length;
                    sumY += y * length;
                    totalPixels += length;
                }
            }

            if (totalPixels == 0) return PointF.Empty;
            return new PointF((float)(sumX / totalPixels), (float)(sumY / totalPixels));
        }

        // 计算圆度
        public double Circularity()
        {
            double area = Area();
            if (area == 0) return 0;

            // 计算周长 (简化版,实际需要更精确的计算)
            double perimeter = 0;
            foreach (var kvp in _rleData)
            {
                int y = kvp.Key;
                foreach (var interval in kvp.Value)
                {
                    // 上边界
                    if (!_rleData.ContainsKey(y - 1) || !HasPixel(y - 1, interval.Start, interval.End))
                        perimeter += interval.Length;

                    // 下边界
                    if (!_rleData.ContainsKey(y + 1) || !HasPixel(y + 1, interval.Start, interval.End))
                        perimeter += interval.Length;

                    // 左边界
                    perimeter += CountLeftEdges(interval.Start, y);

                    // 右边界
                    perimeter += CountRightEdges(interval.End, y);
                }
            }

            return (4 * Math.PI * area) / (perimeter * perimeter);
        }

        private bool HasPixel(int y, int startX, int endX)
        {
            if (!_rleData.TryGetValue(y, out var intervals))
                return false;

            foreach (var interval in intervals)
            {
                if (interval.Start <= endX && interval.End >= startX)
                    return true;
            }
            return false;
        }

        private int CountLeftEdges(int x, int y)
        {
            int count = 0;
            if (!HasPixel(y, x - 1, x - 1)) count++;
            return count;
        }

        private int CountRightEdges(int x, int y)
        {
            int count = 0;
            if (!HasPixel(y, x + 1, x + 1)) count++;
            return count;
        }

        // 转换为位图
        public Bitmap ToBitmap(Bitmap bitmap, Color color ,bool clear=true)
        {
            if (_rleData.Count == 0) return new Bitmap(1, 1);

            Rectangle bb = BoundingBox;
            //Bitmap bitmap = new Bitmap(bb.Width, bb.Height);
            if (clear)
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.Clear(Color.Black);
                }
            }
 



            foreach (var kvp in _rleData)
            {
                int y = kvp.Key ;
                foreach (var interval in kvp.Value)
                {
                    for (int x = interval.Start ; x <= interval.End ; x++)
                    {
                        if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height)
                        {
                            bitmap.SetPixel(x, y,color);
                        }
                    }
                }
            }

            return bitmap;
        }

        // 形态学操作 - 膨胀
        public HRegion Dilation(int radius)
        {
            HRegion result = new HRegion();

            foreach (var kvp in _rleData)
            {
                int y = kvp.Key;
                foreach (var interval in kvp.Value)
                {
                    for (int dy = -radius; dy <= radius; dy++)
                    {
                        int newY = y + dy;
                        int dx = (int)Math.Sqrt(radius * radius - dy * dy);
                        int newStart = interval.Start - dx;
                        int newEnd = interval.End + dx;

                        if (!result._rleData.TryGetValue(newY, out var intervals))
                        {
                            intervals = new List<Interval>();
                            result._rleData[newY] = intervals;
                        }

                        // 合并重叠或相邻的区间
                        bool merged = false;
                        for (int i = 0; i < intervals.Count; i++)
                        {
                            if (newEnd + 1 >= intervals[i].Start && newStart - 1 <= intervals[i].End)
                            {
                                // 合并区间
                                int start = Math.Min(newStart, intervals[i].Start);
                                int end = Math.Max(newEnd, intervals[i].End);
                                intervals[i] = new Interval(start, end);
                                merged = true;

                                // 检查是否需要与后面的区间合并
                                while (i + 1 < intervals.Count && intervals[i].End + 1 >= intervals[i + 1].Start)
                                {
                                    intervals[i] = new Interval(intervals[i].Start, Math.Max(intervals[i].End, intervals[i + 1].End));
                                    intervals.RemoveAt(i + 1);
                                }
                                break;
                            }
                        }

                        if (!merged)
                        {
                            intervals.Add(new Interval(newStart, newEnd));
                            // 保持区间有序
                            intervals.Sort((a, b) => a.Start.CompareTo(b.Start));
                        }
                    }
                }
            }

            result._boundingBoxValid = false;
            return result;
        }

        // 腐蚀操作入口(自动选择最优策略)
        public HRegion ErosionOptimized(int radius, bool useCircle = true)
        {
            if (radius <= 0) return new HRegion();
            if (_rleData.Count == 0) return new HRegion();

            // 超大半径直接返回空(优化极端情况)
            Rectangle bb = BoundingBox;
            if (radius >= Math.Max(bb.Width, bb.Height) * 2)
                return new HRegion();

            // 分阶段腐蚀(自动分解大半径)
            HRegion result = this;
            int remainingRadius = radius;

            while (remainingRadius > 0)
            {
                int currentRadius = Math.Min(5, remainingRadius); // 单次最大半径=5
                result = useCircle ?
                    ErosionCircleSingleStep(result, currentRadius) :
                    ErosionRectSingleStep(result, currentRadius);
                remainingRadius -= currentRadius;
            }

            return result;
        }

        // 单步圆形腐蚀(并行优化)
        private HRegion ErosionCircleSingleStep(HRegion region, int radius)
        {
            var result = new ConcurrentDictionary<int, List<Interval>>();
            var offsets = PrecomputeCircleOffsets(radius); // 预计算圆形偏移量

            Parallel.ForEach(region._rleData.Keys, y =>
            {
                var erodedIntervals = new List<Interval>();
                foreach (var interval in region._rleData[y])
                {
                    int currentStart = -1;

                    for (int x = interval.Start; x <= interval.End; x++)
                    {
                        bool isValid = true;
                        foreach (var (dx, dy) in offsets)
                        {
                            int checkX = x + dx;
                            int checkY = y + dy;

                            if (!region.IsPixelCovered(checkY, checkX))
                            {
                                isValid = false;
                                break;
                            }
                        }

                        // 合并连续区间
                        if (isValid)
                        {
                            if (currentStart == -1)
                                currentStart = x;
                        }
                        else if (currentStart != -1)
                        {
                            erodedIntervals.Add(new Interval(currentStart, x - 1));
                            currentStart = -1;
                        }
                    }

                    if (currentStart != -1)
                        erodedIntervals.Add(new Interval(currentStart, interval.End));
                }

                if (erodedIntervals.Count > 0)
                    result[y] = MergeIntervals(erodedIntervals);
            });

            return new HRegion { _rleData = new Dictionary<int, List<Interval>>(result) };
        }

        // 单步矩形腐蚀(分离为水平+垂直)
        private HRegion ErosionRectSingleStep(HRegion region, int radius)
        {
            // 水平腐蚀(1x(2r+1)矩形)
            var horiEroded = ErosionRect1D(region, radius, 0);
            // 垂直腐蚀((2r+1)x1矩形)
            var vertEroded = ErosionRect1D(horiEroded, 0, radius);
            return vertEroded;
        }

        // 一维矩形腐蚀(高效实现)
        private HRegion ErosionRect1D(HRegion region, int radiusX, int radiusY)
        {
            var result = new ConcurrentDictionary<int, List<Interval>>();
            int totalRadius = radiusX + radiusY;

            Parallel.ForEach(region._rleData.Keys, y =>
            {
                var erodedIntervals = new List<Interval>();
                foreach (var interval in region._rleData[y])
                {
                    int start = interval.Start + radiusX;
                    int end = interval.End - radiusX;
                    if (start > end) continue;

                    // 检查垂直方向
                    bool isValid = true;
                    for (int dy = -radiusY; dy <= radiusY; dy++)
                    {
                        int checkY = y + dy;
                        if (!region.IsIntervalCovered(checkY, start, end))
                        {
                            isValid = false;
                            break;
                        }
                    }

                    if (isValid)
                        erodedIntervals.Add(new Interval(start, end));
                }

                if (erodedIntervals.Count > 0)
                    result[y] = MergeIntervals(erodedIntervals);
            });

            return new HRegion { _rleData = new Dictionary<int, List<Interval>>(result) };
        }

        // 预计算圆形结构元素偏移量
        private List<(int dx, int dy)> PrecomputeCircleOffsets(int radius)
        {
            var offsets = new List<(int, int)>();
            int r2 = radius * radius;

            for (int dy = -radius; dy <= radius; dy++)
                for (int dx = -radius; dx <= radius; dx++)
                    if (dx * dx + dy * dy <= r2)
                        offsets.Add((dx, dy));

            return offsets;
        }

        // 合并重叠/相邻区间
        private List<Interval> MergeIntervals(List<Interval> intervals)
        {
            if (intervals.Count == 0) return intervals;

            var merged = new List<Interval> { intervals[0] };
            for (int i = 1; i < intervals.Count; i++)
            {
                var last = merged[merged.Count - 1];
                if (intervals[i].Start <= last.End + 1)
                    merged[merged.Count - 1] = new Interval(last.Start, Math.Max(last.End, intervals[i].End));
                else
                    merged.Add(intervals[i]);
            }
            return merged;
        }

        // 形态学操作 - 腐蚀
        // 形态学操作 - 腐蚀(支持圆形和矩形结构元素)
        public HRegion Erosion(int radius, bool useCircle = true)
        {
            HRegion result = new HRegion();

            foreach (var kvp in _rleData)
            {
                int y = kvp.Key;
                foreach (var interval in kvp.Value)
                {
                    // 初始候选区间(先应用半径的简单收缩)
                    int candidateStart = interval.Start + radius;
                    int candidateEnd = interval.End - radius;

                    if (candidateStart > candidateEnd) continue;

                    // 检查候选区间内的每个点
                    List<Interval> validIntervals = new List<Interval>();
                    int currentStart = -1;
                    int currentEnd = -1;

                    for (int x = candidateStart; x <= candidateEnd; x++)
                    {
                        bool isValid = true;

                        if (useCircle)
                        {
                            // 圆形结构元素检查
                            for (int dy = -radius; dy <= radius; dy++)
                            {
                                for (int dx = -radius; dx <= radius; dx++)
                                {
                                    // 检查是否在圆形内
                                    if (dx * dx + dy * dy <= radius * radius)
                                    {
                                        int checkX = x + dx;
                                        int checkY = y + dy;

                                        if (!HasPixel(checkY, checkX, checkX))
                                        {
                                            isValid = false;
                                            break;
                                        }
                                    }
                                }
                                if (!isValid) break;
                            }
                        }
                        else
                        {
                            // 矩形结构元素检查
                            for (int dy = -radius; dy <= radius; dy++)
                            {
                                for (int dx = -radius; dx <= radius; dx++)
                                {
                                    int checkX = x + dx;
                                    int checkY = y + dy;

                                    if (!HasPixel(checkY, checkX, checkX))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                }
                                if (!isValid) break;
                            }
                        }

                        // 处理连续的有效区间
                        if (isValid)
                        {
                            if (currentStart == -1)
                            {
                                currentStart = x;
                                currentEnd = x;
                            }
                            else if (x == currentEnd + 1)
                            {
                                currentEnd = x;
                            }
                            else
                            {
                                validIntervals.Add(new Interval(currentStart, currentEnd));
                                currentStart = x;
                                currentEnd = x;
                            }
                        }
                    }

                    // 添加最后一个区间
                    if (currentStart != -1)
                    {
                        validIntervals.Add(new Interval(currentStart, currentEnd));
                    }

                    // 将有效区间添加到结果中
                    if (validIntervals.Count > 0)
                    {
                        if (!result._rleData.TryGetValue(y, out var resultIntervals))
                        {
                            resultIntervals = new List<Interval>();
                            result._rleData[y] = resultIntervals;
                        }
                        resultIntervals.AddRange(validIntervals);
                    }
                }
            }

            // 对每行的区间进行合并和排序
            foreach (var intervals in result._rleData.Values)
            {
                intervals.Sort((a, b) => a.Start.CompareTo(b.Start));

                // 合并重叠或相邻的区间
                for (int i = 0; i < intervals.Count - 1;)
                {
                    if (intervals[i].End + 1 >= intervals[i + 1].Start)
                    {
                        intervals[i] = new Interval(
                            Math.Min(intervals[i].Start, intervals[i + 1].Start),
                            Math.Max(intervals[i].End, intervals[i + 1].End));
                        intervals.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                }
            }

            result._boundingBoxValid = false;
            return result;
        }
        /// <summary>
        /// 检查指定像素 (x,y) 是否被当前区域覆盖
        /// </summary>
        /// <param name="y">行坐标</param>
        /// <param name="x">列坐标</param>
        /// <returns>true如果像素在区域内</returns>
        public bool IsPixelCovered(int y, int x)
        {
            // 1. 检查该行是否存在数据
            if (!_rleData.TryGetValue(y, out var intervals))
                return false;

            // 2. 二分查找优化:快速定位x可能所在的区间
            int left = 0;
            int right = intervals.Count - 1;

            while (left <= right)
            {
                int mid = (left + right) / 2;
                var interval = intervals[mid];

                if (x < interval.Start)
                {
                    right = mid - 1;
                }
                else if (x > interval.End)
                {
                    left = mid + 1;
                }
                else
                {
                    return true; // x在区间[Start, End]内
                }
            }

            return false;
        }

        /// <summary>
        /// 检查指定行y上的区间[start, end]是否完全被覆盖
        /// </summary>
        public bool IsIntervalCovered(int y, int start, int end)
        {
            if (!_rleData.TryGetValue(y, out var intervals))
                return false;

            // 遍历所有区间,检查是否有一个区间完全包含[start, end]
            foreach (var interval in intervals)
            {
                if (interval.Start <= start && interval.End >= end)
                    return true;

                // 区间已排序,如果当前区间.Start > end,后续不可能有覆盖
                if (interval.Start > end)
                    break;
            }

            return false;
        }

        // 开运算 = 先腐蚀后膨胀
        public HRegion Opening(int radius)
        {
            return Erosion(radius).Dilation(radius);
        }

        // 闭运算 = 先膨胀后腐蚀
        public HRegion Closing(int radius)
        {
            return Dilation(radius).Erosion(radius);
        }

        // 连通域分析
        public static List<HRegion> Connection(HRegion region)
        {
            List<HRegion> connectedRegions = new List<HRegion>();
            if (region._rleData.Count == 0) return connectedRegions;

            // 使用并查集算法标记连通区域
            Dictionary<Point, int> labels = new Dictionary<Point, int>();
            int currentLabel = 1;
            UnionFind uf = new UnionFind();

            // 第一遍扫描: 分配临时标签
            foreach (var kvp in region._rleData)
            {
                int y = kvp.Key;
                foreach (var interval in kvp.Value)
                {
                    for (int x = interval.Start; x <= interval.End; x++)
                    {
                        Point p = new Point(x, y);

                        // 检查相邻像素的标签
                        List<int> neighborLabels = new List<int>();

                        // 左邻
                        if (labels.TryGetValue(new Point(x - 1, y), out int leftLabel))
                            neighborLabels.Add(leftLabel);

                        // 上邻
                        if (labels.TryGetValue(new Point(x, y - 1), out int topLabel))
                            neighborLabels.Add(topLabel);

                        if (neighborLabels.Count == 0)
                        {
                            // 新标签
                            int newLabel = currentLabel++;
                            labels[p] = newLabel;
                            uf.MakeSet(newLabel);
                        }
                        else
                        {
                            // 使用最小的邻居标签
                            int minLabel = neighborLabels.Min();
                            labels[p] = minLabel;

                            // 合并等价类
                            foreach (var label in neighborLabels)
                            {
                                if (label != minLabel)
                                    uf.Union(minLabel, label);
                            }
                        }
                    }
                }
            }

            // 第二遍扫描: 分配最终标签并收集区域
            Dictionary<int, HRegion> labelToRegion = new Dictionary<int, HRegion>();

            foreach (var kvp in labels)
            {
                Point p = kvp.Key;
                int label = uf.Find(kvp.Value);

                if (!labelToRegion.TryGetValue(label, out HRegion connectedRegion))
                {
                    connectedRegion = new HRegion();
                    labelToRegion[label] = connectedRegion;
                }

                if (!connectedRegion._rleData.TryGetValue(p.Y, out var intervals))
                {
                    intervals = new List<Interval>();
                    connectedRegion._rleData[p.Y] = intervals;
                }

                // 尝试合并相邻的像素
                bool merged = false;
                for (int i = 0; i < intervals.Count; i++)
                {
                    if (intervals[i].End + 1 == p.X)
                    {
                        intervals[i] = new Interval(intervals[i].Start, p.X);
                        merged = true;
                        break;
                    }
                    else if (intervals[i].Start - 1 == p.X)
                    {
                        intervals[i] = new Interval(p.X, intervals[i].End);
                        merged = true;
                        break;
                    }
                }

                if (!merged)
                {
                    intervals.Add(new Interval(p.X, p.X));
                    // 保持区间有序
                    intervals.Sort((a, b) => a.Start.CompareTo(b.Start));
                }
            }

            // 更新每个连通区域的边界框
            foreach (var r in labelToRegion.Values)
            {
                r.UpdateBoundingBox();
                connectedRegions.Add(r);
            }

            return connectedRegions;
        }

        // 并查集数据结构用于连通域分析
        private class UnionFind
        {
            private Dictionary<int, int> parent = new Dictionary<int, int>();
            private Dictionary<int, int> rank = new Dictionary<int, int>();

            public void MakeSet(int x)
            {
                parent[x] = x;
                rank[x] = 0;
            }

            public int Find(int x)
            {
                if (parent[x] != x)
                    parent[x] = Find(parent[x]);
                return parent[x];
            }

            public void Union(int x, int y)
            {
                int xRoot = Find(x);
                int yRoot = Find(y);

                if (xRoot == yRoot) return;

                if (rank[xRoot] < rank[yRoot])
                    parent[xRoot] = yRoot;
                else if (rank[xRoot] > rank[yRoot])
                    parent[yRoot] = xRoot;
                else
                {
                    parent[yRoot] = xRoot;
                    rank[xRoot]++;
                }
            }
        }
    }
}

测试代码

运行速度在300ms左右,有点儿慢

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
using Image = System.Drawing.Image;
using System.Diagnostics; // 添加Stopwatch命名空间

namespace view3d
{
    public partial class MainForm : Form
    {
        HRegion region = new HRegion();
        Bitmap image;
        public MainForm()
        {
            InitializeComponent();
        }

        private void load_Click(object sender, EventArgs e)
        {
            var stopwatch = Stopwatch.StartNew(); // 开始计时

            // 创建打开文件对话框
            OpenFileDialog openFileDialog = new OpenFileDialog();

            // 设置文件过滤器(只显示图片文件)
            openFileDialog.Filter = "Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif";

            // 设置对话框标题
            openFileDialog.Title = "选择要加载的图片";

            // 显示对话框并检查用户是否点击了确定
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    Image loadedImage = Image.FromFile(openFileDialog.FileName);
                    // 从文件路径创建Image对象
                    image = new Bitmap(loadedImage);


                    string v1 = textBox1.Text;
                    string v2 = textBox2.Text;
                    byte i1 = byte.Parse(v1);
                    byte i2 = byte.Parse(v2);
                    region.FromBitmap((Bitmap)image, i1, i2);
                    // 将图片显示到pictureBox1
                    pictureBox1.Image = region.ToBitmap((Bitmap)image, Color.White);

                    // 设置PictureBox的SizeMode为Zoom,使图片适应控件大小
                    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;

                    stopwatch.Stop(); // 停止计时
                    MessageBox.Show($"图片加载和处理耗时: {stopwatch.ElapsedMilliseconds} 毫秒", "耗时统计");
                }
                catch (Exception ex)
                {
                    // 如果加载失败,显示错误信息
                    MessageBox.Show("加载图片时出错: " + ex.Message, "错误",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {

        }

        private void connection_Click(object sender, EventArgs e)
        {
            var stopwatch = Stopwatch.StartNew(); // 开始计时

            List<HRegion> conns = HRegion.Connection(region);

            using (Graphics g = Graphics.FromImage(image))
            {
                g.Clear(Color.Black);
            }

            // 预定义一组颜色,或者随机生成颜色
            Color[] colors = new Color[]
            {
                Color.Red,
                Color.Green,
                Color.Blue,
                Color.Yellow,
                Color.Magenta,
                Color.Cyan,
                Color.Orange,
                Color.Purple,
                Color.Lime,
                Color.Pink
            };

            for (int i = 0; i < conns.Count; i++)
            {
                HRegion region = conns[i];
                if (region != null)
                {
                    // 使用循环索引选择颜色,如果超过预定义颜色数量则随机生成
                    Color regionColor = i < colors.Length ? colors[i] : GetRandomColor();

                    region.ToBitmap(image, regionColor, false);
                }
            }

            stopwatch.Stop(); // 停止计时
            MessageBox.Show($"连通域分析耗时: {stopwatch.ElapsedMilliseconds} 毫秒", "耗时统计");

            // 刷新显示
            pictureBox1.Invalidate();
        }

        // 辅助方法:生成随机颜色
        private Color GetRandomColor()
        {
            Random rand = new Random();
            return Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256));
        }

        private void Dilation_Click(object sender, EventArgs e)
        {
            var stopwatch = Stopwatch.StartNew(); // 开始计时

            string v1 = textBox1.Text;
            string v2 = textBox2.Text;
            byte i1 = byte.Parse(v1);
            byte i2 = byte.Parse(v2);
            region = region.Dilation(i2);
            region.ToBitmap(image, Color.Yellow);

            stopwatch.Stop(); // 停止计时
            MessageBox.Show($"膨胀操作耗时: {stopwatch.ElapsedMilliseconds} 毫秒", "耗时统计");

            // 刷新显示
            pictureBox1.Invalidate();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            var stopwatch = Stopwatch.StartNew(); // 开始计时

            string v1 = textBox1.Text;
            string v2 = textBox2.Text;
            byte i1 = byte.Parse(v1);
            byte i2 = byte.Parse(v2);
            region = region.ErosionOptimized(i2);
            region.ToBitmap(image, Color.Green);

            stopwatch.Stop(); // 停止计时
            MessageBox.Show($"腐蚀操作耗时: {stopwatch.ElapsedMilliseconds} 毫秒", "耗时统计");

            // 刷新显示
            pictureBox1.Invalidate();
        }
    }
}

测试demo下载

见资源标定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值