I'm new with image processing and stuck on matching different angled images.
I'm trying to detect selected template image in captured camera image. If template image and are exactly same angle everything goes well. When both image angles different, image matching fails.
I used EmguCV to match 2 images.
what i need to use to match two image when different angle?
This is both image same angled. https://imgur.com/K6bUAZp
This is both image different angled. https://imgur.com/qatg2CV
Image<Bgr, byte> source = new Image<Bgr, byte>(grayMain); // Camera image
Image<Bgr, byte> template = new Image<Bgr, byte>(FrameImage); // Template image
Image<Bgr, byte> lastImage = source.Copy();
using (Image<Gray, float> result = source.MatchTemplate(template, TemplateMatchingType.CcoeffNormed))
{
double[] minVal, maxVal;
System.Drawing.Point[] minLocations, maxLocations;
result.MinMax(out minVal, out maxVal, out minLocations, out maxLocations);
if (maxVal[0] > 0.75)
{
Rectangle match = new Rectangle(maxLocations[0], template.Size);
lastImage.Draw(match, new Bgr(Color.Red), 3);
}
}
pictureBox.Image = lastImage.Bitmap;
I solved my problem with serch rectangle in camera image and crop this image with detected rectangle using AForge.QuadrilateralTransformation. And then using last images (template and cropped image) for matching.
This is after crop image -> https://imgur.com/5JqAL5J
After croping red rectangle and doing image matching resulted this image -> https://imgur.com/Sva3MzO
Hope this help.
Related
I have generated the binary version of an image where the edges of the image are in white and the rest of the image is in black. I used the Canny Edge filter built into Magick.NET and saved the image. Now I need to detect a rectangle on that image which is clearly outlined on the image. I have installed Emgu CV and Emgu CV runtime and used the code below but it's not working , help me make the code below detect the rectangle and returns the rectangle points of a rectangular contour.
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using ImageMagick;
MagickImage image = new MagickImage("original.jpg");
//apply the canny edge filter
image.CannyEdge();
//Save the binary image to disk
image.Write("canny_edge_image.jpg");
// Load the Canny edge image
Image<Gray, byte> cannyImage = new Image<Gray, byte>("canny_edge_image.jpg");
// Find contours in the image
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(cannyImage, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
// Iterate through the contours
for (int i = 0; i < contours.Size; i++)
{
// Approximate the contour to a polygon
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, CvInvoke.ArcLength(contours[i], true) * 0.02, true);
// Check if the polygon has four points (i.e. it's a rectangle)
if (approx.Size == 4)
{
// Draw the rectangle
CvInvoke.DrawContours(cannyImage, contours, i, new MCvScalar(255, 0, 0), 2);
// You can also access the points of the rectangle using:
Point[] points = approx.ToArray();
// Use points[0], points[1], points[2], and points[3] to access the four corner points of the rectangle
}
}
// Display or save the image with the rectangle drawn on it
CvInvoke.Imshow("Rectangle", cannyImage);
CvInvoke.WaitKey(0);
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'm using EmguCV 2.4 in C# for edge detection and ellipse fitting of ellipsoid objects in a picture (e.g. laser spot).
EmguCV has implemented functions for fitting an ellipse to a point cloud using the least squares method, but the ellipses do not fit very well to the ellipsoids, depending on their angle.
Here's a basic code, I'm using:
CHAIN_APPROX_METHOD approxMethod = CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE;
RETR_TYPE RetrType = RETR_TYPE.CV_RETR_LIST;
Bitmap Bmp = new Bitmap(#"C:\Users\pernizki\Downloads\binary2.bmp"); // read Bitmap
Image<Bgr, byte> ImgIn = new Image<Bgr, byte>(Bmp); // Convert to Image<>
Image<Gray, byte> ImgBin = ImgIn.Convert<Gray, byte>(); // convert Bgr to Gray
ImgBin = ImgBin.ThresholdBinary(new Gray(140), new Gray(120)).PyrDown().PyrUp(); // convert to binary and reduce noise
ImgBin = ImgBin.Canny(100, 120); // detect the edges from binary image
Contour<Point> Contour = ImgBin.FindContours(approxMethod, RetrType); // Get Contour from binary Image
int cntr = 0;
PointF[] ContourPts = new PointF[Contour.Total];
// Convert Contour to PointF Array
foreach(Point p in Contour)
{
ContourPts[cntr++] = new PointF(p.X, p.Y);
}
Ellipse fittedEllipse = PointCollection.EllipseLeastSquareFitting(ContourPts);
ImgIn.Draw(Contour, new Bgr(Color.Green), 2);
ImgIn.Draw(fittedEllipse, new Bgr(Color.Tomato), 2);
CvInvoke.cvShowImage("Fitted Ellipse", ImgIn.Ptr);
When I have vertical or horizontal ellipse as an input image, the fitted ellipse is always 90° rotated to the input shape. If the angle is something between 0° and 90° the fitted ellipse is still rotated, but at different angle.
I understand, that this problem is fundamental to the least square method. But are there more robust algorithms to fit an ellipse, that is enclosing all of the points?
The picture in the EmguCV tutorial for fitting an ellipse seems to be exactly, what I'm looking for. Unfortunately, that's not how the function works.
Here's an example image, that I've used.
(sorry for having only one, as I don't have enough reputation for more)
rotated Ellipse
i wonder if it is possible with Emgu Cv to chnage image from BGR to binary image as i try to change the BGR to gray
Image<Bgr, byte> image_pass = new Image<Bgr, byte>(bt1);
Yes, it is possible.
Maybe give this a try:
Image<Gray, Byte> image;
image = image_pass.convert<Gray,Byte>().ThresholdBinaryInv(new Gray(x), new Gray(255));
imageBox.Image(image);
CvInvoke.cvShowImage("binary", image); //To show in a new Window
Where x is your threshold value, and 255 the maximum value.
This would convert the pixel value to 0 if the srcImage(x,y)> threshold or to 255, otherwise.
You can, obviously, change the threshold and your max values
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