Добавление рыбы искажение глаз в растровое изображение


У меня есть следующий класс, который обрабатывает растровое изображение, чтобы разместить искажений "рыбий глаз" на него. Я запустить мое приложение с помощью инструмента traceview и обнаружили, что практически все время обработки расходуется циклической обработке растрового изображения. Один разработчик предложил не используя поплавка, так как это будет медленные вещи вниз, когда дело касается графики. Кроме того, используя математику.через PoW() и ceil()используется не нужны?

На данный момент место эффект перебрав весь рисунок занимает около 42 секунд, да секунд:) я пытался заменить поплавки с целыми числами и что позволило сократить время на 37 секунд, но эффект не присутствует на изображении. Аргумент к изначально поплавок и устанавливает уровень искажений (например 0.0002 Ф). Если я пройду целое число, то эффект не работает.

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

class Filters{
    float xscale;
    float yscale;
    float xshift;
    float yshift;
    int [] s;
    private String TAG = "Filters";
    long getRadXStart = 0;
    long getRadXEnd = 0;
    long startSample = 0;
    long endSample = 0;
    public Filters(){

        Log.e(TAG, "***********inside filter constructor");
    }

    public Bitmap barrel (Bitmap input, float k){
        //Log.e(TAG, "***********INSIDE BARREL METHOD ");

        float centerX=input.getWidth()/2; //center of distortion
        float centerY=input.getHeight()/2;

        int width = input.getWidth(); //image bounds
        int height = input.getHeight();

        Bitmap dst = Bitmap.createBitmap(width, height,input.getConfig() ); //output pic
       // Log.e(TAG, "***********dst bitmap created ");
          xshift = calc_shift(0,centerX-1,centerX,k);

          float newcenterX = width-centerX;
          float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,k);

          yshift = calc_shift(0,centerY-1,centerY,k);

          float newcenterY = height-centerY;
          float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,k);

          xscale = (width-xshift-xshift_2)/width;
        //  Log.e(TAG, "***********xscale ="+xscale);
          yscale = (height-yshift-yshift_2)/height;
        //  Log.e(TAG, "***********yscale ="+yscale);
        //  Log.e(TAG, "***********filter.barrel() about to loop through bm");


          int origPixel;
          long startLoop = System.currentTimeMillis();
          for(int j=0;j<dst.getHeight();j++){
              for(int i=0;i<dst.getWidth();i++){
                 origPixel= input.getPixel(i,j);
                 getRadXStart = System.currentTimeMillis();
                float x = getRadialX((float)j,(float)i,centerX,centerY,k);
                getRadXEnd= System.currentTimeMillis();

                float y = getRadialY((float)j,(float)i,centerX,centerY,k);

                sampleImage(input,x,y);

                int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
    //            System.out.print(i+" "+j+" \\");

                if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 ){
                dst.setPixel(i, j, color);
                }else{
                    dst.setPixel(i,j,origPixel);
                }
              }
            }

        return dst;
    }

    void sampleImage(Bitmap arr, float idx0, float idx1)
    {
         startSample = System.currentTimeMillis();
        s = new int [4];
      if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1)){
        s[0]=0;
        s[1]=0;
        s[2]=0;
        s[3]=0;
        return;
      }

      float idx0_fl=(float) Math.floor(idx0);
      float idx0_cl=(float) Math.ceil(idx0);
      float idx1_fl=(float) Math.floor(idx1);
      float idx1_cl=(float) Math.ceil(idx1);

      int [] s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
      int [] s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
      int [] s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
      int [] s4 = getARGB(arr,(int)idx0_cl,(int)idx1_fl);

      float x = idx0 - idx0_fl;
      float y = idx1 - idx1_fl;

      s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
      s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
      s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
      s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));

      endSample = System.currentTimeMillis();
    }

    int [] getARGB(Bitmap buf,int x, int y){

        int rgb = buf.getPixel(y, x); // Returns by default ARGB.
        int [] scalar = new int[4];
        scalar[0] = (rgb >>> 24) & 0xFF;
        scalar[1] = (rgb >>> 16) & 0xFF;
        scalar[2] = (rgb >>> 8) & 0xFF;
        scalar[3] = (rgb >>> 0) & 0xFF;
        return scalar;
    }

    float getRadialX(float x,float y,float cx,float cy,float k){

      x = (x*xscale+xshift);
      y = (y*yscale+yshift);
      float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
      return res;
    }

    float getRadialY(float x,float y,float cx,float cy,float k){

      x = (x*xscale+xshift);
      y = (y*yscale+yshift);
      float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
      return res;
    }

    float thresh = 1;

    float calc_shift(float x1,float x2,float cx,float k){

      float x3 = (float)(x1+(x2-x1)*0.5);
      float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
      float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));

      if(res1>-thresh && res1 < thresh)
        return x1;
      if(res3<0){
        return calc_shift(x3,x2,cx,k);
      }
      else{
        return calc_shift(x1,x3,cx,k);
      }
    }



}// end of filters class


1191
8
задан 19 июня 2011 в 04:06 Источник Поделиться
Комментарии
2 ответа

Эта линия будет жрать много производительности:

if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= 150 )

Сначала для простого возведения в квадрат, напишите ваши собственные функции:

float sqr(float x) { return x*x; }

Вторая и даже более важная, если площадь выражений с обеих сторон (что хорошо, потому что оба положительны), вам не нужно дорогостоящее функция sqrt-функция на левой стороне. Просто написать:

if( sqr(i - centerX) + sqr(j - centerY) <= 150*150 )

Есть много других мелочей, например

float x3 = (float)(x1+(x2-x1)*0.5);

...может быть...

float x3 = (x1+(x2-x1)*0.5f);

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

Я пытался улучшить свою версию. Конечно, я не мог проверить его...

import java.util.Arrays;

class Filters {
float xscale;
float yscale;
float xshift;
float yshift;
int[] s = new int[4];
int[] s1 = new int[4];
int[] s2 = new int[4];
int[] s3 = new int[4];
int[] s4 = new int[4];
private String TAG = "Filters";
long getRadXStart = 0;
long getRadXEnd = 0;
long startSample = 0;
long endSample = 0;
float xr;
float yr;

public Filters() {
//Log.e(TAG, "***********inside filter constructor");
}

public Bitmap barrel(Bitmap input, float k) {
//Log.e(TAG, "***********INSIDE BARREL METHOD ");

float centerX = input.getWidth() / 2; //center of distortion
float centerY = input.getHeight() / 2;

int width = input.getWidth(); //image bounds
int height = input.getHeight();

Bitmap dst = Bitmap.createBitmap(width, height, input.getConfig()); //output pic
// Log.e(TAG, "***********dst bitmap created ");
xshift = calc_shift(0, centerX - 1, centerX, k);

float newcenterX = width - centerX;
float xshift_2 = calc_shift(0, newcenterX - 1, newcenterX, k);

yshift = calc_shift(0, centerY - 1, centerY, k);

float newcenterY = height - centerY;
float yshift_2 = calc_shift(0, newcenterY - 1, newcenterY, k);

xscale = (width - xshift - xshift_2) / width;
// Log.e(TAG, "***********xscale ="+xscale);
yscale = (height - yshift - yshift_2) / height;
// Log.e(TAG, "***********yscale ="+yscale);
// Log.e(TAG, "***********filter.barrel() about to loop through bm");

int origPixel;
long startLoop = System.currentTimeMillis();
for (int j = 0; j < dst.getHeight(); j++) {
for (int i = 0; i < dst.getWidth(); i++) {
origPixel = input.getPixel(i, j);
getRadXStart = System.currentTimeMillis();
getRadialXY(j, i, centerX, centerY, k);
getRadXEnd = System.currentTimeMillis();

sampleImage(input, xr, yr);

int color = ((s[1] & 0x0ff) << 16) | ((s[2] & 0x0ff) << 8) | (s[3] & 0x0ff);
// System.out.print(i+" "+j+" \\");

dst.setPixel(i, j,
(sqr(i - centerX) + sqr(j - centerY) <= 150 * 150)
? color
: origPixel);
}
}

return dst;
}

float sqr(float x) {
return x * x;
}
float cube(float x) {
return x * x * x;
}

void sampleImage(Bitmap arr, float idx0, float idx1) {
startSample = System.currentTimeMillis();
Arrays.fill(s, 0);
if (idx0 < 0 || idx1 < 0 || idx0 > (arr.getHeight() - 1) || idx1 > (arr.getWidth() - 1)) {
return;
}

float idx0_fl = (float) Math.floor(idx0);
float idx0_cl = (float) Math.ceil(idx0);
float idx1_fl = (float) Math.floor(idx1);
float idx1_cl = (float) Math.ceil(idx1);

getARGB(s1, arr, (int) idx0_fl, (int) idx1_fl);
getARGB(s2, arr, (int) idx0_fl, (int) idx1_cl);
getARGB(s3, arr, (int) idx0_cl, (int) idx1_cl);
getARGB(s4, arr, (int) idx0_cl, (int) idx1_fl);

float x = idx0 - idx0_fl;
float y = idx1 - idx1_fl;

//reordered for less multiplications
for(int i = 0; i < 4; i++) {
s[i] = (int) (s1[i] + x*(s4[i]-s1[i]) + y *(s2[i]-s1[i] + x*(s1[i]-s2[i]+s3[i]-s4[i])));
}

endSample = System.currentTimeMillis();
}

void getARGB(int[] scalar, Bitmap buf, int x, int y) {
int rgb = buf.getPixel(y, x); // Returns by default ARGB.
scalar[0] = (rgb >>> 24) & 0xFF;
scalar[1] = (rgb >>> 16) & 0xFF;
scalar[2] = (rgb >>> 8) & 0xFF;
scalar[3] = rgb & 0xFF;
}

void getRadialXY(float x, float y, float cx, float cy, float k) {
x = (x * xscale + xshift);
y = (y * yscale + yshift);
float f = k * (sqr(x - cx) + sqr(y - cy));
xr = x + ((x - cx) * f);
yr = y + ((y - cy) * f);
}
float thresh = 1;

float calc_shift(float x1, float x2, float cx, float k) {

float x3 = x1 + (x2 - x1) * 0.5f;
float res1 = x1 + cube(x1 - cx) * k ;

if (-thresh < res1 && res1 < thresh) {
return x1;
}

float res3 = x3 + cube(x3 - cx) * k;
return (res3 < 0)
? calc_shift(x3, x2, cx, k)
: calc_shift(x1, x3, cx, k);
}
}// end of filters class

3
ответ дан 19 июня 2011 в 06:06 Источник Поделиться

Вы, возможно, захотите рассмотреть возможность работы линии во времени, а не пиксель-в-а-время. Глядя на документацию, это будет означать, называя getPixels и setPixels , а не метода getpixel/методом setpixel. Каждый вызов любой из этих функций необходимо преобразовать (Х, Y) координаты можно указать на смещение в буфере (например. г * line_length + х), и если вы делаете это для каждого пикселя в большие изображения этих умножений можно добавить до.

Что-то вроде...

int pixels[] = new int[width];

for (int y = 0; y<height; ++y)
{
input.getPixels(pixels, 0, width, 0, y, width, 1);

for (int x = 0; x<width; ++x)
{
// TODO: make modification on pixels[x]
}

dst.setPixels(pixels, 0, width, 0, y, width, 1);
}

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

Я тоже согласна с @Landei, что Х * Х лучше, чем ПР(х, 2).

2
ответ дан 19 июня 2011 в 07:06 Источник Поделиться