Android自动聚焦、摄像头拍照、缩放至标准大小的完整实现

为什么把自动聚焦放在前面呢?因为前文http://blog.csdn.net/yanzi1225627/article/details/7738736已经实现了拍照功能,且网上拍照的源码例子很多,自动聚焦很多人写的很简单,但结果发现不中。我这里就总结下,我的自动聚焦的实现。

手机华为U9200,

Android4.0.3,

预览的参数:myParameters.setPreviewSize(1280, 720)

图片参数:myParameters.setPictureSize(2048, 1152); //1280, 720

图片最终尺寸:宽600 * 高800

(关于setPreviewSize和setPictureSize的问题可以参照我以前的文章http://blog.csdn.net/yanzi1225627/article/details/7738736

 

参照http://www.cnblogs.com/liuan/archive/2012/01/10/2318300.html, 上面的思路是弄了一个定时器来进行自动聚焦,但发现根本不中,一按拍照程序就挂掉。而且由于定时器一直在重复循环,相机就在那聚焦来聚焦去,也就是一下清 晰一下又模糊了。后来我把程序改成,当拍照后把定时器关闭掉发现还是不中。经反复实验,终于成功。南无阿弥陀佛,本着我为人人,人人为我。将源码贴在此 处:

第一,布局文件。里面有一个surfaceview和三个按钮,分别是预览、拍照、保存。

 

  1. <?xml version=“1.0” encoding=“utf-8”?>
  2. <LinearLayout xmlns:Android=“http://schemas.android.com/apk/res/android”
  3.     android:layout_width=“fill_parent”
  4.     android:layout_height=“fill_parent”
  5.     android:orientation=“vertical” >
  6. <SurfaceView
  7.     android:id=“@+id/mySurfaceView”
  8.     android:layout_width=“fill_parent”
  9.     android:background=“#D1EEEE”
  10.     android:layout_height=“800px”
  11.     android:gravity=“center” />
  12. <LinearLayout
  13.     android:id=“@+id/LinearLayout01”
  14.     android:layout_width=“wrap_content”
  15.     android:layout_height=“wrap_content”
  16.     android:layout_gravity=“center_horizontal”
  17.     android:paddingTop=“20dip”
  18.     android:orientation=“horizontal” >
  19.     <Button
  20.         android:id=“@+id/btnPreview”
  21.         android:layout_width=“wrap_content”
  22.         android:layout_height=“wrap_content”
  23.         android:text=“预览” />
  24.     <Button
  25.         android:id=“@+id/btnPhoto”
  26.         android:layout_width=“wrap_content”
  27.         android:layout_height=“wrap_content”
  28.         android:text=“拍照” />
  29.     <Button
  30.         android:id=“@+id/btnSave”
  31.         android:layout_width=“wrap_content”
  32.         android:layout_height=“wrap_content”
  33.         android:text=“保存” />
  34. </LinearLayout>
  35. </LinearLayout>

第2,源程序:

  1. package yan.guoqi.testphoto;
  2. import java.io.BufferedOutputStream;
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.util.Timer;
  7. import java.util.TimerTask;
  8. import android.app.Activity;
  9. import android.app.AlertDialog;
  10. import android.app.AlertDialog.Builder;
  11. import android.content.DialogInterface;
  12. import android.graphics.Bitmap;
  13. import android.graphics.BitmapFactory;
  14. import android.graphics.PixelFormat;
  15. import android.hardware.Camera;
  16. import android.hardware.Camera.PictureCallback;
  17. import android.hardware.Camera.ShutterCallback;
  18. import android.os.Bundle;
  19. import android.util.Log;
  20. import android.view.SurfaceHolder;
  21. import android.view.SurfaceView;
  22. import android.view.View;
  23. import android.view.View.OnClickListener;
  24. import android.view.Window;
  25. import android.view.WindowManager;
  26. import android.widget.Button;
  27. import android.widget.Toast;
  28. public class TestPhotoActivity extends Activity implements SurfaceHolder.Callback{
  29.     /** Called when the activity is first created. */
  30.     private static final  String TAG = “yan:”;
  31.     SurfaceView mySurfaceView = null;
  32.     SurfaceHolder mySurfaceHolder = null;
  33.     Button btnPreview = null;
  34.     Button btnPhoto = null;
  35.     Button btnSave = null;
  36.     Camera myCamera = null;
  37.     Camera.Parameters myParameters;
  38.     boolean isView = false;
  39.     Bitmap bm;
  40.     String savePath = “/mnt/sdcard/testPhoto/”;
  41.     int cntSave = 0;
  42.     private Camera.AutoFocusCallback mAutoFocusCallback;
  43.     //private Camera.PreviewCallback mPreviewCallback;
  44.     private Timer mTimer;
  45.     private TimerTask mTimerTask;
  46.     @Override
  47.     public void onCreate(Bundle savedInstanceState) {
  48.         super.onCreate(savedInstanceState);
  49.         //璁剧疆鍏ㄥ睆鏃犳爣棰?       requestWindowFeature(Window.FEATURE_NO_TITLE);
  50.         int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
  51.         Window myWindow = this.getWindow();
  52.         myWindow.setFlags(flag, flag);
  53.         setContentView(R.layout.main); //璁剧疆甯冨眬
  54.         mySurfaceView = (SurfaceView)findViewById(R.id.mySurfaceView);
  55.         mySurfaceView.setZOrderOnTop(true);
  56.         mySurfaceHolder = mySurfaceView.getHolder();
  57.         mySurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
  58.         btnPreview = (Button)findViewById(R.id.btnPreview);
  59.         btnPhoto = (Button)findViewById(R.id.btnPhoto);
  60.         btnSave = (Button)findViewById(R.id.btnSave);
  61.         if(!isFolderExist(savePath)) //濡傛灉鍒涘缓鏂囦欢澶瑰け璐?       {
  62.             AlertDialog.Builder alertDialog = new Builder(TestPhotoActivity.this);
  63.             alertDialog.setTitle(“閿欒”);
  64.             alertDialog.setMessage(“鍥剧墖淇濆瓨鏂囦欢澶瑰垱寤哄け璐ワ紒”);
  65.             alertDialog.setPositiveButton(“纭畾”new DialogInterface.OnClickListener() {
  66.                 public void onClick(DialogInterface dialog, int which) {
  67.                     // TODO Auto-generated method stub
  68.                     dialog.dismiss();
  69.                     TestPhotoActivity.this.finish();
  70.                 }
  71.             });
  72.             alertDialog.show();
  73.         }
  74.         else
  75.             Toast.makeText(TestPhotoActivity.this,
  76.                     “鎮ㄧ殑鐓х墖灏嗕繚瀛樺湪锛? + savePath,
  77.                     Toast.LENGTH_SHORT).show();
  78.         mySurfaceHolder.addCallback(this);
  79.         mySurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  80.         mAutoFocusCallback = new Camera.AutoFocusCallback() {
  81.             public void onAutoFocus(boolean success, Camera camera) {
  82.                 // TODO Auto-generated method stub
  83.                 if(success){
  84.                     myCamera.setOneShotPreviewCallback(null);
  85.                     Toast.makeText(TestPhotoActivity.this,
  86.                             “鑷姩鑱氱劍鎴愬姛锛?,
  87.                             Toast.LENGTH_SHORT).show();
  88.                 }
  89.             }
  90.         };
  91.         mTimer = new Timer();
  92.         mTimerTask = new CameraTimerTask();
  93.         //mTimer.schedule(mTimerTask, 0, 500);
  94.         btnPreview.setOnClickListener(new BtnListener());
  95.         btnPhoto.setOnClickListener(new BtnListener());
  96.         btnSave.setOnClickListener(new BtnListener());
  97.     }
  98.     ShutterCallback myShutterCallback = new ShutterCallback() {
  99.         public void onShutter() {
  100.             // TODO Auto-generated method stub
  101.         }
  102.     };
  103.     PictureCallback myRawCallback = new PictureCallback() {
  104.         public void onPictureTaken(byte[] data, Camera camera) {
  105.             // TODO Auto-generated method stub
  106.         }
  107.     };
  108.     PictureCallback myjpegCalback = new PictureCallback() {
  109.         public void onPictureTaken(byte[] data, Camera camera) {
  110.             // TODO Auto-generated method stub
  111.             Log.i(TAG, “onPictureTaken……..”);
  112.             bm = BitmapFactory.decodeByteArray(data, 0, data.length);
  113.             isView = false;
  114.             myCamera.stopPreview();
  115.             myCamera.release();
  116.             myCamera = null;
  117.             isView = false;
  118.         }
  119.     };
  120.     class BtnListener implements OnClickListener{
  121.         public void onClick(View v) {
  122.             // TODO Auto-generated method stub
  123.             switch(v.getId()){
  124.             case R.id.btnPreview:
  125.                 Toast.makeText(TestPhotoActivity.this,
  126.                         “鎮ㄦ寜浜嗛瑙堟寜閽?,
  127.                         Toast.LENGTH_SHORT).show();
  128.                 initCamera();
  129.                 break;
  130.             case R.id.btnPhoto:
  131.                 if(isView && myCamera!=null){
  132.                     myCamera.takePicture(myShutterCallback, myRawCallback, myjpegCalback);
  133.                 }
  134.                 else
  135.                     Toast.makeText(TestPhotoActivity.this, “璇峰厛棰勮鐒跺悗鎷嶇収锛?, Toast.LENGTH_SHORT).show();
  136.                 break;
  137.             case R.id.btnSave:
  138.                   if(bm == null)
  139.                   {
  140.                       Toast.makeText(TestPhotoActivity.this“璇锋媿鎽勬垚鍔熷悗鍐嶄繚瀛橈紒锛侊紒”, Toast.LENGTH_SHORT).show();
  141.                       return;
  142.                   }
  143.                 int b =0, c=1;
  144.                 File fTest = new File(savePath + b + c + “.JPG”);
  145.                 while(fTest.exists()){
  146.                     if(c==9){
  147.                         b++;
  148.                         c = 0;
  149.                     }
  150.                     else
  151.                         c++;
  152.                     if(b==9){
  153.                         b = 0;
  154.                         Toast.makeText(TestPhotoActivity.this, “姝ゅ織鎰胯€呮牱鏈暟鐩凡瓒呰繃100锛?,
  155.                                 Toast.LENGTH_SHORT).show();
  156.                     }
  157.                     fTest = new File(savePath + b + c + “.JPG”);
  158.                 }
  159.                 try {
  160.                     FileOutputStream fout = new FileOutputStream(fTest);
  161.                     BufferedOutputStream bos = new BufferedOutputStream(fout);
  162.                     Bitmap mBitmap = Bitmap.createScaledBitmap(bm, 600, 800, false);
  163.                     mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
  164.                     //bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
  165.                     bos.flush();
  166.                     bos.close();
  167.                     cntSave++;
  168.                     Toast.makeText(TestPhotoActivity.this“鎮ㄦ媿鐨勭”+cntSave+“寮爌icture淇濆瓨鎴愬姛锛佺紪鍙凤細”+ b + c,
  169.                             Toast.LENGTH_SHORT).show();
  170.                 }  catch (IOException e) {
  171.                     // TODO Auto-generated catch block
  172.                     e.printStackTrace();
  173.                     Toast.makeText(TestPhotoActivity.this,
  174.                             “淇濆瓨澶辫触”,
  175.                             Toast.LENGTH_SHORT).show();
  176.                 }
  177.                 break;
  178.                 default:
  179.             }
  180.         }
  181.     }
  182.     public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
  183.         // TODO Auto-generated method stub
  184.     }
  185.     public void surfaceCreated(SurfaceHolder arg0) {
  186.         // TODO Auto-generated method stub
  187.     }
  188.     public void surfaceDestroyed(SurfaceHolder arg0) {
  189.         // TODO Auto-generated method stub
  190.     }
  191.     //鍒濆鍖栨憚鍍忓ご
  192.     public void initCamera()
  193.     {
  194.         if(myCamera == null && !isView)
  195.         {
  196.             myCamera = Camera.open();
  197.             Log.i(TAG, “camera.open”);
  198.         }
  199.         if(myCamera != null && !isView) {
  200.             try {
  201.                     myParameters = myCamera.getParameters();
  202.                     myParameters.setPictureFormat(PixelFormat.JPEG);
  203.                     myParameters.setPreviewSize(1280, 720);
  204.                     //myParameters.setFocusMode(“auto”);
  205.                     myParameters.setPictureSize(2048, 1152); //1280, 720
  206.                     myParameters.set(“rotation”, 90);
  207.                     myCamera.setDisplayOrientation(90);
  208.                     myCamera.setParameters(myParameters);
  209.                     myCamera.setPreviewDisplay(mySurfaceHolder);
  210.                     myCamera.startPreview();
  211.                     isView = true;
  212.                     myCamera.autoFocus(mAutoFocusCallback);
  213.             } catch (Exception e) {
  214.                 // TODO: handle exception
  215.                 e.printStackTrace();
  216.                 Toast.makeText(TestPhotoActivity.this, “鍒濆鍖栫浉鏈洪敊璇?,
  217.                         Toast.LENGTH_SHORT).show();
  218.             }
  219.         }
  220.     }
  221.     class CameraTimerTask extends TimerTask{
  222.         @Override
  223.         public void run() {
  224.             // TODO Auto-generated method stub
  225.             if(myCamera != null)
  226.             {
  227.                 myCamera.autoFocus(mAutoFocusCallback);
  228.             }
  229.         }
  230.     }
  231.     //鍒ゆ柇鏂囦欢澶规槸鍚﹀瓨鍦紝濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓涓€涓?       public boolean isFolderExist(String folderPath){
  232.             boolean result = false;
  233.             File f = new File(folderPath);
  234.             if(!f.exists()){
  235.                 if(f.mkdir()){
  236.                     result = true;
  237.                 }
  238.                 else
  239.                     result = false;
  240.             }
  241.             else
  242.                 result = true;
  243.             return result;
  244.         }
  245. }

自动聚焦部分,核心的代码有,构造函数里的

private Camera.AutoFocusCallback mAutoFocusCallback;
mAutoFocusCallback = new Camera.AutoFocusCallback() {

public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
if(success){
myCamera.setOneShotPreviewCallback(null);
Toast.makeText(TestPhotoActivity.this,
“自动聚焦成功” , Toast.LENGTH_SHORT).show();
}

}
};
和initCamera里的myCamera.autoFocus(mAutoFocusCallback);调用!

 

第三,AndroidManifest文件,红线部分是添加的对摄像头操作、sd存储的权限许可。

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android
package=”yan.guoqi.testphoto”
android:versionCode=”1″
android:versionName=”1.0″ >
<uses-sdk android:minSdkVersion=”15″ />
<!– 鍦╯d鍗′腑鍒涘缓鍜屽垹闄ゆ枃浠剁殑鏉冮檺 –>
    <uses-permission android:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS” />
<!– 鍦╯d鍗′腑鍐欏叆鏁版嵁鐨勬潈闄?–>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<!– 浣跨敤鎷嶇収鐨勬潈闄?–>
<uses-permission android:name=”android.permission.CAMERA” />

    <uses-feature android:name=”android.hardware.camera” />

<application
android:icon=”@drawable/ic_launcher”
android:label=”@string/app_name” >
<activity
android:name=”.TestPhotoActivity”
android:label=”@string/app_name” >
<intent-filter>
<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>

</manifest>

 
上两张效果图,来看下摄像头相同的previewSize、pictureSize下,自动对焦前后的差别:

效果差别不是一般的大啊!

1,上面的源程序里mTimer、mTimerTask等这些是我第一种思路,用定时器来控制聚焦,结果是失败的。碰到这些,大家略过去就行了。

2,这里控制聚焦的核心实现时,在initCamera函数里,执行myCamera.autoFocus(mAutoFocusCallback); 自动聚焦这句话!在构造函数里定义了一个mAutoFocusCallback的回调函数变量。还可以在按下拍照按钮后判断当前是否自动聚焦成功,如果聚 焦成功再拍照!mAutoFocusCallback里的if(success)就是标示自动聚焦成功

3,网上有很多,只是简单的在构造函数里写一句myCamera.setFocus(null),我真怀疑,这不是坑爹么?反正我这样是没弄成功。

4,程序里的乱码部分是文字,由于从linux下拷出来就成乱码了,大家不用太关心,都是些提示性的话。

5,另外还要交代一下,自动聚焦这句话一定要在摄像头正常预览的时候调用,否则是没有意义的,程序也会挂掉。

6,我核心的参考文章:

http://www.cnblogs.com/liuan/archive/2012/01/10/2318300.html

http://www.cnblogs.com/skyseraph/archive/2012/03/26/2418665.html

向他们表示感谢!

遗留的问题:

我第一次按下预览按钮后,会进 行自动聚焦,并提示自动聚焦成功。如果此时执行拍照–保存–再次预览,则自动聚焦是成功的。 如果我预览后,调整了和拍摄物的距离这时想再次自动聚焦,即连续两次按下预览按钮,怎么第二次就不自动聚焦了呢???这是不是和android摄像头内置 的属性有关系?

源码下载链接:http://download.csdn.net/detail/yanzi1225627/4538626

———————-作者yanzi1225627 转载请注明 2012.8.31

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏