detect diamonds from image in C# EmguCv - c#

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);
}

Related

crop detected area from contours emguCV

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);
}

How to avoid rotation of rects, detected by MinAreaRect?

I am trying to detect text fields on Windows Form but CvInvoke.MinAreaRect(contour) returns rectangle, rotated by -7.29419661 Angle.
My code is
Image<Bgr, Byte> a =
new Image<Bgr, byte>(#"d:/Art/documents/Projects/InputFieldsDetector/Images/Form345_1.PNG");
imageBox1.Image = a;
UMat grayed = new UMat();
CvInvoke.CvtColor(a, grayed, ColorConversion.Bgr2Gray);
imageBox2.Image = grayed;
UMat canny = new UMat();
CvInvoke.Canny(grayed, canny, 50, 200, 3);
imageBox3.Image = canny;
VectorOfVectorOfPoint cnts = new VectorOfVectorOfPoint();
UMat hierarchy = new UMat();
CvInvoke.FindContours(canny, cnts, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
Image<Bgr, Byte> justCountor = a.Clone();
List<string> sizes = new List<string>();
int count = cnts.Size;
for (int i = 0; i < count; i++)
{
VectorOfPoint contour = cnts[i];
var area = CvInvoke.ContourArea(contour);
//if (area > 10000 && area < 15000)
if (area > 200 && area < 300)
{
sizes.Add(area.ToString());
Point[] pts = contour.ToArray();
var forDraw = CvInvoke.MinAreaRect(contour);
// forDraw.Angle = 0;
//forDraw.Center.Y += 10;
justCountor.Draw(forDraw, new Bgr(Color.DarkOrange), 2);
}
}
imageBox4.Image = justCountor;
List<double> result = sizes.Select(x => double.Parse(x)).ToList();
result.Sort();
sizes = result.Select(x => x.ToString()).ToList();
File.WriteAllLines("c:/temp/qqq.txt", sizes);
Original image is:
If I uncomment section
forDraw.Angle = 0;
forDraw.Center.Y += 10;
sizes of detected rects are similar to sizes of fields...
Tell me, please, why returned rects are rotated and how to fix that?
You can see in the Canny output that the algorithm is interpreting the shadows as borders. The easiest way to fix that is prefilter the image with a threshold with a high value near to the white of the box background.
Image<Bgr, Byte> a =
new Image<Bgr, byte>(#"d:/Art/documents/Projects/InputFieldsDetector/Images/Form345_1.PNG");
imageBox1.Image = a;
UMat grayed = new UMat();
CvInvoke.CvtColor(a, grayed, ColorConversion.Bgr2Gray);
imageBox2.Image = grayed;
UMat thresholded = new UMat();
CvInvoke.Threshold(grayed, thresholded, 128, 255, ThresholdType.Binary);
imageBox5.Image = thresholded;
UMat canny = new UMat();
CvInvoke.Canny(thresholded, canny, 50, 200, 3);
imageBox3.Image = canny;
VectorOfVectorOfPoint cnts = new VectorOfVectorOfPoint();
UMat hierarchy = new UMat();
CvInvoke.FindContours(canny, cnts, null, RetrType.Tree, ChainApproxMethod.ChainApproxSimple);
Image<Bgr, Byte> justCountor = a.Clone();
List<string> sizes = new List<string>();
int count = cnts.Size;
for (int i = 0; i < count; i++)
{
VectorOfPoint contour = cnts[i];
var area = CvInvoke.ContourArea(contour);
if (area > 200 && area < 300)
{
sizes.Add(area.ToString());
Point[] pts = contour.ToArray();
var forDraw = CvInvoke.MinAreaRect(contour);
// forDraw.Angle = 0;
//forDraw.Center.Y += 10;
if (forDraw.Angle==0)
justCountor.Draw(forDraw, new Bgr(Color.DarkOrange), 2);
}
}
imageBox4.Image = justCountor;
List<double> result = sizes.Select(x => double.Parse(x)).ToList();
result.Sort();
sizes = result.Select(x => x.ToString()).ToList();
File.WriteAllLines("c:/temp/qqq.txt", sizes);

Finding bitmap inside a bitmap in C# - Doesn't work on a server?

I am trying to automate something with my C# application, for which I use a bitmap detection system to detect if an icon has appeared on screen. This works perfectly on a PC. However, when I put the application on a server, it never works. I am using a Google Cloud instance with a Tesla K80, 2 vcpus running Windows server 2012.
Here is my code:
// Capture the current screen as a bitmap
public static Bitmap CaptureScreen()
{
// Bitmap format
Bitmap ScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
// Capture screen
Graphics GFX = Graphics.FromImage(ScreenCapture);
GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y, 0, 0,
ScreenCapture.Size, CopyPixelOperation.SourceCopy);
return ScreenCapture;
}
// Find a list of all the points of a bitmap within another bitmap
public static List<Point> FindBitmapsEntry(Bitmap SourceBitmap, Bitmap SearchedBitmap)
{
#region Arguments check
if (SourceBitmap == null || SearchedBitmap == null)
throw new ArgumentNullException();
if (SourceBitmap.PixelFormat != SearchedBitmap.PixelFormat)
throw new ArgumentException("Pixel formats aren't equal.");
if (SourceBitmap.Width < SearchedBitmap.Width || SourceBitmap.Height < SearchedBitmap.Height)
throw new ArgumentException("Size of SearchedBitmap is bigger than SourceBitmap!");
#endregion
var PixelFormatSize = Image.GetPixelFormatSize(SourceBitmap.PixelFormat) / 8;
// Copy SourceBitmap to byte array
var SourceBitmapData = SourceBitmap.LockBits(new Rectangle(0, 0, SourceBitmap.Width, SourceBitmap.Height),
ImageLockMode.ReadOnly, SourceBitmap.PixelFormat);
var SourceBitmapByteLength = SourceBitmapData.Stride * SourceBitmap.Height;
var SourceBytes = new byte[SourceBitmapByteLength];
Marshal.Copy(SourceBitmapData.Scan0, SourceBytes, 0, SourceBitmapByteLength);
SourceBitmap.UnlockBits(SourceBitmapData);
// Copy SearchedBitmap to byte array
var SearchingBitmapData =
SearchedBitmap.LockBits(new Rectangle(0, 0, SearchedBitmap.Width, SearchedBitmap.Height),
ImageLockMode.ReadOnly, SearchedBitmap.PixelFormat);
var SearchingBitmapByteLength = SearchingBitmapData.Stride * SearchedBitmap.Height;
var SearchingBytes = new byte[SearchingBitmapByteLength];
Marshal.Copy(SearchingBitmapData.Scan0, SearchingBytes, 0, SearchingBitmapByteLength);
SearchedBitmap.UnlockBits(SearchingBitmapData);
var PointsList = new List<Point>();
// Searching entries, minimizing searching zones
// SourceBitmap.Height - SearchedBitmap.Height + 1
for (var MainY = 0; MainY < SourceBitmap.Height - SearchedBitmap.Height + 1; MainY++)
{
var SourceY = MainY * SourceBitmapData.Stride;
for (var MainX = 0; MainX < SourceBitmap.Width - SearchedBitmap.Width + 1; MainX++)
{
// MainY & MainX - pixel coordinates of SourceBitmap
// SourceY + SourceX = pointer in array SourceBitmap bytes
var SourceX = MainX * PixelFormatSize;
var IsEqual = true;
for (var c = 0; c < PixelFormatSize; c++)
{
// Check through the bytes in pixel
if (SourceBytes[SourceX + SourceY + c] == SearchingBytes[c])
continue;
IsEqual = false;
break;
}
if (!IsEqual) continue;
var ShouldStop = false;
// Find first equation and search deeper
for (var SecY = 0; SecY < SearchedBitmap.Height; SecY++)
{
var SearchY = SecY * SearchingBitmapData.Stride;
var SourceSecY = (MainY + SecY) * SourceBitmapData.Stride;
for (var SecX = 0; SecX < SearchedBitmap.Width; SecX++)
{
// SecX & SecY - coordinates of SearchingBitmap
// SearchX + SearchY = pointer in array SearchingBitmap bytes
var SearchX = SecX * PixelFormatSize;
var SourceSecX = (MainX + SecX) * PixelFormatSize;
for (var c = 0; c < PixelFormatSize; c++)
{
// Check through the bytes in pixel
if (SourceBytes[SourceSecX + SourceSecY + c] == SearchingBytes[SearchX + SearchY + c]) continue;
// Not equal - abort iteration
ShouldStop = true;
break;
}
if (ShouldStop) break;
}
if (ShouldStop) break;
}
if (!ShouldStop) // Bitmap is found
{
PointsList.Add(new Point(MainX, MainY));
}
}
}
return PointsList;
}
And here is how I use it:
Bitmap HighlightBitmap = new Bitmap(Resources.icon);
Bitmap CurrentScreen = CaptureScreen();
List<Point> HighlightPoints = FindBitmapsEntry(CurrentScreen, HighlightBitmap);
with this HighlightPoints[0] is supposed to give me the first point the two bitmaps (icon, screenshot) collide. But as mentioned before, it just doesn't work on the server.
Thanks in advance!
P.S. I am using the server with a RDP so it does have a visual interface to work with

EmguCV SURF - Determine matched pairs of points

I'm currently modifying EmguCV's (Ver 3.0.0.2157) SurfFeature example (Seen here).
I'm trying to determine the amount of matched pairs of points in order to calculate a percentage of similarity between the inputted images.
From what I understand, this information is stored in the mask variable, but I don't know how to access it?
(This question has been asked before here, but the example source code being referenced is using an older version of EmguCV)
Thanks in advance!
p determine matches
public static Image<Bgr, Byte> Draw(Image<Gray, Byte> modelImage, Image<Gray, byte> observedImage, out long matchTime, out int nonofZeroCount)
{
int returnValue = 0;
Stopwatch watch;
HomographyMatrix homography = null;
SURFDetector surfCPU = new SURFDetector(500, false);
VectorOfKeyPoint modelKeyPoints;
VectorOfKeyPoint observedKeyPoints;
Matrix<int> indices;
Matrix<byte> mask;
int k = 2;
double uniquenessThreshold = 0.8;
if (GpuInvoke.HasCuda)
{
GpuSURFDetector surfGPU = new GpuSURFDetector(surfCPU.SURFParams, 0.01f);
using (GpuImage<Gray, Byte> gpuModelImage = new GpuImage<Gray, byte>(modelImage))
//extract features from the object image
using (GpuMat<float> gpuModelKeyPoints = surfGPU.DetectKeyPointsRaw(gpuModelImage, null))
using (GpuMat<float> gpuModelDescriptors = surfGPU.ComputeDescriptorsRaw(gpuModelImage, null, gpuModelKeyPoints))
using (GpuBruteForceMatcher<float> matcher = new GpuBruteForceMatcher<float>(DistanceType.L2))
{
modelKeyPoints = new VectorOfKeyPoint();
surfGPU.DownloadKeypoints(gpuModelKeyPoints, modelKeyPoints);
watch = Stopwatch.StartNew();
// extract features from the observed image
using (GpuImage<Gray, Byte> gpuObservedImage = new GpuImage<Gray, byte>(observedImage))
using (GpuMat<float> gpuObservedKeyPoints = surfGPU.DetectKeyPointsRaw(gpuObservedImage, null))
using (GpuMat<float> gpuObservedDescriptors = surfGPU.ComputeDescriptorsRaw(gpuObservedImage, null, gpuObservedKeyPoints))
using (GpuMat<int> gpuMatchIndices = new GpuMat<int>(gpuObservedDescriptors.Size.Height, k, 1, true))
using (GpuMat<float> gpuMatchDist = new GpuMat<float>(gpuObservedDescriptors.Size.Height, k, 1, true))
using (GpuMat<Byte> gpuMask = new GpuMat<byte>(gpuMatchIndices.Size.Height, 1, 1))
using (Stream stream = new Stream())
{
matcher.KnnMatchSingle(gpuObservedDescriptors, gpuModelDescriptors, gpuMatchIndices, gpuMatchDist, k, null, stream);
indices = new Matrix<int>(gpuMatchIndices.Size);
mask = new Matrix<byte>(gpuMask.Size);
//gpu implementation of voteForUniquess
using (GpuMat<float> col0 = gpuMatchDist.Col(0))
using (GpuMat<float> col1 = gpuMatchDist.Col(1))
{
GpuInvoke.Multiply(col1, new MCvScalar(uniquenessThreshold), col1, stream);
GpuInvoke.Compare(col0, col1, gpuMask, CMP_TYPE.CV_CMP_LE, stream);
}
observedKeyPoints = new VectorOfKeyPoint();
surfGPU.DownloadKeypoints(gpuObservedKeyPoints, observedKeyPoints);
//wait for the stream to complete its tasks
//We can perform some other CPU intesive stuffs here while we are waiting for the stream to complete.
stream.WaitForCompletion();
gpuMask.Download(mask);
gpuMatchIndices.Download(indices);
if (GpuInvoke.CountNonZero(gpuMask) >= 4)
{
int nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints, indices, mask, 1.5, 20);
if (nonZeroCount >= 4)
homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints, observedKeyPoints, indices, mask, 2);
returnValue = nonZeroCount;
}
watch.Stop();
}
}
}
else
{
//extract features from the object image
modelKeyPoints = surfCPU.DetectKeyPointsRaw(modelImage, null);
Matrix<float> modelDescriptors = surfCPU.ComputeDescriptorsRaw(modelImage, null, modelKeyPoints);
watch = Stopwatch.StartNew();
// extract features from the observed image
observedKeyPoints = surfCPU.DetectKeyPointsRaw(observedImage, null);
Matrix<float> observedDescriptors = surfCPU.ComputeDescriptorsRaw(observedImage, null, observedKeyPoints);
BruteForceMatcher<float> matcher = new BruteForceMatcher<float>(DistanceType.L2);
matcher.Add(modelDescriptors);
indices = new Matrix<int>(observedDescriptors.Rows, k);
using (Matrix<float> dist = new Matrix<float>(observedDescriptors.Rows, k))
{
matcher.KnnMatch(observedDescriptors, indices, dist, k, null);
mask = new Matrix<byte>(dist.Rows, 1);
mask.SetValue(255);
Features2DToolbox.VoteForUniqueness(dist, uniquenessThreshold, mask);
}
int nonZeroCount = CvInvoke.cvCountNonZero(mask);
if (nonZeroCount >= 4)
{
nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints, indices, mask, 1.5, 20);
if (nonZeroCount >= 4)
homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints, observedKeyPoints, indices, mask, 2);
}
returnValue = nonZeroCount;
watch.Stop();
}
int p = mask.ManagedArray.OfType<byte>().ToList().Where(q => q == 1).Count();
//Draw the matched keypoints
Image<Bgr, Byte> result = Features2DToolbox.DrawMatches(modelImage, modelKeyPoints, observedImage, observedKeyPoints,
indices, new Bgr(255, 255, 255), new Bgr(255, 255, 255), mask, Features2DToolbox.KeypointDrawType.DEFAULT);
#region draw the projected region on the image
if (homography != null && p > 20)
{ //draw a rectangle along the projected model
Rectangle rect = modelImage.ROI;
PointF[] pts = new PointF[] {
new PointF(rect.Left, rect.Bottom),
new PointF(rect.Right, rect.Bottom),
new PointF(rect.Right, rect.Top),
new PointF(rect.Left, rect.Top)};
homography.ProjectPoints(pts);
result.DrawPolyline(Array.ConvertAll<PointF, Point>(pts, Point.Round), true, new Bgr(Color.Red), 5);
}
#endregion
matchTime = watch.ElapsedMilliseconds;
nonofZeroCount = returnValue;
return result;
}

EmguCV HaarCascade issue

I have developed a working C# face recognition program using EmguCV.
However, if I load "haarcascade_fullbody.xml" instead of "haarcascade_frontalface_alt_tree.xml" I get the almighty Access Violation.
This is the code;
public Bitmap detection(Bitmap Source)
{
List<Image<Gray, byte>> TrainedImages = this.TrainedImages;
List<String> Names = this.Names;
Image<Bgr, byte> ImageFrame = new Image<Bgr, byte>(Source);
Image<Gray, byte> grayFrame = ImageFrame.Convert<Gray, byte>();
Image<Bgr, byte> overlay = new Image<Bgr, byte>(Source.Width, Source.Height);
Graphics FaceCanvas;
List<String> finimg = new List<String>();
//HaarCascade haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
HaarCascade haar = new HaarCascade("haarcascade_fullbody.xml");
var faces = grayFrame.DetectHaarCascade(haar, 1.1, 3, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new System.Drawing.Size(25, 25))[0];
foreach (var face in faces)
{
overlay.Draw(face.rect, new Bgr(System.Drawing.Color.Green), 3);
tempbmp = new Bitmap(100, 100);
FaceCanvas = Graphics.FromImage(tempbmp);
FaceCanvas.DrawImage(grayFrame.ToBitmap(), 0, 0, face.rect, GraphicsUnit.Pixel);
detected.Add(tempbmp);
if (doit)
{
saveBitmap(tempbmp, trainpath, trainnamer.Text);
doit = false;
}
if (doit10)
{
for (int k = 1; k <= 10; k++)
saveBitmap(tempbmp, trainpath, trainnamer.Text);
doit10 = false;
}
try
{
MCvTermCriteria termCrit = new MCvTermCriteria(TrainedImages.ToArray().Length, 0.001);//????????????
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(TrainedImages.ToArray(), Names.ToArray(), 2500, ref termCrit);
MCvFont font = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 0.5d, 0.5d);
String name = recognizer.Recognize(new Image<Gray, byte>(tempbmp));
if (Names.Contains(name) == false)
name = "Stranger";
else
name = removeformat(name);
overlay.Draw(name, ref font, new System.Drawing.Point(face.rect.Left, face.rect.Top - 5), new Bgr(System.Drawing.Color.Green));
finimg.Add(name);
}
catch (IndexOutOfRangeException)
{
MCvFont font = new MCvFont(FONT.CV_FONT_HERSHEY_TRIPLEX, 0.5d, 0.5d);
ImageFrame.Draw("Stranger", ref font, new System.Drawing.Point(face.rect.Left, face.rect.Top - 5), new Bgr(color));
continue;
}
}
detected.Clear();
Bitmap supra = overlay.ToBitmap();
supra.MakeTransparent(System.Drawing.Color.Black);
return supra;
}
Apparently there is a problem with the xml, as any other haarcascade I try to load loads succesfully. I recommend using the HOGDescriptor instead or "haarcascade_mcs_upperbody.xml" for pedestrian detecting.

Categories