I wrote it like this, but the rectangular bars do not appear. How can I detect these bars?
I specified the problem in the picture.
Thank you..
Bitmap bitmap = (Bitmap)panel1.BackgroundImage;
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 1;
blobCounter.MinWidth = 1;
blobCounter.ObjectsOrder = ObjectsOrder.Size;
blobCounter.ProcessImage(bitmap);
Pen yellowPen = new Pen(Color.Red, 6);
Graphics g = Graphics.FromImage(bitmap);
Blob[] blobs = blobCounter.GetObjectsInformation();
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
foreach (var blob in blobs)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blob);
List<IntPoint> cornerPoints;
if (shapeChecker.IsQuadrilateral(edgePoints, out cornerPoints))
{
if (shapeChecker.CheckPolygonSubType(cornerPoints) == PolygonSubType.RectangledTriangle)
{
List<System.Drawing.Point> Points = new List<System.Drawing.Point>();
foreach (var point in cornerPoints)
{
Points.Add(new System.Drawing.Point(point.X, point.Y));
}
g.DrawPolygon(new Pen(Color.Red, 5.0f), Points.ToArray());
bitmap.Save(#"C:\Users\OkanBerk\Desktop\result.png");
}
}
}
panel1.BackgroundImage = bitmap;
panel1.Invalidate();
https://i.stack.imgur.com/PM4mj.jpg
Related
I am trying to create object detection in C# windows form Project using AForge.NET.
I wrote this code:
public void DetectCorners()
{
// Load image and create everything you need for drawing
Bitmap image = new Bitmap(#"C:\Users\ssammour\Desktop\Unbenannt.PNG");
originalPicture.ImageLocation = #"C:\Users\ssammour\Desktop\Unbenannt.PNG";
BlobCounter blobCounter = new BlobCounter();
blobCounter.ProcessImage(image);
Graphics g = this.CreateGraphics();
Blob[] blobs = blobCounter.GetObjectsInformation();
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Pen redPen = new Pen(Color.Red);
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> corners;
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
if (shapeChecker.IsQuadrilateral(edgePoints, out corners))
{
g.DrawPolygon(redPen, ToPointsArray(corners));
image = new Bitmap(image.Width, image.Height, g);
}
}
// Display
newPicture.Image = image;
}
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
System.Drawing.Point[] array = new System.Drawing.Point[points.Count];
return array;
}
the result is always Black photo, I don't know why.
I used this photo to try the code:
but still receive a black photo.
any help? and why is that?
and if you please can tell me how can I detect all objects inside the image.
You are not doing anything in ToPointsArray. You are just returning an array of the same length.
You should do something like this instead (I don't know IntPoint):
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
System.Drawing.Point[] array = new System.Drawing.Point[points.Count];
int i = 0;
foreach (IntPoint p in points)
{
array[i++] = new System.Drawing.Point(p.X, p.Y);
}
return array;
}
Furthermore you are ruining your image in your for loop. This code works:
public void DetectCorners()
{
// Load image and create everything you need for drawing
Bitmap image = new Bitmap(#"C:\Users\ssammour\Desktop\Unbenannt.PNG");
BlobCounter blobCounter = new BlobCounter();
blobCounter.ProcessImage(image);
Bitmap result = new Bitmap(image.Width, image.Height, Graphics.FromImage(image));
Graphics g = Graphics.FromImage(result);
g.DrawImage(image,0,0);
Blob[] blobs = blobCounter.GetObjectsInformation();
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Pen redPen = new Pen(Color.Red);
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> corners;
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
if (shapeChecker.IsQuadrilateral(edgePoints, out corners))
{
corners.Dump();
g.DrawPolygon(redPen, ToPointsArray(corners, image.Height));
}
}
result.Save(#"c:\result.png", ImageFormat.Png);
}
I get these points:
(0 0),(574 0),(574 398),(0 398)
(161 391),(162 390),(165 393),(165 394)
(301 394),(304 392),(310 398),(303 398)
(552 398),(558 392),(561 392),(562 398)
(155 397),(156 396),(157 398),(155 398)
So, it looks like the BlobCounter doesn't find the blobs you are looking for.
I try to write simple shape detection app. I'm using sample from Aforge.net library. But I always get same error:
cannot convert from 'AForge.Point[]' to 'System.Drawing.PointF[]'
I try to change some things in ImageProcess method as well as in ToPointsArray, but effect is always the same. What else can I try? What I do wrong?
Here is code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
ProcessImage((Bitmap)Bitmap.FromFile(openFileDialog1.FileName));
}
catch
{
MessageBox.Show("Załadowanie obrazu niepowiodło się.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void ProcessImage(Bitmap bitmap)
{
//-------------------------------------
BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
//-------------------------------------
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);
//-------------------------------------
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 5;
blobCounter.MinWidth = 5;
blobCounter.ProcessImage(bitmapData);
Blob[] blobs = blobCounter.GetObjectsInformation();
bitmap.UnlockBits(bitmapData);
//-------------------------------------
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Graphics g = Graphics.FromImage(bitmap);
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]);
{
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.Unknown)
{
pen = (corners.Count == 4) ? redPen : bluePen;
}
else
{
pen = (corners.Count == 4) ? brownPen : greenPen;
}
g.DrawPolygon(pen, ToPointsArray(corners));
}
}
}
redPen.Dispose();
greenPen.Dispose();
bluePen.Dispose();
brownPen.Dispose();
g.Dispose();
// put new image to clipboard
Clipboard.SetDataObject(bitmap);
// and to picture box
pictureBox1.Image = bitmap;
UpdatePictureBoxPosition();
}
private Point[] ToPointsArray(List<IntPoint> points)
{
Point[] array = new Point[points.Count];
for (int i = 0, n = points.Count; i < n; i++)
{
array[i] = new Point(points[i].X, points[i].Y);
}
return array;
}
Your problem is that AForge have there own Point struct so your ToPointArray method actually returns an Aforge Points array rather than an array of the needed .net Point. The simplest solution is to fully qualify the type you want to use, so your method would become
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
System.Drawing.Point[] array = new System.Drawing.Point[points.Count];
...
}
Alternatively, if you wanted to save a few characters you could alias the namespace with a using statement at the top of the class.
using NetPoint = System.Drawing.Point;
private NetPoint ToPointsArray(List<IntPoint> points)
{
NetPoint array = new NetPoint[points.Count];
...
}
As a side note this method could be shortened if linq is available to use. For example,
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
return points.Select(p => new System.Drawing.Point(p.X, p.Y)).ToArray();
}
For me the Aforge rectangle detection gives completely false coordinates.
Here's my code:
public List<System.Drawing.Rectangle> Detect(string path)
{
var image = GetImage(path);
var blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinWidth = 50;
blobCounter.MinHeight = 50;
blobCounter.ProcessImage(image);
var rects = blobCounter.GetObjectsRectangles();
return rects.ToList();
}
public System.Drawing.Bitmap GetImage(string path)
{
BitmapSource bSource = new BitmapImage(new Uri(path));
var image = Helpers.BitmapConverter.GetBitmap(bSource);
return image;
}
and my test image is this:
I've also tried reverting the colors, but nothing seems to help.
I always get just: {X = 16 Y = 42 Width = 51 Height = 141} That is obviously wrong for that rectangle in the image. How do I use Aforge to detect rectangles?
By using the AForge BlobCounter class GetObjectsInformation method.
Using the image provided, a snippet of the code provided in a simple Windows Forms Application with a picture box and a button I was able to detect the rectangle by drawing a lime green line over the original image using the following code.
//after pictureBox1's image has been set to the provided image.
Bitmap image = new Bitmap(pictureBox1.Image);
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinWidth = 50;
blobCounter.MinHeight = 50;
blobCounter.ProcessImage(image);
Blob[] blobs = blobCounter.GetObjectsInformation();
Blob blob = blobs[0];
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Graphics g = Graphics.FromImage(image);
Pen redPen = new Pen(Color.Red, 2);
Pen greenPen = new Pen(Color.Lime, 2);
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blob);
List<IntPoint> corners;
if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
{
PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
Pen pen;
if (subType == PolygonSubType.Unknown)
{
pen = (corners.Count == 4) ? redPen : redPen;
}
else
{
pen = greenPen;
}
System.Drawing.Point[] array = new System.Drawing.Point[corners.Count];
for (int i = 0, n = corners.Count; i < n; i++)
{
array[i] = new System.Drawing.Point(corners[i].X + 1, corners[i].Y + 1);
}
g.DrawPolygon(pen, array);
}
redPen.Dispose();
greenPen.Dispose();
g.Dispose();
pictureBox1.Image = image;
pictureBox1.Width = image.Width;
pictureBox1.Height = image.Height;
Provided Image
Processed Image
I'm trying to draw on an image
Graphics g = Graphics.FromImage(BWImage);
Pen red = new Pen(Color.Red, 2);
foreach (Blob blob in blobs)
{
List<IntPoint> leftPoints, rightPoints, edgePoints = new List<IntPoint>();
// get blob's edge points
blobCounter.GetBlobsLeftAndRightEdges(blob,
out leftPoints, out rightPoints);
edgePoints.AddRange(leftPoints);
edgePoints.AddRange(rightPoints);
// blob's convex hull
List<IntPoint> hull = hullFinder.FindHull(edgePoints);
g.DrawPolygon(red, ToPointsArray(hull));
}
I get frames from a webcam, and for each frame I do some processing then do that code, but it didn't work, I tried to debug it, I found that the line
Graphics g = Graphics.FromImage(BWImage);
It keeps executing forever without executing any line after it!
Any help please? Thanks.
Here is my code
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bitmap = (Bitmap)eventArgs.Frame.Clone();
ProcessImage(bitmap);
}
and the ProcessImage method:
#region Skin Detection
YCbCrFiltering YCbCrFilter = new YCbCrFiltering();
YCbCrFilter.Y = new Range(0, 1);
YCbCrFilter.Cb = new Range(-0.1862745098039216f, 0.0294117647058824f);
YCbCrFilter.Cr = new Range(0.0137254901960784f, 0.2254901960784314f);
// apply the filter
var YCbCrFilteredImage = YCbCrFilter.Apply(bitmap);
#endregion
#region GrayScale
// create grayscale filter (BT709)
Grayscale Gray_filter = new Grayscale(0.2125, 0.7154, 0.0721);
// apply the filter
Bitmap grayImage = Gray_filter.Apply(YCbCrFilteredImage);
Threshold threshold = new Threshold(50);
Bitmap BWImage = threshold.Apply(grayImage);
#endregion
#region Remove noise
// create filter
BlobsFiltering BlobsFilteringfilter = new BlobsFiltering();
// configure filter
BlobsFilteringfilter.CoupledSizeFiltering = true;
BlobsFilteringfilter.MinWidth = 150;
BlobsFilteringfilter.MinHeight = 150;
BlobsFilteringfilter.MaxHeight = 600;
BlobsFilteringfilter.MaxWidth = 600;
// apply the filter
var BWImageFiltered = BlobsFilteringfilter.Apply(BWImage);
#endregion
#region Fill Holes
FillHoles FillHolesfilter = new FillHoles();
FillHolesfilter.MaxHoleHeight = 50;
FillHolesfilter.MaxHoleWidth = 50;
FillHolesfilter.CoupledSizeFiltering = false;
var BWImageFilteredHoles = FillHolesfilter.Apply(BWImageFiltered);
#endregion
#region Contouring
// process image with blob counter
BlobCounter blobCounter = new BlobCounter();
blobCounter.ProcessImage(BWImageFilteredHoles);
Blob[] blobs = blobCounter.GetObjectsInformation();
Graphics g = Graphics.FromImage(BWImageFilteredHoles);
Pen red = new Pen(Color.Red, 2);
// create convex hull searching algorithm
GrahamConvexHull hullFinder = new GrahamConvexHull();
foreach (Blob blob in blobs)
{
List<IntPoint> AllEdgesPoints = new List<IntPoint>();
List<IntPoint> leftPoints, rightPoints, edgePoints = new List<IntPoint>();
// get blob's edge points
blobCounter.GetBlobsLeftAndRightEdges(blob,
out leftPoints, out rightPoints);
edgePoints.AddRange(leftPoints);
edgePoints.AddRange(rightPoints);
// blob's convex hull
List<IntPoint> hull = hullFinder.FindHull(edgePoints);
g.DrawPolygon(red, ToPointsArray(hull));
g.Dispose();
#endregion
pictureBox1.Image = grayImage;
pictureBox2.Image = BWImage;
}
Is there an exception handler around this code that isn't shown? Graphics.FromImage() should be throwing an exception because you're passing an image with an indexed pixel format; Grayscale.Apply() returns an image with Format8bppIndexed, and BlobsFiltering.Apply() would preserve that.
Bottom line, you need to create a new Bitmap with the same size as BWImage, get your Graphics from that, paint BWImage onto the new image, then rectangle your blobs.
I have a requirement wherein I need to merge two different png/jpeg images resulting into a single image using C#.Net. There will be a particular location defined on the source image wherein I need to insert another image. Can anybody suggest some links ?
This method merge two images one in the top of the other you can modify the code to meet for your needs:
public static Bitmap MergeTwoImages(Image firstImage, Image secondImage)
{
if (firstImage == null)
{
throw new ArgumentNullException("firstImage");
}
if (secondImage == null)
{
throw new ArgumentNullException("secondImage");
}
int outputImageWidth = firstImage.Width > secondImage.Width ? firstImage.Width : secondImage.Width;
int outputImageHeight = firstImage.Height + secondImage.Height + 1;
Bitmap outputImage = new Bitmap(outputImageWidth, outputImageHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(outputImage))
{
graphics.DrawImage(firstImage, new Rectangle(new Point(), firstImage.Size),
new Rectangle(new Point(), firstImage.Size), GraphicsUnit.Pixel);
graphics.DrawImage(secondImage, new Rectangle(new Point(0, firstImage.Height + 1), secondImage.Size),
new Rectangle(new Point(), secondImage.Size), GraphicsUnit.Pixel);
}
return outputImage;
}
After all this, I found a new easier method try this ..
It can join multiple photos together:
public static System.Drawing.Bitmap CombineBitmap(string[] files)
{
//read all images into memory
List<System.Drawing.Bitmap> images = new List<System.Drawing.Bitmap>();
System.Drawing.Bitmap finalImage = null;
try
{
int width = 0;
int height = 0;
foreach (string image in files)
{
//create a Bitmap from the file and add it to the list
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);
//update the size of the final bitmap
width += bitmap.Width;
height = bitmap.Height > height ? bitmap.Height : height;
images.Add(bitmap);
}
//create a bitmap to hold the combined image
finalImage = new System.Drawing.Bitmap(width, height);
//get a graphics object from the image so we can draw on it
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
{
//set background color
g.Clear(System.Drawing.Color.Black);
//go through each image and draw it on the final image
int offset = 0;
foreach (System.Drawing.Bitmap image in images)
{
g.DrawImage(image,
new System.Drawing.Rectangle(offset, 0, image.Width, image.Height));
offset += image.Width;
}
}
return finalImage;
}
catch (Exception)
{
if (finalImage != null)
finalImage.Dispose();
//throw ex;
throw;
}
finally
{
//clean up memory
foreach (System.Drawing.Bitmap image in images)
{
image.Dispose();
}
}
}
Disclaimer: I work at Atalasoft
Our DotImage Photo SDK (which is free) can do this.
To open an image
AtalaImage botImage = new AtalaImage("bottomImage.png");
AtalaImage topImage = new AtalaImage("topImage.png");
To overlay one on top of another
Point pos = new Point(0,0); // or whatever you need
OverlayCommand cmd = new OverlayCommand(topImage, pos);
ImageResults res = cmd.Apply(botImage);
If you need the resulting image to be a different size, look at the CanvasCommand. You could also create an AtalaImage of the size you need, then overlay each image onto it.
To save
botImage.Save("newImage.png", new PngEncoder(), null);
String jpg1 = #"c:\images.jpeg";
String jpg2 = #"c:\images2.jpeg";
String jpg3 = #"c:\image3.jpg";
Image img1 = Image.FromFile(jpg1);
Image img2 = Image.FromFile(jpg2);
int width = img1.Width + img2.Width;
int height = Math.Max(img1.Height, img2.Height);
Bitmap img3 = new Bitmap(width, height);
Graphics g = Graphics.FromImage(img3);
g.Clear(Color.Black);
g.DrawImage(img1, new Point(0, 0));
g.DrawImage(img2, new Point(img1.Width, 0));
g.Dispose();
img1.Dispose();
img2.Dispose();
img3.Save(jpg3, System.Drawing.Imaging.ImageFormat.Jpeg);
img3.Dispose();
private void Merge _Click(object sender, EventArgs e)
{
}
DirectoryInfo directory=new DirectoryInfo("D:\\Images");
if(directory!=null)
{
FileInfo[]files = directory.GetFiles();
MergeImages(Image);
}
private void MergeImages(FileInfo[] Image)
{
//change the location to store the final image.
string FImage= #"D:\\Images\\FImage.jpg";
List imageHeights = new List();
int nIndex = 0;
int width = 0;
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
imageHeights.Add(img.Height);
width += img.Width;
img.Dispose();
}
imageHeights.Sort();
int height = imageHeights[imageHeights.Count - 1];
Bitmap NewImg = new Bitmap(width, height);
Graphics Gr= Graphics.FromImage(NewImg);
Gr.Clear(SystemColors.AppWorkspace);
foreach (FileInfo file in files)
{
Image img = Image.FromFile(file.FullName);
if (nIndex == 0)
{
Gr.DrawImage(img, new Point(0, 0));
nIndex++;
width = img.Width;
}
else
{
Gr.DrawImage(img, new Point(width, 0));
width += img.Width;
}
img.Dispose();
}
Gr.Dispose();
NewImg .Save(FImage, System.Drawing.Imaging.ImageFormat.Jpeg);
NewImg .Dispose();
imageLocation.Image = Image.FromFile(FImage);
}