【问题标题】:How to simulate fisheye lens effect by openCV?如何通过openCV模拟鱼眼镜头效果?
【发布时间】:2010-12-27 23:34:07
【问题描述】:

我正在寻找创建鱼眼镜头效果的方法,查看了 openCV 的文档,看起来它包含用于鱼眼等径向失真的相机校准功能。是否可以通过openCV模拟鱼眼失真?

如果可以通过 openCV 来实现,与 openGL 相比,哪一个会产生更好的结果?谢谢。

【问题讨论】:

    标签: opencv simulate fisheye distortion radial


    【解决方案1】:

    我使用 opencv 创建了this app。这就是你说的效果吗? 我基本上编写了维基百科“失真(光学)”上显示的公式,如果需要,我可以显示代码

    更新: 好的,下面是使用 opencv 用 c++ 编写的实际代码(未记录,请随时寻求解释): 程序接收以下参数作为输入:|输入图像| |输出图像| |控制失真量的 K(通常尝试 0.001 左右的值)| |变形中心的 x 坐标| |变形中心的 y 坐标|

    所以程序的关键是双 for 循环,它在结果图像上逐个像素地迭代,并使用径向失真公式在输入图像中寻找匹配的像素(这是通常完成图像变形的方式 - 可能通过从输出到输入的反投影来直观地反击)。有一些细节与输出图像的比例有关(在这个程序中,生成的图像与输入的大小相同),除非你想了解更多细节,否则我不会深入探讨。享受吧。

        #include <cv.h>
        #include <highgui.h>
        #include <math.h>
        #include <unistd.h>
        #include <getopt.h>
        #include <iostream>
    
    
        void sampleImage(const IplImage* arr, float idx0, float idx1, CvScalar& res)
        {
          if(idx0<0 || idx1<0 || idx0>(cvGetSize(arr).height-1) || idx1>(cvGetSize(arr).width-1)){
            res.val[0]=0;
            res.val[1]=0;
            res.val[2]=0;
            res.val[3]=0;
            return;
          }
          float idx0_fl=floor(idx0);
          float idx0_cl=ceil(idx0);
          float idx1_fl=floor(idx1);
          float idx1_cl=ceil(idx1);
    
          CvScalar s1=cvGet2D(arr,(int)idx0_fl,(int)idx1_fl);
          CvScalar s2=cvGet2D(arr,(int)idx0_fl,(int)idx1_cl);
          CvScalar s3=cvGet2D(arr,(int)idx0_cl,(int)idx1_cl);
          CvScalar s4=cvGet2D(arr,(int)idx0_cl,(int)idx1_fl);
          float x = idx0 - idx0_fl;
          float y = idx1 - idx1_fl;
          res.val[0]= s1.val[0]*(1-x)*(1-y) + s2.val[0]*(1-x)*y + s3.val[0]*x*y + s4.val[0]*x*(1-y);
          res.val[1]= s1.val[1]*(1-x)*(1-y) + s2.val[1]*(1-x)*y + s3.val[1]*x*y + s4.val[1]*x*(1-y);
          res.val[2]= s1.val[2]*(1-x)*(1-y) + s2.val[2]*(1-x)*y + s3.val[2]*x*y + s4.val[2]*x*(1-y);
          res.val[3]= s1.val[3]*(1-x)*(1-y) + s2.val[3]*(1-x)*y + s3.val[3]*x*y + s4.val[3]*x*(1-y);
        }
    
        float xscale;
        float yscale;
        float xshift;
        float yshift;
    
        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 = 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)));
    
          //  std::cerr<<"x1: "<<x1<<" - "<<res1<<" x3: "<<x3<<" - "<<res3<<std::endl;
    
          if(res1>-thresh and res1 < thresh)
            return x1;
          if(res3<0){
            return calc_shift(x3,x2,cx,k);
          }
          else{
            return calc_shift(x1,x3,cx,k);
          }
        }
    
        int main(int argc, char** argv)
        {
          IplImage* src = cvLoadImage( argv[1], 1 );
          IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
          IplImage* dst2 = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
          float K=atof(argv[3]);
          float centerX=atoi(argv[4]);
          float centerY=atoi(argv[5]);
          int width = cvGetSize(src).width;
          int height = cvGetSize(src).height;
    
          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);
          //  scale = (centerX-xshift)/centerX;
          xscale = (width-xshift-xshift_2)/width;
          yscale = (height-yshift-yshift_2)/height;
    
          std::cerr<<xshift<<" "<<yshift<<" "<<xscale<<" "<<yscale<<std::endl;
          std::cerr<<cvGetSize(src).height<<std::endl;
          std::cerr<<cvGetSize(src).width<<std::endl;
    
          for(int j=0;j<cvGetSize(dst).height;j++){
            for(int i=0;i<cvGetSize(dst).width;i++){
              CvScalar s;
              float x = getRadialX((float)i,(float)j,centerX,centerY,K);
              float y = getRadialY((float)i,(float)j,centerX,centerY,K);
              sampleImage(src,y,x,s);
              cvSet2D(dst,j,i,s);
    
            }
          }
        #if 0
          cvNamedWindow( "Source1", 1 );
          cvShowImage( "Source1", dst);
          cvWaitKey(0);
        #endif
    
          cvSaveImage(argv[2],dst,0);
    
        #if 0
          for(int j=0;j<cvGetSize(src).height;j++){
            for(int i=0;i<cvGetSize(src).width;i++){
              CvScalar s;
              sampleImage(src,j+0.25,i+0.25,s);
              cvSet2D(dst,j,i,s);
            }
          }
    
          cvNamedWindow( "Source1", 1 );
          cvShowImage( "Source1", src);
          cvWaitKey(0);
    
        #endif  
    
    }
    

    【讨论】:

    • 是的! Wiki 的“失真(光学)”页面上的桶形失真正是我正在寻找的!我想知道如何使用openCV在鱼眼镜头周围映射图像。你能在这里显示你的代码吗?或者给我一些提示?谢谢你。问候
    • 我试图理解代码,但有点犹豫,有许多我不知道为什么会发生的操作。是否可以添加简短的简介或说明?
    【解决方案2】:

    感谢以上 2 提供此代码。我已经用 Java 修改了上面的转录代码以使用 Bitmaps 而不是 BufferedImage。这使代码能够在 Android(不支持 AWT)上运行。我还制作了效果只是操纵圆圈中的像素而不是整个位图,这会产生鱼眼“镜头”效果。希望这可以帮助任何 Android 开发者。

    import android.graphics.Bitmap;
    import android.util.Log;
    
    class Filters{
        float xscale;
        float yscale;
        float xshift;
        float yshift;
        int [] s;
        private String TAG = "Filters";
        public Filters(){
    
            Log.e(TAG, "***********inside 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;
              yscale = (height-yshift-yshift_2)/height;
              Log.e(TAG, "***********about to loop through bm");
              /*for(int j=0;j<dst.getHeight();j++){
                  for(int i=0;i<dst.getWidth();i++){
                    float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                    float y = getRadialY((float)i,(float)j,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+" \\");
    
                    dst.setPixel(i, j, color);
    
                  }
                }*/
    
              int origPixel; // the pixel in orig image
    
              for(int j=0;j<dst.getHeight();j++){
                  for(int i=0;i<dst.getWidth();i++){
                     origPixel= input.getPixel(i,j);
                    float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                    float y = getRadialY((float)i,(float)j,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+" \\");
    
    
    // check whether a pixel is within the circle bounds of 150
    
                    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)
        {
            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));
        }
    
        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);
          }
        }
    }
    

    .

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.FutureTask;
    
    import android.graphics.Bitmap;
    import android.graphics.drawable.BitmapDrawable;
    import android.os.Debug;
    import android.util.Log;
    
    public class MultiRuntimeProcessorFilter {
    
    
    
        private static final String TAG = "mrpf";
        private int x = 0;
        private Bitmap input = null;
        private int radius;
    
    
        public void createBitmapSections(int nOp, int[] sections){
    
            int processors = nOp;
            int jMax = input.getHeight();
            int aSectionSize = (int) Math.ceil(jMax/processors);
            Log.e(TAG, "++++++++++ sections size = "+aSectionSize);
    
    
            int k = 0;
            for(int h=0; h<processors+1; h++){
    
                    sections[h] = k;
                    k+= aSectionSize;
    
    
    
            }
        }// end of createBitmapSections()
    
    
    
        @SuppressWarnings("unchecked")
        public Bitmap barrel (Bitmap input, float k, int r){
              this.radius = r;
              this.input = input;
              int []arr = new int[input.getWidth()*input.getHeight()];
    
    
              Log.e(TAG, "bitmap height = "+input.getHeight()); 
    
    
    
    
              int nrOfProcessors = Runtime.getRuntime().availableProcessors();
              Log.e(TAG, "no of processors = "+nrOfProcessors);
    
              int[] sections = new int[nrOfProcessors+1];
    
    
              createBitmapSections(nrOfProcessors,sections);
              ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);
    
              for(int g=0; g<sections.length;g++){
                  Log.e(TAG, "++++++++++ sections= "+sections[g]);
              }
    
             // ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);
    
              Object[] task = new Object[nrOfProcessors];
    
              for(int z = 0; z < nrOfProcessors; z++){
                 task[z]  = (FutureTask<PartialResult>) threadPool.submit(new PartialProcessing(sections[z], sections[z+1] - 1, input, k));  
                 Log.e(TAG, "++++++++++ task"+z+"= "+task[z].toString()); 
              }
    
             PartialResult[] results = new PartialResult[nrOfProcessors];
    
             try{
                  for(int t = 0; t < nrOfProcessors; t++){
    
                      results[t] = ((FutureTask<PartialResult>) task[t]).get();
    
                      results[t].fill(arr);
                  }
    
              }catch(Exception e){
                  e.printStackTrace();
              }
    
              Bitmap dst2 = Bitmap.createBitmap(arr,input.getWidth(),input.getHeight(),input.getConfig());
    
    
            return dst2;
    
    
            }//end of barrel()
    
    
    
    
        public class PartialResult {
               int startP;
               int endP;
               int[] storedValues;
    
               public PartialResult(int startp, int endp, Bitmap input){
    
                   this.startP = startp;
                   this.endP = endp;
                   this.storedValues = new int[input.getWidth()*input.getHeight()];
    
    
               }
    
               public void addValue(int p, int result) {
                     storedValues[p] = result;
    
               }
    
               public void fill(int[] arr) {
    
    
    
                  for (int p = startP; p < endP; p++){
                      for(int b=0;b<radius;b++,x++)
                     arr[x] = storedValues[x];
    
                  } 
                  Log.e(TAG, "++++++++++ x ="+x);
                  }
    
               }//end of partialResult
    
    
    
    
        public class PartialProcessing implements Callable<PartialResult> {
            int startJ;
            int endJ;
    
    
            private int[] scalar;
            private float xscale;
            private float yscale;
            private float xshift;
            private float yshift;
            private float thresh = 1;
            private int [] s1;
            private int [] s2;
            private int [] s3;
            private int [] s4;
            private int [] s;
            private Bitmap input;
            private float k;
    
    
    
            public PartialProcessing(int startj, int endj, Bitmap input, float k) {
    
                this.startJ = startj;
                this.endJ = endj;
                this.input = input;
                this.k = k;
    
                s = new int[4];
                scalar = new int[4];
                s1 = new int[4];
                s2 = new int[4];
                s3 = new int[4];
                s4 = new int[4];
    
            }
    
            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 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);
                }
              }
    
    
              void sampleImage(Bitmap arr, float idx0, float idx1)
              {
    
                 // 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);
    
    
    
                 s1 = getARGB(arr,(int)idx0_fl,(int)idx1_fl);
                 s2 = getARGB(arr,(int)idx0_fl,(int)idx1_cl);
                 s3 = getARGB(arr,(int)idx0_cl,(int)idx1_cl);
                 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));
    
    
              }
    
    
    
            @Override public PartialResult call() { 
    
                 PartialResult partialResult = new PartialResult(startJ, endJ,input);
    
                 float centerX=input.getWidth()/2; //center of distortion
                 float centerY=input.getHeight()/2;
    
    
    
                 int width = input.getWidth(); //image bounds
                 int height = input.getHeight();
    
    
    
                  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;
    
                  yscale = (height-yshift-yshift_2)/height;
    
    
                int p = startJ*radius; 
                int origPixel = 0;
                int color = 0;
                int i;
    
                for (int j = startJ; j <  endJ; j++){
    
                    for ( i = 0; i < width; i++, p++){
    
    
                 origPixel = input.getPixel(i,j);
    
                 float x = getRadialX((float)j,(float)i,centerX,centerY,k);
    
    
                 float y = getRadialY((float)j,(float)i,centerX,centerY,k);
    
                 sampleImage(input,x,y);
    
                 color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
                //Log.e(TAG, "radius = "+radius);
    
                 if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*(radius/4)){
    
                                     partialResult.addValue(p, color);
    
    
                }else{
    
    
                    partialResult.addValue(p, origPixel);
    
    
    
                }
    
                    }//end of inner for
    
            }//end of outer for
    
                return partialResult;
        }//end of call
    
    
    }// end of partialprocessing
    
    }//end of MultiProcesorFilter
    

    @And_Dev 承诺

    下面是让用户触摸坐标然后在选定区域调用过滤器的视图。所选区域是绳索,例如圆心加上半径(圆)。该代码在隆胸应用程序中执行此操作的两倍:)只需注释掉 Horizo​​ntalSlider 代码,因为您不需要它。

    import java.io.BufferedInputStream;
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff.Mode;
    import android.graphics.PorterDuffXfermode;
    import android.os.Environment;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    import com.tecmark.HorizontalSlider.OnProgressChangeListener;
    
    public class TouchView extends View{
    
    
        private File tempFile;
        private byte[] imageArray;
        private Bitmap bgr;
    
        private Bitmap crop;
        private Bitmap crop2;
        private Bitmap overLay;
        private Bitmap overLay2;
    
    
        private float centreX;
        private float centreY;
        private float centreA = 200;
        private float centreB = 200;
        private Boolean xyFound = false;
        private int Progress = 1;
        private static final String TAG = "*********TouchView";
        private Filters f = null;
        private boolean bothCirclesInPlace = false;
        private MultiProcessorFilter mpf;
        private MultiProcessorFilter mpf2;
        private MultiRuntimeProcessorFilter mrpf;
        private MultiRuntimeProcessorFilter mrpf2;
    
    
    
    
    
        public TouchView(Context context) {
            super(context);
    
        }
    
    
    
    
        public TouchView(Context context, AttributeSet attr) {
            super(context,attr);
            Log.e(TAG, "++++++++++ inside touchview constructor");
    
    
    
            tempFile = new File(Environment.getExternalStorageDirectory().
                    getAbsolutePath() + "/"+"image.jpg");
    
            imageArray = new byte[(int)tempFile.length()];
    
    
         try{
    
                InputStream is = new FileInputStream(tempFile);
                BufferedInputStream bis = new BufferedInputStream(is);
                DataInputStream dis = new DataInputStream(bis);
    
    
                int i = 0;
    
                while (dis.available() > 0) {
                imageArray[i] = dis.readByte();
                i++;
                }
    
                dis.close();
    
           } catch (Exception e) {
    
                   e.printStackTrace();
                }
    
    
           Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length);
    
    
    
    
            bgr = bm.copy(bm.getConfig(), true);;
    
            overLay = null;
            overLay2 = null;
    
    
    
           bm.recycle();
    
        }// end of touchView constructor
    
    
    
    
        public void findCirclePixels(){ 
    
             //  f = new Filters();
             //  mpf = new MultiProcessorFilter();
             //  mpf2 = new MultiProcessorFilter();
             mrpf = new MultiRuntimeProcessorFilter();
             mrpf2 = new MultiRuntimeProcessorFilter();
    
             crop = Bitmap.createBitmap(bgr,Math.max((int)centreX-75,0),Math.max((int)centreY-75,0),150,150);
             crop2 = Bitmap.createBitmap(bgr,Math.max((int)centreA-75,0),Math.max((int)centreB-75,0),150,150);
    
                  new Thread(new Runnable() {
                    public void run() {
                        float prog = (float)Progress/150001;
    
                   // final Bitmap bgr3 = f.barrel(crop,prog);
                   // final Bitmap bgr4 = f.barrel(crop2,prog);
    
                  //  final Bitmap bgr3 = mpf.barrel(crop,prog);
                  //  final Bitmap bgr4 = mpf2.barrel(crop2,prog);
    
                        final Bitmap bgr3 = mrpf.barrel(crop,prog);
                        final Bitmap bgr4 = mrpf2.barrel(crop2,prog);
    
                      TouchView.this.post(new Runnable() {
                        public void run() {
    
    
                          TouchView.this.overLay = bgr3;
                          TouchView.this.overLay2 = bgr4;
    
                          TouchView.this.invalidate();
    
                        }
                      });
                    }
                  }).start();
    
    
            }// end of changePixel()
    
    
    
    
    
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
    
            switch (ev.getAction()) {
    
                case MotionEvent.ACTION_DOWN: {
    
                    if(xyFound == false){
                    centreX = (int) ev.getX();
                    centreY = (int) ev.getY();
                    xyFound = true;
                    }else{
                    centreA = (int) ev.getX();
                    centreB = (int) ev.getY();
                    bothCirclesInPlace  = true;
                    }
    
    
                    break;
                }
    
              /*  case MotionEvent.ACTION_MOVE: {
    
                    if(xyFound == false){
                        centreX = (int) ev.getX();
                        centreY = (int) ev.getY();
                        xyFound = true;
                    }else{
                        centreA = (int) ev.getX();
                        centreB = (int) ev.getY();
                        bothCirclesInPlace = true;
                        }
    
                        findCirclePixels();
                     // TouchView.this.invalidate();
                        break;
    
                }*/           
    
                case MotionEvent.ACTION_UP: 
    
                    break;
    
            }
            return true;
        }//end of onTouchEvent
    
    
    
    
    
        public void initSlider(final HorizontalSlider slider)
        {
    
            slider.setOnProgressChangeListener(changeListener);
    
    
        }
    
    
    
        private OnProgressChangeListener changeListener = new OnProgressChangeListener() {
    
    
            @Override
            public void onProgressChanged(View v, int progress) {
    
    
    
                  setProgress(progress);
    
    
    
            }
        };
    
    
    
    
        @Override
        public void onDraw(Canvas canvas){
            super.onDraw(canvas);
    
            Log.e(TAG, "******about to draw bgr ");
            canvas.drawBitmap(bgr, 0, 0, null);
    
            if(bothCirclesInPlace == true){
    
                    if(overLay != null){
                        Log.e(TAG, "******about to draw overlay1 ");
            canvas.drawBitmap(overLay, centreX-75, centreY-75, null);
                    }
                if(overLay2 != null){
                    Log.e(TAG, "******about to draw overlay2 ");
            canvas.drawBitmap(overLay2, centreA-75, centreB-75, null);
                }
    
            }
    
        }//end of onDraw
    
    
    
    
        protected void setProgress(int progress2) {
            Log.e(TAG, "***********in SETPROGRESS");
            this.Progress = progress2;
    
    
    
            findCirclePixels();
    
    
        }
    
    
    
    
    }
    

    .

    调用活动。

    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.view.Window;
    import android.view.WindowManager;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class Jjilapp extends Activity {
    
    
    
    
        private static final String TAG = "*********jjil";
    
    
        @Override 
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
            setContentView(R.layout.touchview);
            final TouchView touchView = (TouchView)findViewById(R.id.touchview); 
            final HorizontalSlider slider = (HorizontalSlider)findViewById(R.id.slider); 
    
            touchView.initSlider(slider);
    
    
    
    
        }//end of oncreate
    
    
    
    
    }
    

    如果您需要任何帮助,请询问。希望这会有所帮助

    【讨论】:

    • 我已经在 android 中尝试过您的代码,但球体仍然是黑色的。我也在 OpenCV 上试过这个,它工作正常,但我需要在 android 应用程序中使用这个功能。你能指导我吗?谢谢
    • @Challenger 你在哪个版本的 android 上运行它?
    • 我已经调试过了,发现像素的alpha值没有在球体区域设置,为什么它会变黑。设置像素的 alpha 解决了这个问题。感谢您的宝贵时间
    • @challenge 嘿,很高兴你成功了!我实际上已经重新完成了这段代码,所以它使用并行化处理位图。它检查设备以查看有多少处理器可用,例如在我的 htc one X 上有 4 个内核。它将位图分成 4 个,为每个核心分配一个段,然后在完成后将它们全部缝合在一起。如果您愿意,您可以拥有代码,请告诉我。它适用于 android 2.1,但在 android 4.0 上不太好。如果你想玩它,看看你能不能让它继续下去,如果你愿意,我只是要求更新;)
    • 谢谢,感谢您的帮助。我已经使用了上面的代码,它非常适合方形图像,但是当图像的宽度和高度之间的差异太大时,输出球体将从边界变为黑色,也不是从中心,我尝试调试但尚未成功,如果您知道如何解决此问题,请分享。如果您与我分享并行化代码,我会很高兴。
    【解决方案3】:

    感谢您提供该代码。它对我有很大帮助。我为Java对其进行了转码。也许有人有类似的功能来模拟切向失真?

    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import com.jhlabs.image.InterpolateFilter;
    
    class Filters{
        float xscale;
        float yscale;
        float xshift;
        float yshift;
        int [] s;
        public Filters(){
    
        }
    
        public BufferedImage barrel (BufferedImage input, float k){
    
            float centerX=input.getWidth()/2; //center of distortion
            float centerY=input.getHeight()/2;
    
            int width = input.getWidth(); //image bounds
            int height = input.getHeight();
    
            BufferedImage dst = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB); //output pic
    
              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;
              yscale = (height-yshift-yshift_2)/height;
    
              for(int j=0;j<dst.getHeight();j++){
                  for(int i=0;i<dst.getWidth();i++){
                    float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                    float y = getRadialY((float)i,(float)j,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+" \\");
    
                    dst.setRGB(i, j, color);
    
                  }
                }
            return dst;
        }
    
        void sampleImage(BufferedImage arr, float idx0, float idx1)
        {
            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));
        }
    
        int [] getARGB(BufferedImage buf,int x, int y){
            int rgb = buf.getRGB(x, y); // 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);
          }
        }
    }
    

    【讨论】:

    • 嗨,这个java代码正是我需要的。我正在尝试在 Android 上创建相同的效果,但不能使用 bufferedimage,因为 android 不支持它。有没有办法让这段代码在android上运行?任何帮助将不胜感激,谢谢马特
    【解决方案4】:

    我调试了 java 文件,它在我的手机上运行良好(高于 4.0)。它由3个java文件和1个xml文件组成。您必须将 checkerboardback.jpg 文件放在 drawaable 目录下。正如有人所说,缺少 alpha 值,我给它“0x0ff”。另外,有些Looping的upperbound是错误的。

    //1. MultiRuntimeProcessorFilter.java

    public class MultiRuntimeProcessorFilter {
    
    
    
    private static final String TAG = "mrpf";
    private int x = 0;
    private Bitmap input = null;
    private int radius;
    private int mHeight;
    
    
    public void createBitmapSections(int nOp, int[] sections){
    
        int processors = nOp;
        int jMax = input.getHeight();
        int aSectionSize = (int) Math.ceil(jMax/processors);
        Log.e("yoSIZECHK", "++++++++++ sections size = "+aSectionSize);
    
        int k = 0;
        for(int h=0; h<processors+1; h++){
    
                sections[h] = k;
                k+= aSectionSize;
                if(h==processors){
                    sections[h] = mHeight;//Last must cover ceiling
                }
            Log.v("yoSEC","sections = "+h+" "+sections[h]);
    
        }
    }// end of createBitmapSections()
    
    
    //@SuppressWarnings("unchecked")
    public Bitmap barrel (Bitmap input, float k, int r){
          this.radius = r;
          this.input = input;
          int []mArray = new int[input.getWidth()*input.getHeight()];
    
          mHeight = input.getHeight();
          Log.e(TAG, "bitmap height x width = "+mHeight+" "+input.getWidth());
      //Log.v("yoRESULT", "height width = "+ input.getWidth()+" "+input.getHeight());
    
    
    
    
          int nrOfProcessors = Runtime.getRuntime().availableProcessors();
          Log.e(TAG, "no of processors = "+nrOfProcessors);
    
    
          int[] sections = new int[nrOfProcessors+1];
    
    
          createBitmapSections(nrOfProcessors,sections);
          ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);
    
          for(int g=0; g<sections.length;g++){
              Log.e(TAG, "++++++++++ sections= "+sections[g]);
          }
    
      // ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);
    
          Object[] task = new Object[nrOfProcessors];
    
          for(int z = 0; z < nrOfProcessors; z++){
             task[z]  = (FutureTask<PartialResult>) threadPool.submit(new PartialProcessing(sections[z], sections[z+1] - 1, input, k, z));
             Log.e(TAG, "++++++++++ task"+z+"= "+task[z].toString()); 
          }
    
         PartialResult[] results = new PartialResult[nrOfProcessors];
    
         try{
              for(int t = 0; t < nrOfProcessors; t++){
    
                  results[t] = ((FutureTask<PartialResult>) task[t]).get();
    
                  results[t].fill(mArray);
              }
    
          }catch(Exception e){
              e.printStackTrace();
          }
    
     Log.v("yoRESULT", "height width = "+ input.getHeight()+" "+input.getWidth());
          Bitmap dst2 = Bitmap.createBitmap(mArray,input.getWidth(),input.getHeight(),input.getConfig());
    
        return dst2;
    
    
        }//end of barrel()
    
    
    
    
    public class PartialResult {
           int startP;
           int endP;
           int[] storedValues;
    
           public PartialResult(int startp, int endp, Bitmap input){
    
               this.startP = startp;
               this.endP = endp;
               this.storedValues = new int[input.getWidth()*input.getHeight()];
    
    
           }
    
           public void addValue(int p, int result) {
                 storedValues[p] = result;
    
           }
    
           public void fill(int[] mArray) {
    
               Log.v("yo09", startP + " " + endP + " " + input.getWidth());
               //yoko for (int p = startP; p < endP; p++){
           for (int p = startP; p < endP+1; p++){
                   //for(int b=0;b<radius;b++,x++)
                  for(int b=0;b<input.getWidth();b++,x++) {
                      mArray[x] = storedValues[x];
                      if (b == 0) Log.v("yoyoyo", p+" + " + storedValues[x]);
                  }
              } 
              Log.e("yoFill", " ++++++++++ radius x = "+radius+" "+x);
       }
    
           }//end of partialResult
    
    
    
    
    public class PartialProcessing implements Callable<PartialResult> {
        int startJ;
        int endJ;
        int mID;
    
    
        private int[] scalar;
        private float xscale;
        private float yscale;
        private float xshift;
        private float yshift;
        private float thresh = 1;
        private int [] s1;
        private int [] s2;
        private int [] s3;
        private int [] s4;
        private int [] s;
        private Bitmap input;
        private float k;
    
    
    
        public PartialProcessing(int startj, int endj, Bitmap input, float k, int mID) {
    
            this.startJ = startj;
            this.endJ = endj;
            this.input = input;
            this.k = k;
            this.mID = mID;
    
            s = new int[4];
            scalar = new int[4];
            s1 = new int[4];
            s2 = new int[4];
            s3 = new int[4];
            s4 = new int[4];
    
        }
    
        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 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);
            }
          }
    
    
          //void sampleImage(Bitmap mArray, float idx0, float idx1)
        int [] sampleImage(Bitmap mArray2, float idx0, float idx1)
          {
    
             // s = new int [4];
            if(idx0<0 || idx1<0 || idx0>(mArray2.getHeight()-1) || idx1>(mArray2.getWidth()-1)){
              s[0]=0;
              s[1]=0;
              s[2]=0;
              s[3]=0;
              return s;// yoko
            }
    
            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);
    
    
    
        s1 = getARGB(mArray2,(int)idx0_fl,(int)idx1_fl);
        s2 = getARGB(mArray2,(int)idx0_fl,(int)idx1_cl);
        s3 = getARGB(mArray2,(int)idx0_cl,(int)idx1_cl);
        s4 = getARGB(mArray2,(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));
    
              return s;
    
          }
    
    
    
        @Override
        public PartialResult call() {
    
             PartialResult partialResult = new PartialResult(startJ, endJ,input);
    
             float centerX=input.getWidth()/2; //center of distortion
             float centerY=input.getHeight()/2;
    
    
    
             int width = input.getWidth(); //image bounds
             int height = input.getHeight();
    
    
    
              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;
    
              yscale = (height-yshift-yshift_2)/height;
    
    
            // yoko int p = startJ*radius;
            int p = startJ*width;//yoko
            int origPixel = 0;
            int color = 0;
            int i;
    
        Log.v("yokoIJ","PartialResult startJ endJ "+startJ+"  "+endJ);
            //yoko for (int j = startJ; j <  endJ; j++){
            for (int j = startJ; j <  endJ+1; j++){
                for ( i = 0; i < width; i++, p++){
        s = new int [4];//yoko added
    
        origPixel = input.getPixel(i,j);
    
        float x = getRadialX((float)j,(float)i,centerX,centerY,k);
        float y = getRadialY((float)j,(float)i,centerX,centerY,k);
        //sampleImage(input,x,y); //yoko
        s= sampleImage(input,x,y);
    
        color = (0xff<<24)|((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
        //Log.e(TAG, "radius = "+radius);
    
         //Not understand why it is not radius but radius/2
             //yoko if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*(radius/4)){
        if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*radius){
                    //yo if(j%10 == 1 && i%10 == 1)
                        //yo Log.v("yoJI", mID+" "+j + " " + i );
            partialResult.addValue(p, color);
        }else{
            partialResult.addValue(p, origPixel);
            }
    
                }//end of inner for
    
        }//end of outer for
    
            return partialResult;
    }//end of call
    }// end of partialprocessing
    }//end of MultiProcesorFilter
    

    // 2.Filters.java:

    class Filters{
    float xscale;
    float yscale;
    float xshift;
    float yshift;
    int [] s;
    private static String TAG = "Filters";
    public Filters(){
        Log.e(TAG, "***********inside constructor");
    }
    
    public Bitmap barrel (Bitmap input, float k, boolean check, int Range){
        Log.e(TAG, "***********inside barrel method : hasAlpha = ");
        float centerX=input.getWidth()/2; //center of distortion
        float centerY=input.getHeight()/2;
    
        int width = input.getWidth(); //image bounds
        int height = input.getHeight();
    
    //yoko        Log.v("yoQQ", width+" "+height+" "+centerX+" "+centerY);
        if(check)return input;
    
        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;
          yscale = (height-yshift-yshift_2)/height;
          Log.e(TAG, "***********about to loop through bm");
      Log.v("yoQQ2", xscale + " " + yscale);
      //if(check==1)return input;//yoko
          /*for(int j=0;j<dst.getHeight();j++){
              for(int i=0;i<dst.getWidth();i++){
                float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                float y = getRadialY((float)i,(float)j,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+" \\");
    
                dst.setPixel(i, j, color);
    
              }
            }*/
    
          int origPixel; // the pixel in orig image
          int i=0,j=0;
          for(j=0;j<dst.getHeight();j++){
              for(i=0;i<dst.getWidth();i++){
                s = new int [4];//yoko added
                 origPixel= input.getPixel(i,j);
                float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                float y = getRadialY((float)i,(float)j,centerX,centerY,k);
                //yoko sampleImage(input,x,y);
                s = sampleImage(input,x,y);
                //yoko int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
                int color = (0xff<<24)|((s[1]&0xff)<<16)|((s[2]&0xff)<<8)|(s[3]&0xff);
                //Log.v("yoQQ3", j + " " + i + " : "+dst.getHeight()+" "+dst.getWidth());
    
    
        // check whether a pixel is within the circle bounds of 150
    
                if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= Range ){
            dst.setPixel(i, j, color);
                    //if(j%10 == 1 && i%10 == 1)
                    //    Log.v("yoJI", j + " " + i );
                }else{
                    dst.setPixel(i,j,origPixel);
                }
              }
            }
        Log.v("yoDONE", "========  Loop End ======== "+j+" "+i+" : " + dst.getHeight()+" "+dst.getWidth());
        return dst;
    }//barrel
    
    //    void sampleImage(Bitmap arr, float idx0, float idx1) // yoko
    int[] sampleImage(Bitmap arr, float idx0, float idx1)
    {
        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 s;
      }
    
      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));
      return s;///yoko added to make return the result value
    }//sampleImage
    
    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;
    }//getARGB
    
    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;
    }//getRadial1X
    
    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;
    }//getRadialY
    
    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);
      }
    }//calc_shift
    }
    

    并且 //3 MainActivity.java,顶级类。

    public class MainActivity extends Activity {
    
    ImageView iv1=null;
    ImageView iv2=null;
    Button bT, bB, b0;
    Bitmap bitmap1, bitmap2, bitmapSP;
    Boolean view1 = true;
    private static final String TAG = "*********jjil";
    public static int mH,mW,RADIUS;
    
    @Override 
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
        setContentView(R.layout.activity_main);
    
        Resources res = this.getResources();
        //bitmap1 = BitmapFactory.decodeResource(res, R.drawable.checkerboard);
        bitmap1 = BitmapFactory.decodeResource(res, R.drawable.checkerboardback);
        mH=bitmap1.getHeight();
        mW=bitmap1.getWidth();
        RADIUS = mH/3;
    
        bT = (Button)findViewById(R.id.buttontoggle);
        bT.setOnClickListener(onClickToggleView);
        bB = (Button)findViewById(R.id.buttonbarrel);
        bB.setOnClickListener(onClickToggleView);
        b0 = (Button)findViewById(R.id.button0);
        b0.setOnClickListener(onClickToggleView);
    
        iv1=(ImageView)findViewById(R.id.touchview1);
        iv1.setImageBitmap(bitmap1);
        iv1.setVisibility(View.VISIBLE);
    
    
    }//end of oncreate
    
    public View.OnClickListener onClickToggleView = new View.OnClickListener() {
        public void onClick(View v) {
            if (v == bT) {
    
        /// fromhere
                new AsyncTask<Void, Void, String>() {
                    com.example.owner.opengl2.Filters mFilers = new com.example.owner.opengl2.Filters();
                    TextView tx = (TextView)findViewById(R.id.mStatus);
                    Bitmap bitmapSP;long start,end;
    
                    protected void onPreExecute() {
                        start = System.nanoTime();
                        iv1.setImageBitmap(bitmap1);
                        tx.setText("- Running -");
                    }
    
                    protected String doInBackground(Void... params) {
                         bitmapSP = mFilers.barrel(bitmap1,(float)0.00005,false,RADIUS);
                        return "message";
                    }
    
                    protected void onPostExecute(String msg) {
                        end = System.nanoTime();
                        long elapsedTime = end - start;
                        long seconds = elapsedTime / 1000000;
    
                        iv1.setImageBitmap(bitmapSP);
                        tx.setText("- READY : ElapsedTime(ms) = "+seconds);
                        // Post Code
                        // Use `msg` in code
                    }
                }.execute();
        ///upto here
    
    
    
            } else if (v == bB){
    
        /// fromhere
                new AsyncTask<Void, Void, String>() {
                    com.example.owner.opengl2.MultiRuntimeProcessorFilter mFilers = new com.example.owner.opengl2.MultiRuntimeProcessorFilter();
                    TextView tx = (TextView)findViewById(R.id.mStatus);
                    Bitmap bitmapSP;long start,end;
    
                    protected void onPreExecute() {
                        start = System.nanoTime();
                        iv1.setImageBitmap(bitmap1);
                        tx.setText("- Running -");
                    }
    
                    protected String doInBackground(Void... params) {
                        bitmapSP = mFilers.barrel(bitmap1,(float)0.00005,RADIUS);
                        return "message";
                    }
    
                    protected void onPostExecute(String msg) {
                        end = System.nanoTime();
                        long elapsedTime = end - start;
                        //double seconds = (double)elapsedTime / 1000000000.0;
                        long seconds = elapsedTime / 1000000;
                        iv1.setImageBitmap(bitmapSP);
                        tx.setText("- READY : ElapsedTime(ms) = "+seconds);
                        // Post Code
                        // Use `msg` in code
                    }
                }.execute();
    
    
            } else if (v == b0){
                new AsyncTask<Void, Void, String>() {
                    protected String doInBackground(Void... Unused) {
                        return "OK";
                    }
                    protected void onPostExecute(String message) {
                        Log.v("YO", "---------------------------------");
                        Log.v("YO", "----------ORIGINAL SHAPE-------- "+message);
                        Log.v("YO", "---------------------------------");
                        iv1.setImageBitmap(bitmap1);
    
                        TextView tx = (TextView)findViewById(R.id.mStatus);
                        tx.setText("- READY : w h RADIUS = "+mW+" "+mH+" "+RADIUS);
                    }
                }.execute();
    
            }
            ///upto here
    
        }
    };
    

    }

    这里是 XML 文件 //4 activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    
    <LinearLayout
        android:id="@+id/buttons"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    
        <Button
            android:id="@+id/buttontoggle"
            android:text="Barrel 1P"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <Button
        android:id="@+id/buttonbarrel"
        android:text="Barrele NP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
        <Button
            android:id="@+id/button0"
            android:text="ORIGINAL"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    
    </LinearLayout>
    <TextView
        android:id="@+id/mStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=" - Ready - "
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_below="@+id/buttons"
        android:layout_centerHorizontal="true"
        />
    
    <ImageView
        android:id="@+id/touchview1"
        android:layout_below="@+id/mStatus"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
         />
    
    <!--ImageView
        android:id="@+id/touchview2"
        android:layout_below="@+id/touchview1"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true" /-->
    

    【讨论】:

      【解决方案5】:

      你想在sintetic图像上使用这种失真,还是想应用到摄像机或其他东西上?

      在 OpenCv 中,您应该能够进行相机校准(使用内置函数,张氏算法)..

      OpenGL 看到这个。

      问候

      【讨论】:

        猜你喜欢
        • 2010-12-27
        • 2012-03-28
        • 2012-10-12
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        • 2012-11-01
        • 2014-01-13
        相关资源
        最近更新 更多