For instance, below image, a photo is background, and there is a character 'Iniesta' at the center of the photo. But the character is some hard to read because the color is not good. Is there any good algorithm for getting color to make character on image outstanding?
问题:
回答1:
Instead of making a rectangular background (that indeed doesn't look very nice) you could use this trick:
- Pick two contrasting colors (e.g. white and black)
- Stroke the text using first color and a wide pen (e.g. 5 pixels)
- Draw the text filled using the second color
If you cannot stroke the text with a wide pen an alternative is drawing the text multiple times with small offsets; e.g. (Python)
for dy in range(-3, 4):
for dx in range(-3, 4):
draw_text(color1, x+dx, y+dy, message)
draw_text(color2, x, y, message)
For example a one-pixel border would look like this...
回答2:
Here's another idea: choose a box around your text area, or the whole image if it's relatively homogeneous in color. Now compute the average color in this area by summing up the color values and dividing by the number of pixels.
Now choose a color which contrasts well with this average color. For instance, you could use the simple formula (255-r,255-g,255-b)
to get a contrasting color. However, this would fail if the average color is close to 128-gray, so you'd need to special-case on that.
Another way is to convert the average color into HSL or HSV color space, and then play with the hue; for instance, just add 180 to it, and/or invert the "lightness" (value/luminosity). Again, you'd need to special-case the grayscale (saturation close to 0) cases.
回答3:
There are many approaches that differs for static and dynamic scene. I assume static image so i focus on that. here some basic approaches:
Paper area
clear space behind text with paper color and render text with ink color as you mentioned this is not cool for complex images.
Stroke,shadows,3D
render text with 2 colors. Inside with text color and stroke with contrast color to it. If you do not have the capability then you can render character with bigger font/boldness size in stroke color first and then overwrite with smaller font size with inside color
+/-
shift the position to center the fonts. The shifting method determine if you render stroke or shadow or even 3D text can be achieved like thisTransparency
Instead of render pixels of text by constant color add some color value to the original pixel color. You can also substract color or use alpha mixing instead ...
XOR
instead render pixel with color
XOR
the original color with another color or by white
This is how it looks like:
Here the source in VCL/C++:
void TMain::draw()
{
if (!_redraw) return;
// needed variables
AnsiString txt,a;
TColor c0=clBlack,c1=clWhite;
int tx=50,ty=50,tys=30,dty=tys*1.5;
int x,y,x0,x1,y0,y1,i,b;
// clear whole image
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
// copy photo
bmp->Canvas->Draw(0,0,in);
// render texts ...
txt="Paper area ";
bmp->Canvas->Font ->Size=tys;
bmp->Canvas->Font ->Color=c1;
bmp->Canvas->Brush->Color=c0;
bmp->Canvas->Brush->Style=bsSolid;
bmp->Canvas->TextOutA(tx,ty,txt); ty+=dty;
txt="Stroke";
bmp->Canvas->Brush->Style=bsClear;
for (x=tx,y=ty,i=1;i<=txt.Length();i++)
{
a=txt[i];
// stroked char
bmp->Canvas->Font ->Size=tys+3;
bmp->Canvas->Font ->Color=c0;
bmp->Canvas->Font ->Style=TFontStyles()<<fsBold;
x0=bmp->Canvas->TextWidth(a);
y0=bmp->Canvas->TextHeight(a);
bmp->Canvas->TextOutA(x,y,a);
// inside char
bmp->Canvas->Font ->Size=tys;
bmp->Canvas->Font ->Color=c1;
bmp->Canvas->Font ->Style=TFontStyles();
x1=bmp->Canvas->TextWidth(a);
y1=bmp->Canvas->TextHeight(a);
bmp->Canvas->TextOutA(x+((x0-x1)>>1),y+((y0-y1)>>1),a);
// next char position
x+=x0;
} ty+=dty;
txt="Shadow/3D text";
bmp->Canvas->Brush->Style=bsClear;
bmp->Canvas->Font ->Size=tys;
bmp->Canvas->Font ->Color=c0;
for (i=0;i<5;i++)
bmp->Canvas->TextOutA(tx-i,ty+i,txt);
bmp->Canvas->Font ->Color=c1;
bmp->Canvas->TextOutA(tx,ty,txt); ty+=dty;
Graphics::TBitmap *tmp=new Graphics::TBitmap;
tmp->PixelFormat=pf32bit;
tmp->HandleType=bmDIB;
txt="Transparent";
tmp->Canvas->Brush->Style=bsSolid;
tmp->Canvas->Brush->Color=0x00000000; // max black
tmp->Canvas->Font ->Size=tys;
tmp->Canvas->Font ->Color=0x00808080; // color offset
x=bmp->Canvas->TextWidth(txt);
y=bmp->Canvas->TextHeight(txt);
tmp->SetSize(x,y);
tmp->Canvas->FillRect(TRect(0,0,x,y));
tmp->Canvas->TextOutA(0,0,txt);
union col { DWORD dd; BYTE db[4]; } *p0,*p1;
for (y0=0,y1=ty;y0<y;y0++,y1++)
{
p0=(col*)tmp->ScanLine[y0];
p1=(col*)bmp->ScanLine[y1];
for (x0=0,x1=tx;x0<x;x0++,x1++)
for (i=0;i<4;i++)
{
b=WORD(p0[x0].db[i])+WORD(p1[x1].db[i]);
if (b>255) b=255;
p1[x1].db[i]=b;
}
} ty+=dty;
txt="XOR";
tmp->Canvas->Brush->Style=bsSolid;
tmp->Canvas->Brush->Color=0x00000000; // max black
tmp->Canvas->Font ->Size=tys;
tmp->Canvas->Font ->Color=0x00FFFFFF; // max white
x0=bmp->Canvas->TextWidth(txt);
y0=bmp->Canvas->TextHeight(txt);
tmp->SetSize(x0,y0);
tmp->Canvas->FillRect(TRect(0,0,x0,y0));
tmp->Canvas->TextOutA(0,0,txt);
bmp->Canvas->CopyMode=cmSrcInvert;
bmp->Canvas->Draw(tx,ty,tmp); ty+=dty;
bmp->Canvas->CopyMode=cmSrcCopy;
delete tmp;
// render backbuffer
Main->Canvas->Draw(0,0,bmp);
_redraw=false;
}
it uses just VCL encapsulated GDI things so it should be clear enough...
bmp
is backbuffer image
in
is your image
tmp
is temp image for custom combining the text and image