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

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

    #include <cv.h>
    #include <highgui.h>
    #include <math.h>
    #include <unistd.h>
    #include <getopt.h>
    #include <iostream>


    void sampleImage(const IplImage* arr, float idx0, float idx1, CvScalar& res)
    
      if(idx0<0 || idx1<0 || idx0>(cvGetSize(arr).height-1) || idx1>(cvGetSize(arr).width-1))
        res.val[0]=0;
        res.val[1]=0;
        res.val[2]=0;
        res.val[3]=0;
        return;
      
      float idx0_fl=floor(idx0);
      float idx0_cl=ceil(idx0);
      float idx1_fl=floor(idx1);
      float idx1_cl=ceil(idx1);

      CvScalar s1=cvGet2D(arr,(int)idx0_fl,(int)idx1_fl);
      CvScalar s2=cvGet2D(arr,(int)idx0_fl,(int)idx1_cl);
      CvScalar s3=cvGet2D(arr,(int)idx0_cl,(int)idx1_cl);
      CvScalar s4=cvGet2D(arr,(int)idx0_cl,(int)idx1_fl);
      float x = idx0 - idx0_fl;
      float y = idx1 - idx1_fl;
      res.val[0]= s1.val[0]*(1-x)*(1-y) + s2.val[0]*(1-x)*y + s3.val[0]*x*y + s4.val[0]*x*(1-y);
      res.val[1]= s1.val[1]*(1-x)*(1-y) + s2.val[1]*(1-x)*y + s3.val[1]*x*y + s4.val[1]*x*(1-y);
      res.val[2]= s1.val[2]*(1-x)*(1-y) + s2.val[2]*(1-x)*y + s3.val[2]*x*y + s4.val[2]*x*(1-y);
      res.val[3]= s1.val[3]*(1-x)*(1-y) + s2.val[3]*(1-x)*y + s3.val[3]*x*y + s4.val[3]*x*(1-y);
    

    float xscale;
    float yscale;
    float xshift;
    float yshift;

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

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

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

      //  std::cerr<<"x1: "<<x1<<" - "<<res1<<" x3: "<<x3<<" - "<<res3<<std::endl;

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

    int main(int argc, char** argv)
    
      IplImage* src = cvLoadImage( argv[1], 1 );
      IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
      IplImage* dst2 = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
      float K=atof(argv[3]);
      float centerX=atoi(argv[4]);
      float centerY=atoi(argv[5]);
      int width = cvGetSize(src).width;
      int height = cvGetSize(src).height;

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

      yshift = calc_shift(0,centerY-1,centerY,K);
      float newcenterY = height-centerY;
      float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,K);
      //  scale = (centerX-xshift)/centerX;
      xscale = (width-xshift-xshift_2)/width;
      yscale = (height-yshift-yshift_2)/height;

      std::cerr<<xshift<<" "<<yshift<<" "<<xscale<<" "<<yscale<<std::endl;
      std::cerr<<cvGetSize(src).height<<std::endl;
      std::cerr<<cvGetSize(src).width<<std::endl;

      for(int j=0;j<cvGetSize(dst).height;j++)
        for(int i=0;i<cvGetSize(dst).width;i++)
          CvScalar s;
          float x = getRadialX((float)i,(float)j,centerX,centerY,K);
          float y = getRadialY((float)i,(float)j,centerX,centerY,K);
          sampleImage(src,y,x,s);
          cvSet2D(dst,j,i,s);

        
      
    #if 0
      cvNamedWindow( "Source1", 1 );
      cvShowImage( "Source1", dst);
      cvWaitKey(0);
    #endif

      cvSaveImage(argv[2],dst,0);

    #if 0
      for(int j=0;j<cvGetSize(src).height;j++)
        for(int i=0;i<cvGetSize(src).width;i++)
          CvScalar s;
          sampleImage(src,j+0.25,i+0.25,s);
          cvSet2D(dst,j,i,s);
        
      

      cvNamedWindow( "Source1", 1 );
      cvShowImage( "Source1", src);
      cvWaitKey(0);

    #endif  


【讨论】:

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

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

import android.graphics.Bitmap;
import android.util.Log;

class Filters
    float xscale;
    float yscale;
    float xshift;
    float yshift;
    int [] s;
    private String TAG = "Filters";
    public Filters()

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

    public Bitmap barrel (Bitmap input, float k)
        Log.e(TAG, "***********inside barrel method ");
        float centerX=input.getWidth()/2; //center of distortion
        float centerY=input.getHeight()/2;

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

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

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

          xscale = (width-xshift-xshift_2)/width;
          yscale = (height-yshift-yshift_2)/height;
          Log.e(TAG, "***********about to loop through bm");
          /*for(int j=0;j<dst.getHeight();j++)
              for(int i=0;i<dst.getWidth();i++)
                float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                float y = getRadialY((float)i,(float)j,centerX,centerY,k);
                sampleImage(input,x,y);
                int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
    //            System.out.print(i+" "+j+" \\");

                dst.setPixel(i, j, color);

              
            */

          int origPixel; // the pixel in orig image

          for(int j=0;j<dst.getHeight();j++)
              for(int i=0;i<dst.getWidth();i++)
                 origPixel= input.getPixel(i,j);
                float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                float y = getRadialY((float)i,(float)j,centerX,centerY,k);
                sampleImage(input,x,y);
                int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
    //            System.out.print(i+" "+j+" \\");


// check whether a pixel is within the circle bounds of 150

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

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

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

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

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

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

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

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

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

    float thresh = 1;

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

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

.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Debug;
import android.util.Log;

public class MultiRuntimeProcessorFilter 



    private static final String TAG = "mrpf";
    private int x = 0;
    private Bitmap input = null;
    private int radius;


    public void createBitmapSections(int nOp, int[] sections)

        int processors = nOp;
        int jMax = input.getHeight();
        int aSectionSize = (int) Math.ceil(jMax/processors);
        Log.e(TAG, "++++++++++ sections size = "+aSectionSize);


        int k = 0;
        for(int h=0; h<processors+1; h++)

                sections[h] = k;
                k+= aSectionSize;



        
    // end of createBitmapSections()



    @SuppressWarnings("unchecked")
    public Bitmap barrel (Bitmap input, float k, int r)
          this.radius = r;
          this.input = input;
          int []arr = new int[input.getWidth()*input.getHeight()];


          Log.e(TAG, "bitmap height = "+input.getHeight()); 




          int nrOfProcessors = Runtime.getRuntime().availableProcessors();
          Log.e(TAG, "no of processors = "+nrOfProcessors);

          int[] sections = new int[nrOfProcessors+1];


          createBitmapSections(nrOfProcessors,sections);
          ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

          for(int g=0; g<sections.length;g++)
              Log.e(TAG, "++++++++++ sections= "+sections[g]);
          

         // ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

          Object[] task = new Object[nrOfProcessors];

          for(int z = 0; z < nrOfProcessors; z++)
             task[z]  = (FutureTask<PartialResult>) threadPool.submit(new PartialProcessing(sections[z], sections[z+1] - 1, input, k));  
             Log.e(TAG, "++++++++++ task"+z+"= "+task[z].toString()); 
          

         PartialResult[] results = new PartialResult[nrOfProcessors];

         try
              for(int t = 0; t < nrOfProcessors; t++)

                  results[t] = ((FutureTask<PartialResult>) task[t]).get();

                  results[t].fill(arr);
              

          catch(Exception e)
              e.printStackTrace();
          

          Bitmap dst2 = Bitmap.createBitmap(arr,input.getWidth(),input.getHeight(),input.getConfig());


        return dst2;


        //end of barrel()




    public class PartialResult 
           int startP;
           int endP;
           int[] storedValues;

           public PartialResult(int startp, int endp, Bitmap input)

               this.startP = startp;
               this.endP = endp;
               this.storedValues = new int[input.getWidth()*input.getHeight()];


           

           public void addValue(int p, int result) 
                 storedValues[p] = result;

           

           public void fill(int[] arr) 



              for (int p = startP; p < endP; p++)
                  for(int b=0;b<radius;b++,x++)
                 arr[x] = storedValues[x];

               
              Log.e(TAG, "++++++++++ x ="+x);
              

           //end of partialResult




    public class PartialProcessing implements Callable<PartialResult> 
        int startJ;
        int endJ;


        private int[] scalar;
        private float xscale;
        private float yscale;
        private float xshift;
        private float yshift;
        private float thresh = 1;
        private int [] s1;
        private int [] s2;
        private int [] s3;
        private int [] s4;
        private int [] s;
        private Bitmap input;
        private float k;



        public PartialProcessing(int startj, int endj, Bitmap input, float k) 

            this.startJ = startj;
            this.endJ = endj;
            this.input = input;
            this.k = k;

            s = new int[4];
            scalar = new int[4];
            s1 = new int[4];
            s2 = new int[4];
            s3 = new int[4];
            s4 = new int[4];

        

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

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

        



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

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

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

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



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

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

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


          void sampleImage(Bitmap arr, float idx0, float idx1)
          

             // s = new int [4];
            if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1))
              s[0]=0;
              s[1]=0;
              s[2]=0;
              s[3]=0;
              return;
            

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



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

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

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


          



        @Override public PartialResult call()  

             PartialResult partialResult = new PartialResult(startJ, endJ,input);

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



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



              xshift = calc_shift(0,centerX-1,centerX,k);

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

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

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

              xscale = (width-xshift-xshift_2)/width;

              yscale = (height-yshift-yshift_2)/height;


            int p = startJ*radius; 
            int origPixel = 0;
            int color = 0;
            int i;

            for (int j = startJ; j <  endJ; j++)

                for ( i = 0; i < width; i++, p++)


             origPixel = input.getPixel(i,j);

             float x = getRadialX((float)j,(float)i,centerX,centerY,k);


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

             sampleImage(input,x,y);

             color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
            //Log.e(TAG, "radius = "+radius);

             if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*(radius/4))

                                 partialResult.addValue(p, color);


            else


                partialResult.addValue(p, origPixel);



            

                //end of inner for

        //end of outer for

            return partialResult;
    //end of call


// end of partialprocessing

//end of MultiProcesorFilter

@And_Dev 承诺

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

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.tecmark.HorizontalSlider.OnProgressChangeListener;

public class TouchView extends View


    private File tempFile;
    private byte[] imageArray;
    private Bitmap bgr;

    private Bitmap crop;
    private Bitmap crop2;
    private Bitmap overLay;
    private Bitmap overLay2;


    private float centreX;
    private float centreY;
    private float centreA = 200;
    private float centreB = 200;
    private Boolean xyFound = false;
    private int Progress = 1;
    private static final String TAG = "*********TouchView";
    private Filters f = null;
    private boolean bothCirclesInPlace = false;
    private MultiProcessorFilter mpf;
    private MultiProcessorFilter mpf2;
    private MultiRuntimeProcessorFilter mrpf;
    private MultiRuntimeProcessorFilter mrpf2;





    public TouchView(Context context) 
        super(context);

    




    public TouchView(Context context, AttributeSet attr) 
        super(context,attr);
        Log.e(TAG, "++++++++++ inside touchview constructor");



        tempFile = new File(Environment.getExternalStorageDirectory().
                getAbsolutePath() + "/"+"image.jpg");

        imageArray = new byte[(int)tempFile.length()];


     try

            InputStream is = new FileInputStream(tempFile);
            BufferedInputStream bis = new BufferedInputStream(is);
            DataInputStream dis = new DataInputStream(bis);


            int i = 0;

            while (dis.available() > 0) 
            imageArray[i] = dis.readByte();
            i++;
            

            dis.close();

        catch (Exception e) 

               e.printStackTrace();
            


       Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length);




        bgr = bm.copy(bm.getConfig(), true);;

        overLay = null;
        overLay2 = null;



       bm.recycle();

    // end of touchView constructor




    public void findCirclePixels() 

         //  f = new Filters();
         //  mpf = new MultiProcessorFilter();
         //  mpf2 = new MultiProcessorFilter();
         mrpf = new MultiRuntimeProcessorFilter();
         mrpf2 = new MultiRuntimeProcessorFilter();

         crop = Bitmap.createBitmap(bgr,Math.max((int)centreX-75,0),Math.max((int)centreY-75,0),150,150);
         crop2 = Bitmap.createBitmap(bgr,Math.max((int)centreA-75,0),Math.max((int)centreB-75,0),150,150);

              new Thread(new Runnable() 
                public void run() 
                    float prog = (float)Progress/150001;

               // final Bitmap bgr3 = f.barrel(crop,prog);
               // final Bitmap bgr4 = f.barrel(crop2,prog);

              //  final Bitmap bgr3 = mpf.barrel(crop,prog);
              //  final Bitmap bgr4 = mpf2.barrel(crop2,prog);

                    final Bitmap bgr3 = mrpf.barrel(crop,prog);
                    final Bitmap bgr4 = mrpf2.barrel(crop2,prog);

                  TouchView.this.post(new Runnable() 
                    public void run() 


                      TouchView.this.overLay = bgr3;
                      TouchView.this.overLay2 = bgr4;

                      TouchView.this.invalidate();

                    
                  );
                
              ).start();


        // end of changePixel()






    @Override
    public boolean onTouchEvent(MotionEvent ev) 

        switch (ev.getAction()) 

            case MotionEvent.ACTION_DOWN: 

                if(xyFound == false)
                centreX = (int) ev.getX();
                centreY = (int) ev.getY();
                xyFound = true;
                else
                centreA = (int) ev.getX();
                centreB = (int) ev.getY();
                bothCirclesInPlace  = true;
                


                break;
            

          /*  case MotionEvent.ACTION_MOVE: 

                if(xyFound == false)
                    centreX = (int) ev.getX();
                    centreY = (int) ev.getY();
                    xyFound = true;
                else
                    centreA = (int) ev.getX();
                    centreB = (int) ev.getY();
                    bothCirclesInPlace = true;
                    

                    findCirclePixels();
                 // TouchView.this.invalidate();
                    break;

            */           

            case MotionEvent.ACTION_UP: 

                break;

        
        return true;
    //end of onTouchEvent





    public void initSlider(final HorizontalSlider slider)
    

        slider.setOnProgressChangeListener(changeListener);


    



    private OnProgressChangeListener changeListener = new OnProgressChangeListener() 


        @Override
        public void onProgressChanged(View v, int progress) 



              setProgress(progress);



        
    ;




    @Override
    public void onDraw(Canvas canvas)
        super.onDraw(canvas);

        Log.e(TAG, "******about to draw bgr ");
        canvas.drawBitmap(bgr, 0, 0, null);

        if(bothCirclesInPlace == true)

                if(overLay != null)
                    Log.e(TAG, "******about to draw overlay1 ");
        canvas.drawBitmap(overLay, centreX-75, centreY-75, null);
                
            if(overLay2 != null)
                Log.e(TAG, "******about to draw overlay2 ");
        canvas.drawBitmap(overLay2, centreA-75, centreB-75, null);
            

        

    //end of onDraw




    protected void setProgress(int progress2) 
        Log.e(TAG, "***********in SETPROGRESS");
        this.Progress = progress2;



        findCirclePixels();


    





.

调用活动。

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Jjilapp extends Activity 




    private static final String TAG = "*********jjil";


    @Override 
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.touchview);
        final TouchView touchView = (TouchView)findViewById(R.id.touchview); 
        final HorizontalSlider slider = (HorizontalSlider)findViewById(R.id.slider); 

        touchView.initSlider(slider);




    //end of oncreate





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

【讨论】:

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

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

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import com.jhlabs.image.InterpolateFilter;

class Filters
    float xscale;
    float yscale;
    float xshift;
    float yshift;
    int [] s;
    public Filters()

    

    public BufferedImage barrel (BufferedImage input, float k)

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

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

        BufferedImage dst = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB); //output pic

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

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

          xscale = (width-xshift-xshift_2)/width;
          yscale = (height-yshift-yshift_2)/height;

          for(int j=0;j<dst.getHeight();j++)
              for(int i=0;i<dst.getWidth();i++)
                float x = getRadialX((float)i,(float)j,centerX,centerY,k);
                float y = getRadialY((float)i,(float)j,centerX,centerY,k);
                sampleImage(input,x,y);
                int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
    //            System.out.print(i+" "+j+" \\");

                dst.setRGB(i, j, color);

              
            
        return dst;
    

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

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

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

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

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

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

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

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

    float thresh = 1;

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

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

【讨论】:

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

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

//1. MultiRuntimeProcessorFilter.java

public class MultiRuntimeProcessorFilter 



private static final String TAG = "mrpf";
private int x = 0;
private Bitmap input = null;
private int radius;
private int mHeight;


public void createBitmapSections(int nOp, int[] sections)

    int processors = nOp;
    int jMax = input.getHeight();
    int aSectionSize = (int) Math.ceil(jMax/processors);
    Log.e("yoSIZECHK", "++++++++++ sections size = "+aSectionSize);

    int k = 0;
    for(int h=0; h<processors+1; h++)

            sections[h] = k;
            k+= aSectionSize;
            if(h==processors)
                sections[h] = mHeight;//Last must cover ceiling
            
        Log.v("yoSEC","sections = "+h+" "+sections[h]);

    
// end of createBitmapSections()


//@SuppressWarnings("unchecked")
public Bitmap barrel (Bitmap input, float k, int r)
      this.radius = r;
      this.input = input;
      int []mArray = new int[input.getWidth()*input.getHeight()];

      mHeight = input.getHeight();
      Log.e(TAG, "bitmap height x width = "+mHeight+" "+input.getWidth());
  //Log.v("yoRESULT", "height width = "+ input.getWidth()+" "+input.getHeight());




      int nrOfProcessors = Runtime.getRuntime().availableProcessors();
      Log.e(TAG, "no of processors = "+nrOfProcessors);


      int[] sections = new int[nrOfProcessors+1];


      createBitmapSections(nrOfProcessors,sections);
      ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

      for(int g=0; g<sections.length;g++)
          Log.e(TAG, "++++++++++ sections= "+sections[g]);
      

  // ExecutorService threadPool = Executors.newFixedThreadPool(nrOfProcessors);

      Object[] task = new Object[nrOfProcessors];

      for(int z = 0; z < nrOfProcessors; z++)
         task[z]  = (FutureTask<PartialResult>) threadPool.submit(new PartialProcessing(sections[z], sections[z+1] - 1, input, k, z));
         Log.e(TAG, "++++++++++ task"+z+"= "+task[z].toString()); 
      

     PartialResult[] results = new PartialResult[nrOfProcessors];

     try
          for(int t = 0; t < nrOfProcessors; t++)

              results[t] = ((FutureTask<PartialResult>) task[t]).get();

              results[t].fill(mArray);
          

      catch(Exception e)
          e.printStackTrace();
      

 Log.v("yoRESULT", "height width = "+ input.getHeight()+" "+input.getWidth());
      Bitmap dst2 = Bitmap.createBitmap(mArray,input.getWidth(),input.getHeight(),input.getConfig());

    return dst2;


    //end of barrel()




public class PartialResult 
       int startP;
       int endP;
       int[] storedValues;

       public PartialResult(int startp, int endp, Bitmap input)

           this.startP = startp;
           this.endP = endp;
           this.storedValues = new int[input.getWidth()*input.getHeight()];


       

       public void addValue(int p, int result) 
             storedValues[p] = result;

       

       public void fill(int[] mArray) 

           Log.v("yo09", startP + " " + endP + " " + input.getWidth());
           //yoko for (int p = startP; p < endP; p++)
       for (int p = startP; p < endP+1; p++)
               //for(int b=0;b<radius;b++,x++)
              for(int b=0;b<input.getWidth();b++,x++) 
                  mArray[x] = storedValues[x];
                  if (b == 0) Log.v("yoyoyo", p+" + " + storedValues[x]);
              
           
          Log.e("yoFill", " ++++++++++ radius x = "+radius+" "+x);
   

       //end of partialResult




public class PartialProcessing implements Callable<PartialResult> 
    int startJ;
    int endJ;
    int mID;


    private int[] scalar;
    private float xscale;
    private float yscale;
    private float xshift;
    private float yshift;
    private float thresh = 1;
    private int [] s1;
    private int [] s2;
    private int [] s3;
    private int [] s4;
    private int [] s;
    private Bitmap input;
    private float k;



    public PartialProcessing(int startj, int endj, Bitmap input, float k, int mID) 

        this.startJ = startj;
        this.endJ = endj;
        this.input = input;
        this.k = k;
        this.mID = mID;

        s = new int[4];
        scalar = new int[4];
        s1 = new int[4];
        s2 = new int[4];
        s3 = new int[4];
        s4 = new int[4];

    

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

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

    



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

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

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

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



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

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

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


      //void sampleImage(Bitmap mArray, float idx0, float idx1)
    int [] sampleImage(Bitmap mArray2, float idx0, float idx1)
      

         // s = new int [4];
        if(idx0<0 || idx1<0 || idx0>(mArray2.getHeight()-1) || idx1>(mArray2.getWidth()-1))
          s[0]=0;
          s[1]=0;
          s[2]=0;
          s[3]=0;
          return s;// yoko
        

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



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

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

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

          return s;

      



    @Override
    public PartialResult call() 

         PartialResult partialResult = new PartialResult(startJ, endJ,input);

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



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



          xshift = calc_shift(0,centerX-1,centerX,k);

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

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

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

          xscale = (width-xshift-xshift_2)/width;

          yscale = (height-yshift-yshift_2)/height;


        // yoko int p = startJ*radius;
        int p = startJ*width;//yoko
        int origPixel = 0;
        int color = 0;
        int i;

    Log.v("yokoIJ","PartialResult startJ endJ "+startJ+"  "+endJ);
        //yoko for (int j = startJ; j <  endJ; j++)
        for (int j = startJ; j <  endJ+1; j++)
            for ( i = 0; i < width; i++, p++)
    s = new int [4];//yoko added

    origPixel = input.getPixel(i,j);

    float x = getRadialX((float)j,(float)i,centerX,centerY,k);
    float y = getRadialY((float)j,(float)i,centerX,centerY,k);
    //sampleImage(input,x,y); //yoko
    s= sampleImage(input,x,y);

    color = (0xff<<24)|((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
    //Log.e(TAG, "radius = "+radius);

     //Not understand why it is not radius but radius/2
         //yoko if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*(radius/4))
    if(((i-centerX)*(i-centerX) + (j-centerY)*(j-centerY)) <= radius*radius)
                //yo if(j%10 == 1 && i%10 == 1)
                    //yo Log.v("yoJI", mID+" "+j + " " + i );
        partialResult.addValue(p, color);
    else
        partialResult.addValue(p, origPixel);
        

            //end of inner for

    //end of outer for

        return partialResult;
//end of call
// end of partialprocessing
//end of MultiProcesorFilter

// 2.Filters.java:

class Filters
float xscale;
float yscale;
float xshift;
float yshift;
int [] s;
private static String TAG = "Filters";
public Filters()
    Log.e(TAG, "***********inside constructor");


public Bitmap barrel (Bitmap input, float k, boolean check, int Range)
    Log.e(TAG, "***********inside barrel method : hasAlpha = ");
    float centerX=input.getWidth()/2; //center of distortion
    float centerY=input.getHeight()/2;

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

//yoko        Log.v("yoQQ", width+" "+height+" "+centerX+" "+centerY);
    if(check)return input;

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

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

      xscale = (width-xshift-xshift_2)/width;
      yscale = (height-yshift-yshift_2)/height;
      Log.e(TAG, "***********about to loop through bm");
  Log.v("yoQQ2", xscale + " " + yscale);
  //if(check==1)return input;//yoko
      /*for(int j=0;j<dst.getHeight();j++)
          for(int i=0;i<dst.getWidth();i++)
            float x = getRadialX((float)i,(float)j,centerX,centerY,k);
            float y = getRadialY((float)i,(float)j,centerX,centerY,k);
            sampleImage(input,x,y);
            int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
//            System.out.print(i+" "+j+" \\");

            dst.setPixel(i, j, color);

          
        */

      int origPixel; // the pixel in orig image
      int i=0,j=0;
      for(j=0;j<dst.getHeight();j++)
          for(i=0;i<dst.getWidth();i++)
            s = new int [4];//yoko added
             origPixel= input.getPixel(i,j);
            float x = getRadialX((float)i,(float)j,centerX,centerY,k);
            float y = getRadialY((float)i,(float)j,centerX,centerY,k);
            //yoko sampleImage(input,x,y);
            s = sampleImage(input,x,y);
            //yoko int color = ((s[1]&0x0ff)<<16)|((s[2]&0x0ff)<<8)|(s[3]&0x0ff);
            int color = (0xff<<24)|((s[1]&0xff)<<16)|((s[2]&0xff)<<8)|(s[3]&0xff);
            //Log.v("yoQQ3", j + " " + i + " : "+dst.getHeight()+" "+dst.getWidth());


    // check whether a pixel is within the circle bounds of 150

            if( Math.sqrt( Math.pow(i - centerX, 2) + ( Math.pow(j - centerY, 2) ) ) <= Range )
        dst.setPixel(i, j, color);
                //if(j%10 == 1 && i%10 == 1)
                //    Log.v("yoJI", j + " " + i );
            else
                dst.setPixel(i,j,origPixel);
            
          
        
    Log.v("yoDONE", "========  Loop End ======== "+j+" "+i+" : " + dst.getHeight()+" "+dst.getWidth());
    return dst;
//barrel

//    void sampleImage(Bitmap arr, float idx0, float idx1) // yoko
int[] sampleImage(Bitmap arr, float idx0, float idx1)

    s = new int [4];
  if(idx0<0 || idx1<0 || idx0>(arr.getHeight()-1) || idx1>(arr.getWidth()-1))
    s[0]=0;
    s[1]=0;
    s[2]=0;
    s[3]=0;
    return s;
  

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

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

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

  s[0]= (int) (s1[0]*(1-x)*(1-y) + s2[0]*(1-x)*y + s3[0]*x*y + s4[0]*x*(1-y));
  s[1]= (int) (s1[1]*(1-x)*(1-y) + s2[1]*(1-x)*y + s3[1]*x*y + s4[1]*x*(1-y));
  s[2]= (int) (s1[2]*(1-x)*(1-y) + s2[2]*(1-x)*y + s3[2]*x*y + s4[2]*x*(1-y));
  s[3]= (int) (s1[3]*(1-x)*(1-y) + s2[3]*(1-x)*y + s3[3]*x*y + s4[3]*x*(1-y));
  return s;///yoko added to make return the result value
//sampleImage

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

float getRadialX(float x,float y,float cx,float cy,float k)
  x = (x*xscale+xshift);
  y = (y*yscale+yshift);
  float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
  return res;
//getRadial1X

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

float thresh = 1;

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

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

并且 //3 MainActivity.java,***类。

public class MainActivity extends Activity 

ImageView iv1=null;
ImageView iv2=null;
Button bT, bB, b0;
Bitmap bitmap1, bitmap2, bitmapSP;
Boolean view1 = true;
private static final String TAG = "*********jjil";
public static int mH,mW,RADIUS;

@Override 
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main);

    Resources res = this.getResources();
    //bitmap1 = BitmapFactory.decodeResource(res, R.drawable.checkerboard);
    bitmap1 = BitmapFactory.decodeResource(res, R.drawable.checkerboardback);
    mH=bitmap1.getHeight();
    mW=bitmap1.getWidth();
    RADIUS = mH/3;

    bT = (Button)findViewById(R.id.buttontoggle);
    bT.setOnClickListener(onClickToggleView);
    bB = (Button)findViewById(R.id.buttonbarrel);
    bB.setOnClickListener(onClickToggleView);
    b0 = (Button)findViewById(R.id.button0);
    b0.setOnClickListener(onClickToggleView);

    iv1=(ImageView)findViewById(R.id.touchview1);
    iv1.setImageBitmap(bitmap1);
    iv1.setVisibility(View.VISIBLE);


//end of oncreate

public View.OnClickListener onClickToggleView = new View.OnClickListener() 
    public void onClick(View v) 
        if (v == bT) 

    /// fromhere
            new AsyncTask<Void, Void, String>() 
                com.example.owner.opengl2.Filters mFilers = new com.example.owner.opengl2.Filters();
                TextView tx = (TextView)findViewById(R.id.mStatus);
                Bitmap bitmapSP;long start,end;

                protected void onPreExecute() 
                    start = System.nanoTime();
                    iv1.setImageBitmap(bitmap1);
                    tx.setText("- Running -");
                

                protected String doInBackground(Void... params) 
                     bitmapSP = mFilers.barrel(bitmap1,(float)0.00005,false,RADIUS);
                    return "message";
                

                protected void onPostExecute(String msg) 
                    end = System.nanoTime();
                    long elapsedTime = end - start;
                    long seconds = elapsedTime / 1000000;

                    iv1.setImageBitmap(bitmapSP);
                    tx.setText("- READY : ElapsedTime(ms) = "+seconds);
                    // Post Code
                    // Use `msg` in code
                
            .execute();
    ///upto here



         else if (v == bB)

    /// fromhere
            new AsyncTask<Void, Void, String>() 
                com.example.owner.opengl2.MultiRuntimeProcessorFilter mFilers = new com.example.owner.opengl2.MultiRuntimeProcessorFilter();
                TextView tx = (TextView)findViewById(R.id.mStatus);
                Bitmap bitmapSP;long start,end;

                protected void onPreExecute() 
                    start = System.nanoTime();
                    iv1.setImageBitmap(bitmap1);
                    tx.setText("- Running -");
                

                protected String doInBackground(Void... params) 
                    bitmapSP = mFilers.barrel(bitmap1,(float)0.00005,RADIUS);
                    return "message";
                

                protected void onPostExecute(String msg) 
                    end = System.nanoTime();
                    long elapsedTime = end - start;
                    //double seconds = (double)elapsedTime / 1000000000.0;
                    long seconds = elapsedTime / 1000000;
                    iv1.setImageBitmap(bitmapSP);
                    tx.setText("- READY : ElapsedTime(ms) = "+seconds);
                    // Post Code
                    // Use `msg` in code
                
            .execute();


         else if (v == b0)
            new AsyncTask<Void, Void, String>() 
                protected String doInBackground(Void... Unused) 
                    return "OK";
                
                protected void onPostExecute(String message) 
                    Log.v("YO", "---------------------------------");
                    Log.v("YO", "----------ORIGINAL SHAPE-------- "+message);
                    Log.v("YO", "---------------------------------");
                    iv1.setImageBitmap(bitmap1);

                    TextView tx = (TextView)findViewById(R.id.mStatus);
                    tx.setText("- READY : w h RADIUS = "+mW+" "+mH+" "+RADIUS);
                
            .execute();

        
        ///upto here

    
;

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_
android:layout_ 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_
    android:layout_>

    <Button
        android:id="@+id/buttontoggle"
        android:text="Barrel 1P"
        android:layout_
        android:layout_ />

    <Button
    android:id="@+id/buttonbarrel"
    android:text="Barrele NP"
    android:layout_
    android:layout_ />

    <Button
        android:id="@+id/button0"
        android:text="ORIGINAL"
        android:layout_
        android:layout_ />


</LinearLayout>
<TextView
    android:id="@+id/mStatus"
    android:layout_
    android:layout_
    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_
    android:layout_
    android:layout_centerHorizontal="true"
     />

<!--ImageView
    android:id="@+id/touchview2"
    android:layout_below="@+id/touchview1"
    android:layout_alignParentBottom="true"
    android:layout_
    android:layout_
    android:layout_centerHorizontal="true" /-->

【讨论】:

【参考方案5】:

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

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

在OpenGL 看到这个。

问候

【讨论】:

以上是关于如何通过openCV模拟鱼眼镜头效果?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV - 校准鱼眼镜头误差(病态矩阵)

使用 opencv 3.0 beta 进行鱼眼镜头校准

OpenCV3.0.0dev中鱼眼摄像机模型的主要参考是什么?

如何使用opencv将鱼眼相机拍摄的图像转换为平面(矩形)图像?

VS2019+OpenCV4.5 鱼眼相机图像畸变矫正

OpenCV:鱼眼相机去畸变=图像去畸变+点去畸变