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;
}
}
}
this color in the yellow the diffrenet pixels all the time because i'm calling the method CalcDifference in the constructor. but what i want is that only when the rotating pie is over/above this diffrenet pixels then color this diffrenet pixels that are under the pie and not all the diffrenet pixels.
on the left side is when coloring the diffrenet pixels with the method CalcDifference. on the right side the image at it's original.
the goal is to make a doppler radar effect that detect the clouds when the pie is rotating abvoe them.
CodePudding user response:
Yes, you can use a little trick to change the colors of the clouds under the pie and skip the others.
- To optimize your
CalcDifference
method and speed things up, get from each image only the pie region to process. The rest of the image does not change and you don't need to traverse the data of that region. - Pass the clipped images to the
CalcDifference
method and change the colors of the clouds in that region. All of them. Note, I have changed the method to convert the original images to32bppArgb
images if needed so you can pass images of different formats that theLockBits
supports to process. - Assign the full-size image with clouds to the
.Image
property of thePictureBox
. - Here's the trick. Handle the
PictureBox.Paint
event and create aGraphicsPath
object, add the pie and pass it toGraphics.SetClip
method. Draw the yellow clouds image then reset the clip (Graphics.ResetClip
) to draw the pie.
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);
}
}
}
Taken from your previous questions for this demo.