rotating an image modifies the resolution and clarity - c#

Consider the code below to rotate an image.
The problem is the resolution of the image is getting low and the image is getting unclear.
How can I avoid this problem?
private Bitmap rotateImage(Bitmap b, float angle)
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);
//move rotation point to center of image
g.TranslateTransform((float)this.Width / 2, (float)this.Height / 2);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
//rotate
g.RotateTransform(angle);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.TranslateTransform(-(float)this.Width / 2, -(float)this.Height / 2);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
//draw passed in image onto graphics object
g.DrawImage(b, new Point(0, 0));
g.Dispose();
return returnBitmap;
}

Repeated rotations will cause quality to drop as the repeated interpolations take their toll on the image. The best way to avoid this is to only rotate the source image once. If you're building a system in which an image gets rotated multiple times simply rotate the source image by the total rotation amount instead of applying small delta rotations to an already rotated image each time.

I have a method that I use to do rotation and it works without reducing quality of image dramatically (that I have seen).
public static Bitmap RotateImage(Image image, float angle)
{
if(image == null)
throw new ArgumentNullException("image");
const double pi2 = Math.PI / 2.0;
double oldWidth = (double) image.Width;
double oldHeight = (double) image.Height;
// Convert degrees to radians
double theta = ((double) angle) * Math.PI / 180.0;
double locked_theta = theta;
// Ensure theta is now [0, 2pi)
while( locked_theta < 0.0 )
locked_theta += 2 * Math.PI;
double newWidth, newHeight;
int nWidth, nHeight; // The newWidth/newHeight expressed as ints
double adjacentTop, oppositeTop;
double adjacentBottom, oppositeBottom;
if( (locked_theta >= 0.0 && locked_theta < pi2) ||
(locked_theta >= Math.PI && locked_theta < (Math.PI + pi2) ) )
{
adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
}
else
{
adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
}
newWidth = adjacentTop + oppositeBottom;
newHeight = adjacentBottom + oppositeTop;
nWidth = (int) Math.Ceiling(newWidth);
nHeight = (int) Math.Ceiling(newHeight);
Bitmap rotatedBmp = new Bitmap(nWidth, nHeight);
using(Graphics g = Graphics.FromImage(rotatedBmp))
{
Point [] points;
if( locked_theta >= 0.0 && locked_theta < pi2 )
{
points = new Point[] {
new Point( (int) oppositeBottom, 0 ),
new Point( nWidth, (int) oppositeTop ),
new Point( 0, (int) adjacentBottom )
};
}
else if( locked_theta >= pi2 && locked_theta < Math.PI )
{
points = new Point[] {
new Point( nWidth, (int) oppositeTop ),
new Point( (int) adjacentTop, nHeight ),
new Point( (int) oppositeBottom, 0 )
};
}
else if( locked_theta >= Math.PI && locked_theta < (Math.PI + pi2) )
{
points = new Point[] {
new Point( (int) adjacentTop, nHeight ),
new Point( 0, (int) adjacentBottom ),
new Point( nWidth, (int) oppositeTop )
};
}
else
{
points = new Point[] {
new Point( 0, (int) adjacentBottom ),
new Point( (int) oppositeBottom, 0 ),
new Point( (int) adjacentTop, nHeight )
};
}
g.DrawImage(image, points);
}
return rotatedBmp;
}

sample code with RotateFlip:
Bitmap bitmap1;
private void InitializeBitmap()
{
try
{
bitmap1 = (Bitmap)Bitmap.FromFile(#"C:\test.bmp");
PictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
PictureBox1.Image = bitmap1;
}
catch(System.IO.FileNotFoundException)
{
MessageBox.Show("There was an error." +
"Check the path to the bitmap.");
}
}
private void Button1_Click(System.Object sender, System.EventArgs e)
{
if (bitmap1 != null)
{
bitmap1.RotateFlip(RotateFlipType.Rotate180FlipNone);
PictureBox1.Image = bitmap1;
}
}
Specifies how much an image is rotated and the axis used to flip the image.
http://msdn.microsoft.com/en-us/library/system.drawing.rotatefliptype.aspx

Related

Pad or Crop Image to achieve square size in C#

I have Bitmap Images that are usually smaller than 500x500 pixels.
But sometimes one or both dimensions can exceed 500 pixels.
If the height is >500 I want to crop the image at the bottom and if the width is >500 I want to crop it on both sides equally.
If the Image is <500 in any dimension I want to pad it with white pixels on each side equally to make it 500x500.
I'm not familliar with .NET but I understand there's a lot that'S already been done for you (I'm a C++ developer).
I appreciate any help! Thanks!
This is what I have so far, which puts the image in the center of a white 500x500 rectangular image. It's just that I cant wrap my head around the cases where one dimension of the original image exceeds 500 pixels. (See the two lines with ??)
public static System.Drawing.Bitmap PadImage(System.Drawing.Bitmap originalImage)
{
if (originalImage.Height > 500)
??
if (originalImage.Width > 500)
??
Size squareSize = new Size(500, 500);
System.Drawing.Bitmap squareImage = new System.Drawing.Bitmap(squareSize.Width, squareSize.Height);
using (Graphics graphics = Graphics.FromImage(squareImage))
{
graphics.FillRectangle(System.Drawing.Brushes.White, 0, 0, squareSize.Width, squareSize.Height);
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.DrawImage(originalImage, (squareSize.Width / 2) - (originalImage.Width / 2), (squareSize.Height / 2) - (originalImage.Height / 2), originalImage.Width, originalImage.Height);
}
return squareImage;
}
Bitmap PadCropImage(Bitmap original)
{
if (original.Width == 500 && original.Height == 500)
return original;
if (original.Width > 500 && original.Height > 500)
{
int x = (original.Width - 500) / 2;
int y = (original.Height - 500) / 2;
return original.Clone(new Rectangle(x, y, 500, 500), original.PixelFormat);
}
Bitmap square = new Bitmap(500, 500);
var g = Graphics.FromImage(square);
if (original.Width > 500)
{
int x = (original.Width - 500) / 2;
int y = (500 - original.Height) / 2;
g.DrawImageUnscaled(original, -x, y);
}
else if (original.Height > 500)
{
int x = (500 - original.Width) / 2;
int y = (original.Height - 500) / 2;
g.DrawImageUnscaled(original, x, -y);
}
else
{
int x = (500 - original.Width) / 2;
int y = (500 - original.Height) / 2;
g.DrawImageUnscaled(original, x, y);
}
return square;
}
Here is an old method I have used many times
public static Image ThumbnailImage(Image sourceImage, int imageSize, bool maintainAspectRatio, bool maintainImageSize, Color backgroundColor)
{
try
{
int thumbnailWidth = imageSize;
int thumbnailHeight = imageSize;
if (maintainAspectRatio)
{
float aspectRatio = (float) sourceImage.Width/sourceImage.Height;
float targetAspectRatio = (float) thumbnailWidth/thumbnailHeight;
if (aspectRatio < targetAspectRatio)
{
thumbnailWidth = (int) (thumbnailHeight*aspectRatio);
}
else if (aspectRatio > targetAspectRatio)
{
thumbnailHeight = (int) (thumbnailWidth/aspectRatio);
}
}
Image thumbnail = sourceImage.GetThumbnailImage(thumbnailWidth, thumbnailHeight, null, new IntPtr());
if (maintainImageSize)
{
var offset = new Point(0, 0);
if (thumbnailWidth != imageSize)
{
offset.X = ((imageSize - thumbnailWidth)/2);
}
if (thumbnailHeight != imageSize)
{
offset.Y = ((imageSize - thumbnailHeight)/2);
}
var bmpImage = new Bitmap(imageSize, imageSize, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmpImage))
{
graphics.Clear(backgroundColor);
graphics.DrawImage(thumbnail, new Rectangle(offset.X, offset.Y, thumbnailWidth, thumbnailHeight), new Rectangle(0, 0, thumbnailWidth, thumbnailHeight), GraphicsUnit.Pixel);
}
thumbnail.Dispose();
return Image.FromHbitmap(bmpImage.GetHbitmap());
}
return thumbnail;
}
catch (Exception exception)
{
const string strExMsg = "Error Creating Thumbnail";
throw new Exception(Assembly.GetExecutingAssembly().GetName().Name + " - " + strExMsg + " Msg : " + exception.Message);
}
}

How can I keep detecting clouds(points) but making the image background to be black?

The class is a bit long and working.
The cone is rotating 360 degrees and any clouds inside the cone area are painting in yellow.
But what I want to do now is that the background image will be in black and only when the cone is rotating over a cloud/s then light them in yellow only when the cone is passing over them one he moved on close the detected clouds. I mean like display the detected clouds only when the cone is passing over them.
What I'm getting today is the original image and when the cone is moving over clouds it's making them yellow:
This screenshot showing what happen when the cone is over clouds.
And this screenshot showing when the cone is not over any clouds:
Now what I want to do is instead displaying the original image in the class I called the variable: bmpWithClouds
I need the bmpWithClouds to scan the clouds but after it I want to use empty black image 512,512 resolution and to make that only when the cone is passing over a cloud/s then show them in yellow.
Then later I want to add my own points(pixels = clouds) make them move random in the black image and when the cone will pass over them to show them.
This is how I'm using the DopplerRadar class in form1 constructor:
DopplerRadar dr = new DopplerRadar();
dr.pb1 = pictureBox1;
dr.Init();
And this is the DopplerRadar class a bit long:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;
using System.Drawing;
using System.Diagnostics;
namespace mws
{
class DopplerRadar
{
[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, int count);
private System.Windows.Forms.Timer timer1;
private Stream mymem;
private Bitmap ConvertedBmp;
private Device D3Ddev = null;
private PresentParameters D3Dpp = null;
private DisplayMode DispMode;
private Sprite D3Dsprite = null;
private Texture backTexture = null;
private Texture scannedCloudsTexture = null;
private byte[] argbValuesOfTransparentTexture;
private float distanceFromCenterPixels;
private float distanceFromCenterKm = 200F;
private List<Point> detectedPoints;
private float[] angleArray, distanceArray;
private double angleCalculation, distance;
private Bitmap bmpnew = new Bitmap(512, 512);
private int bytes = 2048 * 512;
public System.Windows.Forms.PictureBox pb1;
public void Init()
{
timer1 = new System.Windows.Forms.Timer();
timer1.Interval = 10;
timer1.Enabled = false;
timer1.Tick += Timer1_Tick;
ConvertedBmp = ConvertTo24(#"c:\temp\anim3.gif");
mymem = ToStream(ConvertedBmp, ImageFormat.Bmp);
distanceFromCenterPixels = (float)(/*183d*/ ((double)200 / 1.09289617486) * (double)distanceFromCenterKm / 200d);
argbValuesOfTransparentTexture = new byte[bytes];
InitializeDirectX(pb1);
FindPoints();
//initialize angleArray
angleArray = new float[detectedPoints.Count];
distanceArray = new float[detectedPoints.Count];
for (int i = 0; i < detectedPoints.Count; i++)
{
CalculateAngleAndDistance(detectedPoints[i].X, detectedPoints[i].Y, out angleCalculation, out distance);
angleArray[i] = (float)angleCalculation;
distanceArray[i] = (float)distance;
}
timer1.Enabled = true;
}
static float angleF_ = 0.0F;
private void Timer1_Tick(object sender, EventArgs e)
{
if (angleF_ > 360F)
{
angleF_ -= 360F;
}
ReturnTexture(scannedCloudsTexture, detectedPoints, angleArray, angleF_, bmpnew);
DisplayOnScreen(angleF_);
// To change direction to change += to -=
// To change speed to raise the value 1.0d
angleF_ += 1.0F;
}
private Bitmap ConvertTo24(string inputFileName)
{
Stopwatch sw = new Stopwatch();
sw = Stopwatch.StartNew();
Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel;
// Draw the image
g.DrawImageUnscaled(bmpIn, 0, 0);
}
//converted.Save(outputFileName, ImageFormat.Bmp);
sw.Stop();
return converted;
}
public static Stream ToStream(Image image, ImageFormat formaw)
{
var stream = new MemoryStream();
image.Save(stream, formaw);
stream.Position = 0;
return stream;
}
public Boolean InitializeDirectX(System.Windows.Forms.PictureBox pb1)
{
DispMode = Manager.Adapters[Manager.Adapters.Default.Adapter].CurrentDisplayMode;
D3Dpp = new PresentParameters();
D3Dpp.BackBufferFormat = DispMode.Format;
D3Dpp.PresentFlag = PresentFlag.LockableBackBuffer;
D3Dpp.SwapEffect = SwapEffect.Discard;
D3Dpp.PresentationInterval = PresentInterval.One; //wait for vertical sync. Synchronizes the painting with
//monitor refresh rate for smoooth animation
D3Dpp.Windowed = true; //the application has borders
try
{
D3Ddev = new Device(Manager.Adapters.Default.Adapter, DeviceType.Hardware, pb1.Handle,
CreateFlags.SoftwareVertexProcessing, D3Dpp);
//D3Ddev.VertexFormat = CustomVertex.PositionColored.Format;
D3Ddev.RenderState.Lighting = false;
D3Ddev.RenderState.CullMode = Cull.CounterClockwise;
//load imagesBmp to panelTexture
//panelTexture = Texture.FromBitmap(D3Ddev, imagesBmp, Usage.Dynamic, Pool.Default)
backTexture = TextureLoader.FromStream(D3Ddev, mymem);
//scannerTexture = TextureLoader.FromFile(D3Ddev, #"D:\Buttons\Radar\radar.png");
scannedCloudsTexture = new Texture(D3Ddev, 512, 512, 1, Usage.Dynamic, Format.A8R8G8B8, Pool.Default);
//sprite is used to draw the texture
D3Dsprite = new Sprite(D3Ddev);
return true;
}
catch
{
return false;
}
}
Bitmap bmpn;
float angle = 0;
private void DisplayOnScreen(float angleF)
{
if (angle < 360)
{
bmpn = new Bitmap(512, 512);
angle++;
}
else
{
angle = 361;
}
Surface backbuffer;
Brush myBrush = new SolidBrush(Color.FromArgb(110, 0, 255, 0)); //semi transparent color to draw the rotating cone
Graphics g;
//clear the backbuffer with Color.FromArgb(56, 56, 56). This is the double buffer mechanism. Drawing to offscreen
//backbuffer and in the end flipping it to main one which is our panelContainer
D3Ddev.Clear(ClearFlags.Target, Color.FromArgb(56, 56, 56), 1, 0);
D3Ddev.BeginScene();
//Draw Sprites
//////////////////////////////////////////////////////
D3Dsprite.Begin(SpriteFlags.AlphaBlend);
// bitmap with clouds
D3Dsprite.Draw2D(backTexture, new PointF(0, 0), 0F, new PointF(0F, 0F), Color.White);
//the part of clouds that are inside the cone
D3Dsprite.Draw2D(scannedCloudsTexture, new PointF(0F, 0F), 0F, new PointF(0F, 0F), Color.White);
//rotate cone
//D3Dsprite.Draw2D(scannerTexture, new PointF(104.5F, 0F), angle, new PointF(256F, 255F), Color.White);
D3Dsprite.Flush();
D3Dsprite.End();
//////////////////////////////////////////////////////
//Draw the cone.
using (backbuffer = D3Ddev.GetBackBuffer(0, 0, BackBufferType.Mono))
{
using (g = backbuffer.GetGraphics())
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPie(myBrush, 256F - distanceFromCenterPixels, 255F - distanceFromCenterPixels,
distanceFromCenterPixels * 2F, distanceFromCenterPixels * 2F, angleF - 23F, 46F);
if (angle <= 360)
{
}
}
}
D3Ddev.EndScene();
D3Ddev.Present(); //performs the flipping
}
private void CalculateAngleAndDistance(int x, int y, out double angle, out double distance)
{
Double dbl = -1.0d;
Point center = new Point(256, 255);
distance = Math.Sqrt((double)((center.Y - y) * (center.Y - y) + (center.X - x) * (center.X - x)));
if (y == center.Y && x > center.X)
{
dbl = 0d;
angle = dbl;
return;
}
else if (x == center.X && y > center.Y)
{
dbl = 90d;
angle = dbl;
return;
}
else if (y == center.Y && x < center.X)
{
dbl = 180d;
angle = dbl;
return;
}
else if (x == center.X && y < center.Y)
{
dbl = 279d;
angle = dbl;
return;
}
else if (x == center.X && y == center.Y)
{
angle = dbl;
return;
}
if (x > center.X && y > center.Y) //1
{
dbl = Math.Atan(((double)y - (double)center.Y) / ((double)x - (double)center.X));
dbl = 180d * dbl / Math.PI;
}
else if (x < center.X && y > center.Y) //2
{
dbl = Math.Atan(((double)y - (double)center.Y) / ((double)center.X - (double)x));
dbl = 180d * dbl / Math.PI;
dbl = 180d - dbl;
}
else if (x < center.X && y < center.Y) //3
{
dbl = Math.Atan(((double)center.Y - (double)y) / ((double)center.X - (double)x));
dbl = 180d * dbl / Math.PI;
dbl += 180d;
}
else //4
{
dbl = Math.Atan(((double)center.Y - (double)y) / ((double)x - (double)center.X));
dbl = 180d * dbl / Math.PI;
dbl = 360d - dbl;
}
angle = dbl;
}
private void ReturnTexture(Texture texture_take, List<Point> lstPnt, float[] anglArr, float angle, Bitmap bmpNew)
{
int i, j, stride = 2048;
float angleBefore, angleAfter;
GraphicsStream textureStream;
Boolean bl = false;
if (bmpNew.Width != 512 && bmpNew.Height != 512)
throw new Exception("Bitmaps must be of same size.");
//sets texture to complete transparent
unsafe
{
fixed (byte* p = argbValuesOfTransparentTexture)
{
MemSet((IntPtr)p, 0x0, argbValuesOfTransparentTexture.Length);
}
}
angleAfter = angle + 23F;
if (angleAfter >= 360F)
{
angleAfter -= 360F;
}
angleBefore = angleAfter - 46;
if (angleBefore < 0F)
{
angleBefore += 360F;
bl = true;
}
BitmapData bmD = bmpNew.LockBits(new Rectangle(0, 0, bmpNew.Width, bmpNew.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)bmD.Scan0.ToPointer();
//checks all points and draws yellow only those who are inside the cone
for (i = 0; i < lstPnt.Count - 1; i++)
{
if (anglArr[i] == -1F)
{
continue;
}
if (bl == true)
{
if (anglArr[i] <= angleAfter || anglArr[i] >= angleBefore) //if point angle is inside cone. Cone angle is 46 degrees
{
if (distanceArray[i] <= distanceFromCenterPixels)
{
j = lstPnt[i].Y * stride + lstPnt[i].X * 4;
//yellow
argbValuesOfTransparentTexture[j + 0] = (byte)0;
argbValuesOfTransparentTexture[j + 1] = (byte)255;
argbValuesOfTransparentTexture[j + 2] = (byte)255;
argbValuesOfTransparentTexture[j + 3] = (byte)255;
p[j] = (byte)0;
p[j + 1] = (byte)0;
p[j + 2] = (byte)255;
p[j + 3] = (byte)255;
}
}
}
else
{
if (anglArr[i] <= angleAfter && anglArr[i] >= angleBefore) //if point angle is inside cone. Cone angle is 46 degrees
{
if (distanceArray[i] <= distanceFromCenterPixels)
{
j = lstPnt[i].Y * stride + lstPnt[i].X * 4;
//yellow
argbValuesOfTransparentTexture[j + 0] = (byte)0;
argbValuesOfTransparentTexture[j + 1] = (byte)255;
argbValuesOfTransparentTexture[j + 2] = (byte)255;
argbValuesOfTransparentTexture[j + 3] = (byte)255;
p[j] = (byte)0;
p[j + 1] = (byte)0;
p[j + 2] = (byte)255;
p[j + 3] = (byte)255;
}
}
}
}
}
//if (angle <= 360)
// pictureBox1.Image.Save(#"c:\coneimages\" + angle + ".gif");
bmpNew.UnlockBits(bmD);
{
using (textureStream = texture_take.LockRectangle(0, LockFlags.None))
{
textureStream.Write(argbValuesOfTransparentTexture);
texture_take.UnlockRectangle(0);
}
//if (angle <= 360)
// pictureBox1.Image.Save(#"c:\coneimages\" + angle + ".gif");
}
}
private void FindPoints()
{
//Bitmap bmptest;
GraphicsPath gp = new GraphicsPath();
int x, y, p, j, wdthHght;
int bytes;
//byte error_ = 5;
byte[] rgbValuesWithClouds;
byte[] rgbValuesWithoutClouds;
IntPtr ptr;
Rectangle rect;
BitmapData bitmap_Data;
Bitmap bmpWithClouds; //No memory is allocated
Bitmap bmpWithoutClouds; //No memory is allocated
gp.AddEllipse(new RectangleF(73, 72, 367, 367));
//gp.CloseFigure();
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithClouds = new Bitmap(mymem))//#"D:\MyWeatherStation-Images-And-Icons\radartobmp.bmp")) //24 bit bitmap
{
rect = new Rectangle(0, 0, bmpWithClouds.Width, bmpWithClouds.Height);
wdthHght = bmpWithClouds.Width;
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithClouds.Height;
rgbValuesWithClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithClouds.UnlockBits(bitmap_Data);
}
//using the using statement, bmpWithClouds bitmap is automatically disposed at the end of statement. No memory leaks :)
using (bmpWithoutClouds = new Bitmap(
#"D:\C-Sharp\Download File\Downloading-File-Project-Version-012\Downloading File\bin\x86\Release\WithoutClouds.bmp"))//su + "\\WithoutClouds.bmp")) //24 bit bitmap
{
rect = new Rectangle(0, 0, bmpWithoutClouds.Width, bmpWithoutClouds.Height);
//Lock bitmap to copy its color information fast
bitmap_Data = bmpWithoutClouds.LockBits(rect, ImageLockMode.ReadWrite, bmpWithoutClouds.PixelFormat);
ptr = bitmap_Data.Scan0;
bytes = bitmap_Data.Stride * bmpWithoutClouds.Height;
rgbValuesWithoutClouds = new byte[bytes];
//copy color information to rgbValues array
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValuesWithoutClouds, 0, bytes);
//we are done copying so unlock bitmap. We dont need it anymore
bmpWithoutClouds.UnlockBits(bitmap_Data);
}
// Each position in these arrays, rgbValuesWithoutClouds and rgbValuesWithClouds, corresponds a color. eg
// First pixel Second pixel Third pixel Forth pixel .... // bitmaps
// B G R B G R B G R B G R .... // rgbValues arrays
//bmptest = new Bitmap(512, 512);
detectedPoints = new List<Point>();
for (y = 0; y < wdthHght; y++)
{
j = 0;
for (x = 0; x < wdthHght; x++)
{
p = y * wdthHght * 3 + j;
if (rgbValuesWithClouds[p] != rgbValuesWithoutClouds[p])
{
detectedPoints.Add(new Point(x, y));
//bmptest.SetPixel(x, y, Color.Red);
}
j += 3;
}
}
}
}
}

How to add noise to image or convert it to 24bpp?

Noob needs help!
I have an image and I need to add noise on it. I tried using AForge libs to do it but this method works only with 24bpp bitmaps and I get something different after resizing. The question is how to convert a bitmap to 24bpp or how to add noise on it? Maybe there are some libs for making this easier.
Resizing:
private Image Fit(Image image)
{
Image img = image;
if (filepath != null)
{
if (img.Width > pictureBox1.Width)
{
double op = ((pictureBox1.Width - (pictureBox1.Width % 100)) % 100) + (pictureBox1.Width % 100) * 0.01;
double percent = img.Width / (pictureBox1.Width * 0.01);
double temp = ((percent - percent % 100 + 100) - percent) * pictureBox1.Height * 0.01;
double height = pictureBox1.Height * 0.01 * ((percent - percent % 100 + 100) - percent);
System.Drawing.Size sz = new Size(pictureBox1.Width, (int)height);
img = resizeImage(img, sz);
}
if (img.Height > pictureBox1.Height)
{
double percent = img.Height / (pictureBox1.Height * 0.01);
double temp = ((percent - percent % 100 + 100) - percent) * pictureBox1.Width * 0.01;
double width = pictureBox1.Width * 0.01 * ((percent - percent % 100 + 100) - percent);
System.Drawing.Size sz = new Size((int)width, pictureBox1.Height);
img = resizeImage(img, sz);
}
}
return img;
}
P.S.> I have a type of bug - system totally refuses to divide 1 by 100 so I had to multiply 1 by 0.01 or I get 0.
Resizing the image to maintain aspect ratio is pretty easy. You compute the horizontal and vertical scaling factors, and then select the smallest of the two.
double vscale = 1.0;
double hscale = 1.0;
if (img.Width > pictureBox1.Width)
{
hscale = (double)pictureBox1.Width/img.Width;
}
if (img.Height > pictureBox1.Height)
{
vscale = (double)pictureBox1.Height/img.Height;
}
double scale = Math.Min(hscale, vscale);
double width = scale * img.Width;
double height = scale * img.Height;
Size sz = new Size((int)width, (int)height);
img = resizeImage(img, sz)
Note that this only scales if the image is larger than the box. It won't zoom the image to make it fit the box if the image is smaller than the box.
Haven't found anything good. That's how I've solved it:
public void GenerateNoise(Image img, int intense)
{
Bitmap finalBmp = img as Bitmap;
Random r = new Random();
int width = img.Width;
int height = img.Height;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
int def = r.Next(0, 100);
if (def < intense)
{
int op = r.Next(0, 1);
if (op == 0)
{
int num = r.Next(0, intense);
Color clr = finalBmp.GetPixel(x, y);
int R = (clr.R + clr.R + num)/2;
if (R > 255) R = 255;
int G = (clr.G + clr.G + num) / 2;
if (G > 255) G = 255;
int B = (clr.B + clr.B + num) / 2;
if (B > 255) B = 255;
Color result = Color.FromArgb(255, R, G, B);
finalBmp.SetPixel(x, y, result);
}
else
{
int num = r.Next(0, intense);
Color clr = finalBmp.GetPixel(x, y);
Color result = Color.FromArgb(255, (clr.R + clr.R - num) / 2, (clr.G + clr.G - num) / 2,
(clr.B + clr.B - num) / 2);
finalBmp.SetPixel(x, y, result);
}
}
}
}
}

How can I rotate an image by any degree?

I have animated gif and I'm using a class to parse the images(frames) from it.
The class is:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.IO;
public class AnimatedGif
{
private List<AnimatedGifFrame> mImages = new List<AnimatedGifFrame>();
public AnimatedGif(string path)
{
Image img = Image.FromFile(path);
int frames = img.GetFrameCount(FrameDimension.Time);
if (frames <= 1) throw new ArgumentException("Image not animated");
byte[] times = img.GetPropertyItem(0x5100).Value;
int frame = 0;
for (; ; )
{
int dur = BitConverter.ToInt32(times, 4 * frame);
mImages.Add(new AnimatedGifFrame(new Bitmap(img), dur));
if (++frame >= frames) break;
img.SelectActiveFrame(FrameDimension.Time, frame);
}
img.Dispose();
}
public List<AnimatedGifFrame> Images { get { return mImages; } }
}
public class AnimatedGifFrame
{
private int mDuration;
private Image mImage;
internal AnimatedGifFrame(Image img, int duration)
{
mImage = img; mDuration = duration;
}
public Image Image { get { return mImage; } }
public int Duration { get { return mDuration; } }
}
Now in form1 I loop over the frames in this case 4 and I want to rotate the animation by any degree. Now its rotating each 45 or 90 degrees. I want to add more frames(images) to the animation so if I set the rotation to 31 or to 10 degrees so I will see the animation rotating in 10 degrees.
This is the code in Form1 which is not working good. I'm using a function for the rotation which I didn't test yet if its any working.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace AnimatedGifEditor
{
public partial class Form1 : Form
{
Image myImage;
AnimatedGif myGif;
Bitmap bitmap;
public Form1()
{
InitializeComponent();
myImage = Image.FromFile(#"D:\fananimation.gif");
myGif = new AnimatedGif(#"D:\fananimation.gif");
for (int i = 0; i < myGif.Images.Count; i++)
{
pictureBox1.Image = myGif.Images[3].Image;
bitmap = new Bitmap(pictureBox1.Image);
rotateImage(bitmap, 76);
pictureBox1.Image = bitmap;
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
{
int w = bmp.Width;
int h = bmp.Height;
bmp.PixelFormat pf = default(bmp.PixelFormat);
if (bkColor == Color.Transparent)
{
pf = bmp.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tempImg = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tempImg);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
//Using System.Drawing.Drawing2D.Matrix class
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tempImg, 0, 0);
g.Dispose();
tempImg.Dispose();
return newImg;
}
}
}
The animated gif I'm using for the test can be found here:
I didn't understand what's your problem but I think that your code could be improved. I think that you don't need to use directly the Matrix class. There are some functions that does this work for you. Infact the only things you need are: set the point of the rotation as the center, rotate the graphics and draw on it, using some functions by the Graphics class.
So to rotate an image you can use this simple code:
private Bitmap RotateImage(Bitmap bmp, float angle) {
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
rotatedImage.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedImage)) {
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(- bmp.Width / 2, - bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
Based on the previous answers I created this code that doesn't cut the image (the other examples were not working for me)
private Bitmap RotateImage(Bitmap bmp, float angle)
{
float height = bmp.Height;
float width = bmp.Width;
int hypotenuse = System.Convert.ToInt32(System.Math.Floor(Math.Sqrt(height * height + width * width)));
Bitmap rotatedImage = new Bitmap(hypotenuse, hypotenuse);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform((float)rotatedImage.Width / 2, (float)rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-(float)rotatedImage.Width / 2, -(float)rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, (hypotenuse - width) / 2, (hypotenuse - height) / 2, width, height);
}
return rotatedImage;
}
I tried the answer of #Omar myself and realized, that the original image gets cut at the sides ... i've rewritten it so it resizes the image to the new sizes:
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
float alpha = angle;
//edit: negative angle +360
while(alpha <0) alpha +=360;
float gamma = 90;
float beta = 180 - angle - gamma;
float c1 = bmp.Height;
float a1 = (float)(c1 * Math.Sin(alpha * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float b1 = (float)(c1 * Math.Sin(beta * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float c2 = bmp.Width;
float a2 = (float)(c2 * Math.Sin(alpha * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float b2 = (float)(c2 * Math.Sin(beta * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
int width = Convert.ToInt32(b2 + a1);
int height = Convert.ToInt32(b1 + a2);
Bitmap rotatedImage = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotatedImage.Width / 2, rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotatedImage.Width / 2, -rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, new Point((width - bmp.Width) / 2, (height - bmp.Height) / 2)); //draw the image on the new bitmap
}
return rotatedImage;
}
Have you tried RotateFlip?
public partial class Form1 : Form
{
Image myImage;
AnimatedGif myGif;
Bitmap bitmap;
public Form1()
{
InitializeComponent();
myImage = Image.FromFile(#"D:\fananimation.gif");
bitmap = new Bitmap(myImage);
bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
this.pictureBox1.Image = bitmap;
}
}
Source
I was using this function in VB:
Public Function RotateImage(ByRef image As Image, ByVal angle As Single) As Drawing.Bitmap
If image Is Nothing Then
Throw New ArgumentNullException("image")
End If
Dim pi2 As Single = Math.PI / 2.0
Dim oldWidth As Single = image.Width
Dim oldHeight As Single = image.Height
Dim theta As Single = angle * Math.PI / 180.0
Dim locked_theta As Single = theta
If locked_theta < 0.0 Then locked_theta += 2 * Math.PI
Dim newWidth, newHeight As Single
Dim nWidth, nHeight As Integer
Dim adjacentTop, oppositeTop As Single
Dim adjacentBottom, oppositeBottom As Single
If (locked_theta >= 0.0 And locked_theta < pi2) Or _
(locked_theta >= Math.PI And locked_theta < (Math.PI + pi2)) Then
adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth
oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth
adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight
oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight
Else
adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight
oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight
adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth
oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth
End If
newWidth = adjacentTop + oppositeBottom
newHeight = adjacentBottom + oppositeTop
nWidth = Int(Math.Ceiling(newWidth))
nHeight = Int(Math.Ceiling(newHeight))
Dim rotatedBmp As New Drawing.Bitmap(nWidth, nHeight)
Dim g As Graphics = Graphics.FromImage(rotatedBmp)
Dim points(2) As Point
If (locked_theta >= 0.0 And locked_theta < pi2) Then
points(0) = New Point(Int(oppositeBottom), 0)
points(1) = New Point(nWidth, Int(oppositeTop))
points(2) = New Point(0, Int(adjacentBottom))
ElseIf locked_theta >= pi2 And locked_theta < Math.PI Then
points(0) = New Point(nWidth, Int(oppositeTop))
points(1) = New Point(Int(adjacentTop), nHeight)
points(2) = New Point(Int(oppositeBottom), 0)
ElseIf locked_theta >= Math.PI And locked_theta < (Math.PI + pi2) Then
points(0) = New Point(Int(adjacentTop), nHeight)
points(1) = New Point(0, Int(adjacentBottom))
points(2) = New Point(nWidth, Int(oppositeTop))
Else
points(0) = New Point(0, Int(adjacentBottom))
points(1) = New Point(Int(oppositeBottom), 0)
points(2) = New Point(Int(adjacentTop), nHeight)
End If
g.DrawImage(image, points)
g.Dispose()
image.Dispose()
Return rotatedBmp
End Function
I checked the answers and they all have at least one of the following problems:
Cropping/incorrect centering
Unnecessary margin
Errors with some angle ranges
Unnecessarily complicated calculations/code
This solution can handle any angle (positive, negative, over 360° etc.). There is no cropping or excessive margins. No memory leaks either.
public Bitmap RotateBitmap(Bitmap bmp, float angle)
{
double radianAngle = angle / 180.0 * Math.PI;
double cosA = Math.Abs(Math.Cos(radianAngle));
double sinA = Math.Abs(Math.Sin(radianAngle));
int newWidth = (int)(cosA * bmp.Width + sinA * bmp.Height);
int newHeight = (int)(cosA * bmp.Height + sinA * bmp.Width);
var rotatedBitmap = new Bitmap(newWidth, newHeight);
rotatedBitmap.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedBitmap))
{
g.TranslateTransform(rotatedBitmap.Width / 2, rotatedBitmap.Height / 2);
g.RotateTransform(angle);
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
g.DrawImage(bmp, new Point(0, 0));
}
bmp.Dispose();//Remove if you want to keep oryginal bitmap
return rotatedBitmap;
}
Depending on Timo's code, i made some improvements, with improvement, negative angles (up to -360) can be give as a parameter succesfully
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
float alpha = angle;
//edit: negative angle +360
while (alpha < 0) alpha += 360;
float gamma = 90;
float beta = 180 - angle - gamma;
float c1 = bmp.Height;
float a1 = Math.Abs((float)(c1 * Math.Sin(alpha * Math.PI / 180)));
float b1 = Math.Abs((float)(c1 * Math.Sin(beta * Math.PI / 180)));
float c2 = bmp.Width;
float a2 = Math.Abs((float)(c2 * Math.Sin(alpha * Math.PI / 180)));
float b2 = Math.Abs((float)(c2 * Math.Sin(beta * Math.PI / 180)));
int width = Convert.ToInt32(b2 + a1);
int height = Convert.ToInt32(b1 + a2);
Bitmap rotatedImage = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotatedImage.Width / 2, rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotatedImage.Width / 2, -rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, new Point((width - bmp.Width) / 2, (height - bmp.Height) / 2)); //draw the image on the new bitmap
}
return rotatedImage;
}

How to fill enclosed area in the Bitmap object with a color

Give point within the region with a color to fill the region, similar to the "drawing" in the paint bucket function.
The. NET Framework, there is no direct equivalent.
but i hope use C# to do it.
is it possible?
Here's a very naive flood fill algorithm that should get you started
void Form1_Paint(object sender, PaintEventArgs e)
{
using (Bitmap bitmap = new Bitmap(500, 500))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.Clear(Color.White);
List<Point> points = new List<Point>();
for (double i = 0; i < 10; i++)
{
double dist = (i % 2 == 0) ? 100 : 50;
double x = 200 + Math.Cos(i / 10d * Math.PI * 2d) * dist;
double y = 200 + Math.Sin(i / 10d * Math.PI * 2d) * dist;
points.Add(new Point((int)x, (int)y));
}
g.DrawPolygon(Pens.Black, points.ToArray());
}
FloodFill(bitmap, 200, 200, Color.Red);
e.Graphics.DrawImage(bitmap, 0, 0);
}
}
void FloodFill(Bitmap bitmap, int x, int y, Color color)
{
BitmapData data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int[] bits = new int[data.Stride / 4 * data.Height];
Marshal.Copy(data.Scan0, bits, 0, bits.Length);
LinkedList<Point> check = new LinkedList<Point>();
int floodTo = color.ToArgb();
int floodFrom = bits[x + y * data.Stride / 4];
bits[x + y * data.Stride / 4] = floodTo;
if (floodFrom != floodTo)
{
check.AddLast(new Point(x, y));
while (check.Count > 0)
{
Point cur = check.First.Value;
check.RemoveFirst();
foreach (Point off in new Point[] {
new Point(0, -1), new Point(0, 1),
new Point(-1, 0), new Point(1, 0)})
{
Point next = new Point(cur.X + off.X, cur.Y + off.Y);
if (next.X >= 0 && next.Y >= 0 &&
next.X < data.Width &&
next.Y < data.Height)
{
if (bits[next.X + next.Y * data.Stride / 4] == floodFrom)
{
check.AddLast(next);
bits[next.X + next.Y * data.Stride / 4] = floodTo;
}
}
}
}
}
Marshal.Copy(bits, 0, data.Scan0, bits.Length);
bitmap.UnlockBits(data);
}

Categories

Resources