如何使用 CameraSource 拍照?

Posted

技术标签:

【中文标题】如何使用 CameraSource 拍照?【英文标题】:How to take a photo using CameraSource? 【发布时间】:2017-12-26 19:27:12 【问题描述】:

当我想使用相机拍照时,CameraSource 出现了一些问题。 我想要的只是用我在 xml 文件上制作的按钮拍照并使用“CameraSource”拍照,因为我也在使用“TextRecognizer”。 相机工作正常,但是当我按下按钮拍照时出现问题。

清单文件:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

我的变量:

SurfaceView cameraView;
TextView textView;
CameraSource camera_source;
final int RequestCameraPermissionID = 1001;

类:

// Starting the CameraSource. This will be in the 'OnCreate' function. This function works.
private void OpenCameraSource()
        final TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
        if (!textRecognizer.isOperational()) 
            Log.w("Steal_Activity", "Detector activity are not yet available");
            Toast.makeText(getApplicationContext(),"Detector activity are not yet available",Toast.LENGTH_SHORT).show();
         else 
            camera_source = new CameraSource.Builder(getApplicationContext(),textRecognizer)
                    .setFacing(CameraSource.CAMERA_FACING_BACK)
                    .setRequestedPreviewSize(1280, 1024)
                    .setRequestedFps(2.0f)
                    .setAutoFocusEnabled(true)
                    .build();
            cameraView.getHolder().addCallback(new SurfaceHolder.Callback() 
                @Override
                public void surfaceCreated(SurfaceHolder surfaceHolder) 
                    try 
                        if (ActivityCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) 
                            ActivityCompat.requestPermissions(Steal.this,
                                    new String[]android.Manifest.permission.CAMERA,
                                    RequestCameraPermissionID);
                            return;
                        
                        camera_source.start(cameraView.getHolder());
                    catch (IOException ex)
                        ex.printStackTrace();
                    
                
                @Override
                public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) 
                
                @Override
                public void surfaceDestroyed(SurfaceHolder surfaceHolder) 
                    camera_source.stop();
                
            );
            textRecognizer.setProcessor(new Detector.Processor<TextBlock>() 
                // Some Stuff here
            
        );
    



// This function will be launched when the button is pressed
public void OnClick_TakeShot(View view)
        try//I GET ERROR HERE
            camera_source.takePicture(null,pictureCallback);
        catch (Exception ex)
            Toast.makeText(getApplicationContext(),"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
        


// Callback for 'takePicture'
CameraSource.PictureCallback pictureCallback = new CameraSource.PictureCallback() 
        @Override
        public void onPictureTaken(byte[] bytes) 
            File file_image = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES+"/pics");
            Bitmap bitmap = BitmapFactory.decodeByteArray(bytes , 0, bytes .length);
            if(bitmap!=null)
                if(!file_image.isDirectory())
                    file_image.mkdir();
                
                file_image=new File(file_image,"mylastpic.jpg");
                try
                    FileOutputStream fileOutputStream=new FileOutputStream(file_image);
                    bitmap.compress(Bitmap.CompressFormat.JPEG,100, fileOutputStream);
                    fileOutputStream.flush();
                    fileOutputStream.close();
                
                catch(Exception exception) 
                    Toast.makeText(getApplicationContext(),"Error saving: "+ exception.toString(),Toast.LENGTH_LONG).show();
                
            
        
;

当我按下按钮拍照时不工作

【问题讨论】:

您是在尝试使用其他应用拍照还是尝试制作相机应用? 一个可以使用播放服务读取文本并拍照的相机应用,但我想使用CameraSource 而不是Intent 方法。 从表面上看,OnClick_TakeShot() 中的 camera_source 为空。要么你没有调用 OpenCameraSource(),要么它默默地失败了。 【参考方案1】:

尝试使用这种方式(我正在使用来自 Google Vision 的 OCR 并使用 CameraSource 拍照)Pd:闪光灯按钮我还没有修复它......

您必须使用:在您的依赖项中编译“com.google.android.gms:play-services-vision:9.2.1”以实现 OCR 兼容性

public class CustomCamaraActivity extends BaseActivity implements Callback,
    OnClickListener 

private Context context;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private Camera camera;
private Button flipCamera;
private Button flashCameraButton;
private Button captureImage;
private Button BtnCapturarFoto;
private int cameraId;
private boolean flashmode = false;
private int rotation;
private ActionBar actionBar;
private CameraSource cameraSource;
private StringBuilder builder;
private TextView txTextoCapturado;


private static CustomCamaraActivity instance;
private Activity activity;
private String nombreProyecto;
public static final int REQUEST_IMAGE_CAPTURE = 0020;
private File file;
private String ubicacion;
private static final String TAG = "FOTOGRAFIA";
private int Height = 620, Width = 480;
private TextRecognizer recognizer;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.custom_camara_layout);
    context = this;
    // camera surface view created
    cameraId = CameraInfo.CAMERA_FACING_BACK;
    flipCamera = (Button) findViewById(R.id.flipCamera);
    flashCameraButton = (Button) findViewById(R.id.flash);
    captureImage = (Button) findViewById(R.id.captureImage);
    BtnCapturarFoto = (Button) findViewById(R.id.btnCapturarFoto);
    surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    txTextoCapturado = (TextView) findViewById(R.id.tvTextoCapturado);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    flipCamera.setOnClickListener(this);
    captureImage.setOnClickListener(this);
    flashCameraButton.setOnClickListener(this);
    BtnCapturarFoto.setOnClickListener(this);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    /*if (Camera.getNumberOfCameras() > 1) 
        flipCamera.setVisibility(View.VISIBLE);
    */
    if (!getBaseContext().getPackageManager().hasSystemFeature(
            PackageManager.FEATURE_CAMERA_FLASH)) 
        flashCameraButton.setVisibility(View.GONE);
        flipCamera.setVisibility(View.GONE);
    


    recognizer = new TextRecognizer.Builder(getApplicationContext()).build();
    if (recognizer.isOperational()) 

        cameraSource = new CameraSource.Builder(getApplicationContext(), recognizer)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedPreviewSize(1280, 1024)
                .setRequestedFps(15.0f)
                .setAutoFocusEnabled(true)
                .build();

        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() 
            @Override
            public void surfaceCreated(SurfaceHolder holder) 
                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) 
                    ActivityCompat.requestPermissions(CustomCamaraActivity.this, new String[]Manifest.permission.CAMERA, 100);
                    return;
                
                try 
                    releaseCamera();
                    cameraSource.start(surfaceView.getHolder());
                 catch (IOException e) 
                    e.printStackTrace();
                
            

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 

            

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) 
                if(cameraSource != null)
                    cameraSource.stop();
                
            
        );
        recognizer.setProcessor(new Detector.Processor<TextBlock>() 
            @Override
            public void release() 

            

            @Override
            public void receiveDetections(Detector.Detections<TextBlock> detections) 
                final SparseArray<TextBlock> items = detections.getDetectedItems();
                if (items.size() != 0) 
                    builder = new StringBuilder();
                    for (int i = 0; i < items.size(); i++) 
                        TextBlock it = items.valueAt(i);
                        builder.append(it.getValue());
                    
                    final String read = builder.toString().trim();
                    //String read = builder.toString().trim().replace(" ", "").replace("\n", "");
                    try
                        runOnUiThread(new Runnable() 
                            @Override
                            public void run() 
                                txTextoCapturado.setText(read);
                            
                        );
                    catch (Exception ex)
                        Log.e("error","Error al actualizar texto OCR");
                    

                    //It continues doing other things here
                
            
        );
    


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 
    switch (requestCode) 
        case 100:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 
                try 
                    if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) 
                        return;
                    
                    cameraSource.start(surfaceView.getHolder());
                 catch (IOException e) 
                    e.printStackTrace();
                
            
            break;
    



public String getUbicacion() 
    return ubicacion;


@Override
protected void onResume() 
    super.onResume();


@Override
protected void onPause() 
    super.onPause();
    if (camera != null) 
        camera.setPreviewCallback(null);
        camera.setErrorCallback(null);
        camera.stopPreview();
        camera.release();
        camera = null;
    


@Override
public void onBackPressed() 
    super.onBackPressed();
    if(camera != null)
        camera.setPreviewCallback(null);
        camera.setErrorCallback(null);
        camera.stopPreview();
        camera.release();
        camera = null;
    


@Override
public void surfaceCreated(SurfaceHolder holder) 
    if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) 
        alertCameraDialog();
    



private boolean openCamera(int id) 
    boolean result = false;
    cameraId = id;
    //releaseCamera();
    try 
        camera = Camera.open(cameraId);
     catch (Exception e) 
        e.printStackTrace();
    
    if (camera != null) 
        try 
            setUpCamera(camera);
            camera.setErrorCallback(new ErrorCallback() 

                @Override
                public void onError(int error, Camera camera) 

                
            );
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
            result = true;
         catch (IOException e) 
            e.printStackTrace();
            result = false;
            releaseCamera();
        
    
    return result;


private void setUpCamera(Camera c) 
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    rotation = getWindowManager().getDefaultDisplay().getRotation();
    int degree = 0;
    switch (rotation) 
        case Surface.ROTATION_0:
            degree = 0;
            break;
        case Surface.ROTATION_90:
            degree = 90;
            break;
        case Surface.ROTATION_180:
            degree = 180;
            break;
        case Surface.ROTATION_270:
            degree = 270;
            break;

        default:
            break;
    

    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
        // frontFacing
        rotation = (info.orientation + degree) % 330;
        rotation = (360 - rotation) % 360;
     else 
        // Back-facing
        rotation = (info.orientation - degree + 360) % 360;
    
    c.setDisplayOrientation(rotation);
    Parameters params = c.getParameters();

    showFlashButton(params);

    List<String> focusModes = params.getSupportedFlashModes();
    if (focusModes != null) 
        if (focusModes
                .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) 
            params.setFlashMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        
    

    params.setRotation(rotation);


private void showFlashButton(Parameters params) 
    boolean showFlash = (getPackageManager().hasSystemFeature(
            PackageManager.FEATURE_CAMERA_FLASH) && params.getFlashMode() != null)
            && params.getSupportedFlashModes() != null
            && params.getSupportedFocusModes().size() > 1;

    flashCameraButton.setVisibility(showFlash ? View.VISIBLE
            : View.INVISIBLE);



private void releaseCamera() 
    try 
        if (camera != null) 
            camera.setPreviewCallback(null);
            camera.setErrorCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
        
     catch (Exception e) 
        e.printStackTrace();
        Log.e("error", e.toString());
        camera = null;
    


private void releaseCameraSource() 
    try 
        if (cameraSource != null) 
            cameraSource.stop();
            cameraSource.release();
            cameraSource = null;
        
     catch (Exception e) 
        e.printStackTrace();
        Log.e("error", e.toString());
        cameraSource = null;
    


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
                           int height) 



@Override
public void surfaceDestroyed(SurfaceHolder holder) 



@Override
public void onClick(View v) 
    switch (v.getId()) 
        case R.id.flash:
            flashOnButton();
            break;
        case R.id.flipCamera:
            flipCamera();
            break;
        case R.id.captureImage:
            takeImage();
            break;
        case R.id.btnCapturarFoto:
            takeImage();
            break;

        default:
            break;
    


private void takeImage() 
    try
        //openCamera(CameraInfo.CAMERA_FACING_BACK);
        //releaseCameraSource();
        //releaseCamera();
        //openCamera(CameraInfo.CAMERA_FACING_BACK);
        //setUpCamera(camera);
        //Thread.sleep(1000);
        cameraSource.takePicture(null, new CameraSource.PictureCallback() 

            private File imageFile;
            @Override
            public void onPictureTaken(byte[] bytes) 
                try 
                    // convert byte array into bitmap
                    Bitmap loadedImage = null;
                    Bitmap rotatedBitmap = null;
                    loadedImage = BitmapFactory.decodeByteArray(bytes, 0,
                            bytes.length);

                    // rotate Image
                    Matrix rotateMatrix = new Matrix();
                    rotateMatrix.postRotate(rotation);
                    rotatedBitmap = Bitmap.createBitmap(loadedImage, 0, 0,
                            loadedImage.getWidth(), loadedImage.getHeight(),
                            rotateMatrix, false);
                    String state = Environment.getExternalStorageState();
                    File folder = null;
                    if (state.contains(Environment.MEDIA_MOUNTED)) 
                        folder = new File(Environment
                                .getExternalStorageDirectory() + "/Demo");
                     else 
                        folder = new File(Environment
                                .getExternalStorageDirectory() + "/Demo");
                    

                    boolean success = true;
                    if (!folder.exists()) 
                        success = folder.mkdirs();
                    
                    if (success) 
                        java.util.Date date = new java.util.Date();
                        imageFile = new File(folder.getAbsolutePath()
                                + File.separator
                                //+ new Timestamp(date.getTime()).toString()
                                + "Image.jpg");

                        imageFile.createNewFile();
                     else 
                        Toast.makeText(getBaseContext(), "Image Not saved",
                                Toast.LENGTH_SHORT).show();
                        return;
                    

                    ByteArrayOutputStream ostream = new ByteArrayOutputStream();

                    // save image into gallery
                    rotatedBitmap = resize(rotatedBitmap, 800, 600);
                    rotatedBitmap.compress(CompressFormat.JPEG, 100, ostream);

                    FileOutputStream fout = new FileOutputStream(imageFile);
                    fout.write(ostream.toByteArray());
                    fout.close();
                    ContentValues values = new ContentValues();

                    values.put(Images.Media.DATE_TAKEN,
                            System.currentTimeMillis());
                    values.put(Images.Media.MIME_TYPE, "image/jpeg");
                    values.put(MediaStore.MediaColumns.DATA,
                            imageFile.getAbsolutePath());

                    CustomCamaraActivity.this.getContentResolver().insert(
                            Images.Media.EXTERNAL_CONTENT_URI, values);

                    setResult(Activity.RESULT_OK); //add this
                    finish();
                 catch (Exception e) 
                    e.printStackTrace();
                
            
        );

    catch (Exception ex)
        txTextoCapturado.setText("Error al capturar fotografia!");
    



private void flipCamera() 
    int id = (cameraId == CameraInfo.CAMERA_FACING_BACK ? CameraInfo.CAMERA_FACING_FRONT
            : CameraInfo.CAMERA_FACING_BACK);
    if (!openCamera(id)) 
        alertCameraDialog();
    


private void alertCameraDialog() 
    AlertDialog.Builder dialog = createAlert(CustomCamaraActivity.this,
            "Camera info", "error to open camera");
    dialog.setNegativeButton("OK", new DialogInterface.OnClickListener() 
        @Override
        public void onClick(DialogInterface dialog, int which) 
            dialog.cancel();

        
    );

    dialog.show();


private Builder createAlert(Context context, String title, String message) 

    AlertDialog.Builder dialog = new AlertDialog.Builder(
            new ContextThemeWrapper(context,
                    android.R.style.Theme_Holo_Light_Dialog));
    dialog.setIcon(R.drawable.ic_launcher);
    if (title != null)
        dialog.setTitle(title);
    else
        dialog.setTitle("Information");
    dialog.setMessage(message);
    dialog.setCancelable(false);
    return dialog;



private void flashOnButton() 
    if (camera != null) 
        try 
            Parameters param = camera.getParameters();
            if (flashmode) 
                param.setFlashMode(Parameters.FLASH_MODE_OFF);
                flashCameraButton.setBackground(getResources().getDrawable(R.drawable.ic_flash_off));
             else 
                param.setFlashMode(Parameters.FLASH_MODE_TORCH);
                flashCameraButton.setBackground(getResources().getDrawable(R.drawable.ic_flash_on));
            
            //param.setFlashMode(!flashmode ? Parameters.FLASH_MODE_TORCH : Parameters.FLASH_MODE_OFF);
            camera.setParameters(param);
            flashmode = !flashmode;
         catch (Exception e) 
            e.printStackTrace();
            // TODO: handle exception
        

    


/**
 * Metodo para cambiar el tamaño de la fotografia una resolucion predeterminada.
 *
 * @param image
 * @param maxWidth
 * @param maxHeight
 * @return
 */
private Bitmap resize(Bitmap image, int maxWidth, int maxHeight) 
    if (maxHeight > 0 && maxWidth > 0) 
        int width = image.getWidth();
        int height = image.getHeight();
        float ratioBitmap = (float) width / (float) height;
        float ratioMax = (float) maxWidth / (float) maxHeight;

        int finalWidth = maxWidth;
        int finalHeight = maxHeight;
        if (ratioMax > 1) 
            finalWidth = (int) ((float) maxHeight * ratioBitmap);
         else 
            finalHeight = (int) ((float) maxWidth / ratioBitmap);
        
        image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
        return image;
     else 
        return image;
    

这是布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_ >

<SurfaceView
    android:id="@+id/surfaceView"
    android:layout_
    android:layout_ />

<LinearLayout
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true">

    <TextView
        android:id="@+id/tvTextoCapturado"
        android:layout_
        android:layout_
        android:gravity="center"
        android:textAlignment="center"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:textStyle="bold" />
</LinearLayout>

<LinearLayout
    android:layout_
    android:layout_
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginBottom="10dp"
    android:elevation="0dp"
    android:orientation="horizontal"
    android:weightSum="30">

    <Button
        android:id="@+id/flash"
        android:layout_
        android:layout_
        android:layout_alignBaseline="@+id/captureImage"
        android:layout_alignBottom="@+id/captureImage"
        android:layout_marginLeft="27dp"
        android:layout_marginRight="27dp"
        android:layout_toLeftOf="@+id/captureImage"
        android:layout_toStartOf="@+id/captureImage"
        android:layout_weight="4"
        android:background="@drawable/ic_flash_off"
        android:gravity="center" />

    <Button
        android:id="@+id/captureImage"
        android:layout_
        android:layout_
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="27dp"
        android:layout_marginRight="27dp"
        android:layout_weight="10"
        android:background="@android:drawable/ic_menu_camera"
        android:visibility="gone" />

    <Button
        android:id="@+id/btnCapturarFoto"
        style="@style/blue_button"
        android:layout_
        android:layout_
        android:layout_marginLeft="27dp"
        android:layout_marginRight="27dp"
        android:layout_weight="20"
        android:elevation="0dp"
        android:text="Tomar fotografia" />

    <Button
        android:id="@+id/flipCamera"
        android:layout_
        android:layout_
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="27dp"
        android:layout_marginRight="27dp"
        android:layout_toRightOf="@id/captureImage"
        android:layout_weight="4"
        android:background="@drawable/ic_rotate"
        android:visibility="invisible" />

</LinearLayout>

【讨论】:

【参考方案2】:

你可以像这样通过 CameraSource 类来实现它:

mCameraSource = builder
                .setFlashMode(if (useFlash) Camera.Parameters.FLASH_MODE_TORCH else null)
                .build()

将以下代码添加到按钮点击监听器:

mCameraSource.takePicture(null, CameraSource.PictureCallback  data ->
   // here data is a byteArray, you can play with it :)

【讨论】:

【参考方案3】:

您必须将 XML 对象“SurfaceView”添加到您的活动中,而不是将其声明为变量:

在你的 main_activity.xml 中

<SurfaceView
            android:id="@+id/cameraView"
            android:layout_
            android:layout_ />

在你的activity.kt中

 val cameraView: SurfaceView = findViewById(R.id.cameraView)

【讨论】:

以上是关于如何使用 CameraSource 拍照?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 视觉 CameraSource 中添加放大/缩小手势

如何更改像 setPreviewSize 和 PictureSize 这样的 CameraSource 大小

如何在适用于 Android 的 Google API 的 CameraSource 中保存带有叠加层的图像?

从com.google.android.gms.vision.CameraSource访问相机并增加/减少预览亮度

如何在使用 Android 移动视觉库时处理单个相机帧

Mobile VisionbarcodeScanner:SurfaceView为啥不更新CameraSource?