Drawing a contrasted string on an image

2020-03-06 01:53发布

So, I have a snapshot of a video source, which I get into an Image, grab a Graphics object for it, and then draw a timestamp in the bottom right of the image. No problem thus far. However, I cannot guarantee what colour is going to be behind the text, so no matter what brush I use, it will almost certainly clash with some of the images that it is drawn on, making the text unreadable.

I am wondering if anyone knows of a way (either a method in .net, or a nice algorithm), for determining the best colour for a string based on the image behind it.

Cheers

6条回答
时光不老,我们不散
2楼-- · 2020-03-06 02:04
 just draw the string 5 times.
 One time 1(or2) pixels to the left in black
 One time 1(or2) pixels to the right in black
 One time 1(or2) pixels above it in black
 One time 1(or2) pixels below it in black
 and the final time in white on the place where you want it
查看更多
干净又极端
3楼-- · 2020-03-06 02:11

The only reliable way is to use a contrasting outline.

查看更多
家丑人穷心不美
4楼-- · 2020-03-06 02:16

Or, if it is allowed, you could use a background color (your choice) for the text (for example white text on black background).

Otherwise, you would need to capture the rectangle where the text is written (for every frame), create the negative image of it, and then get the median color in the rectangle and use it to write the text.

A more complex solution would get you to use two layers (initial picture - L1 and Text (transparent background, black text) - L2), and before combining them, take all the pixels from L2 that contain text and change the color for the each pixel of the text to the "negative" underlying pixel color value of the L1, but you won't get something that's too usable from a "viewer's" point of view.

查看更多
ら.Afraid
5楼-- · 2020-03-06 02:17

The following snippet shows how to invert a color (background) and then applies Dinah's suggestion to create the background using Graphics.DrawString().

private static Color InvertColor(Color c)
{
  return Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B);
}
// In the following, constants and inplace vars can be parameters in your code
const byte ALPHA = 192;
var textColor = Color.Orange;
var textBrush = new SolidBrush(Color.FromArgb(ALPHA, textColor));
var textBrushBkg = new SolidBrush(Color.FromArgb(ALPHA, InvertColor(textColor)));
var font = new Font("Tahoma", 7);
var info = "whatever you wanna write";
var r = new Rectangle(10, 10, 10, 10);

// write the text
using (var g = Graphics.FromImage(yourBitmap))
{
  g.Clear(Color.Transparent);
  // to avoid bleeding of transparent color, must use SingleBitPerPixelGridFit
  g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  // Draw background for text
  g.DrawString(info, font, textBrushBkg, r.Left - 1, r.Top - 1);
  g.DrawString(info, font, textBrushBkg, r.Left + 1, r.Top + 1);
  g.DrawString(info, font, textBrushBkg, r.Left + 1, r.Top - 1);
  g.DrawString(info, font, textBrushBkg, r.Left - 1, r.Top + 1);
  // Draw text
  g.DrawString(info, font, textBrush, r.Left, r.Top);
}
查看更多
成全新的幸福
6楼-- · 2020-03-06 02:21

This could be a number of variations on the answer by reinier.

  1. Draw underlying text (the four offset ones mentioned by reinier) not in black, but actually in a contrasting color to the foreground color of the actualy text.
  2. Draw the text twice: once in a contrasting color but in bold and/or a slightly larger size, then in the text foreground color over that. Might have to fiddle a bit with coordinates and even need to do the drawing per word or even character to get both passes to nicely align and not give an ugly end result.
  3. Do what reinier suggested, but perhaps not four times (all four directions), but maybe three or even two times to get a kind of "shaded" look.
  4. Let go of the whole "draw text pixel by pixel using API calls" approach and use advanced multilayer compositing techniques like the ones available in WPF design.

For some examples of the last option, check out slides 18 and 21 in Advanced OSM Cartography on SlideShare.

查看更多
小情绪 Triste *
7楼-- · 2020-03-06 02:27

Back in the days of Commodore 64 sprite graphics, if you wanted something to stand out against any background, you used XOR blitting. Some people referred to this as 'reverse video'.

You can draw lines this way using ControlPaint.DrawReversibleLine, but that won't work for text.

This CodeProject article shows how you can create an XOR brush using interop to gdi32.dll.

查看更多
登录 后发表回答