I want to auto crop the image which I took it from tablet camera. Actually I want to take the picture of id cards and need to auto corp it, I am using black background but sometimes it is too glaze and there is a reflection also, at that time its not cropped properly. Can anyone assist me with c# code to crop the images(Note : I am using phone cameras to take the image of id cards, mostly the background will be black and sometime it will be some other things).
Below I mentioned my code also:
private void ProcessImage(Bitmap bitmap)
{
// lock image
BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
// step 1 - turn background to black
ColorFiltering colorFilter = new ColorFiltering();
colorFilter.Red = new IntRange(0, 64);
colorFilter.Green = new IntRange(0, 64);
colorFilter.Blue = new IntRange(0, 64);
colorFilter.FillOutsideRange = false;
colorFilter.ApplyInPlace(bitmapData);
// step 2 - locating objects
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 5;
blobCounter.MinWidth = 5;
blobCounter.ProcessImage(bitmapData);
Blob[] blobs = blobCounter.GetObjectsInformation();
bitmap.UnlockBits(bitmapData);
// step 3 - check objects' type and highlight
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Graphics g = Graphics.FromImage(bitmap);
Pen yellowPen = new Pen(Color.Yellow, 2); // circles
Pen redPen = new Pen(Color.Red, 2); // quadrilateral
Pen brownPen = new Pen(Color.Brown, 2); // quadrilateral with known sub-type
Pen greenPen = new Pen(Color.Green, 2); // known triangle
Pen bluePen = new Pen(Color.Blue, 2); // triangle
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
DoublePoint center;
double radius;
List<IntPoint> corners;
// is triangle or quadrilateral
if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
{
// get sub-type
PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
Pen pen;
if (subType == PolygonSubType.Rectangle)
{
pen = (corners.Count == 4) ? redPen : bluePen;
}
else
{
pen = (corners.Count == 4) ? brownPen : greenPen;
}
//g.DrawPolygon( pen, ToPointsArray( corners ) );
if (pen.Color.Name == "Red")
{
int intdummy = 0;
g.DrawRectangle(pen, corners[0].X, corners[0].Y, 1150, 750);
//Code for corpping///////
pictureBox2.Image = bitmap;
pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
Bitmap croppedBitmap = new Bitmap("E:\\xxx\\Vicas Tablet\\WinImager\\cropimage\\cropimage\\Testing Images\\Image1.jpg");
//croppedBitmap = croppedBitmap.Clone(new Rectangle(corners[0].X, corners[0].Y,1150,750),System.Drawing.Imaging.PixelFormat.DontCare);
croppedBitmap = croppedBitmap.Clone(
new Rectangle(corners[0].X, corners[0].Y, ((int)corners[1].X - (int)corners[0].X), ((int)corners[2].Y - (int)corners[1].Y)), System.Drawing.Imaging.PixelFormat.DontCare);
pictureBox2.Image = croppedBitmap;
////End code for cropping///////////
}
}
Related
I have started image processing recently, and I want to write a program for detecting shapes such as circles in images, My sample code is as below but it isn't working:(
I read most of the related questions and answers in this forum and tried to solve my problem but I haven't been succeed. This code is running but hasn't any proper output.
If any body there to help me, I would be so thankful.
DialogResult x;
x = openFileDialog1.ShowDialog();
if (x == DialogResult.Cancel)
return;
pic1.ImageLocation = openFileDialog1.FileName;
Bitmap bmp = (Bitmap)Bitmap.FromFile(pic1.ImageLocation);
Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height);
BlobCounter blobcounter = new BlobCounter();
blobcounter.ProcessImage(bmp2);
blobcounter.FilterBlobs = true;
blobcounter.MinHeight = bmp2.Height;
blobcounter.MinWidth = bmp2.Width;
Blob[] blobs = blobcounter.GetObjectsInformation();
Graphics g = Graphics.FromImage(bmp2);
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Pen yellowpen = new Pen(Color.Yellow, 2);
for (int i = 0; i < blobs.Length; i++ )
{
List<IntPoint> edgePoints = blobcounter.GetBlobsEdgePoints(blobs[i]);
AForge.Point center;
float radius;
if(shapeChecker.IsCircle(edgePoints, out center, out radius))
{
g.DrawEllipse(yellowpen,
(int)(center.X - radius),
(int)(center.Y - radius),
(int)(radius * 2),
(int)(radius * 2));
}
}
yellowpen.Dispose();
g.Dispose();
}
I've run into an issue with drawing text and basic graphic drawing operations not having the proper placement & quality when the drawing matrix has large offset values. I've tried number SmoothMode, InterpolationMode, & TextRenderingHint options with no luck.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public void RenderImageClosePointDrawing()
{
float x = 68336, y = 99460;
PointF anchorPoint = new PointF(17494176, 25461836);
PointF anchorPoint2= new PointF(17494076, 25461836);
string textLabel = "9318";
float textFontSize = 20;
float symbolsize = 34;
string fontFamly = "Arial";
Bitmap bitmap = new Bitmap(256, 256);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
graphics.Transform = new Matrix(1, 0, 0, 1, -x * 256, -y * 256);
//Draw the circle
Pen polyPen = new Pen(new SolidBrush(Color.Black), 2);
Brush polyBrush = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
RectangleF drawnArea = new RectangleF(anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
Pen polyPen2 = new Pen(new SolidBrush(Color.Black), 1);
Brush polyBrush2 = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
RectangleF drawnArea2 = new RectangleF(anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
Pen polyPen3 = new Pen(new SolidBrush(Color.Red), 1);
graphics.DrawRectangle(polyPen3, drawnArea.X, drawnArea.Y, drawnArea.Width, drawnArea.Height);
graphics.DrawRectangle(polyPen3, drawnArea2.X, drawnArea2.Y, drawnArea2.Width, drawnArea2.Height);
//Draw the text
Pen textOutlinePen = new Pen(new SolidBrush(Color.Orange), (float)4);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
Brush textFillBrush = new SolidBrush(Color.Teal);
FontFamily textFontFamily = new FontFamily(fontFamly);
PointF textAnchor = new PointF(anchorPoint.X, anchorPoint.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea, textFontFamily, ref textAnchor);
var textPath = new GraphicsPath();
textPath.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
graphics.DrawPath(textOutlinePen, textPath);
graphics.FillPath(textFillBrush, textPath);
//Draw the text2
Pen textOutlinePen2 = new Pen(new SolidBrush(Color.Orange), (float)1);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
PointF textAnchor2 = new PointF(anchorPoint2.X, anchorPoint2.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea2, textFontFamily, ref textAnchor2);
var textPath2 = new GraphicsPath();
textPath2.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor2,
new StringFormat()
);
graphics.DrawPath(textOutlinePen2, textPath2);
graphics.FillPath(textFillBrush, textPath2);
}
bitmap.Save(#"C:\ClosePointDrawing.png", ImageFormat.Png);
}
private static void ShiftTextAnchor_NW(string textLabel, float textFontSize, ref RectangleF drawnArea, FontFamily textFontFamily, ref PointF textAnchor)
{
GraphicsPath tempPath = new GraphicsPath();
tempPath.AddString(
textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
var textBounds = tempPath.GetBounds();
var offsetX = textBounds.X - textAnchor.X;
var offsetY = textBounds.Y - textAnchor.Y;
textAnchor = new PointF(drawnArea.Left - (textBounds.Width + offsetX), drawnArea.Top - (textBounds.Height + offsetY));
}
When you run this code you'll get this for output: ClosePointDrawing.png
You'll notice that the text doesn't not look nice (distorted some) and also that the Black stroke outline around the circle is only lined up properly with its Teal color filled circle with the one on the left when using a 1 pixel stroke. The one on the right uses a 2 pixel stroke. You'll also see that the Red Squares are not lined up with the Teal Circle, they should be completely encapsulating it.
Now if you change the first few values in the code so that it doesn't use a large offset as follows:
float x = 0, y = 0;
PointF anchorPoint = new PointF(150, 50);
PointF anchorPoint2 = new PointF(50, 50);
You'll get this for output: ClosePointDrawing2.png
Notice that the Text looks much better, and that the strokes are perfectly lined up with the filled circles as well as the red squares.
Is there anything that can be done, so that it will render it properly with the larger matrix?
hi,
I need to use color tracking.
The blob does not match my target object when I run my code in surface pro 4.
but the code is correct when I test it on my Acer.
anyone knows that why?
public void forobject(Bitmap image)//put setted color value into image1
{
BlobCounter blobCounter = new BlobCounter();
blobCounter.MinWidth = 5;
blobCounter.MinHeight = 5;
blobCounter.FilterBlobs = true;
blobCounter.ObjectsOrder = ObjectsOrder.Size;
//Grayscale griFiltre = new Grayscale(0.2125, 0.7154, 0.0721);
//Grayscale griFiltre = new Grayscale(0.2, 0.2, 0.2);
//Bitmap griImage = griFiltre.Apply(image);
BitmapData objectsData = image.LockBits(new Rectangle(0, 0, image.Width/2, image.Height/2), ImageLockMode.ReadOnly, image.PixelFormat);
// grayscaling
Grayscale grayscaleFilter = new Grayscale(0.2125, 0.7154, 0.0721);
UnmanagedImage grayImage = grayscaleFilter.Apply(new UnmanagedImage(objectsData));
// unlock image
image.UnlockBits(objectsData);
blobCounter.ProcessImage(image);
Rectangle[] rects = blobCounter.GetObjectsRectangles();
Blob[] blobs = blobCounter.GetObjectsInformation();
pictureBox_tracking.Image = image;//????
if (rdiobtn_singletracking.Checked)
{
// Single Tracking--------
foreach (Rectangle recs in rects)
{
if (rects.Length > 0)
{
Rectangle objectRect = rects[0];
//Graphics g = Graphics.FromImage(image);
Graphics g = pictureBox_real.CreateGraphics();
using (Pen pen = new Pen(Color.FromArgb(252, 3, 26), 2))
{
g.DrawRectangle(pen, objectRect);
}
//Drawn by the rectangle coordinates is taken away.
//int objectX = objectRect.X; //+ (objectRect.Width / 2);
//int objectY = objectRect.Y; //+ (objectRect.Height / 2);
x = objectRect.X;
y = objectRect.Y;
w = objectRect.Width;
h = objectRect.Height;
// g.DrawString(objectX.ToString() + "X" + objectY.ToString(), new Font("Arial", 12), Brushes.Red, new System.Drawing.Point(250, 1));
g.Dispose();
}
I'm trying to dynamically change my cursor to a rectangle that is translucent. I have everything worked out except the color of transparency is too pale. It's almost like I need to boost the saturation. I want a high intensity yellow that is translucent. If I increase the matrix33 float toward 1.0 it becomes more opaque. Any ideas how to accomplish this?
Here's my current (nearly) working code.
private Cursor RecCursor(int x, int y)
{
//Cursor CustomCursor = RecCursor(200, 200);
Cursor c = null;
try
{
var pic = new Bitmap(x, y);
Graphics gr = Graphics.FromImage(pic);
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create location and size of rectangle.
float a = 0.0F;
float b = 0.0F;
float width = x;
float height = y;
Color tColor = Color.FromArgb(255, 255, 255, 0);
SolidBrush brush = new SolidBrush(tColor);
//create a Bitmap the size of the image provided
Bitmap bmp = new Bitmap(pic.Width, pic.Height);
//create a graphics object from the image
using (Graphics gfx = Graphics.FromImage(bmp))
{
//create a color matrix object
ColorMatrix matrix = new ColorMatrix();
//set the opacity
matrix.Matrix33 = 0.5f;
//create image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color(opacity) of the image
attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Default);
gr.FillRectangle(brush, a, b, width, height);
gr.DrawRectangle(blackPen, a, b, width, height);
//now draw the image
gfx.DrawImage(pic, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, pic.Width, pic.Height, GraphicsUnit.Pixel, attributes);
}
IntPtr ptr = bmp.GetHicon();
Bitmap bitonalBMP = new Bitmap((int)width, (int)height, PixelFormat.Format1bppIndexed);
//This changes the hotspot of the cursor
IconInfo tmp = new IconInfo();
GetIconInfo(ptr, ref tmp);
tmp.hbmColor = bmp.GetHbitmap();
tmp.hbmMask = bitonalBMP.GetHbitmap();
tmp.xHotspot = 0;
tmp.yHotspot = 0;
tmp.fIcon = false;
ptr = CreateIconIndirect(ref tmp);
c = new Cursor(ptr);
//if (tmp.hbmColor != IntPtr.Zero) DeleteObject(tmp.hbmColor);
//if (tmp.hbmMask != IntPtr.Zero) DeleteObject(tmp.hbmMask);
//if (ptr != IntPtr.Zero) DestroyIcon(ptr);
pic.Dispose();
gr.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return c;
}
Building a little paint program and am trying to incorporate the concept of layers.
I'm using a PictureBox control to display the image, and getting the Graphics object from the image being displayed by the PictureBox and drawing to that.
My problem is I'm trying to figure out how to draw to a new Graphics object that is overlayed on top of the picture box, and be able to get the newly drawn image without the original image absorbed into the graphic.
If I do something like:
Graphics gr = Graphics.FromImage(myPictureBox.image);
gr.DrawRectangle(blah blah)
...I am editing the original image in the picture box. I want a way to only capture the new stuff being drawn as a separate image, but still have it displayed as an overlay over top of what was already there.
Anyone able to point me in the right direction? Thanks!
I would reckon to use the transparent control and do some modification so it can be used as image layers:
http://www.codeproject.com/Articles/26878/Making-Transparent-Controls-No-Flickering
Probably something like this (make any modification as necessary).
class LayerControl : UserControl
{
private Image image;
private Graphics graphics;
public LayerControl(int width, int height)
{
this.Width = width;
this.Height = height;
image = new Bitmap(width, height);
graphics = Graphics.FromImage(image);
// Set style for control
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}
// this function will draw your image
protected override void OnPaint(PaintEventArgs e)
{
var bitMap = new Bitmap(image);
// by default the background color for bitmap is white
// you can modify this to follow your image background
// or create a new Property so it can dynamically assigned
bitMap.MakeTransparent(Color.White);
image = bitMap;
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.GammaCorrected;
float[][] mtxItens = {
new float[] {1,0,0,0,0},
new float[] {0,1,0,0,0},
new float[] {0,0,1,0,0},
new float[] {0,0,0,1,0},
new float[] {0,0,0,0,1}};
ColorMatrix colorMatrix = new ColorMatrix(mtxItens);
ImageAttributes imgAtb = new ImageAttributes();
imgAtb.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(image,
ClientRectangle,
0.0f,
0.0f,
image.Width,
image.Height,
GraphicsUnit.Pixel,
imgAtb);
}
// this function will grab the background image to the control it self
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Graphics g = e.Graphics;
if (Parent != null)
{
BackColor = Color.Transparent;
int index = Parent.Controls.GetChildIndex(this);
for (int i = Parent.Controls.Count - 1; i > index; i--)
{
Control c = Parent.Controls[i];
if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
{
Bitmap bmp = new Bitmap(c.Width, c.Height, g);
c.DrawToBitmap(bmp, c.ClientRectangle);
g.TranslateTransform(c.Left - Left, c.Top - Top);
g.DrawImageUnscaled(bmp, Point.Empty);
g.TranslateTransform(Left - c.Left, Top - c.Top);
bmp.Dispose();
}
}
}
else
{
g.Clear(Parent.BackColor);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, Color.Transparent)), this.ClientRectangle);
}
}
// simple drawing circle function
public void DrawCircles()
{
using (Brush b = new SolidBrush(Color.Red))
{
using (Pen p = new Pen(Color.Green, 3))
{
this.graphics.DrawEllipse(p, 25, 25, 20, 20);
}
}
}
// simple drawing rectable function
public void DrawRectangle()
{
using (Brush b = new SolidBrush(Color.Red))
{
using (Pen p = new Pen(Color.Red, 3))
{
this.graphics.DrawRectangle(p, 50, 50, 40, 40);
}
}
}
// Layer control image property
public Image Image
{
get
{
return image;
}
set
{
image = value;
// this will make the control to be redrawn
this.Invalidate();
}
}
}
Example how to use it:
LayerControl lc = new LayerControl(100, 100);
lc.Location = new Point(0, 0);
lc.DrawRectangle();
LayerControl lc2 = new LayerControl(100, 100);
lc2.Location = new Point(0, 0);
lc2.DrawCircles();
LayerControl lc3 = new LayerControl(100, 100);
lc3.Location = new Point(0, 0);
lc3.Image = new Bitmap(#"<Image Path>");
// adding control
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);
With this method you can have multiple layers that can put overlapping each other (due to the transparency feature it has).
If you want to add it in top of your PictureBox make sure to re-order the control. The Layer Control should be added before your PictureBox control.
// adding control
this.Controls.Clear();
this.Controls.Add(dc);
this.Controls.Add(dc2);
this.Controls.Add(dc3);
this.Controls.Add(PictureBox1);
Hopefully it help.
example code which working fine - take dummy image and layered the original image with custom text
public void LayerImage(System.Drawing.Image Current, int LayerOpacity)
{
Bitmap bitmap = new Bitmap(Current);
int h = bitmap.Height;
int w = bitmap.Width;
Bitmap backg = new Bitmap(w, h + 20);
Graphics g = null;
try
{
g = Graphics.FromImage(backg);
g.Clear(Color.White);
Font font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
RectangleF rectf = new RectangleF(70, 90, 90, 50);
Color color = Color.FromArgb(255, 128, 128, 128);
Point atpoint = new Point(backg.Width / 2, backg.Height - 10);
SolidBrush brush = new SolidBrush(color);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString("BRAND AMBASSADOR", font, brush, atpoint, sf);
g.Dispose();
MemoryStream m = new MemoryStream();
backg.Save(m, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch { }
Color pixel = new Color();
for (int x = 0; x < bitmap.Width; x++)
{
for (int y = 0; y < bitmap.Height; y++)
{
pixel = bitmap.GetPixel(x, y);
backg.SetPixel(x, y, Color.FromArgb(LayerOpacity, pixel));
}
}
MemoryStream m1 = new MemoryStream();
backg.Save(m1, System.Drawing.Imaging.ImageFormat.Jpeg);
m1.WriteTo(Response.OutputStream);
m1.Dispose();
base.Dispose();
}
Got it working, perhaps I wasn't clear enough in my original question.
Essentially what I ended up doing was storing each layer as a separate Image object, then just hooking into the OnPaint method of my control and manually drawing the graphics in order, instead of just drawing to PictureBox.Image. Works like a charm!
The graphics capabilities of .NET drawing libraries are simple. Their main purpose is direct drawing of GUI. If you want to have layering, alpha transparency or advanced filters, then you should either use 3rd party library or roll your own drawing code.