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?
Related
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 have another question. Idk what is happening buti tried to make Canny edge detector. Problem is that when i want to detect edges on simple shape like square, the program is able to detect it. But when i want to detect shapes on not very simple image program just gives me image filled by only black color. Do you guys have an idea what is going on?
I use this code below:
public Bitmap CannyEdge(Bitmap bmp)
{
Image<Gray, Byte> Cannybmp;
Image<Gray, Byte> GrayBmp;
Image<Bgr, Byte> orig = new Image<Bgr, Byte>(bmp);
Image<Bgr, Byte> imgSmooth;
Bitmap output;
imgSmooth = orig.PyrDown().PyrUp();
imgSmooth._SmoothGaussian(3);
GrayBmp = imgSmooth.Convert<Gray, byte>();
Gray grayCannyThreshold = new Gray(160.0);
Gray grayThreshLinking = new Gray(80.0);
Cannybmp = GrayBmp.Canny(grayCannyThreshold.Intensity, grayThreshLinking.Intensity);
output = Cannybmp.ToBitmap();
//int a = 5;
return output;
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.Image);
pictureBox2.Image = CannyEdge(bmp);
}
Did you try to set your grayCannyThreshold to become lesser the value of your grayThreshLinking?
Gray grayCannyThreshold = new Gray(80.0);
Gray grayThreshLinking = new Gray(160.0);
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");
i have a blood image and i applied watershed on it .. its works and determines the cells but i don't know how to put each cell in a separate image .. i'm working with emgu.cv can i get some help
here i segment the picture using my watershed method and then put the marker on the original image
Image<Gray, Int32> boundaryImage = watershedSegmenter.Process(image);
Image<Gray, Byte> test = watershedSegmenter.GetWatersheds(); Image<Bgr, byte>dest=new Image<Bgr, byte>(image.Width, image.Height);
dest = image.And(image, test);
pictureBox1.Width = boundaryImage.ToBitmap().Width;
pictureBox1.Height = boundaryImage.ToBitmap().Height;
pictureBox1.BackgroundImage = boundaryImage.ToBitmap();
It seems like EMGUcv cvWatershed() is having some bugs which is not yet resolved. The Marker Image is always returning white image. Can you share your 1st stage output images?
I'm not able to view any images by using this code.
Image<Bgr, Byte> image = Img_Source_Bgr.Copy();
Image<Gray, Int32> marker = new Image<Gray, Int32>(image.Width, image.Height);
Rectangle rect = image.ROI;
marker.Draw(
new CircleF(
new PointF(rect.Left + rect.Width / 2.0f, rect.Top + rect.Height / 2.0f),
/*(float)(Math.Min(image.Width, image.Height) / 20.0f)*/ 5.0f),
new Gray(255),
0);
Image<Bgr, Byte> result = image.ConcateHorizontal(marker.Convert<Bgr, byte>());
Image<Gray, Byte> mask = new Image<Gray, byte>(image.Size);
CvInvoke.cvWatershed(image, marker);
CvInvoke.cvCmpS(marker, 0.10, mask, CMP_TYPE.CV_CMP_GT);
imageBox1.Image = mask;
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.