YLScsDrawing Antialiased Edges - c#

There's a neat little library called YLScsDrawing that allows you to skew a bitmap between four corners, and then draw it. Unfortunately, whenever I attempt this, my rectangular bitmap always has incredibly aliased edges, even with IsBilinearInterpolation = True. How could I go about changing this library so that it antialiases the edges?
An example of what I mean can be found below. Look at the top of the green line.

Related

Find image within image (object detection)

I do have different images which all have some kind of border around the "real" image. What I would like to achieve is to find the "real" image (size and location in pixels).
For me the challenge is that the border is not always black (can be any kind of black or grey with a lot of noise) and the "real" image (water with shark in this example) can have any combination of color, saturation, ...
Now in general I'm aware of algorithms like Canny, Blob detection, hough lines, ..., but I have just started using them. So far I managed to find the border for a specific image, but as soon as I try to apply the same algorithms and parameters to the next image it doesn't work. My current approach looks like this (pseudo code):
convert to gray CvInvoke.CvtColor(_processedImage, tempMat, CvEnum.ColorConversion.Rgb2Gray)
downsample with CvInvoke.PyrDown(srcImage, targetImage) and CvInvoke.PyrUp(srcImage, targetImage)
blur image with CvInvoke.GaussianBlur(_processedImage, bluredImage, New Drawing.Size(5, 5), 0)
Binarize with CvInvoke.Threshold(_processedImage, blackWhiteImage, _parameters.BinarizeThreshold, 255, CvEnum.ThresholdType.Binary)
Detect Edges with CvInvoke.Canny(_processedImage, imgEdges, 60, 100)
Find Contours with CvInvoke.FindContours(_processedImage, contours, Nothing, CvEnum.RetrType.External, CvEnum.ChainApproxMethod.ChainApproxSimple)
Assume that largest contour is the real image
I already tried different approaches based on for example:
Thresholding saturation channel and bounding box
Thresholding, canny edge and finding contours
Any hint especially on how to find proper parameters (that apply for all images) for algorithms like (adaptive) threshold and canny as well as ideas for improving the processing pipeline would be highly appreciated.
you can try to subtract black image from this image , and you will get the inside image , way to do this:
Use image subtraction to compare images in C# ,
If the border was uniform, this would be easy. Use cv::reduce to find MIN and MAX of each row and column; then count the top,left,bottom,right rows/columns whose MIN and MAX are equal (or very close) to the pixel value in a nearby corner. For sanity, maybe check the border colour is the same on all sides.
In your example the border contains faint red stuff, but a row/column approach might still be a useful way to simplify the problem. Maybe, as Nofar suggests, take an absolute difference with what you think is the background colour; square it, convert to grey, then reduce to Sums of rows and columns. You still need to find edges, but have reduced the data from two dimensions to one.
If there's a large border and lots of noise, maybe iterate: in the second pass, exclude the rows you think comprise the border, from statistics on columns (and vice versa).
EDIT: The above only works for an upright rectangle! If it could be rotated then the row/column projection method won't work. In that case I might go for sum-of-squared differences as above (don't start by converting to grey as it could throw away information), followed by blurring or some morphology, edge detection then some kind of Hough transform to find straight edges.

Eliminating a border effect

This is a work project. I inherited some code using SharpDX (a DirectX layer). One of my tasks is to fix a piece of code where certain image effects are applying to a geometric shape containing a fill. If the filter is applied to the fill itself, it doesn't conform to the edges. I've figured out the code to pull out an excerpt using the Geometry of the object. For various reasons, they want to keep the fill that exists outside of the shape (namely, we have some distortion effects that pull in pixels outside of the shape), so I need to overlay it over the background. The problem I'm running into is that I'm getting this single-pixel border...
Applying the Soft Edge filter to the visible part
The background with the shape cut out
The two composited together in the program
What I'm actually getting
I can't share a good bit of the code, due to parts of it being proprietary, but the mask is a byte array. I'm building it using the following code:
SingleChannelBitmap mask = new SingleChannelBitmap(MaxRequiredPixels.Width, MaxRequiredPixels.Height, 255);
mask.FillShape(new RectangleF(new PointF(0,0), mask.Size), this.Geometry, 0);
255 is the maximum Alpha value (transparent). I invert it to take the slice out of the background. The only thing I can think of is that, when I do the masking, it's not including the outer edge of the Geometry. I'm going to try expanding the mask by one pixel in the crudest way possible (basically, scanning through and taking anything which is 0 transparency and adding a 0 transparency pixel to the left, right, up, and down), but I know there has to be a more elegant solution.
This has to work for the 3D Edge bevel filter as well, so doing an arbitrarily large whitespace probably won't work for me either.
What you describe is essentially the same haloing problem that sometimes occurs with displaying PNG images. The PNG export process from several programs will store a solid color for any portions of the PNG that has zero alpha, instead of the actual color at those pixels. This makes them function similar to other image formats (GIF) which use a specific color to encode transparent pixels. This significantly reduces the size of the file, however, can cause issues when sampling the image.
Your situation is similar. Although the masked pixels have zero alpha, when doing bilinear sampling, you may sample in between pixels, mixing both color and alpha values (unless pixel and texel centers are perfectly aligned). For example, if you have a 100% alpha, white pixel, next to a 0% alpha red pixel, and sample in between both, the result will be a pink pixel at 50% alpha.
There are several possible solutions:
You could extend the borders of the color layer, such that the 0% alpha border has the same color as its non-0% alpha adjacent pixels.
Intentionally line up the pixel and texel centers, although this can be tricky and/or not possible, depending on your requirements (mostly dependent on resolution).
Use 'nearest' sampling, instead of bilinear when displaying the image. This way, you will never blend in a 0% alpha pixel. However, this may also not be desirable, because your image will likely exhibit more aliasing effects.

Find then hide drawn shape in image?

This may seem like a strange question, but I have a set of pictures I want to use as a fading screen saver, and I want each picture to have an accompanying quote, but each quote will be in a different place, relative to the picture.
Rather than coding a Rectangle for the area of each image, it would be easier just to draw a rectangle in the image, and have it drawn in there.
Now, the drawn shape would be a stark, uniform coloured border (lime green, for instance) because the colour doesn't appear in the pictures, and it would be on a solid coloured background, like black for instance.
My question is: If I draw a lime green rectangle on each image, how could I then, using C#, find that rectangle in the image, get the dimensions of it, and replace the lime green with the background colour, so in the end product, it'd look like the shape was never there to begin with?
I have not tried anything, I have no code to show, because it's an idea I had and though I'm sure it must be possible, I don't even know what to start searching for.
I hope this is possible, if it isn't, then I'll just draw a rectangle for each one, but that's a last resort. :)
Have you thought about using either the emgucv or aforge libraries? They are able to detect shapes in images quite easily. Though they don't detect edges perfectly, if all you want to detect is a rectangle, either one should work well.
Here are two tutorials on shape detection for emgu cv and aforge. Once you have the shape detected, then you can easily cut it out for the background. Say, for example, that you used the aforge Detection of quadrilaterals (in the link), then you could easily get the rectangles position and size by the calling of blobs[i].Rectangle; and create a rectangle with same size and position with picture background color.
If you need more clarification please feel free to comment. Nice idea!

Drawing "transparent" text via C# Graphics, but in a way that it turns the drawn text to be "missing" so it's transparent in the resulting image

I am looking to draw a string on a DC (Graphics - I am using C#) - but I want the drawn text to be "deleted" from the image so that what's left is essentially a cut-out of the text.
If I was to DrawString with a transparent brush obviously nothing would have happened.
Is there a way of drawing something like that, or do I need to use 2 DCs and BitBlt with some combination of NOTs or XOR or whatever (I did similar things years ago, but was wondering if there's an easiery way)?
If you want to cut sth out of the image, you can do it like this:
Drawing2D.GraphicsContainer c = graphics.BeginContainer();
GraphicsPath p = new GraphicsPath();
p.AddString(...);
graphics.SetClip(p, CombineMode.Xor);
graphics.DrawImage(this.Image, this.Location);
graphics.EndContainer(c);
It's like the solution farther above, but first without SetClip the Graphics-Object doesn't get updated, and second, you need to use Xor.
Note, that making a GraphicsContainer is optional, but makes encapsulation easier, especially if you work with transforms.
You might want to try:
// g is your Graphics object
using (var path = new GraphicsPath())
{
path.AddString(.... );
g.Clip.Exclude(path);
}
// Do your other painting here
Sounds like this may require you to make a new image and draw the old one on top. I'm not to sure of your situation though.
You could set Graphics.CompositingMode to CompositingMode.SourceCopy - but I'm not sure if that will work with transparent content.
The way around this is to:
Draw your text to a separate image using red brush over black background.
Iterate over each pixel of text image and target image...
...manually set target image pixel color's Alpha value according to text's image Red component.
If speed is not a concern and you deal with small bitmaps, you can use GetPixel and SetPixel methods. But I would recommend using LockBits to access BitmapData directly and process pixels in a byte array. This is fast and not-so-hard-to-implement solution, although you'll have to deal with "unsafe" code (or use the Marshal class).
LockBits reference on MSDN
Marshal reference on MSDN
From a quick search it unfortunately doesn't look like System.Drawing supports XOR drawing and you need to use unmanaged calls to GDI+. This answer to a similar question links to a page that might explain how to do that - the interesting file is here.
Hope this helps.

Custom InkCanvas (MSDN Code Sample not working properly)

I want to use custom brushes with the InkCanvas.
Their is a code snippet from MSDN. (http://msdn.microsoft.com/en-us/library/ms747347.aspx)
If i use that code and move my mouse VERY fast i get space between the brushes(ellipses):
And my question is of course how to fix this but I'm also curious why this is happening (I want to learn from it) I thought maybe i did something wrong but even if i cut/paste the example it's happening.
One little thing i noticed when reading the code was this comment in the CustomStroke class
// Draw linear gradient ellipses between
// all the StylusPoints in the Stroke
Seems to me like it should draw ellipses between the points not only at the points.
I'm using C#.NET.
Again in short:
Why is this happening
Help me fix it :)
Why this is happening
The custom InkCanvas in the example draws an ellipse at every collected StrokePoint but makes no attempt to draw lines between them. The standard InkCanvas control is implemented by drawing lines between the points it is given. This is why the custom InkCanvas implementation from the example leaves gaps and the built-in one doesn't.
How to "fix" it
The custom code could easily be extended to not leave gaps: In addition to drawing ellipses at each point, it could draw lines between each pair of points.
Code to draw connecting lines might be added before the code to draw the ellipses, like this:
// Draw connecting lines
var geo = new StreamGeometry();
using(geoContext = geo.Open())
{
geoContext.StartFigure(stylusPoints[0], false, false);
geoContext.PolyLineTo(stylusPoints.Skip(1).Cast<Point>(), true, false);
}
drawingContext.DrawGeometry(null, connectingLinePen, geo);
// Draw ellipses
for(int i = 1; i < stylusPoints.Count; i++)
{
... etc ...
This code works by constructing a polyline StreamGeometry and then drawing it to the context. Using a StreamGeometry in this context is generally more efficient than creating a PathGeometry with a Polyline or doing a bunch of DrawLine calls directly on the drawingCanvas.
Note: Using a better digitizer won't solve the underlying problem, which is that the custom InkCanvas is actually designed to only show data at the sampled points and not in between.
ReDAeR
Look this
http://msdn.microsoft.com/en-us/library/bb531278.aspx
Why this is happening: The WPF InkCanvas control has a limited number of inputs per second when using a mouse; meaning that your stylus inputs will have greater and greater distances between them as you move the mouse faster and faster. The sample itself appears to draw elipses at every stylus input point, not in-between the points.
How to solve this: use a Tablet PC - a digitizer such as on a Tablet PC has a much higher number of inputs per second so it is more difficult to encounter, or fill in the blanks - essentially estimate based on previous points, perhaps a bezier curve.

Categories