I'm currently working on a program for character recognition using C# and AForge.NET and now I'm struggling with the processing of blobs.
This is how I created the blobs:
BlobCounter bcb = new BlobCounter();
bcb.FilterBlobs = true;
bcb.MinHeight = 30;
bcb.MinWidth = 5;
bcb.ObjectsOrder = ObjectsOrder.XY;
bcb.ProcessImage(image);
I also marked them with rectangles:
Rectangle[] rects;
rects = bcb.GetObjectsRectangles();
Pen pen = new Pen(Color.Red, 1);
Graphics g = Graphics.FromImage(image);
foreach (Rectangle rect in rects)
{
g.DrawRectangle(pen, rect);
}
After execution my reference image looks like this:
BlobImage
As you can see, almost all characters are recognized. Unfortunately, some character include blobs inside a blob, e.g. "g", "o" or "d".
I would like to eliminate the blobs which are inside another blob.
I tried to adjust the drawing of the rectangles to achieve my objective:
foreach (Rectangle rect in rects)
{
for (int i = 0; i < (rects.Length - 1); i++)
{
if (rects[i].Contains(rects[i + 1]))
rects[i] = Rectangle.Union(rects[i], rects[i + 1]);
}
g.DrawRectangle(pen, rect);
}
...but it wasn't successful at all.
Maybe some of you can help me?
you can try to detect rectangles within rectangles by check their corner indices,
I have one MATLAB code for this which i have written for similar kind of problem:
Here is snippet of the code is:
function varargout = isBoxMerg(ReferenceBox,TestBox,isNewBox)
X = ReferenceBox; Y = TestBox;
X1 = X(1);Y1 = X(2);W1 = X(3);H1 = X(4);
X2 = Y(1);Y2 = Y(2);W2 = Y(3);H2 = Y(4);
if ((X1+W1)>=X2 && (Y2+H2)>=Y1 && (Y1+H1)>=Y2 && (X1+W1)>=X2 && (X2+W2)>=X1)
Intersection = true;
else
`Intersection = false;`
end
Where X and Y are upper left corner indices of the bounding rectangle; W and H are width and height respectively.
in above if Intersection variable becomes true that means the boxes having intersection. you can use this code for further customization.
Thank You
Related
I am using following functions to detect images. However, it detects thousands of circles instead of 16. How can I make sure it only detects what I see? Changing Radius or Relative intensity do not make any difference.
The images I used is this :
Bitmap ImageBitmap = (Bitmap)pictureBox1.Image;
var filter = new FiltersSequence(new IFilter[]
{
Grayscale.CommonAlgorithms.BT709,
new Threshold(0x40)
});
var binaryImage = filter.Apply(ImageBitmap);
// for (int i = 0; i < 10000; i++)
{
// System.Drawing.Image image = System.Drawing.Image.FromFile(imagePath);
// GrayBMP_File.CreateGrayBitmapFile(image, "c:/path/to/8bpp/image.bmp");
// Bitmap ImageBitmap = Convert.Gra ImageBitmap.Con
HoughCircleTransformation circleTransform = new HoughCircleTransformation(50);
// apply Hough circle transform
circleTransform.ProcessImage(binaryImage);
Bitmap houghCirlceImage = circleTransform.ToBitmap();
// get circles using relative intensity
HoughCircle[] circles = circleTransform.GetCirclesByRelativeIntensity(0.9);
int numCircles = circleTransform.CirclesCount;
label1.Text = numCircles.ToString();
pictureBox1.Image = houghCirlceImage;
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(ImageBitmap);
foreach (HoughCircle circle in circles)
{
g.DrawEllipse(Pens.Green, circle.X, circle.Y, 10,10);
}
pictureBox1.Image = ImageBitmap;
// ImageBitmap.Dispose();
// binaryImage.Dispose();
}
Try this python solution from here:
import cv2
import numpy as np
img = cv2.imread('test.jpg',0)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
param1=50,param2=30,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
d=1
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
crop_img=img[i[0]-i[2]-2:i[0]+i[2]+2,i[1]-i[2]-2:i[1]+i[2]+2]
cv2.imshow('cropped circle',crop_img)
cv2.imwrite('test_%d.png'%d,crop_img)
cv2.waitKey(0)
d+=1
cv2.imshow('detected circles',cimg)
print(len(circles[0,:]))
cv2.waitKey(0)
cv2.destroyAllWindows()
OUTPUT:
16
SO basically, I need performance. Currently in my job we use GDI+ graphics to draw bitmap. Gdi+ graphics contains a method called DrawImage(Bitmap,Points[]). That array contains 3 points and the rendered image result with a skew effect.
Here is an image of what is a skew effect :
Skew effect
At work, we need to render between 5000 and 6000 different images each single frame which takes ~ 80ms.
Now I thought of using SharpDX since it provides GPU accelerations. I use direct2D since all I need is in 2 dimensions. However, the only way I saw to reproduce a skew effect is the use the SharpDX.effects.Skew and calculate matrix to draw the initial bitmap with a skew effect ( I will provide the code below). The rendered image is exactly the same as GDI+ and it is what I want. The only problem is it takes 600-700ms to render the 5000-6000images.
Here is the code of my SharpDX :
To initiate device :
private void InitializeSharpDX()
{
swapchaindesc = new SwapChainDescription()
{
BufferCount = 2,
ModeDescription = new ModeDescription(this.Width, this.Height, new Rational(60, 1), Format.B8G8R8A8_UNorm),
IsWindowed = true,
OutputHandle = this.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput,
Flags = SwapChainFlags.None
};
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport | DeviceCreationFlags.Debug, swapchaindesc, out device, out swapchain);
SharpDX.DXGI.Device dxgiDevice = device.QueryInterface<SharpDX.DXGI.Device>();
surface = swapchain.GetBackBuffer<Surface>(0);
factory = new SharpDX.Direct2D1.Factory1(FactoryType.SingleThreaded, DebugLevel.Information);
d2device = new SharpDX.Direct2D1.Device(factory, dxgiDevice);
d2deviceContext = new SharpDX.Direct2D1.DeviceContext(d2device, SharpDX.Direct2D1.DeviceContextOptions.EnableMultithreadedOptimizations);
bmpproperties = new BitmapProperties(new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied),
96, 96);
d2deviceContext.AntialiasMode = AntialiasMode.Aliased;
bmp = new SharpDX.Direct2D1.Bitmap(d2deviceContext, surface, bmpproperties);
d2deviceContext.Target = bmp;
}
And here is my code I use to recalculate every image positions each frame (each time I do a mouse zoom in or out, I asked for a redraw). You can see in the code two loop of 5945 images where I asked to draw the image. No effects takes 60ms and with effects, it takes up to 700ms as I mentionned before :
private void DrawSkew()
{
d2deviceContext.BeginDraw();
d2deviceContext.Clear(SharpDX.Color.Blue);
//draw skew effect to 5945 images using SharpDX (370ms)
for (int i = 0; i < 5945; i++)
{
AffineTransform2D effect = new AffineTransform2D(d2deviceContext);
PointF[] points = new PointF[3];
points[0] = new PointF(50, 50);
points[1] = new PointF(400, 40);
points[2] = new PointF(40, 400);
effect.SetInput(0, actualBmp, true);
float xAngle = (float)Math.Atan(((points[1].Y - points[0].Y) / (points[1].X - points[0].X)));
float yAngle = (float)Math.Atan(((points[2].X - points[0].X) / (points[2].Y - points[0].Y)));
Matrix3x2 Matrix = Matrix3x2.Identity;
Matrix3x2.Skew(xAngle, yAngle, out Matrix);
Matrix.M11 = Matrix.M11 * (((points[1].X - points[0].X) + (points[2].X - points[0].X)) / actualBmp.Size.Width);
Matrix.M22 = Matrix.M22 * (((points[1].Y - points[0].Y) + (points[2].Y - points[0].Y)) / actualBmp.Size.Height);
effect.TransformMatrix = Matrix;
d2deviceContext.DrawImage(effect, new SharpDX.Vector2(points[0].X, points[0].Y));
effect.Dispose();
}
//draw no effects, only actual bitmap 5945 times using SharpDX (60ms)
for (int i = 0; i < 5945; i++)
{
d2deviceContext.DrawBitmap(actualBmp, 1.0f, BitmapInterpolationMode.NearestNeighbor);
}
d2deviceContext.EndDraw();
swapchain.Present(1, PresentFlags.None);
}
After benching a lot, I realized the line that make it really slow is :
d2deviceContext.DrawImage(effect, new SharpDX.Vector2(points[0].X, points[0].Y));
My guess is my code or my setup does not use GPU acceleration of SharpDX like it should and this is why the code is really slow. I would expect at least better performance from SharpDX than GDI+ for this kind of stuff.
I'm trying to achieve this kind of shadow, my research led me to using the CGPathRefto draw the shadow myself, but I can't figure out how it actually works.
Drawing the label.layer.shadowPath looks like a good plan, can anyone show me/point me to how I should proceed?
EDIT : I'm now to the point of trying to draw a UIBezierPath based on the string in the current label, the path being the actual shape of the shadow I need. I'm not sure that's the best option but it looks more promising.
EDIT 2 : Here is the code i'm now working with. this outlines the text of the label as an image, but it's pretty much the exact same text as the label itself, i still have to work my way around making it look like a shadow. Note, we're using Xamarin
public override void Draw (CoreGraphics.CGRect rect)
{
base.Draw (rect);
using (CGContext g = UIGraphics.GetCurrentContext ()) {
UIBezierPath completePath = UIBezierPath.Create ();
g.ScaleCTM (1, -1);
g.TranslateCTM (2, -(this.Bounds.Height / 2) - (this.Font.LineHeight / 3));
CTLine line = new CTLine (this.AttributedText);
CTRun[] runs = line.GetGlyphRuns ();
for (int i = 0; i < runs.Length; i++) {
CTRun run = runs [i];
CTFont font = run.GetAttributes ().Font;
for (int j = 0; j < run.GlyphCount; j++) {
NSRange currentRange = new NSRange (j, 1);
CGPoint[] positions = run.GetPositions (currentRange);
ushort[] glyphs = run.GetGlyphs (currentRange);
CGPath letter = font.GetPathForGlyph (glyphs [0]);
CGAffineTransform transform = CGAffineTransform.MakeTranslation (positions [0].X, positions [0].Y);
CGPath path = new CGPath (letter, transform);
UIBezierPath newPath = UIBezierPath.FromPath (path);
completePath.AppendPath (newPath);
}
}
completePath.LineWidth = 1;
UIColor.Red.SetStroke ();
UIColor.Blue.SetFill ();
completePath.Stroke ();
completePath.Fill ();
completePath.ClosePath ();
//Here I will try to loop over my current points and go down & right at every step of the loop, see how it goes performance-wise. Instead of one complex drawing I'll just have a very simple drawing that has thousands of points :o
g.AddPath (completePath.CGPath);
g.DrawPath (CGPathDrawingMode.FillStroke);
}
There is no built in way to achieve this effect. You have to implement the drawing code on your own.
Here are two ideas to create the shadow:
Draw the text in dark blue color, repeated n times, starting from the original position in 0.5 pt. steps shifted down right. This has bad performance but is really easy to implement.
Find the text outline using Core Text and implement some algorithm that creates the actual outline of the shadow. This could then be used as the shadowPath property.
I was wondering what the correct way would be to apply filter to a image. The image processing textbook that I am reading only talks about the mathematical and theoretical aspect of filters but doesn't talk much the programming part of it !
I came up with this pseudo code could some one tell me if it is correct cause I applied the sobel edge filter to a image and I am not satisfied with the output. I think it detected many unnecessary points as edges and missed out on several points along the edge.
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};// I dont exactly remember the //sobel filter
int total = 0;
for(int i = 2;i<image.getWidth()-2;i++)
for(int j = 2;j<image.getHeight()-2;j++)
{
total = 0;
for(int k = 0;k<3;k++)
for(int l = 0;l<3;l++)
{
total += intensity(image.getRGB(i,j)) * filter[i+k][j+l];
}
if(total >= threshold){
image.setRGB(i,j,WHITE);
}
}
int intensity(int color)
{
return (((color >> 16) & 0xFF) + ((color >> 8) & 0xFF) + color)/3;
}
Two issues:
(1) The sober operator includes x-direction and y-direction, they are
int filter[][] = {{1d,0d,-1d},{2d,0d,-2d},{1d,0d,-1d}}; and
int filter[][] = {{1d,2d,1d},{0d,0d,0d},{-1d,-2d,-1d}};
(2) The convolution part:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Your code doesn't look quiet right to me. In order to apply the filter to the image you must apply the discrete time convolution algorithm http://en.wikipedia.org/wiki/Convolution.
When you do convolution you want to slide the 3x3 filter over the image, moving it one pixel at a time. At each step you multiply the value of the filter 'pixel' by the corresponding value of the image pixel which is under that particular filter 'pixel' (the 9 pixels under the filter are all affected). The values that result should be added up onto a new resulting image as you go.
Thresholding is optional...
The following is your code modified with some notes:
int filter[][] = {{0d,-1d,0d},{-1d,8d,-1d},{0d,-1d,0d}};
//create a new array for the result image on the heap
int newImage[][][3] = ...
//initialize every element in the newImage to 0
for(int i = 0;i<image.getWidth()-1;i++)
for(int j = 0;j<image.getHeight()-1;j++)
for (int k = 0; k<3; k++)
{
newImage[i][j][k] = 0;
}
//Convolve the filter and the image
for(int i = 1;i<image.getWidth()-2;i++)
for(int j = 1;j<image.getHeight()-2;j++)
{
for(int k = -1;k<2;k++)
for(int l = -1;l<2;l++)
{
newImage[i+k][j+l][1] += getRed(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][2] += getGreen(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
newImage[i+k][j+l][3] += getBlue(image.getRGB(i+k ,j+l)) * filter[k+1][l+1];
}
}
int getRed(int color)
{
...
}
int getBlue(int color)
{
...
}
int getGreen(int color)
{
...
}
Please note that the code above does not handle the edges of the image exactly right. If you wanted to make it absolutely perfect you'd start by sliding the filter mostly off screen (so the first position would apply the lower right corner of the filter to the image 0,0 pixel of the image. Doing this is really a pain though, so usually its easier just to ignore the 2 pixel border around the edges.
Once you've got that working you can experiment by sliding the Sobel filter in the horizontal and then the vertical directions. You will notice that the filter acts most strongly on lines which are perpendicular to the direction of travel (to the filter). So for the best results apply the filter in the horizontal and then the vertical direction (using the same newImage). That way you will detect vertical as well as horizontal lines equally well. :)
You have some serious undefined behavior going on here. The array filter is 3x3 but the subscripts you're using i+k and j+l are up to the size of the image. It looks like you've misplaced this addition:
total += intensity(image.getRGB(i+k,j+l)) * filter[k][l];
Use GPUImage, it's quite good for you.
I'm currently making a 2D game engine, and I'm working in the messages for the characters, for this I'm using the fillText method of 2DContext however I have no idea how to stroke a text, I have already tried this way:
context.lineWidth = 1;
context.strokeStyle = '#000';
context.fillText(line, x, y);
context.stroke();
But it doesnt work, I already modified the text color and style like so:
context.font = '18pt Arial';
context.fillStyle = "black";
But no clue about the stroke.
When working with the Canvas, the cascade operator .. can help make the code more readable:
context..lineWidth = 3
..strokeStyle = "black"
..strokeText(line, x, y)
..fillStyle = "white"
..fillText(line, x, y);
Found it! the correct way of doing it is:
context.lineWidth = 3;
context.strokeStyle = "black";
context.strokeText(line, x, y);
context.fillStyle = "white";
context.fillText(line, x, y);
Don't forget the fillText after the stroke otherwise what you'll see is a very bold version of the text in the color of the stroke.