Какой хороший алгоритм для получения цвета, чтобы сделать текст на изображении выдающимся?

Например, под изображением внизу фотография является фоном, а в центре фотографии есть символ "Иньеста". Но характер немного трудно читать, потому что цвет не очень хорош. Есть ли хороший алгоритм для получения цвета, чтобы сделать персонажа на изображении выдающимся?

введите описание изображения здесь

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)

Например, граница в один пиксель будет выглядеть так...введите описание изображения здесь

Есть много подходов, которые отличаются для статической и динамической сцены. Я предполагаю статическое изображение, поэтому я сосредоточен на этом. вот несколько основных подходов:

  1. Область бумаги

    освободите место за текстом с цветом бумаги и отредактируйте текст с цветом чернил, как вы упоминали, это не круто для сложных изображений.

  2. Инсульт, тень,3D

    визуализировать текст в 2 цвета. Внутри цвет текста и обводка с контрастным цветом. Если у вас нет такой возможности, вы можете сначала визуализировать символ с большим размером шрифта / жирности в цвете обводки, а затем перезаписать меньшим размером шрифта с помощью внутреннего цвета. +/- сместить позицию, чтобы центрировать шрифты. Метод смещения определяет, можно ли выполнить рендеринг обводки, тени или даже трехмерного текста следующим образом.

  3. прозрачность

    Вместо рендеринга пикселей текста постоянным цветом добавьте некоторое значение цвета к исходному цвету пикселя. Вы также можете вычесть цвет или использовать альфа-микширование...

  4. 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).

Другие вопросы по тегам