How do I fill a non-standard size SurfaceView with a cropped camera preview using Camera2?










1















I am using a SurfaceView to show a feed from the camera using the Camera2 api - it works but no matter what I do the image seems to come out stretched or zoomed in to a really noticeable degree.



I have tried using the SurfaceView frame size and just making the view larger than the screen with negative boundaries ( like this ), but that was stretching the image. Now I am trying to use SCALER_CROP_REGION but that seems to be zooming in to a ratio of something like 2:1 when the actual SurfaceView is about 90 pixels smaller than the image resolution. The part of my code configuring things looks basically like this, except the real code is more of a scattered, experiment-riddled wreck:



 int width = mTextureView.getWidth();
int height = mTextureView.getHeight();
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size mCameraSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class));
int xOffset = Math.floor((mCameraSize.x - width) / 2);
int yOffset = Math.floor((mCameraSize.y - height) / 2);
Rect cropRectangle = new Rect(xOffset, yOffset, width, height);
mCaptureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRectangle );


The important thing is that it gets the image displayed on the SurfaceView but it is zoomed in. So for example:



  • The best-fit camera dimensions for my phone in portrait mode are 720 x 1280.

  • The SurfaceView size is 720 x 1184.

  • The cropRectangle starts at 0, 48 and has dimensions of 720 x 1184.

What I would expect to see is the top and bottom of the image cropped slightly but the width unchanged. What I see instead is the image is zoomed in so that - at a guess - I am getting approximately the middle 50% of the view zoomed to fill the screen. As far as I can tell it is also stretched a little vertically? When I take a picture from this preview, it shows the normal size view and makes it clear how zoomed in the preview was.



What am I doing wrong with my cropping to cause this problem? Would I be better going back to the previous approach of extending the SurfaceView to be bigger than the screen?










share|improve this question

















  • 1





    There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

    – Alex Cohn
    Nov 14 '18 at 10:05















1















I am using a SurfaceView to show a feed from the camera using the Camera2 api - it works but no matter what I do the image seems to come out stretched or zoomed in to a really noticeable degree.



I have tried using the SurfaceView frame size and just making the view larger than the screen with negative boundaries ( like this ), but that was stretching the image. Now I am trying to use SCALER_CROP_REGION but that seems to be zooming in to a ratio of something like 2:1 when the actual SurfaceView is about 90 pixels smaller than the image resolution. The part of my code configuring things looks basically like this, except the real code is more of a scattered, experiment-riddled wreck:



 int width = mTextureView.getWidth();
int height = mTextureView.getHeight();
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size mCameraSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class));
int xOffset = Math.floor((mCameraSize.x - width) / 2);
int yOffset = Math.floor((mCameraSize.y - height) / 2);
Rect cropRectangle = new Rect(xOffset, yOffset, width, height);
mCaptureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRectangle );


The important thing is that it gets the image displayed on the SurfaceView but it is zoomed in. So for example:



  • The best-fit camera dimensions for my phone in portrait mode are 720 x 1280.

  • The SurfaceView size is 720 x 1184.

  • The cropRectangle starts at 0, 48 and has dimensions of 720 x 1184.

What I would expect to see is the top and bottom of the image cropped slightly but the width unchanged. What I see instead is the image is zoomed in so that - at a guess - I am getting approximately the middle 50% of the view zoomed to fill the screen. As far as I can tell it is also stretched a little vertically? When I take a picture from this preview, it shows the normal size view and makes it clear how zoomed in the preview was.



What am I doing wrong with my cropping to cause this problem? Would I be better going back to the previous approach of extending the SurfaceView to be bigger than the screen?










share|improve this question

















  • 1





    There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

    – Alex Cohn
    Nov 14 '18 at 10:05













1












1








1








I am using a SurfaceView to show a feed from the camera using the Camera2 api - it works but no matter what I do the image seems to come out stretched or zoomed in to a really noticeable degree.



I have tried using the SurfaceView frame size and just making the view larger than the screen with negative boundaries ( like this ), but that was stretching the image. Now I am trying to use SCALER_CROP_REGION but that seems to be zooming in to a ratio of something like 2:1 when the actual SurfaceView is about 90 pixels smaller than the image resolution. The part of my code configuring things looks basically like this, except the real code is more of a scattered, experiment-riddled wreck:



 int width = mTextureView.getWidth();
int height = mTextureView.getHeight();
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size mCameraSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class));
int xOffset = Math.floor((mCameraSize.x - width) / 2);
int yOffset = Math.floor((mCameraSize.y - height) / 2);
Rect cropRectangle = new Rect(xOffset, yOffset, width, height);
mCaptureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRectangle );


The important thing is that it gets the image displayed on the SurfaceView but it is zoomed in. So for example:



  • The best-fit camera dimensions for my phone in portrait mode are 720 x 1280.

  • The SurfaceView size is 720 x 1184.

  • The cropRectangle starts at 0, 48 and has dimensions of 720 x 1184.

What I would expect to see is the top and bottom of the image cropped slightly but the width unchanged. What I see instead is the image is zoomed in so that - at a guess - I am getting approximately the middle 50% of the view zoomed to fill the screen. As far as I can tell it is also stretched a little vertically? When I take a picture from this preview, it shows the normal size view and makes it clear how zoomed in the preview was.



What am I doing wrong with my cropping to cause this problem? Would I be better going back to the previous approach of extending the SurfaceView to be bigger than the screen?










share|improve this question














I am using a SurfaceView to show a feed from the camera using the Camera2 api - it works but no matter what I do the image seems to come out stretched or zoomed in to a really noticeable degree.



I have tried using the SurfaceView frame size and just making the view larger than the screen with negative boundaries ( like this ), but that was stretching the image. Now I am trying to use SCALER_CROP_REGION but that seems to be zooming in to a ratio of something like 2:1 when the actual SurfaceView is about 90 pixels smaller than the image resolution. The part of my code configuring things looks basically like this, except the real code is more of a scattered, experiment-riddled wreck:



 int width = mTextureView.getWidth();
int height = mTextureView.getHeight();
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size mCameraSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class));
int xOffset = Math.floor((mCameraSize.x - width) / 2);
int yOffset = Math.floor((mCameraSize.y - height) / 2);
Rect cropRectangle = new Rect(xOffset, yOffset, width, height);
mCaptureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRectangle );


The important thing is that it gets the image displayed on the SurfaceView but it is zoomed in. So for example:



  • The best-fit camera dimensions for my phone in portrait mode are 720 x 1280.

  • The SurfaceView size is 720 x 1184.

  • The cropRectangle starts at 0, 48 and has dimensions of 720 x 1184.

What I would expect to see is the top and bottom of the image cropped slightly but the width unchanged. What I see instead is the image is zoomed in so that - at a guess - I am getting approximately the middle 50% of the view zoomed to fill the screen. As far as I can tell it is also stretched a little vertically? When I take a picture from this preview, it shows the normal size view and makes it clear how zoomed in the preview was.



What am I doing wrong with my cropping to cause this problem? Would I be better going back to the previous approach of extending the SurfaceView to be bigger than the screen?







android android-camera2






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 21:28









glenatronglenatron

8,14995493




8,14995493







  • 1





    There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

    – Alex Cohn
    Nov 14 '18 at 10:05












  • 1





    There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

    – Alex Cohn
    Nov 14 '18 at 10:05







1




1





There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

– Alex Cohn
Nov 14 '18 at 10:05





There is no true reason for the negative margins approach to produce distorted picture, probably the sizes are not correct. If you use a TextureView instead of SurfaceView, you may find that OpenGL transformation is easier to handle than SCALER_CROP_REGION. The question about the latter is whether your device supports android.distortionCorrection.mode control.

– Alex Cohn
Nov 14 '18 at 10:05












1 Answer
1






active

oldest

votes


















1














Unfortunately, SCALER_CROP_REGION cannot help you compensate the distortion. This defines a region of the sensor to read out for capture, but the result does not go straight to the screen, it is passed to an output stream.




Output streams use this rectangle to produce their output, cropping to a smaller region if necessary to maintain the stream's aspect ratio, then scaling the sensor input to match the output's configured resolution.




See this answer for example of handling the distortion differently.






share|improve this answer























  • Brilliant, this is so helpful, thank you.

    – glenatron
    Nov 14 '18 at 13:33










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53289763%2fhow-do-i-fill-a-non-standard-size-surfaceview-with-a-cropped-camera-preview-usin%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Unfortunately, SCALER_CROP_REGION cannot help you compensate the distortion. This defines a region of the sensor to read out for capture, but the result does not go straight to the screen, it is passed to an output stream.




Output streams use this rectangle to produce their output, cropping to a smaller region if necessary to maintain the stream's aspect ratio, then scaling the sensor input to match the output's configured resolution.




See this answer for example of handling the distortion differently.






share|improve this answer























  • Brilliant, this is so helpful, thank you.

    – glenatron
    Nov 14 '18 at 13:33















1














Unfortunately, SCALER_CROP_REGION cannot help you compensate the distortion. This defines a region of the sensor to read out for capture, but the result does not go straight to the screen, it is passed to an output stream.




Output streams use this rectangle to produce their output, cropping to a smaller region if necessary to maintain the stream's aspect ratio, then scaling the sensor input to match the output's configured resolution.




See this answer for example of handling the distortion differently.






share|improve this answer























  • Brilliant, this is so helpful, thank you.

    – glenatron
    Nov 14 '18 at 13:33













1












1








1







Unfortunately, SCALER_CROP_REGION cannot help you compensate the distortion. This defines a region of the sensor to read out for capture, but the result does not go straight to the screen, it is passed to an output stream.




Output streams use this rectangle to produce their output, cropping to a smaller region if necessary to maintain the stream's aspect ratio, then scaling the sensor input to match the output's configured resolution.




See this answer for example of handling the distortion differently.






share|improve this answer













Unfortunately, SCALER_CROP_REGION cannot help you compensate the distortion. This defines a region of the sensor to read out for capture, but the result does not go straight to the screen, it is passed to an output stream.




Output streams use this rectangle to produce their output, cropping to a smaller region if necessary to maintain the stream's aspect ratio, then scaling the sensor input to match the output's configured resolution.




See this answer for example of handling the distortion differently.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 14 '18 at 11:10









Alex CohnAlex Cohn

41.6k553189




41.6k553189












  • Brilliant, this is so helpful, thank you.

    – glenatron
    Nov 14 '18 at 13:33

















  • Brilliant, this is so helpful, thank you.

    – glenatron
    Nov 14 '18 at 13:33
















Brilliant, this is so helpful, thank you.

– glenatron
Nov 14 '18 at 13:33





Brilliant, this is so helpful, thank you.

– glenatron
Nov 14 '18 at 13:33



















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53289763%2fhow-do-i-fill-a-non-standard-size-surfaceview-with-a-cropped-camera-preview-usin%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3

Museum of Modern and Contemporary Art of Trento and Rovereto