GDI+ text has a black edge - c#

I'm clearing an image with a transparent color (120 alpha) and then drawing a string onto it with a gradient, and then drawing that image onto a larger image but the text has blackish edge to it instead of being nice and smooth like it should be. The text looks fine if the background is drawn with 255 alpha.
120 Alpha: Image
255 Alpha: Image
As you can see, the text is much easier to read with the background fully opaque
Note: the green dot is my cursor
Edit: gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; removes the black edges but it's blurry, I'll try some other combinations of graphics settings and see how this goes.
Edit: gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; Looks much better, although the A's in the Arial font look a little funky

This is normal behaviour. You must change your drawing order to get it right.
Since you draw the text onto a semi-transparent surface its anti-aliasing pixels will be semi-transparent, too, but somwehre in-between the text color and the background of the first image.
Now, if you draw the result onto another image you will have uniform transparent pixels where no text is, no transparency where text is and varying tranparencies and colors for the antialiasing pixels.
Note that those will have various colors as the antialiasing tries to spread color diferences as well as differences in brightness.
Either write on a non-transparent surface or delay the writing to the end. (Or turn off all anti-aliasing. But that's not nice.)

Related

How to optimal preprocess images for Tesseract in C#, when grayscaled image text color "interferes" with the background color?

I'm struggling with finding a optimal binarization as preprocessing step for OCR (tesseract in C#).
The images are 1624 X 1728 of pixel size and contain car gui elements (Buttons, Sliders, Info Boxes) and corresponding text from a car navigation command interface generation (different use case scenarios like radio control, car control, etc.). The images contain multiple colors, most of images are dark blue, and the text is white/gray or close to white. Unfortunately, I cannot share the images due to data privacy.
Problem: I cannot separate the text from the background in a efficent way (text to be black, everything else to be white), because the text color has a high range and is partialy the same with the background color (speaking of grayscaled images).
Actual procedure: First I convert the RGB Image from System.Drawing.Image to OpenCvSharp.Mat. Then I convert the Mat image from colored to gray and then from gray to binarized.
This is the main code for the binarization:
Mat binarized = grayscaled.Threshold(tresh, maxVal, ThresholdTypes.BinaryInv);
I use 255 as maxVal. If I use tresh=90, the binarized image looks ok overall (even if tesseract results are bad here), but some pixels of the bottom control elements text (and some other text) are white, because the tresh is too high (so some text characters are unsharp and not complete).
If I use like tresh = 40, the characters of the bottom control elements become complete and sharp (as the should be), but the background (middle of the image) gets completely black, which means that some text in there disappears inside of a big black chunk.
So the problem is a high text pixel color range inside of the grayscaled image that "interferes" with the colors of other elements or background, which makes the text extraction hard.
Note: I already tried AdaptiveThresholding like MeanC and GaussianC with different treshholds, kernel sizes and mean substraction constants without good results.
Question: What would be a efficient solution for the preprocessing?
I'm thinking about writing a method that binarizas from RGB, not from grayscaled. So the method would take a RGB image as input and binarize that white text color range into black and everything else into white.
One approach is to remove any frequencies in the image lower than that of your text. This can be done by creating a blurred copy of the image, with a kernel a bit larger than your text, and subtract this blurred image from the original. This should keep high frequencies, i.e. text and other edges, while removing any vignetting or other gradients over the image. Keep in mind that the resulting image will have a different range of values, where some will probably be negative.
Another option would be to split the image into sections, and use different thresholds in each, but that may lead to artifacts at the section boundaries.

ImageSharp: Corner rounding transparency fades dark instead of light

I'm using the ImageSharp library (available on NuGet as 1.0.0-beta0001) for image generation and manipulation in .NET Core 2.0, and have encountered something that I can't seem to find a way around.
Using this example as a basis, I'm trying to round the corners of a white image. What I'm finding is that the transparent IPath corners being punched out end up antialiasing dark, as if the transparent "color" were black or gray (whereas it really shouldn't be considered any color at all).
Here's the upper-right quadrant of the image to demonstrate what I mean:
I tried all the options for PixelBlenderMode at this part of the code and none have produced what I'm after:
img.Mutate(x => x.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
{
BlenderMode = PixelBlenderMode.Src // enforces that any part of this shape that has color is punched out of the background
}));
The problem you are seeing is the consequence of incorrect pixel sampling. Pixels with low transparency were affecting the average value of the individual components too much.
Quoting some of the text from below link as an example as it explains the issues well.
A pixel in the white area has a color of RGBA(1.00, 1.00, 1.00, 1.00). A pixel in the red area has color RGBA(1.00, 0.00, 0.00, 0.10). If you average those numbers together, you get (1.00, 0.50, 0.50, 0.55). That’s the color a typical pixel on the boundary would have if you resize the image in the straightforward way.
But that color – a half-opaque light red – is the wrong color! You can see a faint red halo around the border, which shouldn’t be there:
http://entropymine.com/imageworsener/resizealpha/
The fix is simple, values must be premultiplied by their alpha component first before sampling.
However, I don't know whether this issue is happening due to resizing the generated image (fixed in the latest nightlies), or during the fill process. I would need to see sample code first to be sure as I do not know how you are providing the source image.

How to convert true type font to bitmap image?

I have a difficulty as I am trying to render a character with a specific font style to the bitmap image (black and white). My question is the font is basically black and white and I am writing the character in black (against white background), however when I convert it to bitmap image I get a coloured thin outline around the bindery of my character.
Can anyone tell me where that grey color comes from while I am writing it with black color and how can i get ONLY black and white pixels?
The pixels that aren't completely black or completely white are the result of anti-aliasing. Anti-aliasing is used by default since everyone who doesn't know about it probably wants it.
I suggest two alternatives. One, create your bitmap with a one bit per pixel format, which will not give anti-aliasing a chance. Second, you can go through the resulting image after the text has been drawn pixel by pixel and adjust each pixel to either black or white based on a threshold. I.e. if the picture is darker than half then it's black, otherwise it's white. e.g. if (red+green+blue > 383) set_pixel_white() else set_pixel_black(); But you'll need be ready for some rather funny results. You may need to play with the thresholds.
PS there's a better solution, you can tweak anti-aliasing. MSDN You'll set your rendering to System.Drawing.Text.TextRenderingHint.SingleBitPerPixel or something that suits you.

Change background colour of an anti-aliased image using C# with anti-aliasing

I have an image where I need to change the background colour (E.g. changing the background of the example image below to blue).
However, the image is anti-aliased so I cannot simply do a replace of the background colour with a different colour.
One way I have tried is creating a second image that is just the background and changing the colour of that and merging the two images into one, however this does not work as the border between the two images is fuzzy.
Is there any way to do this, or some other way to achieve this that I have no considered?
Example image
Just using GDI+
Image image = Image.FromFile("cloud.png");
Bitmap bmp = new Bitmap(image.Width, image.Height);
using (Graphics g = Graphics.FromImage(bmp)) {
g.Clear(Color.SkyBlue);
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.None;
g.DrawImage(image, Point.Empty);
}
resulted in:
Abstractly
Each pixel in your image is a (R, G, B) vector, where each component is in the range [0, 1]. You want a transform, T, that will convert all of the pixels in your image to a new (R', G', B') under the following constraints:
black should stay black
T(0, 0, 0) = (0, 0, 0)
white should become your chosen color C*
T(1, 1, 1) = C*
A straightforward way to do this is to choose the following transform T:
T(c) = C* .* c (where .* denotes element-wise multiplication)
This is just standard image multiplication.
Concretely
If you're not worried about performance, you can use the (very slow) methods GetPixel and SetPixel on your Bitmap to apply this transform for each pixel in it. If it's not clear how to do this, just say so in a comment and I'll add a detailed explanation for that part.
Comparison
Compare this to the method presented by LarsTech. The method presented here is on the top; the method presented by LarsTech is on the bottom. Notice the undesirable edge effects on the bottom icon (white haze on the edges).
And here is the image difference of the two:
Afterthought
If your source image has a transparent (i.e. transparent-white) background and black foreground (as in your example), then you can simply make your transform T(a, r, g, b) = (a, 0, 0, 0) then draw your image on top of whatever background color you want, as LarsTech suggested.
If it is a uniform colour you want to replace you could convert this to an alpha. I wouldn't like to code it myself!
You could use GIMP's Color To Alpha source code (It's GPL), here's a version of it
P.S. Not sure how to get the latest.
Background removal /replacement, IMO is more art than science, you’ll not find one algorithm fit all solution for this BUT depending on how desperate or interested you are in solving this problem, you may want to consider the following explanation:
Let’s assume you have a color image.
Use your choice of decoding mechanism and generate a gray scale / luminosity image of your color image.
Plot a graph (metaphorically speaking) of numeric value of the pixel(x) vs number of pixels in the image for that value(y). Aka. a luminosity histogram.
Now if your background is large enough (or small), you’d see a part of the graph representing the distribution of a range of pixels which constitute your background. You may want to select a slightly wider range to handle the anti-aliasing (based on a fixed offset that you define if you are dealing with similar images) and call it the luminosity range for your background.
It would make your life easier if you know at least one pixel (sample/median pixel value) out of the range of pixels which defines your background, that way you can ‘look up’ the part of the graph which defines your background.
Once you have the range of luminosity pixels for the background, you may run through the original image pixels, compare their luminosity values with the range you have, if it falls within, replace the pixel in the original image with the desired color, preferably luminosity shifted based on the original pixel and the sample pixel, so that the replaced background looks anti-aliased too.
This is not a perfect solution and there are a lot of scenarios where it might fail / partially fail, but again it would work for the sample image that you had attached with your question.
Also there are a lot of performance improvement opportunities, including GPGPU etc.
Another possible solution would be to use some of the pre-built third party image processing libraries, there are a few open source such as Camellia but I am not sure of what features are provided and how sophisticated they are.

Image Modification (cropping and de-skewing) in C#

With a mobile device I take a picture of a flat light object on a dark surface. (for instance a coupon clipped out of a newspaper).
The image is then run through a brightness/contrast filter. If it is too dark, vital components are left out. If it is too bright, the writing on the coupon is lost.
This image is then converted into a bitonal image. Any pixel that is 50% or more dark is converted to black, everything else is white. (done)
I am left with a skewed bitonal image (think of a white trapezoid inside a larger rectangle with a black background).
I need to figure out how to crop the image - which when it's on a black background is easier than when it's on a white background. Then, I have to de-skew the image so it is rectangular instead of trapezoidal, while attempting to preserve aspect.
The end result should be a nicely cropped, bitonal, readable image of the coupon.
To crop your image, you can use the LockBits method and scan through all your pixels to find the first pixel with content from the top, left, right and bottom, respectively. How to use LockBits is described nicely here: https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspx
Assuming your image is not rotated, and that the skewing comes from the camera held at an angle against the table where the coupon is being photographed, you should now have a skewed image of the coupon, fitting perfectly within the bounds of the cropped bitmap. You should also know the four corners of the trapezoid.
"Undistorting" an image is not as easy as you might think though. However, good people have solved this problem and you can probably port their code to your own use. Here is a link I used to explore this problem in a similar case some time ago:
http://ryoushin.com/cmerighi/en-US/2007-10-29_61/Image_Distortion_Enhancements
I also have some code stored somewhere if you can't make any sense of what you find.

Categories

Resources