Android Studio开发文字拍摄App:如何实现相机自动对焦?
解决Android相机自动对焦问题(拍摄文字清晰化)
嘿,我明白你现在的困扰——用系统相机Intent拍出来的照片不对焦,文字根本看不清对吧?咱们一步步来解决这个问题:
为什么当前代码无法自动对焦?
你现在用的MediaStore.ACTION_IMAGE_CAPTURE是调用系统自带的相机App,对焦逻辑完全由那个App控制。有些系统相机默认不会自动对焦到文字,或者只在特定场景触发对焦,而且这个Intent返回的还是缩略图,本身分辨率就低,放大后自然模糊。
方案一:给系统相机Intent添加对焦参数(简单尝试)
虽然不是所有系统相机都支持,但可以先试试给Intent添加对焦模式参数,强制开启自动对焦:
修改你创建Intent的代码,加上这几行:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 添加连续自动对焦参数,适合静态物体(比如文字) intent.putExtra(MediaStore.EXTRA_FOCUS_MODE, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // 额外:指定输出文件获取高清照片(默认返回的是缩略图) File photoFile = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis() + ".jpg"); Uri photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); startActivityForResult(intent, 100);
然后修改onActivityResult,从指定文件加载高清照片:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == RESULT_OK) { // 从指定文件加载Bitmap File photoDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); // 这里要注意匹配刚才生成的文件名,或者你可以把文件名存在全局变量里 File photoFile = new File(photoDir, System.currentTimeMillis() + ".jpg"); Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath()); camView.setImageBitmap(bitmap); } }
注意:使用FileProvider需要在AndroidManifest.xml里配置,避免文件权限问题:
<application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
然后在res/xml目录下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_images" path="Pictures" /> </paths>
方案二:用CameraX实现可控的自动对焦(推荐)
如果系统相机的参数不生效,或者你需要更稳定的对焦效果,强烈推荐用Jetpack CameraX——它是Google官方推出的相机组件,兼容Android 5.0+,自动处理各种设备兼容性问题,对焦设置也非常简单。
步骤1:添加CameraX依赖
在你的app/build.gradle(Module级别)里添加依赖:
dependencies { def camerax_version = "1.3.0" implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version" }
步骤2:修改布局文件
替换原来的ImageView,用CameraX的PreviewView来显示相机预览:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.camera.view.PreviewView android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/camBTN" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="24dp" android:text="拍照"/> <ImageView android:id="@+id/camView" android:layout_width="100dp" android:layout_height="100dp" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" android:layout_margin="16dp" android:background="#80000000"/> </RelativeLayout>
步骤3:修改CameraActivity代码
用CameraX实现自动对焦和拍照:
import android.Manifest; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Environment; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageCapture; import androidx.camera.core.ImageCaptureException; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.view.PreviewView; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import com.google.common.util.concurrent.ListenableFuture; import java.io.File; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; public class CameraActivity extends AppCompatActivity { private PreviewView previewView; private Button camBtn; private ImageView camView; private ImageCapture imageCapture; private static final int CAMERA_PERMISSION_REQUEST_CODE = 101; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); previewView = findViewById(R.id.previewView); camBtn = findViewById(R.id.camBTN); camView = findViewById(R.id.camView); // 先检查相机权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); return; } // 启动相机 startCamera(); // 拍照按钮点击事件 camBtn.setOnClickListener(v -> takePhoto()); } private void startCamera() { // 获取CameraProvider实例 ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); Executor mainExecutor = ContextCompat.getMainExecutor(this); cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); // 配置预览用例 Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 配置拍照用例,开启连续自动对焦 imageCapture = new ImageCapture.Builder() .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) .setFocusMode(ImageCapture.FOCUS_MODE_CONTINUOUS_AUTO) // 关键:连续自动对焦 .build(); // 选择后置相机 CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA; // 绑定用例到Activity生命周期 cameraProvider.unbindAll(); cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); Toast.makeText(this, "相机初始化失败", Toast.LENGTH_SHORT).show(); } }, mainExecutor); } private void takePhoto() { if (imageCapture == null) return; // 创建保存照片的文件 File photoDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File photoFile = new File(photoDir, System.currentTimeMillis() + ".jpg"); // 配置输出选项 ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build(); // 执行拍照 imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() { @Override public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) { // 照片保存成功,加载到小ImageView预览 Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath()); camView.setImageBitmap(bitmap); Toast.makeText(CameraActivity.this, "照片已保存到:" + photoFile.getAbsolutePath(), Toast.LENGTH_SHORT).show(); } @Override public void onError(@NonNull ImageCaptureException exception) { exception.printStackTrace(); Toast.makeText(CameraActivity.this, "拍照失败:" + exception.getMessage(), Toast.LENGTH_SHORT).show(); } }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startCamera(); } else { Toast.makeText(this, "需要相机权限才能使用拍照功能", Toast.LENGTH_SHORT).show(); finish(); } } } }
这个方案的优势在于:
- 稳定的自动对焦:
FOCUS_MODE_CONTINUOUS_AUTO会让相机持续对焦,确保文字清晰 - 高清照片:直接保存全分辨率照片,不会像系统Intent那样返回缩略图
- 兼容性强:CameraX自动适配不同Android版本和设备,不用自己处理复杂的相机API逻辑
最后总结
如果只是快速尝试,先给系统Intent添加对焦参数并指定输出文件;如果需要长期稳定的效果,果断切换到CameraX,这也是现在Android相机开发的主流方案。
内容的提问来源于stack exchange,提问作者S.Koren




