get all points of all counters in emgu cv - c#

I want to draw a rotated rectangle. The canny image is not one counter it is a set of counters. So I want to get all points of all counters. e.g.
Points[] pts = points of all counters.
Please see attached image.

The canny show all edges in your image, not an external contour. This one way (but not the only one) to do object detection (foreground / background extraction).
The following snippet extract object roi (Min area rect) by using a canny edge detector. Be carrefull about canny thresh parameteres comming from otsu threshold.
Hope it helps.
Detection result
Image<Gray,byte> imageFullSize = new Image<Gray, byte>(imagePath);
Rectangle roi = new Rectangle(Your Top Left X,Your Top Left Y,Your ROI Width,Your ROI Height);
//Now get a roi (No copy, it is a new header pointing original image
Image<Gray,byte> image = imageFullSize.GetSubRect(roi);
//Step 1 : contour detection using canny
//Gaussian noise removal, eliminate background false détections
image._SmoothGaussian(15);
//Canny thresh based on otsu threshold value:
Mat binary = new Mat();
double otsuThresh = CvInvoke.Threshold(image, binary, 0, 255, ThresholdType.Binary | ThresholdType.Otsu);
double highThresh = otsuThresh;
double lowThresh = otsuThresh * 0.5;
var cannyImage = image.Canny(lowThresh, highThresh);
//Step 2 : contour extraction
Mat hierarchy=new Mat();
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(cannyImage,contours,hierarchy,RetrType.External,ChainApproxMethod.ChainApproxSimple);
//Step 3 : contour fusion
List<Point> points=new List<Point>();
for(int i = 0; i < contours.Size; i++)
{
points.AddRange(contours[i].ToArray());
}
//Step 4 : Rotated rect
RotatedRect minAreaRect = CvInvoke.MinAreaRect(points.Select(pt=>new PointF(pt.X,pt.Y)).ToArray());
Point[] vertices = minAreaRect.GetVertices().Select(pt => new Point((int)pt.X, (int)pt.Y)).ToArray();
//Step 5 : draw result
Image <Bgr,byte > colorImageFullSize =new Image<Bgr, byte>(imagePath);
Image <Bgr,byte > colorImage =colorImageFullSize.GetSubRect(roi);
colorImage.Draw(vertices,new Bgr(Color.Red),2 );

Related

OpenCV FindContours does not find the correct rectangle

Using CvInvoke.Canny and CvInvoke.FindContours I'm trying to find the rectangle containing the item name (Schematic: Maple Desk). This rectangle is shown in the image below:
I'm able to find a lot of rectangles but I'm not able to get this one. Tried a lot of different thresholds for Canny but to no effect. The following image shows all rectangles I currently get:
Any ideas how to tackle this? Do I need to use other thresholds or another approach? I already experimented using grayscale and blurring but that didn't give better result. I added my current source below and the original image I'm using is this:
public Mat ProcessImage(Mat img)
{
UMat filter = new UMat();
UMat cannyEdges = new UMat();
Mat rectangleImage = new Mat(img.Size, DepthType.Cv8U, 3);
//Convert the image to grayscale and filter out the noise
//CvInvoke.CvtColor(img, filter, ColorConversion.Bgr2Gray);
//Remove noise
//CvInvoke.GaussianBlur(filter, filter, new System.Drawing.Size(3, 3), 1);
// Canny and edge detection
double cannyThreshold = 1.0; //180.0
double cannyThresholdLinking = 1.0; //120.0
//CvInvoke.Canny(filter, cannyEdges, cannyThreshold, cannyThresholdLinking);
CvInvoke.Canny(img, cannyEdges, cannyThreshold, cannyThresholdLinking);
// Find rectangles
List<RotatedRect> rectangleList = new List<RotatedRect>();
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
CvInvoke.FindContours(cannyEdges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
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, CvInvoke.ArcLength(contour, true) * 0.05, true);
// Only consider contours with area greater than 250
if (CvInvoke.ContourArea(approxContour, false) > 250)
{
// The contour has 4 vertices.
if (approxContour.Size == 4)
{
// Determine if all the angles in the contour are within [80, 100] degree
bool isRectangle = true;
System.Drawing.Point[] pts = approxContour.ToArray();
LineSegment2D[] edges = Emgu.CV.PointCollection.PolyLine(pts, true);
for (int j = 0; j < edges.Length; j++)
{
double angle = Math.Abs(edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
if (angle < 80 || angle > 100)
{
isRectangle = false;
break;
}
}
if (isRectangle) rectangleList.Add(CvInvoke.MinAreaRect(approxContour));
}
}
}
}
}
// Draw rectangles
foreach (RotatedRect rectangle in rectangleList)
{
CvInvoke.Polylines(rectangleImage, Array.ConvertAll(rectangle.GetVertices(), System.Drawing.Point.Round), true,
new Bgr(Color.DarkOrange).MCvScalar, 2);
}
//Drawing a light gray frame around the image
CvInvoke.Rectangle(rectangleImage,
new Rectangle(System.Drawing.Point.Empty,
new System.Drawing.Size(rectangleImage.Width - 1, rectangleImage.Height - 1)),
new MCvScalar(120, 120, 120));
//Draw the labels
CvInvoke.PutText(rectangleImage, "Rectangles", new System.Drawing.Point(20, 20),
FontFace.HersheyDuplex, 0.5, new MCvScalar(120, 120, 120));
Mat result = new Mat();
CvInvoke.VConcat(new Mat[] { img, rectangleImage }, result);
return result;
}
Edit 1:
After some more fine tuning with the following thresholds for Canny
cannyThreshold 100
cannyThresholdLinking 400
And using a minimum size for all ContourAreas of 10000 I can get the following result:
Edit 2:
For those interested, solved using the current detection, no changes were needed. Used the 2 detected rectangles in the screenshot above to get the location of the missing rectangle containing the item name.
Result can be found here:
https://github.com/josdemmers/NewWorldCompanion
For those interested, solved using the current detection, no changes were needed. Used the 2 detected rectangles in the screenshot above to get the location of the missing rectangle containing the item name.
Result can be found here: https://github.com/josdemmers/NewWorldCompanion

Crop white space around black image based on color

I using Imaemagick and c# and wondering:
Is it possible to crop image to border without exactly sizes?
From first to second?
First image
Second
To remove the white space around the sudoku square you can loop over the pixels. Since the image is black and white it makes it a lot easier because we can check when any of the R, G or B values drop below a certain white threshold and become black.
In this example, I'm just using an arbitrary 200 value to check.
I'm walking in from the top left and bottom right corners. This will only work if your image is always a perfect square. but you can easily adjust this code to check coordinates more accurately to meet your purposes.
using (var image = new Bitmap(Image.FromFile("firstImage.jpg")))
{
int topX = 0, topY = 0;
int bottomX = image.Width - 1, bottomY = image.Height - 1;
var color = image.GetPixel(topX, topY);
while(color.R > 200)
color = image.GetPixel(++topX, ++topY);
color = image.GetPixel(bottomX, bottomY);
while(color.R > 200)
color = image.GetPixel(--bottomX, --bottomY);
Bitmap croppedImage = new Bitmap(image);
Rectangle cropRect = new Rectangle(topX, topY, bottomX - topX + 1, bottomY - topY + 1);
croppedImage = croppedImage.Clone(cropRect, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
croppedImage.Save("firstImageNoBorder.jpg");
}
Original:
Cropped:

Search and cut contour Opencv C #

It is necessary to cut an object by photo using a mask and blur the edges.
Code to search for edges. But what about the blur?
Mat imgGray = new Mat();
Cv2.CvtColor(segmentationMap, imgGray, ColorConversionCodes.BGR2GRAY, 0);
Cv2.Blur(imgGray,imgGray, new Size(3,3));
Mat imgCanny = new Mat();
Cv2.Canny(imgGray,imgCanny, 2, 3);
Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(imgCanny, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
Mat drawing = new Mat(imgCanny.Size(), MatType.CV_8UC3);
for (int i = 0; i < contours.Length; i++)
{
Scalar color = Scalar.Red;
Cv2.DrawContours(drawing,contours, i, color);
}
Paint the area inside the contour.
Cut by mask
Blur the edges
Mask
Contour (But he is not closed for some reason)

How to find circle inside Rectangle in AForge

I am trying to detect Circle inside Rectangle in AForge. I have successfully determined Rectangles but unable to find circles inside Rectangle. How to find shape inside another shape in AForge.
string strPath = Server.MapPath("~/Recipt001.png");
Bitmap myBitmap = new Bitmap(strPath);
//Some filters Grayscale, invert, threshold
//Blod Filtering
BlobCounter blobCounter = new BlobCounter();
blobCounter.ProcessImage(temp);
blobCounter.ObjectsOrder = ObjectsOrder.YX;
blobCounter.FilterBlobs = true;
Blob[] blobs = blobCounter.GetObjectsInformation();
Graphics g = Graphics.FromImage(myBitmap);
Pen redPen = new Pen(Color.Red, 2);
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
// dictionary of color to highlight different shapes
Dictionary<PolygonSubType, Color> colors = new Dictionary<PolygonSubType, Color>();
colors.Add(PolygonSubType.Unknown, Color.White);
colors.Add(PolygonSubType.Trapezoid, Color.Orange);
colors.Add(PolygonSubType.Parallelogram, Color.Red);
colors.Add(PolygonSubType.Rectangle, Color.Green);
colors.Add(PolygonSubType.Square, Color.Blue);
colors.Add(PolygonSubType.Rhombus, Color.Gray);
colors.Add(PolygonSubType.EquilateralTriangle, Color.Pink);
colors.Add(PolygonSubType.IsoscelesTriangle, Color.Purple);
colors.Add(PolygonSubType.RectangledTriangle, Color.SkyBlue);
colors.Add(PolygonSubType.RectangledIsoscelesTriangle, Color.SeaGreen);
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> corners;
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
Point center;
double radius;
if (shapeChecker.IsQuadrilateral(edgePoints, out corners))
{
if (shapeChecker.CheckPolygonSubType(corners) == PolygonSubType.Rectangle)
{
g.DrawPolygon(redPen, ToPointsArray(corners));
}
}
}
redPen.Dispose();
g.Dispose();
None of image processing libraries and even image processing in MATLAB lets you search ROI inside ROI (ROI - region of intrest like rectangles or circles). Concept is CROP REGION -> SEARCH OBJECTS IN REGION
So first locate primary rectangles, thereafter crop image to rectangles and perform circle search inside them. Otherwise search for all circles and all rectangles and then classify circles to be belonging to which rectangle using simple maths.

How to copy segment from the image?

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));

Categories

Resources