Как реализовать рамку или размытие по Гауссу на iOS - PullRequest
19 голосов
/ 17 июля 2009

Я хочу иметь возможность сделать снимок и сделать его относительно быстро (скажем, за 0,1 с). Размер изображения почти никогда не будет больше 256 x 256 пикселей.

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

PS : я знаю, что множественные размытия могут приближаться к размытию по Гауссу.

Ответы [ 7 ]

35 голосов
/ 23 ноября 2010

Я нашел очень быстрый, довольно дурацкий способ для приложений iOS3.2 +

  UIView *myView = [self view];
  CALayer *layer = [myView layer];
  [layer setRasterizationScale:0.25];
  [layer setShouldRasterize:YES];

Это растеризует вид до кусков 4x4 пикселей, затем масштабирует его обратно с помощью билинейной фильтрации ... это ЧРЕЗВЫЧАЙНО быстро и выглядит нормально, если вы просто хотите размыть фоновое изображение при модальном виде.

Чтобы отменить его, просто установите масштаб растеризации обратно на 1,0 или отключите растеризацию.

5 голосов
/ 10 августа 2009

С как-то-я-создаю размытый текст-в-iphone-view:

Взгляните на образец Apple GLImageProcessing для iPhone. Это делает некоторые размытия, между прочим.

Соответствующий код включает в себя:

static void blur(V2fT2f *quad, float t) // t = 1
{
    GLint tex;
    V2fT2f tmpquad[4];
    float offw = t / Input.wide;
    float offh = t / Input.high;
    int i;

    glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);

    // Three pass small blur, using rotated pattern to sample 17 texels:
    //
    // .\/.. 
    // ./\\/ 
    // \/X/\   rotated samples filter across texel corners
    // /\\/. 
    // ../\. 

    // Pass one: center nearest sample
    glVertexPointer  (2, GL_FLOAT, sizeof(V2fT2f), &quad[0].x);
    glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &quad[0].s);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glColor4f(1.0/5, 1.0/5, 1.0/5, 1.0);
    validateTexEnv();
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // Pass two: accumulate two rotated linear samples
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    for (i = 0; i < 4; i++)
    {
        tmpquad[i].x = quad[i].s + 1.5 * offw;
        tmpquad[i].y = quad[i].t + 0.5 * offh;
        tmpquad[i].s = quad[i].s - 1.5 * offw;
        tmpquad[i].t = quad[i].t - 0.5 * offh;
    }
    glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &tmpquad[0].x);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glActiveTexture(GL_TEXTURE1);
    glEnable(GL_TEXTURE_2D);
    glClientActiveTexture(GL_TEXTURE1);
    glTexCoordPointer(2, GL_FLOAT, sizeof(V2fT2f), &tmpquad[0].s);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB,      GL_INTERPOLATE);
    glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB,         GL_TEXTURE);
    glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB,         GL_PREVIOUS);
    glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB,         GL_PRIMARY_COLOR);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB,     GL_SRC_COLOR);
    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA,    GL_REPLACE);
    glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA,       GL_PRIMARY_COLOR);

    glColor4f(0.5, 0.5, 0.5, 2.0/5);
    validateTexEnv();
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // Pass three: accumulate two rotated linear samples
    for (i = 0; i < 4; i++)
    {
        tmpquad[i].x = quad[i].s - 0.5 * offw;
        tmpquad[i].y = quad[i].t + 1.5 * offh;
        tmpquad[i].s = quad[i].s + 0.5 * offw;
        tmpquad[i].t = quad[i].t - 1.5 * offh;
    }
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // Restore state
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glClientActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, Half.texID);
    glDisable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB,     GL_SRC_ALPHA);
    glActiveTexture(GL_TEXTURE0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glDisable(GL_BLEND);
}
4 голосов
/ 17 июля 2009

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

  1. Предварительно вычислите изображение фильтра G (u, v), которое является двумерным гауссианом
  2. Применение преобразования Фурье к входному изображению f (x, y) -> F (u, v)
  3. Фильтр по умножению: H (u, v) = F (u, v). * G (u, v) (пиксельное умножение, не матричное умножение)
  4. Преобразование вашего отфильтрованного изображения обратно в пространственную область с помощью обратного преобразования Фурье: H (u, v) -> h (x, y)

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

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

Кроме этого, я полагаю, поскольку iPhone поддерживает OpenGL, вы можете использовать его функции текстурирования / рисования для этого. Извините, однако, что я не эксперт по OpenGL и не могу дать практического совета, как это сделать.

3 голосов
/ 17 июля 2009

Вот два трюка для размытия бедного человека:

  1. Возьмите изображение, нарисуйте его с частичной непрозрачностью 5 или 6 (или сколько угодно) раз, каждый раз сдвигая пару пикселей в другом направлении. рисование большего количества раз в большем количестве направлений дает вам лучшее размытие, но вы, очевидно, тратите время на обработку. Это хорошо работает, если вы хотите размытие с относительно небольшим радиусом.

  2. Для монохроматических изображений вы можете фактически использовать построение в тени как простое размытие.

2 голосов
/ 17 июля 2009

Возможно, вы захотите взглянуть на алгоритм StakBlur Марио Клингемана. Это не совсем гауссовски, но довольно близко.

1 голос
/ 20 июля 2009

Любой алгоритм, который модифицирует изображения на уровне пикселей через openGL, будет немного медленным; попиксельное манипулирование текстурой openGL с последующим обновлением каждого кадра, к сожалению, не соответствует производительности.

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

0 голосов
/ 20 ноября 2010

Самая базовая размытость (или, возможно, более мягкое) заключается в усреднении 2 соседних пикселей и применении среднего к обоим пикселям. Повторите это по всему изображению, и вы получите небольшое размытие (смягчение).

...