Какой хороший алгоритм для получения цвета, чтобы сделать текст на изображении выдающимся?
Например, под изображением внизу фотография является фоном, а в центре фотографии есть символ "Иньеста". Но характер немного трудно читать, потому что цвет не очень хорош. Есть ли хороший алгоритм для получения цвета, чтобы сделать персонажа на изображении выдающимся?
3 ответа
Вместо создания прямоугольного фона (который на самом деле выглядит не очень красиво), вы можете использовать этот трюк:
- Выберите два контрастных цвета (например, белый и черный)
- Выделите текст, используя первый цвет и широкое перо (например, 5 пикселей)
- Нарисуйте текст, заполненный вторым цветом
Если вы не можете обводить текст широкой ручкой, альтернативой является рисование текста несколько раз с небольшими смещениями; например (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)
Например, граница в один пиксель будет выглядеть так...
Есть много подходов, которые отличаются для статической и динамической сцены. Я предполагаю статическое изображение, поэтому я сосредоточен на этом. вот несколько основных подходов:
Область бумаги
освободите место за текстом с цветом бумаги и отредактируйте текст с цветом чернил, как вы упоминали, это не круто для сложных изображений.
Инсульт, тень,3D
визуализировать текст в 2 цвета. Внутри цвет текста и обводка с контрастным цветом. Если у вас нет такой возможности, вы можете сначала визуализировать символ с большим размером шрифта / жирности в цвете обводки, а затем перезаписать меньшим размером шрифта с помощью внутреннего цвета.
+/-
сместить позицию, чтобы центрировать шрифты. Метод смещения определяет, можно ли выполнить рендеринг обводки, тени или даже трехмерного текста следующим образом.прозрачность
Вместо рендеринга пикселей текста постоянным цветом добавьте некоторое значение цвета к исходному цвету пикселя. Вы также можете вычесть цвет или использовать альфа-микширование...
XOR
вместо того, чтобы сделать пиксель с цветом
XOR
оригинальный цвет с другим цветом или белым
Вот как это выглядит:
Вот источник в 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;
}
он использует только GCL- объекты, инкапсулированные в VCL, поэтому это должно быть достаточно ясно...
bmp
это изображение буфераin
ваше изображениеtmp
является временным изображением для пользовательского сочетания текста и изображения
Вот еще одна идея: выберите рамку вокруг текстовой области или всего изображения, если оно относительно однородно по цвету. Теперь вычислите средний цвет в этой области путем суммирования значений цвета и деления на количество пикселей.
Теперь выберите цвет, который хорошо контрастирует с этим средним цветом. Например, вы можете использовать простую формулу (255-r,255-g,255-b)
чтобы получить контрастный цвет. Однако это не получится, если средний цвет будет близок к 128-серому, поэтому вам нужно будет использовать специальный случай.
Другой способ - преобразовать средний цвет в цветовое пространство HSL или HSV, а затем поиграть с оттенком; например, просто добавьте 180 и / или инвертируйте "легкость" (значение / яркость). Опять же, вам понадобится особый случай шкалы яркости (насыщенность, близкая к 0).