winforms 如何绘制黄色的差异像素,只有当饼是旋转以上的像素?

pvcm50d1  于 2022-12-23  发布在  其他
关注(0)|答案(1)|浏览(111)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Doppler_Radar
{
    public partial class Form1 : Form
    {
        int myPiePercent = 15;
        float distanceFromCenterPixels;
        float distanceFromCenterKm = 200F;

        public Form1()
        {
            InitializeComponent();

            pictureBox1.Image = Image.FromFile(@"D:\New folder (4)\Weather Radar\WithClouds.bmp");
            timer1.Enabled = true;
            distanceFromCenterPixels = (float)(183d * (double)distanceFromCenterKm / 200d);
            
            pictureBox1.Image = CalcDifference(new Bitmap(pictureBox1.Image),
                new Bitmap(@"D:\New folder (4)\Weather Radar\WithoutClouds.bmp"));
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            DrawPieOnPicturebox(e.Graphics);
        }

        public void DrawPieOnPicturebox(Graphics myPieGraphic)
        {
            Color myPieColors = Color.FromArgb(150, Color.LightGreen);
            Size myPieSize = new Size((int)distanceFromCenterPixels, (int)distanceFromCenterPixels);
            Point myPieLocation = new Point((pictureBox1.Width - myPieSize.Width) / 2, (pictureBox1.Height - myPieSize.Height) / 2);
            DrawMyPie(myPiePercent, myPieColors, myPieGraphic, myPieLocation, myPieSize);
        }

        public void DrawMyPie(int myPiePerecent, Color myPieColor, Graphics myPieGraphic, Point
      myPieLocation, Size myPieSize)
        {
            using (SolidBrush brush = new SolidBrush(myPieColor))
            {
                myPieGraphic.FillPie(brush, new Rectangle(myPieLocation, myPieSize), Convert.ToSingle(myPiePerecent * 360 / 100), Convert.ToSingle(15 * 360 / 100));
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            myPiePercent++;
            pictureBox1.Invalidate();
        }

        public Bitmap CalcDifference(Bitmap bmp1, Bitmap bmp2)
        {
            Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height);
            BitmapData bitmapdata = bmp1.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            IntPtr source = bitmapdata.Scan0;
            BitmapData data2 = bmp2.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            IntPtr ptr2 = data2.Scan0;
            int length = (bmp1.Width * bmp1.Height) * 4;
            byte[] destination = new byte[length];
            byte[] buffer2 = new byte[length];
            Marshal.Copy(source, destination, 0, length);
            Marshal.Copy(ptr2, buffer2, 0, length);
            for (int i = 0; i < length; i += 4)
            {
                if (((destination[i] == buffer2[i]) && (destination[i + 1] == buffer2[i + 1])) && (destination[i + 2] == buffer2[i + 2]))
                {
                    destination[i] = 0xff;
                    destination[i + 1] = 0xff;
                    destination[i + 2] = 0xff;
                    destination[i + 3] = 0;
                }
                else
                {
                        destination[i] = 0;
                        destination[i + 1] = 255;
                        destination[i + 2] = 255;
                }
            }
            Marshal.Copy(destination, 0, source, length);
            bmp1.UnlockBits(bitmapdata);
            bmp2.UnlockBits(data2);

            return bmp1;
        }
    }
}

因为我在构造函数中调用了CalcDifference方法,所以始终将差分像素着色为黄色。但我想要的是,只有当旋转饼位于差分像素之上/之上时,才对饼之下的差分像素着色,而不是对所有差分像素着色。
左侧是使用CalcDifference方法对差分像素进行着色时。右侧是原始图像。
目标是产生多普勒雷达效应,当饼在云上方旋转时探测云。

kyxcudwk

kyxcudwk1#

是的,你可以使用一个小技巧来改变馅饼下面的云的颜色,跳过其他的。

  • 要优化CalcDifference方法并加快速度,只需从每个图像中获取要处理的饼图区域,图像的其余部分不变,也不需要遍历该区域的数据。
  • 将剪切后的图像传递给CalcDifference方法,并更改该区域中云的颜色。注意,如果需要的话,我已经更改了将原始图像转换为32bppArgb图像的方法,以便您可以传递LockBits支持的不同格式的图像进行处理。
  • 将带有云的全尺寸图像分配给PictureBox.Image属性。
  • 这里的技巧。处理PictureBox.Paint事件并创建一个GraphicsPath对象,添加饼并将其传递给Graphics.SetClip方法。绘制黄色云彩图像,然后重置剪辑(Graphics.ResetClip)绘制饼。
public partial class SomeForm : Form
{
    private float startAngle;
    private readonly SolidBrush brPie;
    private Rectangle pieRect;
    private Bitmap imgWithYellowClouds;

    public SomeForm()
    {
        InitializeComponent();

        brPie = new SolidBrush(Color.FromArgb(150, Color.LightGreen));
        picWithoutClouds.Image = Image.FromFile(@"...");
        picWithClouds.Image = picCanvas.Image = Image.FromFile(@"...");

        CreateYellowCloudsImage();
    }

    protected override void OnFormClosed(FormClosedEventArgs e)
    {
        base.OnFormClosed(e);
        brPie.Dispose();
        imgWithYellowClouds?.Dispose();
    }

    private void picCanvas_Resize(object sender, EventArgs e) =>
        CreateYellowCloudsImage();

    private void picCanvas_Paint(object sender, PaintEventArgs e)
    {
        if (pieRect.Width < 1 || pieRect.Height < 1 || 
            imgWithYellowClouds == null) return;
        var g = e.Graphics;

        using (var gp = new GraphicsPath())
        {
            gp.AddPie(pieRect, startAngle, 360f / 8);
            g.SetClip(gp);
            g.DrawImage(imgWithYellowClouds, pieRect);
            g.ResetClip();
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillPath(brPie, gp);
        }
    }

    private void SomeButton(object sender, EventArgs e)
    {
        timer1.Enabled = !timer1.Enabled;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        // Change as needed...
        startAngle = (startAngle + 10) % 360;
        picCanvas.Invalidate();
    }

    public Bitmap CalcDifference(Bitmap bmp1, Bitmap bmp2)
    {
        var disImg1 = !Is32bppArgbFormat(bmp1);
        var disImg2 = !Is32bppArgbFormat(bmp2);
        var img1 = disImg1 ? To32bppArgbFormat(bmp1) : new Bitmap(bmp1);
        var img2 = disImg2 ? To32bppArgbFormat(bmp2) : bmp2;
        var img1Data = img1.LockBits(
            new Rectangle(Point.Empty, img1.Size),
            ImageLockMode.ReadOnly,
            PixelFormat.Format32bppArgb);
        var img2Data = img2.LockBits(
            new Rectangle(Point.Empty, img2.Size),
            ImageLockMode.ReadOnly,
            PixelFormat.Format32bppArgb);
        var img1Buffer = new byte[img1Data.Stride * img1Data.Height];
        var img2Buffer = new byte[img2Data.Stride * img2Data.Height];

        Marshal.Copy(img1Data.Scan0, img1Buffer, 0, img1Buffer.Length);
        Marshal.Copy(img2Data.Scan0, img2Buffer, 0, img2Buffer.Length);
        img2.UnlockBits(img2Data);

        for (int i = 0; i + 4 < img1Buffer.Length; i += 4)
        {
            if (img1Buffer[i] == img2Buffer[i] &&
                img1Buffer[i + 1] == img2Buffer[i + 1] &&
                img1Buffer[i + 2] == img2Buffer[i + 2])
            {
                img1Buffer[i] = 0;
                img1Buffer[i + 1] = 0;
                img1Buffer[i + 2] = 0;
                img1Buffer[i + 3] = 0;
            }
            else
            {
                img1Buffer[i] = 0;
                img1Buffer[i + 1] = 255;
                img1Buffer[i + 2] = 255;
            }
        }

        Marshal.Copy(img1Buffer, 0, img1Data.Scan0, img1Buffer.Length);
        img1.UnlockBits(img1Data);

        if (disImg2) img2.Dispose();

        return img1;
    }

    private bool Is32bppArgbFormat(Bitmap bmp) =>
        Image.GetPixelFormatSize(bmp.PixelFormat) == 32 && 
        bmp.PixelFormat != PixelFormat.Indexed;

    private Bitmap To32bppArgbFormat(Bitmap src)
    {
        var bmp = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);

        using (var g = Graphics.FromImage(bmp))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.DrawImage(src, new Rectangle(0, 0, bmp.Width, bmp.Height),
                0, 0, src.Width, src.Height, GraphicsUnit.Pixel);

            return bmp;
        }
    }

    private void CreateYellowCloudsImage()
    {
        var cs = picCanvas.ClientSize;

        // Change as needed...
        var sz = new Size(128, 128);

        pieRect = new Rectangle(
            (cs.Width - sz.Width) / 2, 
            (cs.Height - sz.Height) / 2, 
            sz.Width, sz.Height);

        // To get the image rectangle regardless of the SizeMode property
        // so we can get the pie's region to process...
        var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
                BindingFlags.NonPublic | BindingFlags.Instance);
        var imageRect = (Rectangle)method.Invoke(picCanvas,
            new object[] { picCanvas.SizeMode });
        var cx = picCanvas.Image.Width / (float)imageRect.Width;
        var cy = picCanvas.Image.Height / (float)imageRect.Height;
        var r2 = RectangleF.Intersect(imageRect, pieRect);
        r2.Offset(-imageRect.X, -imageRect.Y);
        var cloneRect = new RectangleF(
            r2.X * cx, 
            r2.Y * cy, 
            r2.Width * cx, 
            r2.Height * cy);

        imgWithYellowClouds?.Dispose();
        imgWithYellowClouds = null;

        using (var cloulds = (picWithClouds.Image as Bitmap)
            .Clone(cloneRect, picWithClouds.Image.PixelFormat))
        using (var noClouds = (picWithoutClouds.Image as Bitmap)
            .Clone(cloneRect, picWithoutClouds.Image.PixelFormat))
        {
            // The yellow clouds image...
            imgWithYellowClouds = CalcDifference(cloulds, noClouds);
        }
    }
}

摘自您之前针对本演示提出的问题。

相关问题