如何实现仅在旋转雷达扇形覆盖时将差异像素标为黄色?
实现多普勒雷达扫过式差异像素标记(C# WinForms)
要实现雷达扇形扫过才标记差异像素的效果,核心思路是先预存所有差异像素的坐标,再在雷达旋转的每一帧中,仅标记当前扇形覆盖范围内的差异像素,具体修改步骤如下:
1. 预存差异像素坐标,避免一次性标记
修改CalcDifference方法,不再直接给像素上色,而是把差异像素的坐标存入集合,后续按需处理:
// 全局集合,存储所有差异像素的坐标 private List<Point> _differencePixels = new List<Point>(); private void CalcDifference(Bitmap prevFrame, Bitmap currFrame) { _differencePixels.Clear(); // 遍历所有像素,筛选差异点 for (int y = 0; y < prevFrame.Height; y++) { for (int x = 0; x < prevFrame.Width; x++) { Color prevColor = prevFrame.GetPixel(x, y); Color currColor = currFrame.GetPixel(x, y); // 自定义差异判断阈值,可根据实际需求调整 bool hasDifference = Math.Abs(prevColor.R - currColor.R) > 30 || Math.Abs(prevColor.G - currColor.G) > 30 || Math.Abs(prevColor.B - currColor.B) > 30; if (hasDifference) { _differencePixels.Add(new Point(x, y)); } } } }
2. 实现雷达扇形的角度判断逻辑
添加跟踪雷达旋转状态的字段,以及判断像素是否在当前扇形内的方法:
// 雷达中心(取PictureBox控件中心) private Point _radarCenter; // 当前扇形的起始角度(弧度,0为正右方向,顺时针递增) private double _currentStartAngle; // 扇形的角度宽度(示例为60度,转成弧度) private double _sectorWidth = Math.PI / 3; // 在Form_Load或构造函数中初始化中心坐标 private void Form1_Load(object sender, EventArgs e) { _radarCenter = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2); } // 判断指定像素是否在当前雷达扇形范围内 private bool IsPixelInSector(Point pixel) { // 计算像素相对于雷达中心的向量角度 double dx = pixel.X - _radarCenter.X; double dy = pixel.Y - _radarCenter.Y; double pixelAngle = Math.Atan2(dy, dx); // 将角度转换为[0, 2π]范围 if (pixelAngle < 0) pixelAngle += 2 * Math.PI; // 计算扇形结束角度,处理跨360度的情况 double sectorEndAngle = _currentStartAngle + _sectorWidth; if (sectorEndAngle > 2 * Math.PI) sectorEndAngle -= 2 * Math.PI; // 判断角度是否在扇形区间内 if (_currentStartAngle <= sectorEndAngle) { return pixelAngle >= _currentStartAngle && pixelAngle <= sectorEndAngle; } else { // 扇形跨过0度(360度)的特殊情况 return pixelAngle >= _currentStartAngle || pixelAngle <= sectorEndAngle; } }
3. 动态更新雷达角度,按需标记差异像素
用定时器控制雷达旋转,在重绘时仅标记当前扇形内的差异像素:
// 控制雷达旋转的定时器 private Timer _radarRotateTimer; // 在构造函数或Form_Load中初始化定时器 private void Form1_Load(object sender, EventArgs e) { _radarRotateTimer = new Timer(); _radarRotateTimer.Interval = 50; // 每50ms刷新一次,控制旋转速度 _radarRotateTimer.Tick += RadarRotateTimer_Tick; _radarRotateTimer.Start(); // 初始化雷达中心 _radarCenter = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2); } // 定时器事件:更新雷达角度并触发重绘 private void RadarRotateTimer_Tick(object sender, EventArgs e) { // 每次增加0.05弧度(约2.86度),控制旋转速度 _currentStartAngle += 0.05; if (_currentStartAngle >= 2 * Math.PI) _currentStartAngle -= 2 * Math.PI; // 触发PictureBox重绘 pictureBox1.Invalidate(); } // PictureBox的Paint事件:绘制雷达扇形+标记差异像素 private void PictureBox1_Paint(object sender, PaintEventArgs e) { // 先绘制当前雷达背景帧(替换成你的实际帧对象) e.Graphics.DrawImage(currFrame, 0, 0); // 绘制半透明的雷达扇形 using (Brush sectorBrush = new SolidBrush(Color.FromArgb(100, Color.DodgerBlue))) { e.Graphics.FillPie(sectorBrush, _radarCenter.X - pictureBox1.Width / 2, _radarCenter.Y - pictureBox1.Height / 2, pictureBox1.Width, pictureBox1.Height, (float)(_currentStartAngle * 180 / Math.PI), // 转成角度 (float)(_sectorWidth * 180 / Math.PI)); } // 仅标记当前扇形内的差异像素为黄色 foreach (Point pixel in _differencePixels) { if (IsPixelInSector(pixel)) { e.Graphics.FillRectangle(Brushes.Yellow, pixel.X, pixel.Y, 1, 1); } } }
4. 调整差异计算的触发时机
删掉构造函数中对CalcDifference的调用,改成在新帧到来时触发(比如你获取雷达新帧的定时器事件中):
// 示例:获取新雷达帧的定时器 private void FrameUpdateTimer_Tick(object sender, EventArgs e) { Bitmap prevFrame = currFrame; currFrame = GetNewRadarFrame(); // 替换成你获取新帧的实际方法 if (prevFrame != null) { CalcDifference(prevFrame, currFrame); } }
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

