android-vision
android-vision copied to clipboard
CameraSourcePreview doesn't fill whole screen height
I'm having everything the same as in this sample except my activity layout is this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
android:weightSum="100"
android:orientation="horizontal">
<be.citylife.communitypurchaseapp.view.camera.CameraSourcePreview
android:id="@+id/preview"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="60">
<be.citylife.communitypurchaseapp.view.camera.GraphicOverlay
android:id="@+id/overlay"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</be.citylife.communitypurchaseapp.view.camera.CameraSourcePreview>
<FrameLayout
android:id="@+id/sideContainer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="40"/>
</LinearLayout>
My tablet is in landscape and I want that the cameraPreviewSource is always left and fills the whole screen in the height and then right off it I'm having a fragment that fills the rest.
This layout works except my previewsource doesn't fill the whole height (even though it shows correct in the preview). It has a black banner on it. Even my width is actually smaller than I want you can see this on the screenshot:
http://i61.tinypic.com/vctmw0.png
I played with the CameraSourcePreview with the width and height in the onLayout function but it doesn't help.
Anyone an idea how to solve this?
EDIT:
I think there is a problem in the onLayout method off the CameraSourcePreview. That it doesn't calculate it right when you use maybe layout weight or something I don't know.
CameraSourcePreview is included in the example code. This was meant as more of a "Hello World" sample rather than a formal part of the API.
It has to account for getting the aspect ratio of the view to match the aspect ratio of the preview images from the camera, as well as accounting for the camera rotation. So it actually overrides the size of the view to end up with something reasonable. See here:
https://github.com/googlesamples/android-vision/blob/master/visionSamples/FaceTracker/app/src/main/java/com/google/android/gms/samples/vision/face/facetracker/ui/camera/CameraSourcePreview.java#L126
Feel free to copy/modify this class and change it to best meet your needs.
Thats what I thought. The only problem I'm facing right now is that I don't know how to get the width of the screen because my layout uses layout_weight and I don't know how to get 60 % of the width. Otherwise it would be simple I guess, just retrieve the width/height or set them. Any idea or guideline how to do this?
I'm facing the same issue, some extra padding on landscape and portrait mode.
Hi, Comment or remove below lines from CameraSourcePreview and it should be fine. I was having same issue like you and it is solved now.
if (childHeight > layoutHeight) {
childHeight = layoutHeight;
childWidth = (int)(((float) layoutHeight / (float) height) * width);
}
Thank you Abhirav, your suggestion has completely solved the issue in landscape mode (there is still a bit of padding in portrait mode but it is ok).
I removed the lines to but still padding on the bottom in landscape mode. Is this some problem with layout weight?
This is my code, no padding in portrait and fill right in landscape.
I use layoutHeight instead of childHeight in for (int i = 0; i < getChildCount(); ++i){...}
if (mCameraSource != null)
{
Size size = mCameraSource.getPreviewSize();
if (size != null)
{
width = size.getWidth();
height = size.getHeight();
}
}
// Swap width and height sizes when in portrait, since it will be rotated 90 degrees
if (isPortraitMode())
{
int tmp = width;
//noinspection SuspiciousNameCombination
width = height;
height = tmp;
}
final int layoutWidth = right - left;
final int layoutHeight = bottom - top;
// Computes height and width for potentially doing fit width.
int childWidth = layoutWidth;
int childHeight = (int) (((float) layoutWidth / (float) width) * height);
for (int i = 0; i < getChildCount(); ++i)
{
getChildAt(i).layout(0, 0, childWidth, layoutHeight);
}
try
{
startIfReady();
}
catch (SecurityException se)
{
Log.e(TAG, "Do not have permission to start the camera", se);
}
catch (IOException e)
{
Log.e(TAG, "Could not start camera source.", e);
}
}
@abhirav Thanks, this works.
I had the same problem, unnecessary white space on the right in portrait mode.
Another thing which worked for me was removing BOTH what abhirav suggested and removing these lines:
// Computes height and width for potentially doing fit width.
int childWidth = layoutWidth;
int childHeight = (int)(((float) layoutWidth / (float) width) * height);
On the device I tested, this had no effect on how the preview actually looked, but using layoutHeight is the actual device height, whereas childHeight is computed and (in my case) bigger than device's height. But as I said, no effect on how it actually looked.
Code suggested by mmagician and abhirav works perfectly. But, the camera preview is not in the correct ratio in portrait mode. the height is getting stretched. Could you help me out in this regard ?
@Kalen66100 Thanks, your solution worked for me.
Thank you @Kalen66100 , it worked for me too.
@Kalen66100 Thanks you. It worked for me
Thank you @Kalen66100 and @abhirav . You save my code!
The following works, while also preserving the aspect ratio. This will slightly oversize the camera display, requiring cropping along one dimension. Change CameraSourcePreview.onLayout to:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int previewWidth = 320;
int previewHeight = 240;
if (mCameraSource != null) {
Size size = mCameraSource.getPreviewSize();
if (size != null) {
previewWidth = size.getWidth();
previewHeight = size.getHeight();
}
}
// Swap width and height sizes when in portrait, since it will be rotated 90 degrees
if (isPortraitMode()) {
int tmp = previewWidth;
previewWidth = previewHeight;
previewHeight = tmp;
}
final int viewWidth = right - left;
final int viewHeight = bottom - top;
int childWidth;
int childHeight;
int childXOffset = 0;
int childYOffset = 0;
float widthRatio = (float) viewWidth / (float) previewWidth;
float heightRatio = (float) viewHeight / (float) previewHeight;
// To fill the view with the camera preview, while also preserving the correct aspect ratio,
// it is usually necessary to slightly oversize the child and to crop off portions along one
// of the dimensions. We scale up based on the dimension requiring the most correction, and
// compute a crop offset for the other dimension.
if (widthRatio > heightRatio) {
childWidth = viewWidth;
childHeight = (int) ((float) previewHeight * widthRatio);
childYOffset = (childHeight - viewHeight) / 2;
} else {
childWidth = (int) ((float) previewWidth * heightRatio);
childHeight = viewHeight;
childXOffset = (childWidth - viewWidth) / 2;
}
for (int i = 0; i < getChildCount(); ++i) {
// One dimension will be cropped. We shift child over or up by this offset and adjust
// the size to maintain the proper aspect ratio.
getChildAt(i).layout(
-1 * childXOffset, -1 * childYOffset,
childWidth - childXOffset, childHeight - childYOffset);
}
try {
startIfReady();
} catch (IOException e) {
Log.e(TAG, "Could not start camera source.", e);
}
}
Hi all, this is my solution and It worked on SS Note 3, Moto G. I hope it is useful for you in BarcodeCaptureActivity.java - line 204
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Log.e(TAG, "widthPixels: " + metrics.widthPixels + " -- metrics: " + metrics.heightPixels);
CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setRequestedPreviewSize(metrics.heightPixels, metrics.widthPixels)
.setRequestedFps(15.0f);
in CameraSourcePreview.java - replace childWidth, childHeight by width, height
for (int i = 0; i < getChildCount(); ++i) {
getChildAt(i).layout(0, 0, width, height);
}
Hi!
I use the solution "nam2210" and when I run on the Nexus 7 (2013) I don't get full screen. Here is a screenshot: http://i65.tinypic.com/ifvlgg.png
How can I get full screen, please?
Have you tried the solution that I posted above on March 30?
Have you tried the solution that I posted above on March 30?
A preview is displayed in the center? It is not attached to the top left corner?
@pm0733464 Can you confirm that using @nam2210 solution will result in less efficient detection when running on a device having a poor display (low density) but a high res camera?
Especially due to .setRequestedPreviewSize(metrics.heightPixels, metrics.widthPixels)
I know my assumption will probably be false in reality based on latest devices specs. But with the large Android fragmentation, looks like a bad idea to me to base the size of the frames used for the detection on the screen density...
@pm0733464 Can you confirm that using @nam2210 solution will result in less efficient detection when running on a device having a poor display (low density) but a high res camera?
For the face API, using a higher resolution is usually slower than using a lower resolution... slower but sometimes a little more accurate. It's a speed / accuracy trade-off.
Looks like @nam2210's solution matches the camera preview resolution to the display resolution. Assuming that the display resolution isn't very low (e.g., less than 320x240), it probably isn't less efficient in the low density / high res camera scenario. That is, using the display resolution would probably result in a faster detection than using the higher res camera resolution.
But it's a bit of a different story for the barcode API, since the barcode API tends to require higher resolutions for greater accuracy. In that case, you might want to go with a higher resolution than the display resolution if the display resolution is too low.
@pm0733464 sorry I forgot to specify my comment was for barcode detection indeed :)
@pm0733464 tell me please
Have you tried the solution that I posted above on March 30?
A preview is displayed in the center? It is not attached to the top left corner?
@UserSty having the preview centered on the display then cropped a little on the borders make more sense than having it "pinned" on the top left corner then loosing a bigger part on the right|bottom borders of the preview. Your users are going to point the camera onto the "object" they want the detection to happen. Naturally, they are going to place it in the middle of the screen. In that case, the @pm0733464 's solution simply makes more sense ;)
@ggirard07 Thanks
Thank You @abhirav . This really helped me. :+1:
The solution "@pm0733464" does not work correctly on some devices. The same code snippet is used in the "googly-eyes" example. And there is also a problem. User "@ggirard07" wrote that the preview is centered on the screen, but it is not. Apparently there is a bug.
I checked the code work on some devices. On the "HTC One M8 (Android 6)" and "Motorola Moto G (2nd Gen.) (Android 5)" preview centered, and then the image is displayed correctly on the screen using "centerCrop". But on the device, "Asus Nexus 7 2013 (Android 6.0.1)" preview is not centered, and is attached to the top. And now "centerCrop" does not work correctly. Also, there is a problem in the "Samsung Google Galaxy Nexus (Android 4.4.4)" preview is not centered, and already attached to the bottom. And now "centerCrop" does not work correctly.
How do I know when the preview is centered, and when not? Is this a bug in mobileVison?
Help solve this problem or tell me how to get around it, thank you.
@UserSty Hi, could you try the modified barcode I above Modified Barcode Scanner Code and tell me how it goes, from there I might be able to help you.
@Wax911 I tried your code "Modified Barcode Scanner Code" He works too, is not quite correct. I checked the code work on some devices.
On the device, "the Nexus 7 (Android 6)" preview is not displayed on the full screen, and is attached to the upper left corner. This is bad unfortunately.
On the "HTC One M8 (Android 6)" preview is not clear which is tied as the picture is displayed as screen size and still look good.
What I've noticed that if I try to put a different size of previews, it is ignored and displayed differently.
This solution does not work as expected.
Any help please.
@UserSty damn, that's a shame then, the reason why it's ignoring your preview sizes is because I automatically get the screen resolution and best camera res paired together from the camera source code. Can you try playing around with:
private static SizePair selectSizePair(Camera camera, int desiredWidth, int desiredHeight) { List validPreviewSizes = generateValidPreviewSizeList(camera); return validPreviewSizes.get(0); }
At some point as I was playing around with this I realized you don't always the preview size requested so I had to forcefully return the first item in the list of validPreviewSizes, I you find this function which I explained a few comments back you can debug the solution as run the code and see what preview sizes are available. If you need any help feel free to drop me an email, I would also like to try and fix this issue. Oh and BTW when I tested this on a tablet it would fill up the screen if the display was in a landscape format.
@UserSty Not sure how you are doing your tests... But I retested @pm0733464 solution currently implemented in my app on an "Asus Nexus 7 2013 (Android 6.0.1)", and everything looks perfectly fine to me!