crop detected area from contours emguCV - c#

i am using EmguCv in C# .net framework projec. i have used find contours and draw contours and after that the object is cropped and show in another picture box. the problem is i need the objects detected shape not rectangle shape image.
similar to this solution : How to crop the internal area of a contour?
but in emguCV C#.
here is what i have tried so far.
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
var temp = imgInput.Not().SmoothGaussian(5).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(250), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat m = new Mat();
CvInvoke.FindContours(temp, contours, m, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
Rectangle bbox = CvInvoke.BoundingRectangle(contours[0]); // here is the process of cropping rectangle.
imgInput.ROI = bbox;
var img = imgInput.Copy();
imgInput.ROI = Rectangle.Empty;
pictureBox5.Image = img.Bitmap;
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
//moments center of the shape
var moments = CvInvoke.Moments(contours[i]);
int x = (int)(moments.M10 / moments.M00);
int y = (int)(moments.M01 / moments.M00);
pictureBox4.Image = imgInput.Bitmap;
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

Related

detect diamonds from image in C# EmguCv

i am using C# EmguCv library to detect diamonds from the image capture by a live camera and saved into the folder. i have done other task of the project and only remaining the detection part and almost got it but just missing something that i don't know where is the problem . so here is the Image and it should be detected as Image2 perfect as this image so now i am trying something but it not giving me the result i want. here's i what i am getting is image3 and image4.
here is my code:
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
// Convert image to grayscale
Mat grayImage = new Mat();
CvInvoke.CvtColor(imgInput, grayImage, ColorConversion.Bgr2Gray);
// Apply Gaussian blur to reduce noise
CvInvoke.GaussianBlur(grayImage, grayImage, new Size(7, 7), 4);
// Apply Canny edge detection
Mat edges = new Mat();
CvInvoke.Canny(grayImage, edges, 75, 200);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(edges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
var bbox = CvInvoke.BoundingRectangle(contours[i]);
process_img = new Image<Bgr, byte>(img_path);
process_img.ROI = bbox;
var img = process_img.Copy();
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
byte maxRed, maxBlue, maxGreen;
maxRed = maxBlue = maxGreen = 0;
float meanRed, meanBlue, meanGreen;
meanRed = meanBlue = meanGreen = 0;
double medRed,medBlue,medGreen;
medRed = medBlue = medGreen = 0;
FindMax(img.Bitmap, ref maxRed, ref maxBlue, ref maxGreen, ref meanRed, ref meanBlue, ref meanGreen, ref medRed, ref medBlue, ref medGreen);
R_txtbox.Text = maxRed.ToString();
B_txtbox.Text = maxBlue.ToString();
G_txtbox.Text = maxGreen.ToString();
R_mean.Text = meanRed.ToString();
B_mean.Text = meanBlue.ToString();
G_mean.Text = meanGreen.ToString();
R_med.Text = medRed.ToString();
B_med.Text = medBlue.ToString();
G_med.Text = medGreen.ToString();
pictureBox5.Image = img.ToBitmap();
//colorCode.Text = myRgbColor.ToString();
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
pictureBox4.Image = imgInput.Bitmap;
img.Save("F:\\Objects" + "\\" + (i + 1) + ".jpg");
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

scan a specific area of pixels

i want to check if a pixel, in a certain area, has a certain color.
Currently i can only check the middle of my Screen. But i realized that i would rather scan a 10x10 box from the mid of my screen.
This is my code i am actually using at the moment.
Point xy = new Point(Screen.PrimaryScreen.Bounds.Width / 2 + 1, Screen.PrimaryScreen.Bounds.Height / 2 + 1);
Color GetPixel(Point position)
{
using (var bitmap = new Bitmap(1, 1))
{
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.CopyFromScreen(position, new Point(0, 0), new Size(1, 1));
}
return bitmap.GetPixel(0, 0);
}
}
color = GetPixel(xy);
Color purple = Color.FromArgb(255,254,93,255);
if (color.Equals(purple) == true).....
Is there a option of scanning a box from 10x10 for the color purple and return true when the color is in this box?
Try using this function:
private bool ContainsColor(Point StartPosition, int BoxSize, Color ColorToScanFor)
{
using (Bitmap image = new Bitmap(BoxSize, BoxSize))
{
using (Graphics graphics = Graphics.FromImage(image))
{
graphics.CopyFromScreen(StartPosition, Point.Empty, new Size(BoxSize, BoxSize));
for (int X = 0; X < image.Width; X++)
{
for (int Y = 0; Y < image.Height; Y++)
{
if (image.GetPixel(X, Y).ToArgb() == ColorToScanFor.ToArgb())
{
return true;
}
}
}
}
}
return false;
}
And when you want to call the function try something like this:
MessageBox.Show(ContainsColor(new Point(0, 0), 10, Color.Black).ToString());

Detecting ellipse from a Mask uing CVInvoke.AbsDiff Method

I have an ellipse which is growing with time.
To detect the ellipse I have used CvInvoke.AbsDiff method .
and I gets an image like this
I want to put this ellipse to fit-ellipse method and gain the radius es of it.
This is the approach I took.
CvInvoke.AbsDiff(First, img, grayscale);
CvInvoke.CvtColor(grayscale, grayscale, ColorConversion.Bgr2Gray);
CvInvoke.GaussianBlur(grayscale, grayscale, new System.Drawing.Size(11, 11), 15, 15);
CvInvoke.Threshold(grayscale, grayscale, Convert.ToInt16(Threshold), Convert.ToInt16(Threshold * 2), ThresholdType.Binary );
Mat element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new System.Drawing.Size(3, 3), new System.Drawing.Point(-1, -1));
CvInvoke.Dilate(grayscale, grayscale, element, new System.Drawing.Point(-1, 1), 5, BorderType.Constant, new MCvScalar(255, 255, 255));
CvInvoke.Canny(grayscale, grayscale, Threshold, MaxThreshold * 2, 3);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(grayscale, contours, null, RetrType.Ccomp, ChainApproxMethod.ChainApproxTc89Kcos);
double area = 0;
double ContourArea = 0;
int contour = 0;
int CenterX;
int CenterY;
for (int i = 0; i < contours.Size; i++)
{
System.Drawing.Rectangle rec = CvInvoke.BoundingRectangle(contours[i]);
output.Draw(rec, new Bgr(255, 0, 255), 2);
CenterX = ((rec.Width) / 2) + rec.X;
CenterY = ((rec.Height) / 2) + rec.Y;
ContourArea = rec.Width * rec.Height; ;
if ((HWidth - CenterFactor) < CenterX && CenterX < (HWidth + CenterFactor) && (HHeight - CenterFactor) < CenterY && CenterY< (HHeight + CenterFactor) )
{
if (ContourArea < 1000000)
if (area < ContourArea)
{
area = ContourArea;
contour = i;
}
}
}
//if (contour == 0)
//{
// return arr;
//}
System.Drawing.Rectangle rect = CvInvoke.BoundingRectangle(contours[contour]);
output.Draw(rect, new Bgr(0, 255, 0), 3);
But i am not getting the best ellipse everytime. This is the contour which I'm getting
Is there any other way to do this?
Although this method is not completely perfect, this could be a possible direction that you could take.
Mat input = CvInvoke.Imread(#"C:\Users\ajones\Desktop\Images\inputImg.png", ImreadModes.AnyColor);
Mat input2 = input.Clone();
Mat thresh = new Mat();
CvInvoke.GaussianBlur(input, thresh, new System.Drawing.Size(7, 7), 10, 10);
CvInvoke.Threshold(thresh, thresh, 3, 10, ThresholdType.Binary);
CvInvoke.Imshow("The Thresh", thresh);
CvInvoke.WaitKey(0);
Mat output = new Mat();
CvInvoke.CvtColor(thresh, output, ColorConversion.Bgr2Gray);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(output, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);
CvInvoke.DrawContours(input, contours, -1, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image", input);
CvInvoke.WaitKey(0);
int biggest = 0;
int index = 0;
for (int i = 0; i<contours.Size; i++)
{
if (contours[i].Size > biggest)
{
biggest = contours[i].Size;
index = i;
}
}
CvInvoke.DrawContours(input2, contours, index, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image2", input2);
CvInvoke.WaitKey(0);
First blur the image using a Gaussian filter.
Then, using a binary threshold.
Afterwards, find all contours on the image
Finally, all you would need to do is just sort through your contours until you found the biggest one.
Like I said, its not completely perfect, but I should help push you in the right direction.

AccessViolationException in EmguCV

I'm currently scanning few images and store ROIs in a List. Now I loop through the list and check if the ROI has a bar code in it. It works with few images and throws an AccessViolationException at converting mat to image for others and it is not getting caught in the catch block.
The below code is used to check if bar code exists.
List<Mat> subMats = new List<Mat>();
Mat mat = new Mat(image.Mat, enlargeROI(image.Mat,NEWRECTANGLE,PADDING));
subMats.Add(mat);
using (var mImage = new Image<Bgr, byte>(image.Width, image.Height))
{
var barcodeReader = new BarcodeReader();
foreach (var matt in subMats)
{
//TODO : check if the submat is a barcode
try
{
Image<Bgr, byte> img = matt.ToImage<Bgr, byte>(); // EXCEPTION THROWN AT THIS LINE
Bitmap bmp = img.ToBitmap();
if (barcodeReader.Decode(bmp) != null)
{
CvInvoke.Rectangle(image, NEWRECTANGLE, new MCvScalar(0.0, 0.0, 0.0), -1);
}
}
catch (Exception e)
{
Console.WriteLine("**" + e.Message);
}
}
}
The Exception says
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Tried to read it using images like below, but it wouldn't detect the barcodes properly.
public static List<Rectangle> rois = new List<Rectangle>();
rois.Add(NEWRECTANGLE);
using (var mImage = image)
{
var barcodeReader = new BarcodeReader();
int count = 0;
foreach (var roi in rois)
{
//TODO : check if the submat is a barcode
try
{
mImage.ROI = roi;
Bitmap bmp = mImage.ToBitmap();
if (barcodeReader.Decode(bmp) != null)
{
CvInvoke.Rectangle(image, NEWRECTANGLE, new MCvScalar(0.0, 0.0, 0.0), -1);
}
}
catch (Exception e)
{
Console.WriteLine("**" + e.Message);
}
}
}
What could go wrong? Any help would be appreciated.
Thanks.
EDIT
I have identified all my ROIs by finding contours. Looping through the contours I find the rectangles and store them in a List.
CvInvoke.FindContours(fullGrad, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxNone);
for (int i = 0; i < contours.Size; i++)
{
if (CvInvoke.ContourArea(contours[i]) < 2000) {
continue;
}
RotatedRect RECT = CvInvoke.MinAreaRect(contours[i]);
PointF[] VERTIXES = RECT.GetVertices();
int X = (int)VERTIXES[1].X;
int Y = (int)VERTIXES[2].Y;
//OBTAIN RECTANGLE THAT SURROUNDS THE DETECTED CONTOUR
int WIDTH = (int)(VERTIXES[3].X - VERTIXES[1].X);
int HEIGHT = (int)(VERTIXES[0].Y - VERTIXES[2].Y);
Rectangle NEWRECTANGLE = new Rectangle(X, Y, WIDTH, HEIGHT);
Mat mat = new Mat(image.Mat, enlargeROI(image.Mat,NEWRECTANGLE,PADDING));
subMats.Add(mat);

Auto crop a rectangle

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///////////
}
}

Categories