Как реализовать рамку или размытие по Гауссу на iOS

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

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

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

Ответ 1

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

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

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

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

Ответ 2

Из how-do-i-create-blurred-text-in-a-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);
}

Ответ 3

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

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

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

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

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

Ответ 4

Здесь два трюка для размывания бедных:

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

  • Для монохромных изображений вы можете использовать конструкцию в тени как простое размытие.

Ответ 5

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

Ответ 6

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

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

Ответ 7

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