I need to draw two types of histogram, namely monodimensional and tridimensional.
I'm a newbie to EMGU and all of the samples I found on the net are in C++ or C. Are there any samples using C# and Emgucv?
Thanks for helping.
The following code will segment the RED GREEN and BLUE Histogram data and put them in an array of floats for whatever use you want.
float[] BlueHist;
float[] GreenHist;
float[] RedHist;
Image<Bgr, Byte> img = new Image<Bgr, byte>("ImageFileName");
DenseHistogram Histo = new DenseHistogram(255, new RangeF(0, 255));
Image<Gray, Byte> img2Blue = img[0];
Image<Gray, Byte> img2Green = img[1];
Image<Gray, Byte> img2Red = img[2];
Histo.Calculate(new Image<Gray, Byte>[] { img2Blue }, true, null);
//The data is here
//Histo.MatND.ManagedArray
BlueHist = new float[256];
Histo.MatND.ManagedArray.CopyTo(BlueHist, 0);
Histo.Clear();
Histo.Calculate(new Image<Gray, Byte>[] { img2Green }, true, null);
GreenHist = new float[256];
Histo.MatND.ManagedArray.CopyTo(GreenHist, 0);
Histo.Clear();
Histo.Calculate(new Image<Gray, Byte>[] { img2Red }, true, null);
RedHist = new float[256];
Histo.MatND.ManagedArray.CopyTo(RedHist, 0);
and this will do the greyscale histogram:
float[] GrayHist;
Image<Gray, Byte> img_gray = new Image<Gray, byte>("ImageFileName");
Histo.Calculate(new Image<Gray, Byte>[] { img_gray }, true, null);
//The data is here
//Histo.MatND.ManagedArray
GrayHist = new float[256];
Histo.MatND.ManagedArray.CopyTo(GrayHist, 0);
Hope this helps,
Cheers,
Chris
[Edit]
To draw the histogram you will need to use either you own or a designed controls such as Zedgraph (This is supplied with with EMGU) here is a very good article on codeproject that shows it's use.
http://www.codeproject.com/KB/graphics/zedgraph.aspx
Cheers
Chris
Displaying Histograms in Emgu is super easy and fun. Just make a histogramBox control on your form, then call this in your loop and you are done.
histogramBox1.ClearHistogram();
histogramBox1.GenerateHistograms(frame, 256);
histogramBox1.Refresh();
Tridimensional histogram
Image<Bgr, Byte>[] inp = new Image<Bgr, byte>("fileName.jpg");
int nBins = 256;
DenseHistogram hist = new DenseHistogram(new int[] { nBins, nBins, nBins }, new RangeF[] { new RangeF(0, 255), new RangeF(0, 255), new RangeF(0, 255) });
hist.Calculate(inp.Split(), false, null);
// To get value of single bin
int b = 255; int g = 0; int r = 0; //blue
int count = Convert.ToInt32(hist.MatND.ManagedArray.GetValue(b, g, r)); //count = no of pixels in color Bgr(b,g,r)
//To get all values in a single array
List<Tuple<Bgr, int>> histVal = new List<Tuple<Bgr, int>>(nBins * nBins * nBins);
for (int i = 0; i < nBins; i++)
for (int j = 0; j < nBins; j++)
for (int k = 0; k < nBins; k++)
histVal.Add(new Tuple<Bgr, int>(new Bgr(i, j, k), Convert.ToInt32(hist.MatND.ManagedArray.GetValue(i, j, k))));
Monodimensional histogram
int nBins = 256;
float[] valHist = new float[nBins];
Image<Gray, Byte>[] inp = new Image<Gray, byte>("fileName.jpg");
DenseHistogram hist = new DenseHistogram(nBins, new RangeF(0, 255));
hist.Calculate(new Image<Gray, Byte>[] { inp }, true, null);
hist.MatND.ManagedArray.CopyTo(valHist,0);
It is important to follow the procedure to add the Emgu.CV.UI.dll to your toolbox in Windows Forms in order to use all of the Windows Forms controls that Emgu CV provides (HistogramBox included.)
First of all you need to open your form in designer view. From Toolbox, right click in the empty space of 'General' column. This should pop up a selection menu, where 'Choose Items' selection is available, see image below.
Afterwards, click on 'Choose Items'; you will see a 'Choose Toolbox Item' Dialog. From there click the 'Browse..' button on the lower right corner of the dialog.
Select 'Emgu.CV.UI.dll' file from 'Open' dialog, click the 'Open' button.
Now you should notice the ImageBox control has been added to the 'Choose Toolbox Items' dialog. Click 'Ok'. Then you should note the following controls added to your Toolbox (Applies for version 3.10 of Emgu. Some other versions of Emgu may have other controls or lack the controls mentioned below.)
HistogramBox
ImageBox
MatrixBox
PanAndZoomPictureBox.
Then you should be able to drag and drop to your form as you see fit the Windows Forms controls that Emgu CV has built-it. Or you should be able to use them programmatically:
Form frm = new Form();
var img = CvInvoke.Imread(this.PictureBox.ImageLocation, Emgu.CV.CvEnum.LoadImageType.Grayscale).ToImage<Gray, Byte>();
HistogramBox histo = new HistogramBox();
histo.ClearHistogram();
histo.GenerateHistograms(img, 256);
histo.Dock = DockStyle.Fill;
histo.Refresh();
frm.Controls.Add(histo);
frm.ShowDialog();
This answer was inspired in the Add Image Box Control tutorial.
Related
I would like to merge multiple small images to create a big image. As I have a lot of small image I would like to use threads.
OpenCV allows to select an ROI, so I would like to copy a small image in a predefined ROI.
The problem is that by using threads, the ROI changes before having had time to copy the small image into the large one.
To illustrate this problem I have the following code:
private void Test()
{
int size = 256;
//Create RGB Image
Image<Bgr, byte> R = new Image<Bgr, byte>(size, size, new Bgr(Color.Red));
Image<Bgr, byte> G = new Image<Bgr, byte>(size, size, new Bgr(Color.Green));
Image<Bgr, byte> B = new Image<Bgr, byte>(size, size, new Bgr(Color.Blue));
Image<Bgr, byte>[] imageArray = new Image<Bgr, byte>[3] { R, G, B};
Image<Bgr, byte> merger = new Image<Bgr, byte>(size * 3, size, new Bgr(Color.Black));
// Create final image with thread
Parallel.For(0, imageArray.Length, i =>
{
merger.ROI = new Rectangle(i * 256, 0, size, size);
imageArray[i].CopyTo(merger);
});
merger.ROI = Rectangle.Empty;
//Show the image
Utils.ShowImage(merger);
//Free
for (int i = 0; i < 3; i++)
imageArray[i].Dispose();
merger.Dispose();
}
I create 3 small images, one red, one green, one blue. I merge these 3 images into one to create this result:
But with threads I have the following result:
Is there a way to select multiple ROIs and keep the benefit of the threads?
I'm trying to detect contour of an ellipse-like water droplet with Emgu CV. I wrote code for contour detection:
public List<int> GetDiameters()
{
string inputFile = #"path.jpg";
Image<Bgr, byte> imageInput = new Image<Bgr, byte>(inputFile);
Image<Gray, byte> grayImage = imageInput.Convert<Gray, byte>();
Image<Gray, byte> bluredImage = grayImage;
CvInvoke.MedianBlur(grayImage, bluredImage, 9);
Image<Gray, byte> edgedImage = bluredImage;
CvInvoke.Canny(bluredImage, edgedImage, 50, 5);
Image<Gray, byte> closedImage = edgedImage;
Mat kernel = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Ellipse, new System.Drawing.Size { Height = 100, Width = 250}, new System.Drawing.Point(-1, -1));
CvInvoke.MorphologyEx(edgedImage, closedImage, Emgu.CV.CvEnum.MorphOp.Close, kernel, new System.Drawing.Point(-1, -1), 0, Emgu.CV.CvEnum.BorderType.Replicate, new MCvScalar());
System.Drawing.Point(100, 250), 10000, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar()
Image<Gray, byte> contoursImage = closedImage;
Image<Bgr, byte> imageOut = imageInput;
VectorOfVectorOfPoint rescontours1 = new VectorOfVectorOfPoint();
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
CvInvoke.FindContours(contoursImage, contours, null, Emgu.CV.CvEnum.RetrType.List,
Emgu.CV.CvEnum.ChainApproxMethod.LinkRuns);
MCvScalar color = new MCvScalar(0, 0, 255);
int count = contours.Size;
for (int i = 0; i < count; i++)
{
using (VectorOfPoint contour = contours[i])
using (VectorOfPoint approxContour = new VectorOfPoint())
{
CvInvoke.ApproxPolyDP(contour, approxContour,
0.01 * CvInvoke.ArcLength(contour, true), true);
var area = CvInvoke.ContourArea(contour);
if (area > 0 && approxContour.Size > 10)
{
rescontours1.Push(approxContour);
}
CvInvoke.DrawContours(imageOut, rescontours1, -1, color, 2);
}
}
}
}
result so far:
I think there is a problem with approximation. How to get rid of internal lines and close external contour?
I might need some more information to exactly pinpoint your issue, but it might be something to do with your median blur. I would see if you are blurring enough that EmguCV things the blur is enough that you can canny edge detection. Another method that you could use is Dilate. Try Dialating your Canny edge detection and see if you get any better results.
EDIT
Here is the code below
public List<int> GetDiameters()
{
//List to hold output diameters
List<int> diametors = new List<int>();
//File path to where the image is located
string inputFile = #"C:\Users\jones\Desktop\Image Folder\water.JPG";
//Read in the image and store it as a mat object
Mat img = CvInvoke.Imread(inputFile, Emgu.CV.CvEnum.ImreadModes.AnyColor);
//Mat object that will hold the output of the gaussian blur
Mat gaussianBlur = new Mat();
//Blur the image
CvInvoke.GaussianBlur(img, gaussianBlur, new System.Drawing.Size(21, 21), 20, 20, Emgu.CV.CvEnum.BorderType.Default);
//Mat object that will hold the output of the canny
Mat canny = new Mat();
//Canny the image
CvInvoke.Canny(gaussianBlur, canny, 40, 40);
//Mat object that will hold the output of the dilate
Mat dilate = new Mat();
//Dilate the canny image
CvInvoke.Dilate(canny, dilate, null, new System.Drawing.Point(-1, -1), 6, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));
//Vector that will hold all found contours
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
//Find the contours and draw them on the image
CvInvoke.FindContours(dilate, contours, null, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
CvInvoke.DrawContours(img, contours, -1, new MCvScalar(255, 0, 0), 5, Emgu.CV.CvEnum.LineType.FourConnected);
//Variables to hold relevent info on what is the biggest contour
int biggest = 0;
int index = 0;
//Find the biggest contour
for (int i = 0; i < contours.Size; i++)
{
if (contours.Size > biggest)
{
biggest = contours.Size;
index = i;
}
}
//Once all contours have been looped over, add the biggest contour's index to the list
diametors.Add(index);
//Return the list
return diametors;
}
The first thing you do is blur the image.
Then you canny the image.
Then you dilate the image, as to make the final output contours more uniform.
Then you just find contours.
I know the final contours are a little bigger than the water droplet, but this is the best that I could come up with. You can probably fiddle around with some of the settings and the code above to make the result a little cleaner.
My application gets closed when it reaches at creating the recognizer object of EigenObjectRecognizer class without giving any error or warning , am I passing wrong parameters or there is some other problem ? Here is my code
string[] allFaces = Directory.GetFiles(savepath);
if (allFaces != null)
{
Image<Gray, Byte>[] trainingImages = new Image<Gray, Byte>[allFaces.Length];
string[] labels = new String[allFaces.Length];
for (int i = 0; i < allFaces.Length; i++)
{
trainingImages[i] = new Image<Gray, byte>(new Bitmap(allFaces[i]));
labels[i] = allFaces[i].Substring(allFaces[i].LastIndexOf("\\")+1);
}
MCvTermCriteria termCrit = new MCvTermCriteria(allFaces.Length, 0.001);
EigenObjectRecognizer recognizer = new EigenObjectRecognizer(
trainingImages,
labels,
1000,
ref termCrit);
Image<Gray, Byte> testImage = new Image<Gray, Byte>(#"C:\..test\1");
string label = recognizer.Recognize(testImage).Label;
MessageBox.Show(label);
}
Solved the problem by getting an error from raw run of the compiled exe which gave an error of input of not same size from opencv instead of emgucv . When I looked at my training images they were of different size. Hope it helps others
I have an image of a "windows control" lets say a Text-box and I want to get background color of the text written within the text box by finding max color occurred in that picture by pixel color comparison.
I searched in google and I found that every one is talking about histogram and also some code is given to find out histogram of an image but no one described the procedure after finding histogram.
the code I found on some sites is like
// Create a grayscale image
Image<Gray, Byte> img = new Image<Gray, byte>(bmp);
// Fill image with random values
img.SetRandUniform(new MCvScalar(), new MCvScalar(255));
// Create and initialize histogram
DenseHistogram hist = new DenseHistogram(256, new RangeF(0.0f, 255.0f));
// Histogram Computing
hist.Calculate<Byte>(new Image<Gray, byte>[] { img }, true, null);
Currently I have used the code which takes a line segment from the image and finds the max color but which is not the right way to do it.
the currently used code is as follows
Image<Bgr, byte> image = new Image<Bgr, byte>(temp);
int height = temp.Height / 2;
Dictionary<Bgr, int> colors = new Dictionary<Bgr, int>();
for (int i = 0; i < (image.Width); i++)
{
Bgr pixel = new Bgr();
pixel = image[height, i];
if (colors.ContainsKey(pixel))
colors[pixel] += 1;
else
colors.Add(pixel, 1);
}
Bgr result = colors.FirstOrDefault(x => x.Value == colors.Values.Max()).Key;
please help me if any one knows how to get it. Take this image as input ==>
Emgu.CV's DenseHistogram exposes the method MinMax() which finds the maximum and minimum bin of the histogram.
So after computing your histogram like in your first code snippet:
// Create a grayscale image
Image<Gray, Byte> img = new Image<Gray, byte>(bmp);
// Fill image with random values
img.SetRandUniform(new MCvScalar(), new MCvScalar(255));
// Create and initialize histogram
DenseHistogram hist = new DenseHistogram(256, new RangeF(0.0f, 255.0f));
// Histogram Computing
hist.Calculate<Byte>(new Image<Gray, byte>[] { img }, true, null);
...find the peak of the histogram with this method:
float minValue, maxValue;
Point[] minLocation;
Point[] maxLocation;
hist.MinMax(out minValue, out maxValue, out minLocation, out maxLocation);
// This is the value you are looking for (the bin representing the highest peak in your
// histogram is the also the main color of your image).
var mainColor = maxLocation[0].Y;
I found a code snippet in stackoverflow which does my work.
code goes like this
int BlueHist;
int GreenHist;
int RedHist;
Image<Bgr, Byte> img = new Image<Bgr, byte>(bmp);
DenseHistogram Histo = new DenseHistogram(255, new RangeF(0, 255));
Image<Gray, Byte> img2Blue = img[0];
Image<Gray, Byte> img2Green = img[1];
Image<Gray, Byte> img2Red = img[2];
Histo.Calculate(new Image<Gray, Byte>[] { img2Blue }, true, null);
double[] minV, maxV;
Point[] minL, maxL;
Histo.MinMax(out minV, out maxV, out minL, out maxL);
BlueHist = maxL[0].Y;
Histo.Clear();
Histo.Calculate(new Image<Gray, Byte>[] { img2Green }, true, null);
Histo.MinMax(out minV, out maxV, out minL, out maxL);
GreenHist = maxL[0].Y;
Histo.Clear();
Histo.Calculate(new Image<Gray, Byte>[] { img2Red }, true, null);
Histo.MinMax(out minV, out maxV, out minL, out maxL);
RedHist = maxL[0].Y;
I am new to EmguCV and OpenCV. I want to detect the text Regions from an Image using EmguCV.
There are already some solutions posted on Stack using OpenCV.
Extracting text OpenCV
But unable to convert that OpenCV code to EmguCV.
Here is a direct conversion of the accepted answer in the link you provided into c# with EMGU. You might have to make some alterations since its a slightly different implementation but it should get you started. I also doubt it is a very robust so depending on your specific use it might not be suitable. Best of luck.
public List<Rectangle> detectLetters(Image<Bgr, Byte> img)
{
List<Rectangle> rects = new List<Rectangle>();
Image<Gray, Single> img_sobel;
Image<Gray, Byte> img_gray, img_threshold;
img_gray = img.Convert<Gray, Byte>();
img_sobel = img_gray.Sobel(1,0,3);
img_threshold = new Image<Gray, byte>(img_sobel.Size);
CvInvoke.cvThreshold(img_sobel.Convert<Gray, Byte>(), img_threshold, 0, 255, Emgu.CV.CvEnum.THRESH.CV_THRESH_OTSU);
StructuringElementEx element = new StructuringElementEx(3, 17, 1, 6, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT);
CvInvoke.cvMorphologyEx(img_threshold, img_threshold, IntPtr.Zero, element, Emgu.CV.CvEnum.CV_MORPH_OP.CV_MOP_CLOSE, 1);
for (Contour<System.Drawing.Point> contours = img_threshold.FindContours(); contours != null; contours = contours.HNext)
{
if (contours.Area > 100)
{
Contour<System.Drawing.Point> contours_poly = contours.ApproxPoly(3);
rects.Add(new Rectangle(contours_poly.BoundingRectangle.X, contours_poly.BoundingRectangle.Y, contours_poly.BoundingRectangle.Width, contours_poly.BoundingRectangle.Height));
}
}
return rects;
}
Usage:
Image<Bgr, Byte> img = new Image<Bgr, Byte>("VfDfJ.png");
List<Rectangle> rects = detectLetters(img);
for (int i=0;i<rects.Count();i++)
img.Draw(rects.ElementAt<Rectangle>(i),new Bgr(0,255,0),3);
CvInvoke.cvShowImage("Display", img.Ptr);
CvInvoke.cvWaitKey(0);
CvInvoke.cvDestroyWindow("Display");