RedApparat / Fotoapparat

Making Camera for Android more friendly. 📸
Apache License 2.0
3.82k stars 408 forks source link

Photo/Preview aspect ratio mismatch #112

Closed mj3c closed 6 years ago

mj3c commented 7 years ago

What are you trying to achieve or the steps to reproduce?

I would like the preview size to be as close to the photo size in terms of aspect ratio.

How did you initialize FA?

mFotoapparat = Fotoapparat.with(this).into(mCameraView)
        .previewScaleType(ScaleType.CENTER_INSIDE)
//        .previewSize(biggestSize())
        .photoSize(biggestSize())
        .lensPosition(back())
        .focusMode(firstAvailable(
                continuousFocus(),
                autoFocus(),
                fixed()
        ))
        .flash(firstAvailable(
                autoRedEye(),
                autoFlash(),
                torch()
        )).build();

What was the result you received?

Using biggestSize() for photo size ends up being 4208x3120 on my Oneplus One. If I either specify preview size to be biggestSize() as well or not specify it at all, it ends up being 4096x2160 as I figured which is way off.

I also tried supplying my own function for the preview sizes like .previewSize(this::getPreviewSize) with it defined as:

private Size getPreviewSize(Collection<Size> sizes) {
    ...
}

but the sizes that get passed in there is an empty collection, so I guess there are no matching preview sizes for the photo size.

What did you expect?

How do I go about selecting a preview size which is close to the aspect ratio of the photo size?

Context:

Diolor commented 7 years ago

I partially copy the answer from #111 :

Firstly the problem is that camera 1 only informs about available sizes when you start the camera itself. Secondly different phones might have different picture aspect ratios. Thirdly "all you need" is set the view ratio the same as the desired/selected picture ratio.

A way could be to get the available resolutions for that device with Fotoapparat#getCapabilities() without starting the preview (passing an empty CameraRenderer into the .into(cameraView)). Then you decide which one of those you will render, stop the previous session, set the preview (CameraView) dimensions to match the picture's aspect ratio, and open the camera again with the normal view.

I have not tried this to know if Android Camera needs a surface to start or an exception will occur. I guess should be fine. Let us know.

mj3c commented 7 years ago

Quite a bit of work just because my supplied function for choosing the preview size doesn't get all sizes passed in, instead it only gets the ones that match the aspect ratio of the biggest photo size which is 4208x3120, and there are 0 preview sizes that match so I get an empty collection.

I supplied my own photo size chooser that gets the largest resolution with 16:9 aspect ratio (can also allow the user to choose whether he wants 4:3 or 16:9) with an assumption that every single device supports those. This way, when the preview size chooser gets called it will receive available sizes matching the chosen photo aspect ratio, so I can just choose the biggest of those as well.

Here's the workaround I used:

mFotoapparat = ...
        .previewSize(this::getPreviewSize)
        .photoSize(this::getPhotoSize)
        ...

And the functions:

private Size getPreviewSize(Collection<Size> sizes) {
    return Collections.max(sizes, (left, right) -> Integer.compare(left.width, right.width));
}

private Size getPhotoSize(Collection<Size> sizes) {
    double ratio = 16.0 / 9.0;
    sizes.removeIf(size -> Math.abs((double) size.width / (double) size.height - ratio) > 0.02);
    return Collections.max(sizes, (left, right) -> Integer.compare(left.width, right.width));
}
tuba commented 7 years ago

Why is the preview collection empty on some devices?

mj3c commented 7 years ago

I'm not 100% certain, but I think it's because the photo size gets chosen first (by default the largest one), and then the preview sizes that don't exactly match the ratio are filtered out. Apparently some devices, including my Oneplus One, don't have a matching preview size for the biggest available photo size. That's why I had to force the 16:9 ratio for example, as I have described above.

Diolor commented 6 years ago

Addressing back this Q: How do I go about selecting a preview size which is close to the aspect ratio of the photo size?

For exact same aspect ratios, this is done automatically internally. Nothing to worry.

Fyi we have these kind of selectors that you comment :

                    firstAvailable(
                            wideRatio(highestResolution()),
                            standardRatio(highestResolution())
                    )
jzzhrqp commented 6 years ago

I have the same problem on my one plus 6 phone, I don't know how to deal with it.

Diolor commented 6 years ago

We have answered exactly above

jzzhrqp commented 6 years ago

My problem is solved in the following way. I hope @Diolor will update to Fotoapparat, because the camera size of this year's mobile phone screen 19:9 should be very common.

aspectRatio(
         aspectRatio = 19f / 9f,
         Selector = selector,
         Tolerance = tolerance
)
Diolor commented 6 years ago

Good to know, thanks!