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

我正在寻找创build鱼眼镜头效果的方法,查看openCV的文档,看起来它包含像鱼眼这样的径向畸变的相机校准function。 有没有可能通过openCV来模拟鱼眼失真?

如果openCV可以做到这一点,那么与openGL相比,哪一个会产生更好的结果呢? 谢谢。

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

更新 :好的,下面是使用opencv编写的实际代码(没有logging,所以请随意询问解释):程序接收到以下参数作为input: input图像 | | 输出图像 | | 控制失真量的K(通常约为0.001) | | 变形中心的x坐标 | | 变形中心的y坐标 |

所以程序的关键是双循环,它在结果图像上逐个像素地迭代,并使用径向失真的公式在input图像中寻找匹配的像素(这是图像变形通常完成的方式 – 可能是直觉地通过从输出到input的反投影)。 有一些细微之处与输出图像的尺寸有关(在这个程序中产生的图像与input尺寸相同),除非你想了解更多的细节,否则我不会深究。

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

由于上述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承诺

以下是获取用户触摸协调的视图,然后在选定区域调用filter。 选定的区域是线,例如圆的中心加半径(一个圆)。 该代码做了两次,因为它的隆胸应用程序:)只是注释掉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 } 

如果你需要任何帮助队友就问。 希望这可以帮助

感谢您的代码。 它帮助我很多。 我将它encryption为Java。 也许有人有类似的function,以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); } } } 

我debugging的Java文件,它在我的手机(高于4.0)正常工作。 它由3个java文件和1个xml文件组成。 您必须将checkerboardback.jpg文件放在drawable的目录下。 正如有人所说,阿尔法值丢失,我给了它“0x0ff”。 另外,一些循环的上限是错误的。

// 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 : wh 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" /--> 

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.

问候

Interesting Posts