ユーザーがこのアプリケーションでフォーカスモードを選択できるようにしたいカスタムカメラアプリケーションを作成しようとしています。
フォーカスモードは自動でタッチツーフォーカスです
カメラでタッチツーフォーカスを使用したい場合、どのように始めることができますか?
これを試して:
public void takePhoto(File photoFile, String workerName, int width, int height, int quality) {
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
ただし、これが機能することも確認しました。おそらくより正確です。
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if(success) camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
最後のものは、フォーカシングが正常に完了した瞬間に写真を撮ります。 QRスキャンコードでの使用に非常に適しています。このような場合も同じだと思います。
この機能はソフトウェア/ハードウェア/メーカーに依存します。GalaxyNexusのような電話がAndroid 4.xでフラッシュされているのを見つけてから、Android.hardware.Camera.Parameters.getMaxNumFocusAreasを試してみることをお勧めします。 ()その上で、戻り値がゼロより大きい場合は幸運であり、setFocusAreas()を使用して「タッチツーフォーカス」機能を実装できます。
なぜ:
古いAndroidバージョンでは、フォーカスエリアを設定するためのパブリックAPIはありません。多くのメーカーが独自のAPIと実装を作成できましたが、共有しません。
AndroidはAPIレベル14でフォーカスエリアAPIを導入しましたが、電話メーカーはそれを実装しないことを選択する場合があります(つまり、独自のソリューションに固執することを選択します)。 APIがサポートされているかどうかを確認するには、最初にgetMaxNumFocusAreasa()を呼び出すことができます。正の整数が返される場合は、電話がAPIを実装しており、カメラアプリで「タッチフォーカス」機能を有効にすることができます。 (APIは「顔検出」機能のイネーブラーの1つでもあり、顔が認識されると、カメラアプリはAPIを使用して、カメラが顔にオートフォーカスできるようにします。)
APIを適切に使用する方法については、Vanilla Android Cameraアプリのソースコードを参照してください。
参照:
mInitialParams.getMaxNumFocusAreas()
よろしく
Ziteng Chen
すでに実装されていますが、フォーカスにタッチを追加したい場合、これを変更するにはどうすればよいですか?
public void takePhoto(File photoFile, String workerName, int width, int height, int quality) {
if (getAutoFocusStatus()){
camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}else{
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
this.photoFile = photoFile;
this.workerName = workerName;
this.imageOutputWidth = width;
this.imageOutputHeight = height;
}
public void takePhoto(File photoFile, int width, int height, int quality) {
takePhoto(photoFile, null, width, height, quality);
}
私は自分のアプリにフォーカス機能を実装しようとしていて、この機能を思い通りに実現しました。実装する Touch to Focus
以下のコードを参照してください。
CameraPreview.Java
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private OnFocusListener onFocusListener;
private boolean needToTakePic = false;
private Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean arg0, Camera arg1) {
if (arg0) {
mCamera.cancelAutoFocus();
}
}
};
// Constructor that obtains context and camera
@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera) {
super(context);
this.mCamera = camera;
this.mSurfaceHolder = this.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
this.onFocusListener = (OnFocusListener) context;
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
this.mSurfaceHolder.removeCallback(this);
mCamera.release();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
// start preview with new settings
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
// intentionally left blank for a test
e.printStackTrace();
}
}
/**
* Called from PreviewSurfaceView to set touch focus.
*
* @param - Rect - new area for auto focus
*/
public void doTouchFocus(final Rect tfocusRect) {
try {
List<Camera.Area> focusList = new ArrayList<Camera.Area>();
Camera.Area focusArea = new Camera.Area(tfocusRect, 1000);
focusList.add(focusArea);
Camera.Parameters param = mCamera.getParameters();
param.setFocusAreas(focusList);
param.setMeteringAreas(focusList);
mCamera.setParameters(param);
mCamera.autoFocus(myAutoFocusCallback);
} catch (Exception e) {
e.printStackTrace();
}
if (isNeedToTakePic()) {
onFocusListener.onFocused();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
Rect touchRect = new Rect(
(int) (x - 100),
(int) (y - 100),
(int) (x + 100),
(int) (y + 100));
final Rect targetFocusRect = new Rect(
touchRect.left * 2000 / this.getWidth() - 1000,
touchRect.top * 2000 / this.getHeight() - 1000,
touchRect.right * 2000 / this.getWidth() - 1000,
touchRect.bottom * 2000 / this.getHeight() - 1000);
doTouchFocus(targetFocusRect);
}
return false;
}
public boolean isNeedToTakePic() {
return needToTakePic;
}
public void setNeedToTakePic(boolean needToTakePic) {
this.needToTakePic = needToTakePic;
}
}
MainActivity.Java
public class MainActivity extends Activity
implements OnFocusListener {
private Button captureButton, switchCameraButton;
private Camera mCamera;
private CameraPreview mCameraPreview;
private int currentCameraId;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent().hasExtra("camera_id")) {
currentCameraId = getIntent().getIntExtra("camera_id", Camera.CameraInfo.CAMERA_FACING_BACK);
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
// Obtain MotionEvent object
v.setEnabled(false);
mCameraPreview.setNeedToTakePic(true);
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis() + 100;
float x = mCameraPreview.getWidth() / 2;
float y = mCameraPreview.getHeight() / 2;
// List of meta states found here: developer.Android.com/reference/Android/view/KeyEvent.html#getMetaState()
int metaState = 0;
MotionEvent motionEvent = MotionEvent.obtain(
downTime,
eventTime,
MotionEvent.ACTION_DOWN,
x,
y,
metaState
);
// Dispatch touch event to view
mCameraPreview.dispatchTouchEvent(motionEvent);
}
});
switchCameraButton = (Button) findViewById(R.id.button_switch_camera);
switchCameraButton.setVisibility(
Camera.getNumberOfCameras() > 1 ? View.VISIBLE : View.GONE);
switchCameraButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCamera.stopPreview();
//NB: if you don't release the current camera before switching, you app will crash
mCameraPreview.getHolder().removeCallback(mCameraPreview);
mCamera.release();
//swap the id of the camera to be used
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
mCamera = getCameraInstance(currentCameraId);
mCameraPreview = new CameraPreview(MainActivity.this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.removeAllViews();
preview.addView(mCameraPreview);
}
});
}
@Override
protected void onResume() {
super.onResume();
mCamera = getCameraInstance(currentCameraId);
mCameraPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mCameraPreview);
}
/**
* Helper method to access the camera returns null if it cannot get the
* camera or does not exist
*
* @return
*/
private Camera getCameraInstance(int currentCameraId) {
Camera camera = null;
try {
camera = Camera.open(currentCameraId);
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
private static File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
// String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
// .format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + "DEMO_" + ".jpg");
if (mediaFile.exists()) mediaFile.delete();
return mediaFile;
}
@Override
public void onFocused() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mCamera.takePicture(null, null, mPicture);
mCameraPreview.setNeedToTakePic(false);
captureButton.setEnabled(true);
}
}, 1500);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
Android:orientation="vertical">
<FrameLayout
Android:id="@+id/camera_preview"
Android:layout_width="fill_parent"
Android:layout_height="0dp"
Android:layout_weight="1" />
<Button
Android:id="@+id/button_switch_camera"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
Android:text="Switch Camera" />
<Button
Android:id="@+id/button_capture"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
Android:text="Capture" />
</LinearLayout>
サンプルアプリは Github-カスタムカメラアプリ にあります。
これを呼び出して、Touch-To-Focusモードを有効にします。
private void setTouchToFocusMode(Camera.Parameters parameters){
String focusMode;
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
}
if (focusMode != null && focusMode.length() > 0){
parameters.setFocusMode(focusMode);
}
}
ユーザーが画面をタップしたら、以下を呼び出してフォーカスエリアを設定します。
private static final int FOCUS_WIDTH = 80;
private static final int FOCUS_HEIGHT = 80;
public static String setFocalPoint(Camera.Parameters params, int x, int y){
String focusMode = "";
if (params != null && params.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusArea = new ArrayList<Camera.Area>();
focusArea.add(new Camera.Area(new Rect(x, y, x + FOCUS_WIDTH, y + FOCUS_HEIGHT), 1000));
params.setFocusAreas(focusArea);
if(params.getMaxNumMeteringAreas() > 0) {
params.setMeteringAreas(focusArea);
}
if(params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
}
}
return focusMode;
}
アクションのためにautoFocus/cancelAutoFocusを呼び出します。
mCamera.cancelAutoFocus();
mCamera.autoFocus(mAutoFocusCallback);