I'm very new to Emgucv, so need a little help?
The code below is mainly taken from various places from Google. It will take a jpg file (which has a green background) and allow, from a separate form to change the values of h1 and h2 settings so as to create (reveal) a mask.
Now what I want to be able to do with this mask is to turn it transparent.
At the moment it will just display a black background around a person (for example), and then saves to file.
I need to know how to turn the black background transparent, if this is the correct way to approach this?
Thanks in advance.
What I have so far is in C# :
imgInput = new Image<Bgr, byte>(FileName);
Image<Hsv, Byte> hsvimg = imgInput.Convert<Hsv, Byte>();
//extract the hue and value channels
Image<Gray, Byte>[] channels = hsvimg.Split(); // split into components
Image<Gray, Byte> imghue = channels[0]; // hsv, so channels[0] is hue.
Image<Gray, Byte> imgval = channels[2]; // hsv, so channels[2] is value.
//filter out all but "the color you want"...seems to be 0 to 128 (64, 72) ?
Image<Gray, Byte> huefilter = imghue.InRange(new Gray(h1), new Gray(h2));
// TURN IT TRANSPARENT somewhere around here?
pictureBox2.Image = imgInput.Copy(mask).Bitmap;
imgInput.Copy(mask).Save("changedImage.png");
I am not sure I really understand what you are trying to do. But a mask is a binary object. A mask is usually black for what you do not want and white for what you do. As far as I know, there is no transparent mask, as to me that makes no sense. Masks are used to extract parts of an image by masking out the rest.
Maybe you could elaborate on what it is you want to do?
Doug
I think I may have the solution I was looking for. I found some code on stackoverflow which I've tweaked a little :
public Image<Bgra, Byte> MakeTransparent(Image<Bgr, Byte> image, double r1, double r2)
{
Mat imageMat = image.Mat;
Mat finalMat = new Mat(imageMat.Rows, imageMat.Cols, DepthType.Cv8U, 4);
Mat tmp = new Mat(imageMat.Rows, imageMat.Cols, DepthType.Cv8U, 1);
Mat alpha = new Mat(imageMat.Rows, imageMat.Cols, DepthType.Cv8U, 1);
CvInvoke.CvtColor(imageMat, tmp, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(tmp, alpha, (int)r1, (int)r2, ThresholdType.Binary);
VectorOfMat rgb = new VectorOfMat(3);
CvInvoke.Split(imageMat, rgb);
Mat[] rgba = { rgb[0], rgb[1], rgb[2], alpha };
VectorOfMat vector = new VectorOfMat(rgba);
CvInvoke.Merge(vector, finalMat);
return finalMat.ToImage<Bgra, Byte>();
}
I'm now looking at adding SmoothGaussian to the mask to create a kind on blend, where the two images are layered, rather than a sharp cut-out.
Related
my goal is, to shift an Image an x-amount of pixels to the right. I guess this can be achieved by using WarpAffine. This is at least what my reseach tells me. I used quite a variety of different approaches, like:
CvInvoke.WarpAffine(realImage, transformedImage, transformationMatrix, new Size(realImage.Size);
//or while m is the Mat used to create realImage
transImage.WarpAffine(m,Emgu.CV.CvEnum.Inter.Area,Emgu.CV.CvEnum.Warp.Default,Emgu.CV.CvEnum.BorderType.Default,new Gray());
I get the Exeption:
Exception thrown: 'Emgu.CV.Util.CvException' in Emgu.CV.Platform.NetStandard.dll
[ WARN:0] global E:\bb\cv_x86\build\opencv\modules\videoio\src\cap_msmf.cpp (436) `anonymous-namespace'::SourceReaderCB::~SourceReaderCB terminating async callback
I guess I am using it the wrong way, but there is no suiting example online for me to learn from.
Does anyone has a clean way to explain it to me?
Thank you in advance!
If you are shifting the pixels x amount to the right, I assume that there would be black empty pixels on the left side? If so, you could create an ROI and cut off some pixels on the right, since you are shifting all pixels to the right, and copy the image onto another image.
//The image that you want to shift pixels with
Image<Bgr, byte> inputImage = new Image<Bgr, byte>(1000, 1000);
//The output image
Image<Bgr, byte> image = new Image<Bgr, byte>(990, 1000);
//Create the roi, with 10 pixels cut off from the right side because of the shift
inputImage.ROI = new Rectangle(0, 0, inputImage.Width - 10, inputImage.Height);
inputImage.CopyTo(image);
CvInvoke.ImShow("The Output", image);
CvInvoke.WaitKey(0);
EDIT
Now lets say you want to keep that black stripe on the left side of the image as well. Doing this is very similar to the code above, but only with a few modifications.
//The image that you want to shift pixels with
Image<Bgr, byte> inputImage = new Image<Bgr, byte>(1000, 1000);
//The output image
Image<Bgr, byte> image = new Image<Bgr, byte>(1000, 1000);
//Create the roi, with 10 pixels cut off from the right side because of the shift
inputImage.ROI = new Rectangle(0, 0, inputImage.Width - 10, inputImage.Height);
//The image we want to shift, the same one we created a ROI with,
//has the dimensions 990 X 1000 and the output image has
//dimensions of 1000 x 1000. Unfortunately, in order to paste
//an image onto another image, they need to be the same dimensions.
//How do we do this? We must create an ROI with the output image
//that has the same dimensions as the input image.
image.ROI = new Rectangle(10, 0, image.Width, image.Height);
//Now we can past the image onto the output because the dimensions match
inputImage.CopyTo(image);
//Inorder to make our output seem normal, we must empty the ROI of the output image
image.ROI = Rectangle.Empty;
CvInvoke.ImShow("The Output", image);
CvInvoke.WaitKey(0);
I have a windows forms application and i want to count number of objects from a medical images. For instance
I used an algorithm which can take the contours of every object from the image.
private void findContoursToolStripMenuItem_Click(object sender, EventArgs e)
{
Image<Gray, byte> imgOutput = imgInput.Convert<Gray, byte>().ThresholdBinary(new Gray(100), new Gray(255));
Emgu.CV.Util.VectorOfVectorOfPoint contours = new Emgu.CV.Util.VectorOfVectorOfPoint();
Mat hier = new Mat();
Image<Gray, byte> imgout = new Image<Gray, byte>(imgInput.Width, imgInput.Height, new Gray(100));
CvInvoke.FindContours(imgOutput, contours, hier, Emgu.CV.CvEnum.RetrType.External, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);
CvInvoke.DrawContours(imgout, contours, -1, new MCvScalar(123, 0, 0));
pictureBox2.Image = imgout.Bitmap;
}
But I can't find out the number of cells from the image. Any advice or algorithm I have to use ?
I search within EMGU documentation but I don't find any function which does somethink like I want.
Any advice or answer will be rewarded.
If you consider that is too broad, I don't want the implemented algorithm. I just need some ideas or a suggestion of algorithm i have to use.
It probably a bit basic and brute force, but how about selecting a random point on the image that is close to the green colour, then effectively search for 'matching' colours (with a tolerance for the same colour. As you visit each pixel, colour it black so you don't look at it again and count how many pixels you have coloured in. Each time you select a pixel, make sure it's not black. Once you can't find any more points, if the number of black pixels is greater than a tolerance (so you only find 'big' polygons), then count it in the number of cells.
My task is to recognize eye borders (not pupil but whole eye).
I can't take the white part of image even using HSV filtering.
I use filtering by hue and saturation and get no result:
Image<Gray, byte> huefilter = imghue.InRange(new Gray(Color.White.GetHue()-10), new Gray(Color.White.GetHue() + 10));
Image<Gray, byte> saturationfilter = imgsaturation.InRange(new Gray(Color.White.GetSaturation() - 10), new Gray(Color.White.GetSaturation() + 10));
Image<Gray, byte> resultImg = huefilter.And(saturationfilter);
Sample images:One Two Three
Please give an advise how to get the light zone around pupil with help of c# EmguCV.
i need to compare two images and identify differences on them as percentage. "Absdiff" function on emgucv doesn't help with that. i already done that compare example on emgucv wiki. what i exactly want is how to get two image difference in numerical format?
//emgucv wiki compare example
//acquire the frame
Frame = capture.RetrieveBgrFrame(); //aquire a frame
Difference = Previous_Frame.AbsDiff(Frame);
//what i want is
double differenceValue=Previous_Frame."SOMETHING";
if you need more detail plz ask.
Thanks in advance.
EmguCV MatchTemplate based comparison
Bitmap inputMap = //bitmap source image
Image<Gray, Byte> sourceImage = new Image<Gray, Byte>(inputMap);
Bitmap tempBitmap = //Bitmap template image
Image<Gray, Byte> templateImage = new Image<Gray, Byte>(tempBitmap);
Image<Gray, float> resultImage = sourceImage.MatchTemplate(templateImage, Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed);
double[] minValues, maxValues;
Point[] minLocations, maxLocations;
resultImage.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);
double percentage = maxValues[0] * 100; //this will be percentage of difference of two images
The two images need to have the same width and height or MatchTemplate will throw an exception. In case if we want to have an exact match.
Or
The template image should be smaller than the source image to get a number of occurrence of the template image on the source image
EmguCV AbsDiff based comparison
Bitmap inputMap = //bitmap source image
Image<Gray, Byte> sourceImage = new Image<Gray, Byte>(inputMap);
Bitmap tempBitmap = //Bitmap template image
Image<Gray, Byte> templateImage = new Image<Gray, Byte>(tempBitmap);
Image<Gray, byte> resultImage = new Image<Gray, byte>(templateImage.Width,
templateImage.Height);
CvInvoke.AbsDiff(sourceImage, templateImage, resultImage);
double diff = CvInvoke.CountNonZero(resultImage);
diff = (diff / (templateImage.Width * templateImage.Height)) * 100; // this will give you the difference in percentage
As per my experience, this is the best method compared to MatchTemplate based comparison. Match template failed to capture very minimal changes in two images.
But AbsDiff will be able to capture very small difference as well
There is a task of recognition red areas on an image and it requires maximum of accuracy. But the quality of a source image is quite bad. I'm trying to minimize a noise on a mask with detected red areas using cvThreshold. Unfortunately, there is no expected effect - gray artifacts stay.
//Converting from Bgr to Hsv
Image<Hsv, Byte> hsvimg = markedOrigRecImg.Convert<Hsv, Byte>();
Image<Gray, Byte>[] channels = hsvimg.Split();
Image<Gray, Byte> hue = channels[0];
Image<Gray, Byte> saturation = channels[1];
Image<Gray, Byte> value = channels[2];
Image<Gray, Byte> hueFilter = hue.InRange(new Gray(0), new Gray(30));
Image<Gray, Byte> satFilter = saturation.InRange(new Gray(100), new Gray(255));
Image<Gray, Byte> valFilter = value.InRange(new Gray(50), new Gray(255));
//Mask contains gray artifacts
Image<Gray,Byte> mask = (hueFilter.And(satFilter)).And(valFilter);
//Gray artifacts stays even if threshold (the third param.) value is 0...
CvInvoke.cvThreshold(mask, mask, 100, 255, THRESH.CV_THRESH_BINARY);
mask.Save("D:/img.jpg");
In the same time here it works fine - saved image is purely white:
#region test
Image<Gray,Byte> some = new Image<Gray, byte>(mask.Size);
some.SetValue(120);
CvInvoke.cvThreshold(some, some, 100, 255, THRESH.CV_THRESH_BINARY);
some.Save("D:/some.jpg");
#endregion
Mask before threshold example:
http://dl.dropbox.com/u/52502108/input.jpg
Mask after threshold example:
http://dl.dropbox.com/u/52502108/output.jpg
Thank You in advance.
Constantine B.
The reason of an appearing of that gray artifacts on saved images after applying of any kind of a threshold is... *.JPG standard saving format of Image<TColor, TDepth>! More precisely, a jpeg compression applied by it. So there was no problem with thresholding itself. Just a spoiled output image. It was confusing strongly though. The right way of saving such images (without artifacts) is, for example: Image<TColor,TDepth>.Bitmap.Save(your_path, ImageFormat.Bmp)