Android camera2 qr代码阅读器

时间:2016-08-10 00:19:32

标签: android qr-code zxing

我有一个片段正在使用camera2 API和zxing(google的斑马线)API扫描qr代码,它适用于所有手机,问题在于这款特定的平板电脑NVIDIA SHIELD。它不会在图像中找到qr,尝试了很多:

  1. 更小,更大的屏幕/图像尺寸。
  2. 所有不同的相机设置,如iso,对比度,更亮,更暗。
  3. 使用JPEG,YUV_422_888 ...
  4. 等所有图像格式
  5. 使用nr 0,1,2 ......
  6. 的飞机

    很抱歉这么大的代码片段,提出问题,会尽快回复。

    这是我的代码:

    public class FragmentDecoder extends Fragment
            implements FragmentCompat.OnRequestPermissionsResultCallback {
    
        private static boolean accessGranted = true;
        private static boolean showingText = false;
        private ImageView camera_guide_image;
        private TextView decoderText;
        private ImageButton flashButton;
        private static final int MAX_PREVIEW_WIDTH = 1920;
        private static final int MAX_PREVIEW_HEIGHT = 1080;
        private int mSensorOrientation;
        private boolean mFlashSupported;
        private static final String TAG = FragmentDecoder.class.getName();
    
        private final CameraCaptureSession.CaptureCallback mCaptureCallback =
                new CameraCaptureSession.CaptureCallback() {
                    private void process(CaptureResult result) {
                    }
    
                    @Override
                    public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request,
                                                    @NonNull CaptureResult partialResult) {
                        process(partialResult);
                    }
    
                    @Override
                    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request,
                                                   @NonNull TotalCaptureResult result) {
                        process(result);
                    }
    
                };
    
        private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
                new TextureView.SurfaceTextureListener() {
    
                    @Override
                    public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
                        openCamera(width, height);
                    }
    
                    @Override
                    public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
                        configureTransform(width, height);
                    }
    
                    @Override
                    public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
    
                        return true;
                    }
    
                    @Override
                    public void onSurfaceTextureUpdated(SurfaceTexture texture) {
    
                    }
    
                };
        private QRCodeReader mQrReader;
        private String mCameraId;
        private AutoFitTextureView mTextureView;
        private final ImageReader.OnImageAvailableListener mOnImageAvailableListener =
                new ImageReader.OnImageAvailableListener() {
    
                    @Override
                    public void onImageAvailable(ImageReader reader) {
                        Image img = null;
                        Result rawResult = null;
                        try {
                            img = reader.acquireLatestImage();
                            if (img == null) throw new NullPointerException("cannot be null");
                            ByteBuffer buffer = img.getPlanes()[0].getBuffer();
                            byte[] data = new byte[buffer.remaining()];
                            buffer.get(data);
    
                            int width = img.getWidth();
                            int height = img.getHeight();
    
                            PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
                            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    
                            rawResult = mQrReader.decode(bitmap);
    
                            if (rawResult == null) {
                                throw new NullPointerException("no QR code");
                            }
                            String decoded = rawResult.getText();
    
                            if (accessGranted) {
                                Log.e(TAG, "entered the accessGranted area!");
                                accessGranted = false;
                                boolean isPrivKey = BRWalletManager.getInstance(getActivity()).confirmSweep(getActivity(), decoded);
                                if (isPrivKey) {
                                    getActivity().runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            BRAnimator.hideDecoderFragment();
                                        }
                                    });
                                    return;
                                }
    
                                String validationString = validateResult(decoded);
    
                                if (Objects.equals(validationString, BRConstants.TEXT_EMPTY)) {
                                    onQRCodeRead((MainActivity) getActivity(), rawResult.getText());
                                } else {
                                    if (!showingText) {
                                        showingText = true;
                                        setCameraGuide(BRConstants.CAMERA_GUIDE_RED);
                                        setGuideText(validationString);
                                        new Handler().postDelayed(new Runnable() {
                                            @Override
                                            public void run() {
                                                showingText = false;
                                            }
                                        }, 1000);
                                    }
                                    accessGranted = true;
                                }
                            }
                        } catch (ReaderException | NullPointerException | IllegalStateException ignored) {
                            if (!showingText)
                                setCameraGuide(BRConstants.CAMERA_GUIDE);
    //                        Log.e(TAG, "Reader shows an exception! ", ignored);
                            /* Ignored */
                        } finally {
                            mQrReader.reset();
                            if (img != null)
                                img.close();
    
                        }
                        if (rawResult == null) {
                            if (!showingText)
                                setCameraGuide(BRConstants.CAMERA_GUIDE);
                        }
                    }
    
                };
        private CameraCaptureSession mCaptureSession;
        private CameraDevice mCameraDevice;
        private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    
            @Override
            public void onOpened(@NonNull CameraDevice cameraDevice) {
                // This method is called when the camera is opened.  We start camera preview here.
                mCameraOpenCloseLock.release();
                mCameraDevice = cameraDevice;
                createCameraPreviewSession();
            }
    
            @Override
            public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                mCameraOpenCloseLock.release();
                cameraDevice.close();
                mCameraDevice = null;
            }
    
            @Override
            public void onError(@NonNull CameraDevice cameraDevice, int error) {
                mCameraOpenCloseLock.release();
                cameraDevice.close();
                mCameraDevice = null;
                getActivity().onBackPressed();
            }
    
        };
    
        private Size mPreviewSize;
        private HandlerThread mBackgroundThread;
        private Handler mBackgroundHandler;
        private ImageReader mImageReader;
        private CaptureRequest.Builder mPreviewRequestBuilder;
        private CaptureRequest mPreviewRequest;
        private final Semaphore mCameraOpenCloseLock = new Semaphore(1);
        private int flashButtonCount;
    
    
        private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
                                              int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
    
    
            List<Size> bigEnough = new ArrayList<>();
    
            List<Size> notBigEnough = new ArrayList<>();
            int w = aspectRatio.getWidth();
            int h = aspectRatio.getHeight();
            for (Size option : choices) {
                if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                        option.getHeight() == option.getWidth() * h / w) {
                    if (option.getWidth() >= textureViewWidth &&
                            option.getHeight() >= textureViewHeight) {
                        bigEnough.add(option);
                    } else {
                        notBigEnough.add(option);
                    }
                }
            }
    
            // Pick the smallest of those big enough. If there is no one big enough, pick the
    
            if (bigEnough.size() > 0) {
                return Collections.min(bigEnough, new CompareSizesByArea());
            } else if (notBigEnough.size() > 0) {
                return Collections.max(notBigEnough, new CompareSizesByArea());
            } else {
                Log.e(TAG, "Couldn't find any suitable preview size");
                return choices[0];
            }
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
    
            View rootView = inflater.inflate(R.layout.fragment_decoder, container, false);
            mQrReader = new QRCodeReader();
    
            mTextureView = new AutoFitTextureView(getActivity());
            RelativeLayout layout = (RelativeLayout) rootView.findViewById(R.id.fragment_decoder_layout);
            camera_guide_image = (ImageView) rootView.findViewById(R.id.decoder_camera_guide_image);
            decoderText = (TextView) rootView.findViewById(R.id.decoder_text);
            flashButton = (ImageButton) rootView.findViewById(R.id.button_flash);
            flashButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    try {
                        if (mPreviewRequestBuilder == null || mCaptureSession == null)
                            return;
    
                        if (++flashButtonCount % 2 != 0) {
                            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
                            mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
                            flashButton.setBackgroundResource(R.drawable.flash_on);
                            SpringAnimator.showAnimation(flashButton);
                        } else {
                            mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
                            mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
                            flashButton.setBackgroundResource(R.drawable.flash_off);
                            SpringAnimator.showAnimation(flashButton);
                        }
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }
            });
    
            layout.addView(mTextureView, 0);
            startBackgroundThread();
            return rootView;
        }
    
        @Override
        public void onResume() {
            super.onResume();
            accessGranted = true;
            showingText = false;
            new Handler().post(new Runnable() {
                @Override
                public void run() {
                    if (camera_guide_image != null)
    
                        SpringAnimator.showExpandCameraGuide(camera_guide_image);
                }
            });
            ((BreadWalletApp) getActivity().getApplication()).hideKeyboard(getActivity());
    
            // When the screen is turned off and turned back on, the SurfaceTexture is already
            // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
            // a camera and start preview from here (otherwise, we wait until the surface is ready in
            // the SurfaceTextureListener).
    
            if (mTextureView.isAvailable()) {
                openCamera(mTextureView.getWidth(), mTextureView.getHeight());
            } else {
                mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
            }
        }
    
        @Override
        public void onPause() {
            closeCamera();
            stopBackgroundThread();
            super.onPause();
        }
    
        private void setUpCameraOutputs(int width, int height) {
            Activity activity = getActivity();
            CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
            try {
                for (String cameraId : manager.getCameraIdList()) {
                    CameraCharacteristics characteristics
                            = manager.getCameraCharacteristics(cameraId);
    
                    // We don't use a front facing camera in this sample.
                    Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                    if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                        continue;
                    }
    
                    StreamConfigurationMap map = characteristics.get(
                            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                    if (map == null) {
                        continue;
                    }
    
                    // For still image captures, we use the largest available size.
                    Size largest = Collections.max(
                            Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
                            new CompareSizesByArea());
                    mImageReader = ImageReader.newInstance(largest.getWidth()/2, largest.getHeight()/2,
                            ImageFormat.YUV_420_888, /*maxImages*/2);
                    mImageReader.setOnImageAvailableListener(
                            mOnImageAvailableListener, mBackgroundHandler);
    
                    // Find out if we need to swap dimension to get the preview size relative to sensor
                    // coordinate.
                    int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
                    //noinspection ConstantConditions
                    mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                    boolean swappedDimensions = false;
                    switch (displayRotation) {
                        case Surface.ROTATION_0:
                        case Surface.ROTATION_180:
                            if (mSensorOrientation == 90 || mSensorOrientation == 270) {
                                swappedDimensions = true;
                            }
                            break;
                        case Surface.ROTATION_90:
                        case Surface.ROTATION_270:
                            if (mSensorOrientation == 0 || mSensorOrientation == 180) {
                                swappedDimensions = true;
                            }
                            break;
                        default:
                            Log.e(TAG, "Display rotation is invalid: " + displayRotation);
                    }
    
                    Point displaySize = new Point();
                    activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
                    int rotatedPreviewWidth = width;
                    int rotatedPreviewHeight = height;
                    int maxPreviewWidth = displaySize.x;
                    int maxPreviewHeight = displaySize.y;
    
                    if (swappedDimensions) {
                        rotatedPreviewWidth = height;
                        rotatedPreviewHeight = width;
                        maxPreviewWidth = displaySize.y;
                        maxPreviewHeight = displaySize.x;
                    }
    
                    if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                        maxPreviewWidth = MAX_PREVIEW_WIDTH;
                    }
    
                    if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                        maxPreviewHeight = MAX_PREVIEW_HEIGHT;
                    }
    
                    // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
                    // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
                    // garbage capture data.
                    mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                            rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                            maxPreviewHeight, largest);
    
                    // We fit the aspect ratio of TextureView to the size of preview we picked.
                    int orientation = getResources().getConfiguration().orientation;
                    if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                        mTextureView.setAspectRatio(
                                mPreviewSize.getWidth(), mPreviewSize.getHeight());
                    } else {
                        mTextureView.setAspectRatio(
                                mPreviewSize.getHeight(), mPreviewSize.getWidth());
                    }
    
                    // Check if the flash is supported.
                    Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                    mFlashSupported = available == null ? false : available;
    
                    mCameraId = cameraId;
                    return;
                }
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    
        private void openCamera(int width, int height) {
            setUpCameraOutputs(width, height);
            configureTransform(width, height);
            CameraManager manager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
            try {
                if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                    throw new RuntimeException("Time out waiting to lock camera opening.");
                }
                if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
                if (mCameraId != null)
                    manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
            }
        }
    
    
        private void closeCamera() {
            try {
                mCameraOpenCloseLock.acquire();
                if (mCaptureSession != null) {
                    mCaptureSession.close();
                    mCaptureSession = null;
                }
                if (mCameraDevice != null) {
                    mCameraDevice.close();
                    mCameraDevice = null;
                }
                if (mImageReader != null) {
                    mImageReader.close();
                    mImageReader = null;
                }
            } catch (InterruptedException e) {
                throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
            } finally {
                mCameraOpenCloseLock.release();
            }
        }
    
        private void startBackgroundThread() {
            mBackgroundThread = new HandlerThread("CameraBackground");
            mBackgroundThread.start();
            mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
        }
    
        private void stopBackgroundThread() {
            try {
                mBackgroundThread.quitSafely();
                mBackgroundThread.join();
                mBackgroundThread = null;
                mBackgroundHandler = null;
            } catch (InterruptedException | NullPointerException e) {
                e.printStackTrace();
                mBackgroundThread = null;
                mBackgroundHandler = null;
            }
        }
    
        private void createCameraPreviewSession() {
            try {
                SurfaceTexture texture = mTextureView.getSurfaceTexture();
                assert texture != null;
    
                // We configure the size of default buffer to be the size of camera preview we want.
                texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    
                Surface surface = new Surface(texture);
                Surface mImageSurface = mImageReader.getSurface();
                mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                mPreviewRequestBuilder.addTarget(mImageSurface);
                mPreviewRequestBuilder.addTarget(surface);
    
                // Here, we create a CameraCaptureSession for camera preview.
                mCameraDevice.createCaptureSession(Arrays.asList(mImageSurface, surface),
                        new CameraCaptureSession.StateCallback() {
                            @Override
                            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                                // The camera is already closed
    //                            Log.e(TAG, "onConfigured");
                                if (mCameraDevice == null) return;
    
                                // When the session is ready, we start displaying the preview.
                                mCaptureSession = cameraCaptureSession;
                                try {
                                    // Auto focus should be continuous for camera preview.
                                    mPreviewRequestBuilder.set(CONTROL_AF_MODE, CONTROL_AF_MODE_CONTINUOUS_PICTURE);
    
    
    
                                    mPreviewRequest = mPreviewRequestBuilder.build();
                                    mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
                                            mBackgroundHandler);
                                } catch (CameraAccessException e) {
                                    e.printStackTrace();
                                }
                            }
    
                            @Override
                            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                                Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.failed),
                                        Toast.LENGTH_SHORT).show();
                            }
                        }, null
                );
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    
        private void configureTransform(int viewWidth, int viewHeight) {
    
            if (mTextureView == null || mPreviewSize == null) return;
    
            int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
            Matrix matrix = new Matrix();
            RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
            RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
            float centerX = viewRect.centerX();
            float centerY = viewRect.centerY();
            if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
                bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
                matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
                float scale = Math.max(
                        (float) viewHeight / mPreviewSize.getHeight(),
                        (float) viewWidth / mPreviewSize.getWidth());
                matrix.postScale(scale, scale, centerX, centerY);
                matrix.postRotate(90 * (rotation - 2), centerX, centerY);
            }
            mTextureView.setTransform(matrix);
        }
    
        private static synchronized void onQRCodeRead(final MainActivity app, final String text) {
            app.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (text != null) {
                        BRAnimator.hideDecoderFragment();
                        Log.e(TAG, "BEFORE processRequest");
                        RequestHandler.processRequest(app, text);
    
                    }
                }
            });
    
        }
    
    
        private static class CompareSizesByArea implements Comparator<Size> {
    
            @Override
            public int compare(Size lhs, Size rhs) {
                // We cast here to ensure the multiplications won't overflow
                return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                        (long) rhs.getWidth() * rhs.getHeight());
            }
    
        }
    
        private int getStatusBarHeight() {
            Rect rectangle = new Rect();
            Window window = getActivity().getWindow();
            window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
            int statusBarHeight = rectangle.top;
            int contentViewTop =
                    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            int titleBarHeight = contentViewTop - statusBarHeight;
    
    
            return statusBarHeight + titleBarHeight;
        }
    
        private String validateResult(String str) {
            RequestObject obj = null;
            try {
                obj = RequestHandler.getRequestFromString(str);
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
            if (obj == null) {
                return getActivity().getResources().getString(R.string.fragmentdecoder_not_a_bitcoin_qr_code);
            }
            if (obj.r != null) {
                return BRConstants.TEXT_EMPTY;
            }
            if (obj.address != null) {
                if (BRWalletManager.validateAddress(obj.address)) {
                    return BRConstants.TEXT_EMPTY;
                } else {
                    return getActivity().getResources().getString(R.string.fragmentdecoder_not_valid_bitcoin_address);
                }
            }
            return getActivity().getResources().getString(R.string.fragmentdecoder_not_a_bitcoin_qr_code);
        }
    
        private void setCameraGuide(final String str) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (str.equalsIgnoreCase(BRConstants.CAMERA_GUIDE)) {
                        camera_guide_image.setImageResource(R.drawable.cameraguide);
                        setGuideText(BRConstants.TEXT_EMPTY);
                    } else if (str.equalsIgnoreCase(BRConstants.CAMERA_GUIDE_RED)) {
                        camera_guide_image.setImageResource(R.drawable.cameraguide_red);
    
                    } else {
                        throw new IllegalArgumentException("CAMERA_GUIDE and CAMERA_GUIDE_RED only");
                    }
                }
            });
        }
    
        private void setGuideText(final String str) {
            Activity activity = getActivity();
            if (activity != null)
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        decoderText.setText(str);
                    }
                });
    
        }
    
    }
    

0 个答案:

没有答案