I need to create a method in C# that will receive an image (or path to it), blur it and then try to merge the blurred image with the original using OpenCvSharp4. So far, I can create the blur image just fine, but the merging part is giving me a hard time. I've had tried a few pieces of sample code found online to no avail. Any idea how to get the merging part ?
-thanks,
var mat = Cv2.ImRead(OriginalFileName, ImreadModes.Unchanged);
Cv2.Resize(mat, mat, new Size(933, 934), 0d, 0d, InterpolationFlags.Linear);
Cv2.CvtColor(mat, mat, ColorConversionCodes.BGR2RGB);
Mat newImage = new Mat();
Cv2.GaussianBlur(mat, newImage, new Size(67, 67), 0d, 0d, BorderTypes.Default);
Cv2.CvtColor(newImage, newImage, ColorConversionCodes.BGR2RGB);
Mat merged = Mat.Ones || Mat.Zeros // HELP NEEDED HERE
Cv2.Merge(new Mat[] { mat, newImage }, merged);
Found a good hint and sample code here: How to merge two images in opencv?
Here's my final solution:
var mat = Cv2.ImRead(OriginalFileName, ImreadModes.Unchanged);
Cv2.Resize(mat, mat, new Size(933, 934), 0d, 0d, InterpolationFlags.Linear);
Cv2.CvtColor(mat, mat, ColorConversionCodes.BGR2RGB);
Mat newImage = new Mat();
Cv2.GaussianBlur(mat, newImage, new Size(67, 67), 0d, 0d, BorderTypes.Default);
Cv2.CvtColor(newImage, newImage, ColorConversionCodes.BGR2RGB);
//merging
double alpha = 0; double beta;
Mat src1, src2, merge;
merge = new Mat();
src1 = mat;
src2 = newImage;
beta = (1.0 - alpha);
Cv2.AddWeighted(src1, alpha, src2, beta, 0.0, merge);
Related
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.
I have lots of colors ranges need to filter then combine achieved images to get single image contained all those filtered colors. like this:
Image<Gray, Byte> grayscale2 = frame2.Convert<Gray, Byte>();
for (int i = 1; i < colors.Length - 1; i++)
{
var color1 = colors[i].Split('-');
var color2 = colors[i+1].Split('-');
var img = frame2.InRange(new Bgr(double.Parse(color1[0]),
double.Parse(color1[1]), double.Parse(color1[2])),
new Bgr(double.Parse(color2[0]), double.Parse(color2[1]),
double.Parse(color2[2]))).Convert<Gray, Byte>();
}
"colors" is an array of RGB saved colors as string.
I am looking for the fastest way to combine (merge) all img in grayscale2.
Thank you.
I don't know exactly what do you want. I made a simple program in opencv in python. AS you have grayscale image you can add this images, but you need to remember this. If in image1 pixel has value 150 and in image2 value 150, final pixel has 255 value. So you have to add them with weight.
import cv2 as cv
import numpy as np
img1= cv.imread('image1.jpg')
img2= cv.imread('image2.jpg')
hsv1 = cv.cvtColor(img1, cv.COLOR_BGR2HSV)
hsv2 = cv.cvtColor(img2, cv.COLOR_BGR2HSV)
lower_blue = np.array([110, 50, 50])
upper_blue = np.array([130, 255, 255])
mask1 = cv.inRange(hsv1, lower_blue, upper_blue)
mask2 = cv.inRange(hsv2, lower_blue, upper_blue)
alpha=0.5
beta =0.5
output =cv.addWeighted( mask1, alpha, mask2, beta, 0.0, )
cv.imshow('av1',img1)
cv.imshow('av2',img2)
cv.imshow('av3',mask1)
cv.imshow('av4',mask2)
cv.imshow('av4',output)
cv.waitKey(0)
I did something like this by convert the images to bitmap first then combine them it's very faster:
public static Bitmap CombineBitmap(string[] files)
{
//change the location to store the final image.
Bitmap img = new Bitmap(files[0]);
Bitmap img3 = new Bitmap(img.Width, img.Height);
Graphics g = Graphics.FromImage(img3);
g.Clear(SystemColors.AppWorkspace);
foreach (string file in files)
{
img = new Bitmap(file);
img.MakeTransparent(Color.White);
g.DrawImage(img, new Point(0, 0));
//img3.MakeTransparent(Color.White);
}
using (var b = new Bitmap(img3.Width, img3.Height))
{
b.SetResolution(img3.HorizontalResolution, img3.VerticalResolution);
using (var g2 = Graphics.FromImage(b))
{
g2.Clear(Color.White);
g2.DrawImageUnscaled(img3, 0, 0);
}
// Now save b as a JPEG like you normally would
return img3;
}
I am using EmguCV and C#. I want to remove small connected objects from my image using ConnectedComponentsWithStats
I have following binary image as input
I am able to draw a rectangle for specified area. Now i want to remove objects from binary image
Here is my code
Image<Gray, byte> imgry = image.Convert<Gray, byte>();
var mask = imgry.InRange(new Gray(50), new Gray(255));
var label = new Mat();
var stats = new Mat();
var centroids = new Mat();
int labels = CvInvoke.ConnectedComponentsWithStats(mask, label, stats,
centroids,
LineType.EightConnected,
DepthType.Cv32S);
var img = stats.ToImage<Gray, int>();
Image<Gray, byte> imgout1 = new Image<Gray, byte>(image.Width, image.Height);
for (var i = 1; i < labels; i++)
{
var area = img[i, (int)ConnectecComponentsTypes.Area].Intensity;
var width = img[i, (int)ConnectecComponentsTypes.Width].Intensity;
var height = img[i, (int)ConnectecComponentsTypes.Height].Intensity;
var top = img[i, (int)ConnectecComponentsTypes.Top].Intensity;
var left = img[i, (int)ConnectecComponentsTypes.Left].Intensity;
var roi = new Rectangle((int)left, (int)top, (int)width, (int)height);
if (area > 1000)
{
CvInvoke.Rectangle(imgout1, roi, new MCvScalar(255), 1);
}
}
Drawn Rectangle for specified area
How can i remove objects of specified size
My output image should be like this
I have achieved one way by using contours it works fine for small image, when i have large image 10240*10240 and more number of particles my application entering to break mode
The following code doesn't compile in EmguCV 3.4.1.
Image<Gray, float> image = new Image<Gray, float>(path);
IntPtr complexImage = CvInvoke.cvCreateImage(image.Size,
Emgu.CV.CvEnum.IplDepth.IplDepth32F, 2);
CvInvoke.cvSetZero(complexImage); // Initialize all elements to Zero
CvInvoke.cvSetImageCOI(complexImage, 1);
CvInvoke.cvCopy(image, complexImage, IntPtr.Zero);
CvInvoke.cvSetImageCOI(complexImage, 0);
Matrix<float> dft = new Matrix<float>(image.Rows, image.Cols, 2);
CvInvoke.cvDFT(complexImage, dft, Emgu.CV.CvEnum.DxtType.Forward, 0);
//The Real part of the Fourier Transform
Matrix<float> outReal = new Matrix<float>(image.Size);
//The imaginary part of the Fourier Transform
Matrix<float> outIm = new Matrix<float>(image.Size);
CvInvoke.cvSplit(dft, outReal, outIm, IntPtr.Zero, IntPtr.Zero);
//Show The Data
CvInvoke.cvShowImage("Real", outReal);
CvInvoke.cvShowImage("Imaginary ", outIm);
Some functions
cvSetZero()
cvDFT()
cvShowImage()
are not available in this version of EmguCV.
How can I get around this issue?
Since version 3.0 EmguCV goes more for Mat instead of Image. Also somemethods were moved from CvInvoke to Mat or Image or were renamed (example: CvInvoke.cvShowImage --> CvInvoke.Imshow).
I also had this problem with dft and tried to port the code from the openCV example to c#. This is what I work with (using EmguCV 3.4.1):
var image = new Mat(path, ImreadModes.Grayscale);
int a = CvInvoke.GetOptimalDFTSize(image.Rows);
int b = CvInvoke.GetOptimalDFTSize(image.Cols);
var extended = new Mat();
CvInvoke.CopyMakeBorder(image, extended, 0, a - image.Rows, 0, b - image.Cols, BorderType.Constant, new MCvScalar(0));
extended.ConvertTo(extended, DepthType.Cv32F);
var vec = new VectorOfMat(extended, new Mat(extended.Size, DepthType.Cv32F, 1));
var complex = new Mat();
CvInvoke.Merge(vec, complex);
CvInvoke.Dft(complex, complex, DxtType.Forward, 0);
CvInvoke.Split(complex, vec);
vec[0].ConvertTo(vec[0], DepthType.Cv8U);
vec[1].ConvertTo(vec[1], DepthType.Cv8U);
CvInvoke.Imshow("Real", vec[0]);
CvInvoke.Imshow("Img", vec[1]);
Some methods have been renamed or moved. Use CvInvoke.Dft with Image.toUMat and UMat for the image manipulation. ImageViewer can be used for displaying images.
Image<Gray, float> image = new Image<Gray, float>(path);
UMat dftImage = new UMat(image.Size, Emgu.CV.CvEnum.DepthType.Cv32F, 2);
CvInvoke.Dft(image, dftImage, Emgu.CV.CvEnum.DxtType.Forward, image.Rows);
I have Emgu image :
Image<Bgr,byte> image = new Image<Bgr,byte>("image.jpg");
Here is how the file(image.jpg) looks like:
All pixels that inside red-yellow triangle I want to copy to the new image called:
Image<Bgr,byte> copiedSegment;
Any idea how to implement it if I have coordinates all coordinates of the triangle contour.
Thank you in advance.
In the opencv c++ api you can just use the matrix copy function with a mask composed of your triangular components.
Mat image = imread("image.jpg",CV_LOAD_IMAGE_COLOR);
vector<Point> triangleRoi;
Mat mask;
//draw your trianlge on the mask
cv::fillConvexPoly(mask, triangleRoi, 255);
Mat copiedSegment;
image.copyTo(copiedSegment,mask);
You should beable to write some similar code in emgu based on this.
// no we apply filter to get rid of Equalization Noise.
ImageBilateral = new Image<Gray, Byte>(grayImg.Size);
CvInvoke.BilateralFilter(grayImg, ImageBilateral, 0, 20.0, 2.0);
//ImageBilateral.Save(String.Format("C:\\Temp\\BilateralFilter{0}.jpg", counter));
retImage = AlignFace(ImageBilateral);
Point faceCenter = new Point(ImageBilateral.Width / 2, (int)Math.Round(ImageBilateral.Height * FACE_ELLIPSE_CY));
Size size = new Size((int)Math.Round(ImageBilateral.Width * FACE_ELLIPSE_W), (int)Math.Round(ImageBilateral.Width * FACE_ELLIPSE_H));
// Filter out the corners of the face, since we mainly just care about the middle parts.
// Draw a filled ellipse in the middle of the face-sized image.
Image<Gray, Byte> mask = new Image<Gray, Byte>(ImageBilateral.Size);
// draw Ellipse on Mask
CvInvoke.Ellipse(mask, faceCenter, size, 0, 0, 360, new MCvScalar(255, 255, 255), -1, Emgu.CV.CvEnum.LineType.AntiAlias, 0);
mask.Save(String.Format("C:\\Temp\\mask{0}.bmp", counter));
Image<Gray, Byte> temp1 = ImageBilateral.Copy(mask);
ImageBilateral.Save(String.Format("C:\\Temp\\ImageBilateral.CopyTo(mask){0}.bmp", counter));
temp1.Save(String.Format("C:\\Temp\\temp1{0}.bmp", counter));