When the Bitmap is scaled, it goes like this - c#

I have an image drawn in the picturebox and I need to scale it using a trackbar. But this happens whenever I scale it up, and if I continue scaling - it becomes more blurry.
My code:
Image Drawing
public LayerClass ImageDrawing(LayerClass.Type img, Bitmap bm, Rectangle imgRect, String filepath, int angle, PaintEventArgs e)
{
bm = ImageClass.GrayscaleImage(bm);
bm = MakeTransparentImage(bm);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
bm = RotateImage(bm, angle);
imgRect = new Rectangle((int)(Shape.center.X - (bm.Width / 2)), (int)(Shape.center.Y - (bm.Height / 2)), (int)bm.Width, (int)bm.Height);
e.Graphics.DrawRectangle(new Pen(Color.Red, 1), imgRect);
e.Graphics.DrawImage(bm, imgRect);
this.imageBitmap = bm;
this.filePath = filePath;
this.rotationAngle = angle;
this.location = location;
this.imageRect = imgRect;
return new LayerClass(LayerClass.Type.Image, this, filePath, imgRect);
}
Scaling
private void trackBar_ScaleImg_Scroll(object sender, EventArgs e)
{
//Width Scaling
if(rb_WidthImage.Checked)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.X = (int)(Shape.center.X - (imgRect.Width / 2));
lbl_imgWidth.Text = Math.Round((trackBar_ScaleImg.Value * 25.4) / 96).ToString();
toolTip_Scroll.SetToolTip(trackBar_ScaleImg, lbl_imgWidth.Text);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
}

Related

How to resize a cropped image?

Goal:
My current goal is to crop the original image from pictureBox1 and show it in pictureBox2 and increase it's size (Height & Width) by 0.8.
Current Code:
//...
private Point LocationXY;
private Point LocationX1Y1;
private void button1_Click(object sender, EventArgs e)
{
if (Clipboard.ContainsImage())
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = Clipboard.GetImage();
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
LocationXY = e.Location;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
LocationX1Y1 = e.Location;
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
LocationX1Y1 = e.Location;
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (MouseButtons == MouseButtons.Left)
e.Graphics.DrawRectangle(Pens.Red, GetRect());
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
var src = GetRect();
if (src == Rectangle.Empty) return;
var des = new Rectangle(0, 0, src.Width, src.Height);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.DrawImage(pictureBox1.Image,
des, src, GraphicsUnit.Pixel);
}
private Rectangle GetRect()
{
return new Rectangle(
Math.Min(LocationXY.X, LocationX1Y1.X),
Math.Min(LocationXY.Y, LocationX1Y1.Y),
Math.Abs(LocationXY.X - LocationX1Y1.X),
Math.Abs(LocationXY.Y - LocationX1Y1.Y)
);
}
//...
Cropping the image:
//...
private Bitmap GetCroppedImage()
{
var src = GetRect();
if (src == Rectangle.Empty) return null;
var des = new Rectangle(0, 0, src.Width, src.Height);
var b = new Bitmap(src.Width, src.Height);
using (var g = Graphics.FromImage(b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(pictureBox1.Image, des, src, GraphicsUnit.Pixel);
}
return b;
}
//...
Current code - what does it do
Currently this code is able to mark an red area in pictureBox1 and show the cropped image in pictureBox2.
Question:
How do I increase/resize the cropped image height and width by 0.8?
Calculate the ratio of the scale up against the source size and use it to calculate the new size of the image. Accordingly, the pictureBox2.Paint event code:
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
var src = GetRect();
if (src == Rectangle.Empty || src.Width == 0 || src.Height == 0) return;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
var widthScale = 0.8;
var heightScale = 0.8;
var widthRatio = (src.Width * widthScale + src.Width) / src.Width;
var heightRatio = (src.Height * heightScale + src.Height) / src.Height;
var newWidth = (int)(src.Width * widthRatio);
var newHeight = (int)(src.Height * heightRatio);
var des = new Rectangle(0, 0, newWidth, newHeight);
e.Graphics.DrawImage(pictureBox1.Image,
des, src, GraphicsUnit.Pixel);
}
To apply that on the GetCroppedImage() function:
private Image GetCroppedImage(double scale = 0)
{
var src = GetRect();
if (src == Rectangle.Empty || src.Width == 0 || src.Height == 0) return null;
var widthRatio = (src.Width * scale + src.Width) / src.Width;
var heightRatio = (src.Height * scale + src.Height) / src.Height;
var newWidth = (int)(src.Width * widthRatio);
var newHeight = (int)(src.Height * heightRatio);
if (newWidth == 0 || newHeight == 0) return null;
var des = new Rectangle(0, 0, newWidth, newHeight);
var b = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.DrawImage(pictureBox1.Image, des, src, GraphicsUnit.Pixel);
}
return b;
}
Also, you could use the Image.GetThumbnailImage to get small sizes from the main image. Not recommended if you need to return large ones. Read the Remarks for more information.
public static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Usage:
ResizeImage(originalImg, (int)(originalImg.Width * 0.8), (int)(originalImg.Height * 0.8));

How do I rotate an Image and Scale it up using only one method?

Here's what I do to Rotate and Scale. But so far, if the rotation is working, the scaling isn't and vice versa. So how do I combine rotation and scaling in one method? I feels like they can't coexist using my code.
....................................................................................................................................................................
Here's what I have for now:
Image Drawing:
public LayerClass ImageDrawing(LayerClass.Type img, Bitmap bm, Rectangle imgRect, String filepath, int angle, PaintEventArgs e)
{
bm = ImageClass.GrayscaleImage(bm);
bm = MakeTransparentImage(bm);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
bm = RotateImage(bm, angle, imgRect);
imgRect = new Rectangle((int)(Shape.center.X - (bm.Width / 2)), (int)(Shape.center.Y - (bm.Height / 2)), (int)bm.Width, (int)bm.Height);
e.Graphics.DrawImage(bm, imgRect);
this.imageBitmap = bm;
this.filePath = filePath;
this.rotationAngle = angle;
this.location = location;
this.imageRect = imgRect;
return new LayerClass(LayerClass.Type.Image, this, filePath, imgRect);
}
Rotation:
public static Bitmap RotateImage(Bitmap bitmap, float angle, Rectangle rect)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
rect = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(resultBitmap))
{
Matrix matrix2 = new Matrix();
matrix2.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
g.Transform = matrix2;
g.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
Scaling:
private void trackBar_ScaleImg_Scroll(object sender, EventArgs e)
{
if(rb_BothImage.Checked)
{
if (imgRect.Width > imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Height > imgRect.Width)
{
imgRect.Height = trackBar_ScaleImg.Value; //64mm
imgRect.Width = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Width == imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = trackBar_ScaleImg.Value;
}
imgRect.X = (int)(Shape.center.X - (imgRect.Width / 2));
imgRect.Y = (int)(Shape.center.Y - (imgRect.Height / 2));
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
pictureBox_Canvass.Invalidate();
}
You can add another matrix transformation for scaling: matrix.Scale(2, 2, MatrixOrder.Append);
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
matrix.Scale(2, 2, MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())

C# - Forcing Rectangle to be in a fixed size/ratio

Similar to Photoshop, where you can type in a ratio or in my case a certain dimention such as 800x600, I want to be able to force a Rectangle to be a fixed ratio/size when dragging the mouse..
At the moment I have this:
Which will crop an image using the Rectangle created from clicking and dragging on the PictureBox. The bounding box selects the area without any constraints. I want to be able to force the rectangle to be a certain ratio (prefereably from a set resolution) similar to the way Photoshop's cropping tool works.
My source if anyone needs more detail:
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
public partial class Form1 : Form
{
private static string path;
public Form1(string filePath)
{
InitializeComponent();
path = filePath;
}
private Image _originalImage;
private Image _newImage;
private bool _selecting;
private Rectangle _selection;
private void Form1_Load(object sender, System.EventArgs e)
{
pictureBox1.Image = Image.FromFile(path);
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50 || pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50)
{
Height = Screen.PrimaryScreen.Bounds.Height - 50;
panel1.Height = Size.Height - statusStrip1.Height - buttonSave.Height - 60;
}
if (pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
Size = new Size(Screen.PrimaryScreen.Bounds.Width - 50, Screen.PrimaryScreen.Bounds.Height - 50);
panel1.Width = Size.Width - statusStrip1.Height - buttonSave.Height - 60;
}
pictureBox1.Image = pictureBox1.Image.Fit2PictureBox(pictureBox1);
panel1.Size = new Size(pictureBox1.Image.Width, pictureBox1.Image.Height);
}
Size = new Size(panel1.Size.Width + 50, panel1.Size.Height + buttonSave.Height + statusStrip1.Height + 80);
// Create a copy of the original image for later use
_originalImage = pictureBox1.Image.Clone() as Image;
_newImage = pictureBox1.Image.Clone() as Image;
}
private void buttonOrig_Click(object sender, System.EventArgs e)
{
pictureBox1.Image = _originalImage.Clone() as Image;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Starting point of the selection:
if (e.Button == MouseButtons.Left)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = _originalImage.Clone() as Image;
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Update the actual size of the selection:
if (_selecting)
{
_selection.Width = (e.X - _selection.X);
_selection.Height = (e.Y - _selection.Y);
//int nGCD = GetGreatestCommonDivisor(1920, 1080);
//_selection.Width = _selection.Width / nGCD;
//_selection.Height = _selection.Height / nGCD;
int widthRatio = 16;
int heightRatio = 9;
if (_selection.Height * widthRatio <= _selection.Width)
{
_selection.Width = _selection.Height * widthRatio;
}
else if (_selection.Width * heightRatio <= _selection.Width)
{
_selection.Height = _selection.Width * heightRatio;
}
// Redraw the picturebox:
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_selecting && _selection.Height != 0)
{
// Draw a rectangle displaying the current selection
e.Graphics.DrawRectangle(Pens.WhiteSmoke, _selection);
//e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(50, Color.Gray)), 0, pictureBox1.Height - pictureBox1.Image.Height, pictureBox1.Image.Width, pictureBox1.Image.Height);
e.Graphics.SetClip(_selection, CombineMode.Exclude);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Black)), 0, 0, pictureBox1.Width, pictureBox1.Height);
int nGCD = GetGreatestCommonDivisor(_selection.Width, _selection.Height);
string str = string.Format("{0}:{1}", _selection.Width / nGCD, _selection.Height / nGCD);
toolStripStatusLabel1.Text = "Image Size: " + _selection.Width + "x" + _selection.Height + "px. Aspect Ratio: " + str;
}
}
public static int GetGreatestCommonDivisor(int height, int width)
{
return width == 0 ? height : GetGreatestCommonDivisor(width, height % width);
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left &&
_selecting &&
_selection.Size != new Size())
{
// Create cropped image:
_newImage = pictureBox1.Image.Crop(_selection);
_selecting = false;
try
{
// Set new image to the picturebox:
//pictureBox1.Image = _newImage.Fit2PictureBox(pictureBox1);
pictureBox1.Image = _newImage;
//toolStripStatusLabel1.Text = "Image Cropped.";
}
catch (Exception)
{ }
}
else
{
_selecting = false;
}
}
private void buttonResize_Click(object sender, EventArgs e)
{
pictureBox1.Image = ResizeImage(pictureBox1.Image, new Size(800, 600));
int nGCD = GetGreatestCommonDivisor(pictureBox1.Image.Width, pictureBox1.Image.Height);
string str = string.Format("{0}:{1}", pictureBox1.Image.Width / nGCD, pictureBox1.Image.Height / nGCD);
toolStripStatusLabel1.Text = "Image Resized to " + pictureBox1.Image.Width + "x" + pictureBox1.Image.Height + "px. Aspect Ratio: " + str;
}
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = size.Width / originalWidth;
float percentHeight = size.Height / originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
private void buttonSave_Click(object sender, EventArgs e)
{
string filename = path.Substring(path.LastIndexOf("\\") + 1);
string newPath = path.Substring(0, path.LastIndexOf(".") - 1) + "NEW.png";
toolStripStatusLabel1.Text = "Saving " + filename + " to " + newPath;
pictureBox1.Image.Save(newPath, ImageFormat.Png);
toolStripStatusLabel1.Text = filename + " saved to " + newPath;
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args[0]));
}
public static Image SetImageWithinResolution(this Image image, PictureBox pictureBox)
{
//Bitmap bitmap = null;
if (image.Height > Screen.PrimaryScreen.Bounds.Height)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap(image, );
}
if (image.Width > Screen.PrimaryScreen.Bounds.Width)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap();
}
return image;
}
public static Image Crop(this Image image, Rectangle selection)
{
Bitmap bmp = image as Bitmap;
try
{
// Check if it is a bitmap:
if (bmp == null)
throw new ArgumentException("No valid bitmap");
// Crop the image:
Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);
// Release the resources:
image.Dispose();
return cropBmp;
}
catch (Exception)
{
return bmp;
}
}
public static Image Fit2PictureBox(this Image image, PictureBox picBox)
{
Bitmap bmp = null;
Graphics g;
// Scale:
double scaleY = (double)image.Width / picBox.Width;
double scaleX = (double)image.Height / picBox.Height;
double scale = scaleY < scaleX ? scaleX : scaleY;
// Create new bitmap:
bmp = new Bitmap(
(int)((double)image.Width / scale),
(int)((double)image.Height / scale));
// Set resolution of the new image:
bmp.SetResolution(
image.HorizontalResolution,
image.VerticalResolution);
// Create graphics:
g = Graphics.FromImage(bmp);
// Set interpolation mode:
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the new image:
g.DrawImage(
image,
new Rectangle( // Destination
0, 0,
bmp.Width, bmp.Height),
new Rectangle( // Source
0, 0,
image.Width, image.Height),
GraphicsUnit.Pixel);
// Release the resources of the graphics:
g.Dispose();
// Release the resources of the origin image:
image.Dispose();
return bmp;
}
}
Maybe this example will help; is shows how to restrict a drawn rectangle to a given ratio:
float ratio = 0.33f;
Rectangle setRect()
{
int x = Math.Min(mDown.X, currPt.X);
int y = Math.Min(mDown.Y, currPt.Y);
int w = Math.Max(mDown.X, currPt.X) - x;
int h = Math.Max(mDown.Y, currPt.Y) - y;
if (ratio > 1) h = (int)(1f * w / ratio);
else w = (int)(1f * h * ratio);
return new Rectangle(x, y, w, h);
}
It uses two Points, one set in the MouseDown and one updated in the MouseMove.
It is up to you to integrate it with you programm; instead of painting all those pixels during MouseMove I would simply draw a rubberband rectangle on the surface of the control using the Paint event..
If you are scaling things you may want to switch to using all floats.

Refreshing picturebox stops other controls that need to redraw

So I have this steering wheel control, and when I rotate it with the mouse and refresh the image it stops my other panel control from drawing its graph from updating/redrawing. Below is the code for rotating and redrawing the steering wheel.
private readonly Bitmap _originalHelmImage;
private Bitmap _newHelmImage;
private void HelmPb_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
PictureBox p = (PictureBox) sender;
Bitmap bmp = (Bitmap) p.Image;
//GetPixel works on initial image, not stretched one.
double ratio = (double) p.Image.Width/p.Width;
//Ignore the non-helm portion of the helm.
Color trans = bmp.GetPixel(Convert.ToInt32(ratio*e.X), Convert.ToInt32(ratio*e.Y));
if (trans.A.Equals(0))
{
_dontTurn = true;
return;
}
_offsetAngle = OffsetAngle() - _lastAngleTurn;
_lastAngleTurn = 0;
_dontTurn = false;
}
private double OffsetAngle()
{
int helmXMid = HelmPb.PointToScreen(Point.Empty).X + (HelmPb.Width / 2);
int helmYMid = HelmPb.PointToScreen(Point.Empty).Y + (HelmPb.Height / 2);
double angle = AngleFromPoints(MousePosition, new Point(helmXMid, helmYMid));
return angle;
}
private void HelmPb_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button != MouseButtons.Left) || _dontTurn) return;
double angle = OffsetAngle();
float degrees = Convert.ToSingle(angle - _offsetAngle);
//float diff = ((360 - degrees) - _deltaHelmTurn%360)%360;
//float diff = (_lastAngleTurn - (degrees - 360)) % 360;
double diff = 90 - angle;
_deltaHelmTurn += Convert.ToSingle(diff - _lastAngleTurn);
if (Math.Abs(_deltaHelmTurn) >= (_maxHelmTurn*360.0))
{
_deltaHelmTurn = Convert.ToSingle(_maxHelmTurn*360.0);
degrees = 0;
}
_lastAngleTurn = Convert.ToSingle(degrees);
_newHelmImage = RotateImage(_originalHelmImage, -degrees);
HelmPb.Image.Dispose();
HelmPb.Image = _newHelmImage;
WaterDepthPlot.Invalidate();
HelmPb.Refresh();
}
double AngleFromPoints(Point pt1, Point pt2)
{
Point p = new Point(pt1.X - pt2.X, pt1.Y - pt2.Y);
double alpha;
if (p.Y == 0) alpha = p.X > 0 ? 0d : 180d;
else
{
double f = 1d * p.X / (Math.Sqrt(p.X * p.X + p.Y * p.Y));
alpha = Math.Acos(f) * 180d / Math.PI;
if (p.Y > 0) alpha = 360d - alpha;
}
return alpha;
}
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.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.TranslateTransform(b.Width/2F, b.Height/2F);
//Rotate.
g.RotateTransform(angle);
//Move image back.
g.TranslateTransform(-b.Width/2F, -b.Height/2F);
//Draw passed in image onto graphics object.
g.DrawImage(b, new PointF(0.0F, 0.0F));
return returnBitmap;
}
Below is the code for updating my graph. It is never ran when the steering wheel is being moved. Once the users stops moving, it will update. Is there a way for it to constantly update along with it? I tried throwing a refresh/invalidate of the panel into the mousemove event so whenever the wheel is refreshed, so is the graph; no luck. Any suggestions?
private void WaterDepthPlot_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.FromArgb(70, 75, 80));
int xOffset = WaterDepthPlot.Location.X;
e.Graphics.DrawLine(pen, new Point(0, 0), new Point(WaterDepthPlot.Width, 0));
e.Graphics.DrawLine(pen, new Point(0, (WaterDepthPlot.Height/5)),
new Point(WaterDepthPlot.Width, (WaterDepthPlot.Height/5)));
e.Graphics.DrawLine(pen, new Point(0, (2*WaterDepthPlot.Height/5)),
new Point(WaterDepthPlot.Width, (2*WaterDepthPlot.Height/5)));
e.Graphics.DrawLine(pen, new Point(0, (3*WaterDepthPlot.Height/5)),
new Point(WaterDepthPlot.Width, (3*WaterDepthPlot.Height/5)));
e.Graphics.DrawLine(pen, new Point(0, (4*WaterDepthPlot.Height/5)),
new Point(WaterDepthPlot.Width, (4*WaterDepthPlot.Height/5)));
e.Graphics.DrawLine(pen, new Point((ThirdXScaleUnit.Location.X - xOffset), 0),
new Point((ThirdXScaleUnit.Location.X - xOffset),
(WaterDepthPlot.Height + WaterDepthPlot.Location.Y)));
e.Graphics.DrawLine(pen, new Point((SecondXScaleUnit.Location.X - xOffset), 0),
new Point((SecondXScaleUnit.Location.X - xOffset),
(WaterDepthPlot.Height + WaterDepthPlot.Location.Y)));
e.Graphics.DrawLine(pen, new Point((FirstXScaleUnit.Location.X - xOffset), 0),
new Point((FirstXScaleUnit.Location.X - xOffset),
(WaterDepthPlot.Height + WaterDepthPlot.Location.Y)));
pen = new Pen(Color.Firebrick);
pen.DashStyle = DashStyle.Dash;
float[] dash = {3, 3};
pen.DashPattern = dash;
double diff = (double) WaterDepthPlot.Height/(5*_depthYScale);
int alertDiff = (int)(_alertDepth * diff);
e.Graphics.DrawLine(pen, new Point(0, alertDiff), new Point(WaterDepthPlot.Width, alertDiff));
pen = new Pen(Color.White);
GraphicsPath gp = new GraphicsPath();
if (_depthCurve.Count < 2) return;
gp.AddCurve(_depthCurve.ToArray());
e.Graphics.DrawPath(pen, gp);
}

How do I properly select a certain part of an image inside a picture box in C# and highlight it?

I have been trying to write a program, to be able to load an image on a form and select a rectangle on it, then load that rectangle onto another picture box (pictureBox2), and I also want to be able to highlight what I have selected on the original picture, in pictureBox1, as I move my mouse.
So far I have this code, but it doesn't properly respond to the mouseMove event, the rectangle that I highlight isn't selected properly. What is the problem?
public partial class Form1 : Form
{
Bitmap original;
bool isSelecting;
int x0, y0, x1, y1;
public Form1()
{
InitializeComponent();
pictureBox1.MouseDown += new MouseEventHandler(picOriginal_MouseDown);
pictureBox1.MouseMove += new MouseEventHandler(picOriginal_MouseMove);
pictureBox1.MouseUp += new MouseEventHandler(picOriginal_MouseUp);
}
#region helpder methods
// Start selecting the rectangle.
private void picOriginal_MouseDown(object sender, MouseEventArgs e)
{
if(original != null)
{
isSelecting = true;
// Save the start point.
x0 = e.X;
y0 = e.Y;
}
}
// Continue selecting.
private void picOriginal_MouseMove(object sender, MouseEventArgs e)
{
if(original != null)
{
// Do nothing it we're not selecting an area.
if(!isSelecting) return;
// Save the new point.
x1 = e.X;
y1 = e.Y;
// Make a Bitmap to display the selection rectangle.
Bitmap bm = new Bitmap(original);
// Draw the rectangle.
using(Graphics gr = Graphics.FromImage(bm))
{
gr.DrawRectangle(Pens.Red,
Math.Min(x0, x1), Math.Min(y0, y1),
Math.Abs(x0 - x1), Math.Abs(y0 - y1)
);
}
// Display the temporary bitmap.
pictureBox1.Image = new Bitmap(bm, new Size(pictureBox1.Width, pictureBox1.Height));
}
}
// Finish selecting the area.
private void picOriginal_MouseUp(object sender, MouseEventArgs e)
{
if(original != null)
{
// Do nothing it we're not selecting an area.
if(!isSelecting) return;
isSelecting = false;
// Display the original image.
pictureBox1.Image = original;
// Copy the selected part of the image.
int wid = Math.Abs(x0 - x1);
int hgt = Math.Abs(y0 - y1);
if((wid < 1) || (hgt < 1)) return;
Bitmap area = new Bitmap(wid, hgt);
using(Graphics gr = Graphics.FromImage(area))
{
Rectangle source_rectangle =
new Rectangle(Math.Min(x0, x1), Math.Min(y0, y1),
wid, hgt);
Rectangle dest_rectangle =
new Rectangle(0, 0, wid, hgt);
gr.DrawImage(original, dest_rectangle,
source_rectangle, GraphicsUnit.Pixel);
}
// Display the result.
pictureBox2.Image = area;
}
}
#endregion
private void button1_Click(object sender, EventArgs e)
{
if(original != null)
{
}
}
private void button2_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "jpg files (*.jpg)|*.jpg|All files(*.*)|*.*";
if(dialog.ShowDialog() == DialogResult.OK)
{
original = new Bitmap(dialog.FileName);
pictureBox1.Image = new Bitmap(original, new Size(pictureBox1.Width, pictureBox1.Height));
}
dialog.Dispose();
}
}
I think your problem is the 'original' image size which is not the same as the picturebox size. Try this code to compensate for the zoom ratio between your 'original' image and the picturebox size:
// Draw the rectangle.
float zoomX = (float)original.Size.Width / pictureBox1.Width;
float zoomY = (float)original.Size.Height / pictureBox1.Height;
using (Graphics gr = Graphics.FromImage(bm))
{
gr.DrawRectangle(Pens.Red,
Math.Min(x0, x1) * zoomX, Math.Min(y0, y1) * zoomY,
Math.Abs(x0 - x1) * zoomX, Math.Abs(y0 - y1) * zoomY
);
}
This fixes the red rectangle in my case. But the copied part in picturebox2 is still not correct...
And this fixes the copy to the second picturebox:
// Copy the selected part of the image.
float zoomX = (float)original.Size.Width / pictureBox1.Width;
float zoomY = (float)original.Size.Height / pictureBox1.Height;
int wid = (int)(zoomX * Math.Abs(x0 - x1));
int hgt = (int)(zoomY * Math.Abs(y0 - y1));
if ((wid < 1) || (hgt < 1)) return;
Bitmap area = new Bitmap(wid, hgt);
using (Graphics gr = Graphics.FromImage(area))
{
Rectangle source_rectangle =
new Rectangle((int)(zoomX * Math.Min(x0, x1)), (int)(zoomY * Math.Min(y0, y1)),
wid, hgt);
Rectangle dest_rectangle =
new Rectangle(0, 0, wid, hgt);
gr.DrawImage(original, dest_rectangle,
source_rectangle, GraphicsUnit.Pixel);
}

Categories