Reputation: 43
I am working on an Android application with an embedded QR code scanner using the Google Vision API. The scanner functions, but the SurfaceView that acts as camera preview is stretched vertically. The degree of distortion is different for different emulated devices.
As I understand it, you would use mCameraSource.setRequestedPreviewSize(w,h)
to set the correct size. w
and h
I have set as Resources.getSystem().getDisplayMetrics().widthPixels
and Resources.getSystem().getDisplayMetrics().heightPixels
, respectively. However, I have noticed that regardless of what numbers I parse as width and height, there are no changes in the way it displays.
However, resizing the SurfaceView on which it is displayed does have an effect on the distortion. For one particular emulated Android device I can statically set the right width and height. For different devices, however, with a slightly different pixel w:h ratio, the distortion can become quite large.
I have read various solutions on StackOverflow, but most use the CameraPreview
instead of the CameraSource.Builder
.
My code thus far is (part of ScannerActivity.java
):
private SurfaceView svCamera;
private BarcodeDetector barcodeDetector;
private CameraSource cameraSource;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scanner);
initViews();
initListeners();
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels)
.setAutoFocusEnabled(true)
.build();
svCamera.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
requestPermission();
try {
if (ActivityCompat.checkSelfPermission(ScannerActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
cameraSource.start(svCamera.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
@Override
public void release() {
scanned = true;
}
@Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
...
}
});
} }
Can someone help me with setting preview size?
The way I fixed it with help of Alex Cohn's answer:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
...
cameraSource.setRequestedPreviewSize(1280, 720); // Hardcoded, for now.
And I set the size of the SurfaceView
with:
svCamera.setLayoutParams(new RelativeLayout.LayoutParams(width, width/9*16));
If I remember I will update this to a non-hardcoded version.
Upvotes: 4
Views: 2002
Reputation: 57203
Quite contrary. You cannot choose arbitrary resolution for setRequestedPreviewSize()
. This CameraSource API wraps the ordinary Camera API, which exposes only some, "supported" pairs of width and height.
If you want to display the live view undistorted, you must setup your SurfaceView to match the aspect ratio of chosen camera preview. This means, it's OK to use surface of 320x240 pixel for camera 640x480. It's even OK to use surface of 1280x720 for camera 1920x1080.
But if you have surface of 800x480 for camera of 1280x720 (and if your devices supports such camera resolution), the picture will be slightly stretched.
Upvotes: 3