Android कैमरा पूर्वावलोकन टूट गया


136

मैं एंड्रॉइड पर अपनी कस्टम कैमरा गतिविधि बनाने पर काम कर रहा हूं, लेकिन कैमरे को घुमाते समय, सतह के दृश्य का पहलू अनुपात गड़बड़ हो जाता है।

गतिविधि के लिए मेरी ऑन्क्रिएट में, मैंने फ्रैम्मेलयौट सेट किया जो सतह के दृश्य को रखता है जो कैमरे के मापदंडों को प्रदर्शित करता है।

//FrameLayout that will hold the camera preview
        FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);

        //Setting camera's preview size to the best preview size
        Size optimalSize = null;
        camera = getCameraInstance();
        double aspectRatio = 0;
        if(camera != null){
            //Setting the camera's aspect ratio
            Camera.Parameters parameters = camera.getParameters();
            List<Size> sizes = parameters.getSupportedPreviewSizes();
            optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
            aspectRatio = (float)optimalSize.width/optimalSize.height;
        }

        if(optimalSize!= null){
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            previewHolder.setLayoutParams(params);
            LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            cameraPreview.setLayoutParams(surfaceParams);

        }

        cameraPreview.setCamera(camera);

        //Adding the preview to the holder
        previewHolder.addView(cameraPreview);

फिर, भूतल दृश्य में मैंने कैमरे के मापदंडों को प्रदर्शित करने के लिए सेट किया है

public void setCamera(Camera camera) {
        if (mCamera == camera) { return; }

        mCamera = camera;

        if (mCamera != null) {
            requestLayout();

            try {
                mCamera.setPreviewDisplay(mHolder);
            } catch (IOException e) {
                e.printStackTrace();
            }


            if(mCamera != null){
                //Setting the camera's aspect ratio
                Camera.Parameters parameters = mCamera.getParameters();
                List<Size> sizes = parameters.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);

                parameters.setPreviewSize(optimalSize.width, optimalSize.height);
                mCamera.setParameters(parameters);
            }

            /*
              Important: Call startPreview() to start updating the preview surface. Preview must 
              be started before you can take a picture.
              */
            mCamera.startPreview();
        }

    }

यहां छवि विवरण दर्ज करें

आप देख सकते हैं कि जब फोन घुमाया जाता है तो लेगो आदमी लंबा और पतला हो जाता है:

मैं यह कैसे सुनिश्चित कर सकता हूं कि मेरे कैमरा दृश्य के लिए पहलू अनुपात सही है?


@ ssificific u pls मेरी मदद कर सकता है, जहाँ मुझे उसी विधि का सामना करना पड़ रहा है, जहां मुझे दिया गया तरीका लिखना चाहिए?
1532 में user3233280

मुझे एक ऐसी ही समस्या लग रही थी, लेकिन यह जो तय कर रहा था वह निम्नलिखित था: mCamera.setDisplayOrientation (90) सतह में (कैमरे के लिए मेरे SurfaceView की विधि)
ग्रेग

जवाबों:


163

मैं इस विधि का उपयोग कर रहा हूं -> मेरा पूर्वावलोकन आकार प्राप्त करने के लिए एपीआई डेमो पर आधारित:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio=(double)h / w;

        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

जैसा कि आप देख सकते हैं कि आपको अपनी स्क्रीन की चौड़ाई और ऊँचाई इनपुट करनी होगी। यह विधि उन मानों के आधार पर स्क्रीन अनुपात की गणना करेगी और फिर supportPreview की सूची से यह बताती है कि यह आपके लिए उपलब्ध विकल्पों में से सर्वश्रेष्ठ का चयन करेगा। उस स्थान पर अपनी समर्थित सहायता सूची प्राप्त करें जहां कैमरा ऑब्जेक्ट उपयोग करके रिक्त नहीं है

mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

और फिर onMeasure में आप अपना इष्टतम पूर्वावलोकन प्राप्त कर सकते हैं।

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
           mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

और फिर (सतह कोड विधि में मेरे कोड में, जैसे मैंने कहा कि मैं कैमरा एक्टिविटी कोड के एपीआई डेमो संरचना का उपयोग कर रहा हूं, आप इसे ग्रहण में उत्पन्न कर सकते हैं):

Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();

और आपके लिए एक संकेत, क्योंकि मैंने आपकी तरह लगभग एक ही ऐप किया था। कैमरा गतिविधि के लिए अच्छा अभ्यास स्टेटसबार को छिपाना है। इंस्टाग्राम जैसे एप्लिकेशन इसे कर रहे हैं। यह आपकी स्क्रीन ऊंचाई मान को कम करता है और आपके अनुपात मान को बदलता है। कुछ डिवाइसों पर अजीब पूर्वावलोकन आकार प्राप्त करना संभव है (आपके भूतल को थोड़ा काट दिया जाएगा)


और आपके प्रश्न का उत्तर देने के लिए, कैसे जांचें कि आपका पूर्वावलोकन अनुपात सही है या नहीं? फिर आपके द्वारा निर्धारित मापदंडों की ऊंचाई और चौड़ाई प्राप्त करें:

mCamera.setParameters(parameters);

आपका सेट अनुपात ऊंचाई / चौड़ाई के बराबर है। यदि आप चाहते हैं कि कैमरा आपकी स्क्रीन पर अच्छा दिखे, तो आपके द्वारा सेट किए गए मापदंडों की ऊंचाई / चौड़ाई अनुपात आपकी स्क्रीन की ऊंचाई (माइनस स्टेटस बार) / चौड़ाई अनुपात के समान होना चाहिए।


2
बस एक सवाल: मैं देख रहा हूं कि आप 2 अलग-अलग गणना अनुपात का उपयोग कर रहे हैं: डबल टारगेट रेशियो = (डबल) एच / डब्ल्यू और डबल अनुपात = (डबल) size . उपलब्धता / size.height । पहला एक चौड़ाई से विभाजित ऊंचाई है और दूसरा विपरीत है, ऊंचाई द्वारा विभाजित चौड़ाई। क्या उन्हें समान गणना नहीं करनी चाहिए?
फियाज़लिस

इससे कोई फर्क नहीं पड़ता क्योंकि आकारों की सूची उदाहरण के लिए हर संभावना को ध्यान में रखती है: आपको 480x680 जैसा कुछ मिलेगा, लेकिन जल्द या बाद में 680x480 (परिदृश्य के लिए) होगा, इसलिए आपको बस उस सूची पर जाना होगा और एक को ढूंढना होगा आपकी आवश्यकताओं से मेल खाता है। आप इसे जल्द या बाद में पाएंगे।
F1sher

इसके अलावा, यदि आप चाहते हैं कि आपके चित्र इस आकार के हों (जैसा कि उन्हें शायद होना चाहिए), तो आपने चित्र का आकार निर्धारित कर दिया है parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
मैट लोगन

2
@ F1sher, मुझे हमेशा null पॉइंटर अपवाद पैरामीटर मिलते हैं ।setPreviewSize (mPreviewSize. उपलब्धता, mPreviewSize.height); कोई समाधान नहीं मिल रहा है।
FIXI

3
@ फिजलिस मैं आपसे सहमत हूं। वास्तव में, मुझे उस कोड को अपेक्षित रूप से काम करने के लिए सुधार करना था।
21

149

F1Sher का समाधान अच्छा है लेकिन कभी-कभी काम नहीं करता है। विशेष रूप से, जब आपका सतह दृश्य पूरी स्क्रीन को कवर नहीं करता है। इस स्थिति में आपको onMeasure () विधि को ओवरराइड करने की आवश्यकता है। मैंने आपके संदर्भ के लिए यहां अपना कोड कॉपी कर लिया है।

जब से मैंने चौड़ाई के आधार पर सरफेस व्यू को मापा तब मेरी स्क्रीन के अंत में मेरे पास थोड़ा सा सफेद गैप था जिसे मैंने इसे डिजाइन द्वारा भरा। आप इस समस्या को ठीक करने में सक्षम हैं यदि आप ऊँचाई रखते हैं और अनुपात में चौड़ाई को बढ़ाते हैं। हालाँकि, यह सतह को थोड़ा अलग करेगा।

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";

    private Context mContext;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private List<Camera.Size> mSupportedPreviewSizes;
    private Camera.Size mPreviewSize;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mContext = context;
        mCamera = camera;

        // supported preview sizes
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        for(Camera.Size str: mSupportedPreviewSizes)
                Log.e(TAG, str.width + "/" + str.height);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // empty. surfaceChanged will take care of stuff
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or reformatting changes here
        // start preview with new settings
        try {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            mCamera.setParameters(parameters);
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }

        if (mPreviewSize!=null) {
            float ratio;
            if(mPreviewSize.height >= mPreviewSize.width)
                ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
            else
                ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

            // One of these methods should be used, second method squishes preview slightly
            setMeasuredDimension(width, (int) (width * ratio));
  //        setMeasuredDimension((int) (width * ratio), height);
        }
    }

    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;

        if (sizes == null)
            return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.height / size.width;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;

            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }

        return optimalSize;
    }
}

11
यह सही उत्तर होना चाहिए, यह मामले को संभालता है जब कैमरा का पूर्वावलोकन पूरी स्क्रीन को कवर नहीं कर रहा है। +1।
हौसिन

1
जब मैं अपने गतिविधि आवेदन में बढ़ बंद हो गया <com.app.camera.CameraPreview Android: आईडी = "@ + id / camera_preview" एंड्रॉयड: layout_width = "match_parent" एंड्रॉयड: layout_height = "match_parent" />
fish40

आपको कुछ संशोधन करने की आवश्यकता है, लेकिन मैं इसे एक समाधान के रूप में स्वीकार करता हूं। ऊपर मतदान किया।
JaydeepW

2
हाय @ adnan9011, यह ट्यूटोरियल शायद सहायक हो सकता है। airpair.com/android/android-camera-surface-view-fragment
Hesam

4
getOptimalPreviewSizeमेरे लिए काम करने के लिए ऊंचाई और चौड़ाई को स्विच करने की आवश्यकता है । ऐसा इसलिए है क्योंकि प्रदर्शन अभिविन्यास 90 पर सेट किया गया था? अन्यथा, अनुपात की गणना भी नहीं पास (लक्ष्य 1.7 था और कैमरे के अनुपात 1 से कम थे) थे
ओनो

23

नोट: मेरा समाधान HESAM के समाधान का एक संपर्क है: https://stackoverflow.com/a/22758359/1718734

मुझे क्या पता: हेसम ने कहा कि थोड़ी सफेद जगह है जो कुछ फोन पर दिखाई दे सकती है, जैसे:

नोट: हालांकि पहलू अनुपात सही है, कैमरा पूरी स्क्रीन में नहीं भरता है।

हेसाम ने एक दूसरा समाधान सुझाया, लेकिन वह पूर्वावलोकन को तोड़ देता है। और कुछ उपकरणों पर, यह भारी विकृत करता है।

तो हम इस समस्या को कैसे ठीक करते हैं। यह सरल है ... जब तक यह स्क्रीन में भरता है तब तक पहलू अनुपात को गुणा करके। मैंने देखा है, कई लोकप्रिय ऐप जैसे स्नैपचैट, व्हाट्सएप, आदि उसी तरह से काम करते हैं।

आपको बस इतना करना है कि इसे ऑनमार्ट विधि में जोड़ें:

float camHeight = (int) (width * ratio);
    float newCamHeight;
    float newHeightRatio;

    if (camHeight < height) {
        newHeightRatio = (float) height / (float) mPreviewSize.height;
        newCamHeight = (newHeightRatio * camHeight);
        Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight);
        setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight);
    } else {
        newCamHeight = camHeight;
        setMeasuredDimension(width, (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight);
    }

यह स्क्रीन की ऊँचाई की गणना करेगा और स्क्रीन की ऊँचाई और mPreviewSize ऊँचाई के अनुपात को प्राप्त करेगा। फिर यह कैमरे की चौड़ाई और ऊंचाई को नई ऊंचाई के अनुपात और उसके अनुसार मापा आयाम से गुणा करता है।

यहां छवि विवरण दर्ज करें

और अगली बात जो आप जानते हैं, आप इसे समाप्त करते हैं: डी

यहां छवि विवरण दर्ज करें

यह फ्रंट कैमरा के साथ भी अच्छा काम करता है। मेरा मानना ​​है कि इस बारे में जाने का यह सबसे अच्छा तरीका है। अब मेरे ऐप के लिए केवल एक चीज बची है, वह है "कैप्चर" पर क्लिक करके पूर्वावलोकन को बचाने के लिए। लेकिन हां, यह बात है।


यह बहुत अच्छा काम करता है !! लेकिन यह लैंडस्केप में ठीक से काम नहीं करता है: /
मतान दहन

आपके कोड ने मेरी 2 महीने की खाली ब्लैक स्पेस समस्या हल कर दी :)
कार्तिक कोलनजी

1
यह काम करता है, लेकिन मेरे मामले में .. मेरे पास शीर्ष पर एक्शनबार है इसलिए सफेद बार छोटा था, हालांकि आपके कोड जोड़ने के बाद मेरा कैमरा लुक 40-50% तक ज़ूम हो गया। जब मैं सामने वाले कैमरे पर स्विच कर रहा हूं तो मैं मूल रूप से अपने चेहरे को सीधे (बस थोड़े से बाल) देख नहीं सकता, क्योंकि वह उच्च ज़ूम का है।
मकाले

@Yoosuf मैं सफेद स्क्रीन प्राप्त कर रहा हूं जब मैंने आपके कोड का पालन किया था। में onMeasure(int widthMeasureSpec, int heightMeasureSpec)विधि मैं हमेशा प्राप्त चौड़ाई = 0 और ऊंचाई = 0;
कुश पटेल

10

ठीक है, इसलिए मुझे लगता है कि सामान्य कैमरा पूर्वावलोकन स्ट्रेचिंग समस्या के लिए कोई पर्याप्त जवाब नहीं है। या कम से कम मुझे एक नहीं मिला। मेरे ऐप को इस स्ट्रेचिंग सिंड्रोम का भी सामना करना पड़ा और मुझे इस पोर्टल और इंटरनेट पर सभी उपयोगकर्ता के जवाबों के समाधान के लिए एक साथ पहेली करने में थोड़ा समय लगा।

मैंने @ हेसम के समाधान की कोशिश की, लेकिन यह काम नहीं किया और मेरे कैमरे के पूर्वावलोकन को प्रमुख रूप से विकृत कर दिया।

पहले मैं अपने समाधान का कोड (कोड के महत्वपूर्ण भाग) दिखाता हूं और फिर मैं समझाता हूं कि मैंने वे कदम क्यों उठाए। प्रदर्शन संशोधनों के लिए जगह है।

मुख्य गतिविधि xml लेआउट:

<RelativeLayout 
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
</RelativeLayout>

कैमरा पूर्वावलोकन:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private SurfaceHolder prHolder;
private Camera prCamera;
public List<Camera.Size> prSupportedPreviewSizes;
private Camera.Size prPreviewSize;

@SuppressWarnings("deprecation")
public YoCameraPreview(Context context, Camera camera) {
    super(context);
    prCamera = camera;

    prSupportedPreviewSizes = prCamera.getParameters().getSupportedPreviewSizes();

    prHolder = getHolder();
    prHolder.addCallback(this);
    prHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    try {
        prCamera.setPreviewDisplay(holder);
        prCamera.startPreview();
    } catch (IOException e) {
        Log.d("Yologram", "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (prHolder.getSurface() == null){
      return;
    }

    try {
        prCamera.stopPreview();
    } catch (Exception e){
    }

    try {
        Camera.Parameters parameters = prCamera.getParameters();
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
        parameters.setPreviewSize(prPreviewSize.width, prPreviewSize.height);

        prCamera.setParameters(parameters);
        prCamera.setPreviewDisplay(prHolder);
        prCamera.startPreview();

    } catch (Exception e){
        Log.d("Yologram", "Error starting camera preview: " + e.getMessage());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    setMeasuredDimension(width, height);

    if (prSupportedPreviewSizes != null) {
        prPreviewSize = 
            getOptimalPreviewSize(prSupportedPreviewSizes, width, height);
    }    
}

public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;

    if (sizes == null)
        return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
            continue;

        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

    return optimalSize;
}
}

मुख्य गतिविधि:

public class MainActivity extends Activity {

...

@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);     
    setContentView(R.layout.activity_main);

        maCamera = getCameraInstance();

        maLayoutPreview = (FrameLayout) findViewById(R.id.camera_preview);

        maPreview = new CameraPreview(this, maCamera);

        Point displayDim = getDisplayWH();
        Point layoutPreviewDim = calcCamPrevDimensions(displayDim, 
                maPreview.getOptimalPreviewSize(maPreview.prSupportedPreviewSizes, 
                    displayDim.x, displayDim.y));
        if (layoutPreviewDim != null) {
            RelativeLayout.LayoutParams layoutPreviewParams = 
                (RelativeLayout.LayoutParams) maLayoutPreview.getLayoutParams();
            layoutPreviewParams.width = layoutPreviewDim.x;
            layoutPreviewParams.height = layoutPreviewDim.y;
            layoutPreviewParams.addRule(RelativeLayout.CENTER_IN_PARENT);
            maLayoutPreview.setLayoutParams(layoutPreviewParams);
        }
        maLayoutPreview.addView(maPreview);
}

@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private Point getDisplayWH() {

    Display display = this.getWindowManager().getDefaultDisplay();
    Point displayWH = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(displayWH);
        return displayWH;
    }
    displayWH.set(display.getWidth(), display.getHeight());
    return displayWH;
}

private Point calcCamPrevDimensions(Point disDim, Camera.Size camDim) {

    Point displayDim = disDim;
    Camera.Size cameraDim = camDim;

    double widthRatio = (double) displayDim.x / cameraDim.width;
    double heightRatio = (double) displayDim.y / cameraDim.height;

    // use ">" to zoom preview full screen
    if (widthRatio < heightRatio) {
        Point calcDimensions = new Point();
        calcDimensions.x = displayDim.x;
        calcDimensions.y = (displayDim.x * cameraDim.height) / cameraDim.width;
        return calcDimensions;
    }
    // use "<" to zoom preview full screen
    if (widthRatio > heightRatio) { 
        Point calcDimensions = new Point();
        calcDimensions.x = (displayDim.y * cameraDim.width) / cameraDim.height;
        calcDimensions.y = displayDim.y;
        return calcDimensions;
    }
    return null;
}   
}

मेरी टिप्पणी:

यह सब का मुद्दा यह है कि यद्यपि आप गणना, है इष्टतम कैमरा आकार में getOptimalPreviewSize()आप केवल लेने निकटतम अनुपात अपनी स्क्रीन फिट करने के लिए। इसलिए जब तक कि अनुपात ठीक वैसा ही न हो , पूर्वावलोकन पूर्वावलोकन करेगा।

क्यों खिंचेगा? क्योंकि आपका फ्रेम -आउट कैमरा पूर्वावलोकन लेआउटXml में चौड़ाई और ऊंचाई में match_parent में सेट किया गया है । यही कारण है कि पूर्वावलोकन पूर्ण स्क्रीन तक फैल जाएगा।

चुने गए कैमरा आकार अनुपात से मिलान करने के लिए कैमरा पूर्वावलोकन लेआउट की चौड़ाई और ऊंचाई निर्धारित करने के लिए क्या करना चाहिए , इसलिए पूर्वावलोकन इसका पहलू अनुपात रखता है और विकृत नहीं करेगा।

मैंने CameraPreviewसभी गणनाओं और लेआउट परिवर्तनों को करने के लिए कक्षा का उपयोग करने की कोशिश की , लेकिन मैं इसका पता नहीं लगा सका। मैंने इस समाधान को लागू करने की कोशिश की , लेकिन SurfaceViewपहचान नहीं करता है getChildCount ()या getChildAt (int index)। मुझे लगता है, मैंने इसे अंततः एक संदर्भ के साथ काम कर लिया maLayoutPreview, लेकिन यह दुर्व्यवहार कर रहा था और मेरे पूरे ऐप पर सेट अनुपात लागू किया और पहली तस्वीर लेने के बाद ऐसा किया। इसलिए मैंने इसे जाने दिया और लेआउट संशोधनों को स्थानांतरित कर दिया MainActivity

में CameraPreviewमैं बदल गया prSupportedPreviewSizesऔर getOptimalPreviewSize()करने के लिए सार्वजनिक तो मैं में उपयोग कर सकते हैं MainActivity। तब मुझे डिस्प्ले आयामों की आवश्यकता थी (यदि एक है तो नेविगेशन / स्टेटस बार को घटा दें) और चुने हुए इष्टतम कैमरा आकार । मैंने प्रदर्शन आकार के बजाय RelativeLayout (या FrameLayout) आकार प्राप्त करने का प्रयास किया, लेकिन यह शून्य मान लौटा रहा था। यह समाधान मेरे काम नहीं आया। बाद में onWindowFocusChanged(लॉग में जाँच की गई) लेआउट का मान है ।

इसलिए मेरे पास चुने हुए कैमरा आकार के पहलू अनुपात से मेल खाने के लिए लेआउट आयामों की गणना करने के लिए मेरे तरीके हैं। अब आपको बस LayoutParamsअपना कैमरा प्रीव्यू लेआउट सेट करना होगा। चौड़ाई को बदलें, ऊँचाई और इसे माता-पिता में केन्द्रित करें।

पूर्वावलोकन आयामों की गणना करने के लिए दो विकल्प हैं। या तो आप इसे काली पट्टियों के साथ स्क्रीन पर फिट करना चाहते हैं (यदि विंडोबैकग्राउंड को शून्य पर सेट किया गया है) पक्षों या शीर्ष / तल पर। या आप चाहते हैं कि पूर्वावलोकन पूरी स्क्रीन पर ज़ूम इन हो । मैंने अधिक जानकारी के साथ टिप्पणी छोड़ दी calcCamPrevDimensions()


6

नमस्ते getOptimalPreview () यहाँ है कि मेरे लिए काम नहीं किया तो मैं अपना संस्करण साझा करना चाहते हैं:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    if (sizes==null) return null;

    Camera.Size optimalSize = null;
    double ratio = (double)h/w;
    double minDiff = Double.MAX_VALUE;
    double newDiff;
    for (Camera.Size size : sizes) {
        newDiff = Math.abs((double)size.width/size.height - ratio);
        if (newDiff < minDiff) {
            optimalSize = size;
            minDiff = newDiff;
        }
    }
    return optimalSize;
}

यह एक वर्ग कैमरे में परिवर्तित हो जाता है, यह देखते हुए (१०x10-१०१ after०) इनपुट है, चौड़ाई और ऊंचाई को अनुकूलित करने के बाद (१०x10 My१० testing testing), मेरा परीक्षण उपकरण सैमसंग एस ६ है। क्या मुझे पता है कि क्या कारण है। कृपया साझा करें यदि आपके पास इस मुद्दे के बारे में कोई विचार है।
मोहनराज एस

2

बस इस धागे को और अधिक पूरा करने के लिए मैं अपने उत्तर के संस्करण को जोड़ रहा हूँ:

मैं क्या हासिल करना चाहता था: सतह के दृश्य को बढ़ाया नहीं जाना चाहिए, और इसे पूरी स्क्रीन को कवर करना चाहिए, इसके अलावा, मेरे ऐप में केवल एक लैंडस्केप मोड था।

उपाय:

समाधान F1sher के समाधान के लिए एक बहुत छोटा विस्तार है:

=> पहला कदम F1sher के समाधान को एकीकृत करना है।

=> अब, F1sher के समाधान में एक परिदृश्य उत्पन्न हो सकता है जब सतह दृश्य पूरे स्क्रीन को कवर नहीं करता है, तो इसका समाधान सतह के दृश्य को स्क्रीन आयामों से अधिक बनाना है ताकि यह संपूर्ण स्क्रीन को कवर कर सके, इसके लिए:

    size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight);

    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setPreviewSize(size.width, size.height);


    mCamera.setParameters(parameters);      

    double screenRatio = (double) screenHeight / screenWidth;
    double previewRatio = (double) size.height / size.width;

    if (previewRatio > screenRatio)     /*if preview ratio is greater than screen ratio then we will have to recalculate the surface height while keeping the surface width equal to the screen width*/
    {
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(screenWidth, (int) (screenWidth * previewRatio));
        params1.addRule(RelativeLayout.CENTER_IN_PARENT);
        flPreview.setLayoutParams(params1);

        flPreview.setClipChildren(false);

        LayoutParams surfaceParams = new LayoutParams(screenWidth, (int) (screenWidth * previewRatio));
        surfaceParams.gravity = Gravity.CENTER;
        mPreview.setLayoutParams(surfaceParams);        
    }
    else     /*if preview ratio is smaller than screen ratio then we will have to recalculate the surface width while keeping the surface height equal to the screen height*/
    {
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams((int) ((double) screenHeight / previewRatio), screenHeight);
        params1.addRule(RelativeLayout.CENTER_IN_PARENT);
        flPreview.setLayoutParams(params1);
        flPreview.setClipChildren(false);

        LayoutParams surfaceParams = new LayoutParams((int) ((double) screenHeight / previewRatio), screenHeight);
        surfaceParams.gravity = Gravity.CENTER;
        mPreview.setLayoutParams(surfaceParams);

    }       

    flPreview.addView(mPreview); 

  /*  The TopMost layout used is the RelativeLayout, flPreview is the FrameLayout in which Surface View is added, mPreview is an instance of a class which extends SurfaceView  */

1

मुझे पता चला कि समस्या क्या है - यह अभिविन्यास परिवर्तनों के साथ है । यदि आप कैमरा अभिविन्यास को 90 या 270 डिग्री तक बदलते हैं तो आपको समर्थित आकारों की चौड़ाई और ऊंचाई स्वैप करने की आवश्यकता होती है और सभी ठीक हो जाएंगे।

सतह के दृश्य को एक फ्रेम लेआउट में झूठ होना चाहिए और केंद्र गुरुत्वाकर्षण होना चाहिए।

यहाँ C # (Xamarin) पर उदाहरण दिया गया है:

public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int width, int height)
{
    _camera.StopPreview();

    // find best supported preview size

    var parameters = _camera.GetParameters();
    var supportedSizes = parameters.SupportedPreviewSizes;
    var bestPreviewSize = supportedSizes
        .Select(x => new { Width = x.Height, Height = x.Width, Original = x }) // HACK swap height and width because of changed orientation to 90 degrees
        .OrderBy(x => Math.Pow(Math.Abs(x.Width - width), 3) + Math.Pow(Math.Abs(x.Height - height), 2))
        .First();

    if (height == bestPreviewSize.Height && width == bestPreviewSize.Width)
    {
        // start preview if best supported preview size equals current surface view size

        parameters.SetPreviewSize(bestPreviewSize.Original.Width, bestPreviewSize.Original.Height);
        _camera.SetParameters(parameters);
        _camera.StartPreview();
    }
    else
    {
        // if not than change surface view size to best supported (SurfaceChanged will be called once again)

        var layoutParameters = _surfaceView.LayoutParameters;
        layoutParameters.Width = bestPreviewSize.Width;
        layoutParameters.Height = bestPreviewSize.Height;
        _surfaceView.LayoutParameters = layoutParameters;
    }
}

ध्यान दें कि कैमरा मापदंडों को मूल आकार (स्वैप नहीं) के रूप में सेट किया जाना चाहिए, और सतह दृश्य आकार स्वैप किया जाना चाहिए।


1

मैं ऊपर सभी समाधान की कोशिश की, लेकिन उनमें से कोई भी मेरे लिए काम करता है। अंतिम रूप से मैंने इसे स्वयं हल किया, और पाया कि यह वास्तव में काफी आसान है। दो बिंदु हैं जिनसे आपको सावधान रहने की आवश्यकता है।

parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);

यह पूर्वावलोकन कैमरा समर्थित रिज़ॉल्यूशन में से एक होना चाहिए, जो नीचे दिया जा सकता है:

List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes(); 

आमतौर पर कच्चेसुपोर्टेडसाइज़ में से एक डिवाइस रिज़ॉल्यूशन के बराबर होता है।

दूसरा, अपने SurfaceView को एक फ्रेम -आउट में रखें और सतह लेआउट की ऊँचाई और चौड़ाई को सरचार्ज किए गए तरीके से ऊपर के रूप में सेट करें

FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) surfaceView.getLayoutParams();
layoutParams.height = cameraResolution.x;
layoutParams.width = cameraResolution.y;

ठीक है, काम किया, आशा है कि यह आपकी मदद कर सकता है।


0

मेरी आवश्यकताएं हैं कैमरे का पूर्वावलोकन फुलस्क्रीन होना चाहिए और पहलू अनुपात रखना चाहिए। हेसाम और योसुफ का समाधान बहुत अच्छा था लेकिन मुझे किसी कारण से उच्च ज़ूम की समस्या दिखाई देती है।

विचार समान है, माता-पिता में पूर्वावलोकन कंटेनर केंद्र है और चौड़ाई या ऊँचाई को पहलू अनुपात पर निर्भर करता है जब तक कि यह पूरे स्क्रीन को कवर नहीं कर सकता।

ध्यान देने वाली एक बात यह है कि पूर्वावलोकन आकार परिदृश्य में है क्योंकि हम डिस्प्ले ओरिएंटेशन सेट करते हैं।

camera.setDisplayOrientation (90);

वह कंटेनर जिसे हम भूतल दृश्य में जोड़ेंगे:

<RelativeLayout
    android:id="@+id/camera_preview_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"/>

अपनी गतिविधि में माता-पिता के केंद्र के साथ पूर्वावलोकन को इसके कंटेनर में जोड़ें।

this.cameraPreview = new CameraPreview(this, camera);
cameraPreviewContainer.removeAllViews();
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
cameraPreviewContainer.addView(cameraPreview, 0, params);

CameraPreview वर्ग के अंदर:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (holder.getSurface() == null) {
        // preview surface does not exist
        return;
    }

    stopPreview();

    // set preview size and make any resize, rotate or
    // reformatting changes here
    try {
        Camera.Size nativePictureSize = CameraUtils.getNativeCameraPictureSize(camera);
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(optimalSize.width, optimalSize.height);
        parameters.setPictureSize(nativePictureSize.width, nativePictureSize.height);
        camera.setParameters(parameters);
        camera.setDisplayOrientation(90);
        camera.setPreviewDisplay(holder);
        camera.startPreview();

    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    if (supportedPreviewSizes != null && optimalSize == null) {
        optimalSize = CameraUtils.getOptimalSize(supportedPreviewSizes, width, height);
        Log.i(TAG, "optimal size: " + optimalSize.width + "w, " + optimalSize.height + "h");
    }

    float previewRatio =  (float) optimalSize.height / (float) optimalSize.width;
    // previewRatio is height/width because camera preview size are in landscape.
    float measuredSizeRatio = (float) width / (float) height;

    if (previewRatio >= measuredSizeRatio) {
        measuredHeight = height;
        measuredWidth = (int) ((float)height * previewRatio);
    } else {
        measuredWidth = width;
        measuredHeight = (int) ((float)width / previewRatio);
    }
    Log.i(TAG, "Preview size: " + width + "w, " + height + "h");
    Log.i(TAG, "Preview size calculated: " + measuredWidth + "w, " + measuredHeight + "h");

    setMeasuredDimension(measuredWidth, measuredHeight);
}

-1

आपको cameraView.getLayoutParams () सेट करना होगा। ऊँचाई और cameraView.getLayoutParams ()। आपके द्वारा इच्छित पहलू अनुपात के अनुसार चौड़ाई।


यह मेरे कैमरे के दृश्य के पैरामीटर को इस तरह सेट करने से अलग है (जो मैं वर्तमान में कर रहा हूं): पैरामीटर ।setPreviewSize (imumSize.width, इष्टतमSize.height); mCamera.setParameters (पैरामीटर);
वैज्ञानिक

-2

मैंने गणनाएँ छोड़ दीं और बस उस दृश्य का आकार प्राप्त कर लिया, जहाँ मैं चाहता हूँ कि कैमरा पूर्वावलोकन प्रदर्शित हो और कैमरा का पूर्वावलोकन आकार समान हो (बस फ़्लिप के कारण फ़्लिप के कारण चौड़ाई / ऊँचाई फ़्लिप)।

@Override // CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    Display display = ((WindowManager) getContext().getSystemService(
            Context.WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        final Camera.Parameters params = camera.getParameters();
        // viewParams is from the view where the preview is displayed
        params.setPreviewSize(viewParams.height, viewParams.width);
        camera.setDisplayOrientation(90);
        requestLayout();
        camera.setParameters(params);
    }
    // I do not enable rotation, so this can otherwise stay as is
}

Android doc कहता है: पूर्वावलोकन आकार सेट करते समय, आपको getSupportedPreviewSizes () से मानों का उपयोग करना चाहिए। SetPreviewSize () विधि में मनमाना मान सेट न करें।
जी। स्टीगर्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.