如何用openCV模拟鱼眼镜头效果?

发布于 2024-08-15 20:55:02 字数 130 浏览 10 评论 0原文

我正在寻找创建鱼眼镜头效果的方法,查看了 openCV 的文档,它看起来包含用于像鱼眼这样的径向畸变的相机校准功能。 openCV可以模拟鱼眼畸变吗?

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

I am looking for ways to create fisheye lens effect, looked at documentations for openCV, it looks like it contains Camera Calibration functions for radial distortions like fisheye. Is it possible to simulate fisheye distortion by openCV?

If it is possible to do it by openCV, comparing to openGL, which one will generate better results? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

月隐月明月朦胧 2024-08-22 20:55:02

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

更新
好的,下面是使用 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  

}

I created this app using opencv. Is this the effect you are referring to?
I basically coded the formula shown on wikipedia's "Distortion(optics)" I can show the code if needed

Update:
OK, so below is the actual code written in c++ using opencv (not documented so feel free to ask for explanations):
The program recieves as input the following parameter: |input image| |output image| |K which controlls amount of distortion (typically try values around 0.001)| |x coordinate of center of distortion| |y coordinate of center of distortion|

So the crux of the program is the double for loop which iterates pixel by pixel on the result image and looks for the matching pixel in the input image using the formula for radial distortion (this is the way image warping is generally done - perhaps counter intuitively by back-projection from output to input). There are some subtleties which have to do with the scale of the output image (in this program the resulting image is the same size as the input), and I won't get into it unless you want to get into more details.enjoy.

    #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  

}
紫南 2024-08-22 20:55:02

感谢以上2位提供的这段代码。我修改了上面的 Java 转录代码以使用位图而不是 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




}

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

Thanks to the above 2 for this code. I've modified the above transcribed code in Java to use Bitmaps instead of BufferedImage. This enables the code to run on Android(which doesn't support AWT). I've also made the effect just manipulate the pixels in a circle rather than the whole Bitmap, this gives a fisheye "lens" effect. Hopes this helps any Android developers.

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 as promised

Below is the view that gets the users touch co-ords and then calls the filter on a selected area. the selected area is the cord eg center of circle plus a radius(a circle). the code does this twice as its for a breast augmentation app:) Just comment out the HorizontalSlider code as you don't need this.

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();


    }




}

.

The calling activity.

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




}

If you need any help mate just ask. hope this helps

梅窗月明清似水 2024-08-22 20:55:02

感谢您提供该代码。这对我有很大帮助。我将其转加密为 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);
      }
    }
}

Thanks to you for that code. It helps me a lot. I transcrypted it for Java. Maybe someone has a similar function for symulating tangencial distorsion?

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);
      }
    }
}
小鸟爱天空丶 2024-08-22 20:55:02

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

//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活动_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" /-->

I debugged the java files and it works fine on my phones(higher than 4.0). It consists of 3 java files and 1 xml file. You have to place checkerboardback.jpg file under drawaable directory. As someone said, alpha value was missing and I gave it "0x0ff". In addition, upperbound of some Looping were wrong.

//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
}

And
//3 MainActivity.java, toplevel class.

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

    }
};

}

Here is XML file
//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" /-->

迷鸟归林 2024-08-22 20:55:02

您想在合成图像上使用这种失真,还是想应用于摄像机或其他东西?

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

OpenGL 看到这个。

问候

Do you want to use this distortion on sintetic images, or do you want to apply to a video camera or something ?

In OpenCv you should be able to do camera calibration (using the built-in functions, Zhang's algorithm) ..

In OpenGL see this.

Regards

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文