অ্যান্ড্রয়েড ক্যামেরা পূর্বরূপ প্রসারিত


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();
        }

    }

এখানে চিত্র বর্ণনা লিখুন

আপনি দেখতে পারেন যে ফোনটি ঘোরার সময় লেগো লোকটি লম্বা এবং ত্বকযুক্ত হয়:

আমি কীভাবে নিশ্চিত করতে পারি যে আমার ক্যামেরা দেখার জন্য দিক অনুপাতটি সঠিক?


@ বৈজ্ঞানিক আপনি কি আমাকে সাহায্য করতে পারেন যেখানে আমি একই পদ্ধতির মুখোমুখি দেওয়া পদ্ধতিটি কোথায় লিখব?
ব্যবহারকারী3233280

আমি একই রকম সমস্যা পেয়েছি বলে মনে হয়েছিল, তবে কীটি ঠিক করেছে এটি নিম্নলিখিতটিকে কল করে: mCamera.setDisplayOrientation (90) ক্যামেরাটির জন্য আমার সারফেসভিউয়ের পৃষ্ঠায় তৈরি () পদ্ধতিতে
গ্রেগ

উত্তর:


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;
    }

আপনি দেখতে পাচ্ছেন আপনার স্ক্রিনের প্রস্থ এবং উচ্চতা আপনাকে ইনপুট করতে হবে। এই পদ্ধতিটি সেই মানগুলির উপর নির্ভর করে স্ক্রিন রেশিও গণনা করবে এবং তারপরে সমর্থিতপ্রিভিউ আকারের তালিকা থেকে এটি উপলব্ধযোগ্যগুলির থেকে আপনার পক্ষে সেরাটি চয়ন করবে। যেখানে আপনার ক্যামেরা অবজেক্টটি নাল নয় সেখানে আপনার সমর্থিত পূর্বরূপের আকার তালিকাটি পান

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 টি পৃথক গণিত অনুপাত ব্যবহার করছেন: ডাবল টার্গেটরেটিও = (ডাবল) এইচ / ডাব্লু এবং ডাবল অনুপাত = (দ্বিগুণ) আকার.উইথ / আকারউচ্চতা । প্রথমটি হ'ল উচ্চতা প্রস্থ দ্বারা বিভক্ত এবং অন্যটি বিপরীত, প্রস্থটি দৈর্ঘ্য দ্বারা বিভক্ত। তাদের কি একই গণনা হওয়া উচিত নয়?
ফিজালিস

মাপের তালিকাটি প্রতিটি সম্ভাবনা বিবেচনার জন্য বিবেচনা করে না কারণ: আপনি 480x680 এর মতো কিছু পাবেন তবে শীঘ্রই বা পরে 680x480 (ল্যান্ডস্কেপের জন্য) পাওয়া যাবে, সুতরাং আপনাকে কেবল সেই তালিকাটি পেরিয়ে যেতে হবে এবং একটি খুঁজে পেতে হবে আপনার প্রয়োজন মেলে। আপনি তাড়াতাড়ি বা পরে এটি পাবেন।
F1sher

তদ্ব্যতীত, আপনি যদি নিজের ছবিগুলিও এই আকারের হতে চান (সেগুলি সম্ভবত হওয়া উচিত) তবে আপনি ছবির আকারটি সেট করেছেন parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
ম্যাট লোগান

2
@ এফ 1 শের, আমি সর্বদা নাল পয়েন্টার ব্যতিক্রম প্যারামিটারগুলি পাই set কোনও সমাধান খুঁজে পাচ্ছি না।
FIXI

3
@ ফাইজালিস আমি আপনার সাথে একমত আসলে, কোডটি প্রত্যাশা অনুযায়ী কাজ করার জন্য আমাকে সেই সংশোধন করতে হয়েছিল।
ফার্নিও

149

F1Sher এর সমাধানটি দুর্দান্ত তবে কখনও কখনও কাজ করে না। বিশেষত, যখন আপনার সারফেসভিউ পুরো স্ক্রিনটি কভার করে না। এই ক্ষেত্রে আপনাকে onMeasure () পদ্ধতিটি ওভাররাইড করতে হবে। আমি আপনার রেফারেন্সের জন্য আমার কোড এখানে অনুলিপি করেছি।

যেহেতু আমি প্রস্থের ভিত্তিতে সারফেসভিউ পরিমাপ করেছি তখন আমার স্ক্রিনের শেষে আমার কাছে সাদা ডিজাইন খুব কম যে আমি এটি নকশায় পূরণ করেছি it আপনি যদি উচ্চতা বজায় রাখেন এবং অনুপাতকে গুণিত করে প্রস্থ বৃদ্ধি করেন তবে আপনি এই সমস্যাটি সমাধান করতে সক্ষম হবেন। তবে এটি পৃষ্ঠতলে কিছুটা স্কোয়াশ করবে।

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
Houcine

1
যখন আমি আমার ক্রিয়াকলাপের অ্যাপ্লিকেশনটি বন্ধ করেছিলাম <com.app.camera.CameraPreview android: id = "@ + id / ਕੈਮਰਾ_প্রিভিউ" অ্যান্ড্রয়েড: লেআউট_উইথ = "ম্যাচ_পিতা" অ্যান্ড্রয়েড: বিন্যাস_উত্তর = "ম্যাচ_প্যারেন্ট" />
ফিশ 40

যদিও আপনাকে কিছু পরিবর্তন করতে হবে তবে আমি এটি সমাধান হিসাবে গ্রহণ করি। আপ-ভোট দিয়েছে।
জয়দীপডাব্লু

2
হাই @ adnan9011, এই টিউটোরিয়ালটি সম্ভবত সহায়ক হতে পারে। airpair.com/android/android-camera-surface-view-fragment
Hesam

4
getOptimalPreviewSizeআমার পক্ষে কাজ করার জন্য উচ্চতা এবং প্রস্থের স্যুইচ করা দরকার । এটি কি কারণ ডিসপ্লে ওরিয়েন্টেশনটি 90 এ সেট করা হয়েছিল? অন্যথায়, অনুপাত হিসাব না এমনকি বন্ধ (টার্গেট 1.7 ছিল এবং ক্যামেরা অনুপাত 1 কম ছিল) ছিল
Ono

23

দ্রষ্টব্য: আমার সমাধান হিশামের সমাধানের একটি ধারা: https://stackoverflow.com/a/22758359/1718734

আমি যা সম্বোধন করছি: হেসাম বলেছেন যে এখানে কিছুটা সাদা জায়গা রয়েছে যা কিছু ফোনে প্রদর্শিত হতে পারে:

দ্রষ্টব্য: দিক অনুপাতটি সঠিক হলেও ক্যামেরা পুরো স্ক্রিনে পূরণ করে না।

হেসাম দ্বিতীয় সমাধানের পরামর্শ দিয়েছিলেন, তবে এটি পূর্বরূপটিকে স্কুই করে। এবং কিছু ডিভাইসে এটি প্রচুর পরিমাণে বিকৃত হয়।

সুতরাং আমরা এই সমস্যাটি কীভাবে সমাধান করব। এটি সরল ... স্ক্রিনে ভরাট না হওয়া পর্যন্ত দিক অনুপাতকে গুণ করে। আমি লক্ষ্য করেছি, বেশ কয়েকটি জনপ্রিয় অ্যাপ্লিকেশন যেমন স্ন্যাপচ্যাট, হোয়াটসঅ্যাপ ইত্যাদি একইভাবে কাজ করে।

আপনাকে যা করতে হবে তা হ'ল onMeasure পদ্ধতিতে এটি যুক্ত করুন:

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);
    }

এটি স্ক্রিনের উচ্চতা গণনা করবে এবং স্ক্রিনের উচ্চতা এবং এমপ্রিভিউসাইজ উচ্চতার অনুপাত পাবে। তারপরে এটি ক্যামেরার প্রস্থ এবং উচ্চতাটিকে নতুন উচ্চতার অনুপাত এবং সেই অনুযায়ী সেট করা মাপের মাত্রা দ্বারা গুন করে।

এখানে চিত্র বর্ণনা লিখুন

এবং পরবর্তী জিনিস আপনি জানেন, আপনি এটি দিয়ে শেষ: ডি

এখানে চিত্র বর্ণনা লিখুন

এটি সামনের ক্যামেরায়ও ভাল কাজ করে। আমি বিশ্বাস করি এটি এই সম্পর্কে ভাল উপায়। আমার অ্যাপ্লিকেশনটির কাছে এখন কেবলমাত্র "ক্যাপচার" এ ক্লিক করে পূর্বরূপ সংরক্ষণ করা। তবে হ্যাঁ, এই


এটি খুব ভাল কাজ করে !! তবে এটি ল্যান্ডস্কেপে সঠিকভাবে কাজ করে না: /
মাতান দহন

আপনার কোডটি আমার 2 মাসের খালি কালো জায়গার সমস্যার সমাধান করেছে :)
কার্তিক কোলনজি

1
এটি কাজ করে, তবে আমার ক্ষেত্রে .. আমার উপরে উপরে অ্যাকশনবার রয়েছে যাতে সাদা বারটি আরও ছোট ছিল তবে আপনার কোডটি যুক্ত করার পরে আমার ক্যামেরাটি 40-50% জুমযুক্ত দেখাবে। সামনের সামনের ক্যামেরায় স্যুইচ করার সময় আমি মূলত আমার মুখটি সোজা দেখতে পাচ্ছি না (কেবলমাত্র কিছুটা চুল), কারণ এটি উচ্চ জুম।
মাকালেলে

@ ইউসুফ আপনার কোডটি অনুসরণ করার পরে আমি সাদা পর্দা পাচ্ছি। ইন onMeasure(int widthMeasureSpec, int heightMeasureSpec)পদ্ধতি আমি সবসময় পেতে প্রস্থ = 0 এবং উচ্চতা = 0;
কুশ প্যাটেল

10

ঠিক আছে, তাই আমি মনে করি সাধারণ ক্যামেরা প্রিভিউ প্রসারিত সমস্যার জন্য পর্যাপ্ত উত্তর নেই । বা কমপক্ষে আমি একটিও পাইনি। আমার অ্যাপ্লিকেশনটিও এই স্ট্রেচিং সিনড্রোমের ক্ষতি করেছে এবং এই পোর্টাল এবং ইন্টারনেটের সমস্ত ব্যবহারকারীর উত্তরগুলির একসাথে সমাধান পেতে আমার কিছুটা সময় নিয়েছিল।

আমি @ হেসামের সমাধানটি চেষ্টা করেছি কিন্তু এটি কার্যকর হয়নি এবং আমার ক্যামেরার পূর্বরূপটি মূলত বিকৃত করে ফেলেছে।

প্রথমে আমি আমার সমাধানের কোডটি দেখি (কোডটির গুরুত্বপূর্ণ অংশগুলি) এবং তারপরে আমি কেন এই পদক্ষেপ নিয়েছি তা ব্যাখ্যা করি। কর্মক্ষমতা পরিবর্তনের জন্য জায়গা আছে।

প্রধান ক্রিয়াকলাপ এক্সএমএল লেআউট:

<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()আপনি শুধুমাত্র বাছাই নিকটতম অনুপাত আপনার পর্দা মাপসই। সুতরাং অনুপাতটি ঠিক একইরূপে না হলে পূর্বরূপটি প্রসারিত হবে।

কেন এটি প্রসারিত হবে? আপনার FrameLayout ক্যামেরা প্রিভিউ সেট করা হয় কারণ layout.xml করার match_parent প্রস্থ ও উচ্চতা হবে। এজন্য পূর্বরূপ পুরো পর্দায় প্রসারিত হবে।

যা করা দরকার তা হল নির্বাচিত ক্যামেরার আকারের অনুপাতের সাথে মেলে ক্যামেরার পূর্বরূপ বিন্যাসের প্রস্থ এবং উচ্চতা নির্ধারণ করা , যাতে পূর্বরূপটি তার অনুপাতের অনুপাত রাখে এবং বিকৃত করে না।

আমি CameraPreviewসমস্ত গণনা এবং লেআউট পরিবর্তনগুলি করার জন্য ক্লাসটি ব্যবহার করার চেষ্টা করেছি , তবে আমি এটি বের করতে পারি না। আমি এই সমাধানটি প্রয়োগ করার চেষ্টা করেছি , কিন্তু SurfaceViewচিনতে পারি না getChildCount ()বা করি না getChildAt (int index)। আমি মনে করি, শেষ পর্যন্ত একটি রেফারেন্স সহ এটি কাজ করেছিলাম maLayoutPreview, তবে এটি ছিল খারাপ আচরণ এবং সেটটিকে আমার সম্পূর্ণ অ্যাপ্লিকেশনে প্রয়োগ করে এবং প্রথম ছবি তোলার পরে এটি হয়েছিল। সুতরাং আমি এটি যেতে দিয়েছিলাম এবং লেআউট পরিবর্তনগুলিতে সরানো হয়েছে MainActivity

ইন CameraPreviewআমি পরিবর্তন prSupportedPreviewSizesএবং getOptimalPreviewSize()করতে প্রকাশ্য তাই আমি এটা ব্যবহার করতে পারেন MainActivity। তারপরে আমার প্রদর্শনের মাত্রা প্রয়োজন (মাইনাস নেভিগেশন / স্ট্যাটাস বার যদি থাকে তবে) এবং সর্বোত্তম ক্যামেরার আকার বেছে নেওয়া উচিত । আমি ডিসপ্লে আকারের পরিবর্তে রিলেটিভলআউট (বা ফ্রেমলআউট) আকার পাওয়ার চেষ্টা করেছি, তবে এটি শূন্যের মান ফিরে আসছিল। এই সমাধানটি আমার পক্ষে কার্যকর হয়নি। বিন্যাসটির পরে এর মান পেল onWindowFocusChanged(লগ ইন চেক করা)।

সুতরাং নির্বাচিত ক্যামেরার আকারের অনুপাতের সাথে মেলে লেআউটটির মাত্রা গণনা করার জন্য আমার কাছে আমার পদ্ধতি রয়েছে। এখন আপনাকে কেবল LayoutParamsআপনার ক্যামেরা প্রিভিউ লেআউট সেট করতে হবে । প্রস্থ, উচ্চতা পরিবর্তন করুন এবং এটি প্যারেন্টে কেন্দ্র করুন।

প্রাকদর্শন মাত্রা গণনা করার জন্য দুটি পছন্দ রয়েছে are হয় আপনি এটিকে পাশের বা উপরে / নীচে কালো বারগুলি (যদি উইন্ডোব্যাকগ্রাউন্ডটি নালায় সেট করা থাকে) দিয়ে পর্দা ফিট করতে চান । অথবা আপনি পূর্বদর্শনটি পুরো স্ক্রিনে জুম করাতে চান । আমি আরও তথ্য মন্তব্য মন্তব্য 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;
}

এটি একটি স্কোয়ার ক্যামেরায় রূপান্তরিত হয়, প্রদত্ত ইনপুটটি (1920x1080) প্রস্থ এবং উচ্চতা প্রদত্ত (1088x1088) অনুকূলকরণের পরে (1088x1088), আমার পরীক্ষার ডিভাইসটি স্যামসাং এস 6। আমি কি কারণ জানতে পারি। এই সমস্যাটি সম্পর্কে আপনার কোনও ধারণা থাকলে দয়া করে ভাগ করুন।
মোহনরাজ এস

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 ডিগ্রি পরিবর্তন করেন তবে সব ঠিক হয়ে যাবে।

এছাড়াও পৃষ্ঠের দৃশ্য একটি ফ্রেমের বিন্যাসে থাকা উচিত এবং কেন্দ্রের মাধ্যাকর্ষণ থাকতে হবে।

এখানে সি # (জামারিন) এর উদাহরণ রয়েছে:

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(); 

সাধারণত কাঁচা সাপোর্টড সাইজের একটি ডিভাইস রেজোলিউশনের সমান।

দ্বিতীয়ত, আপনার সারফেসভিউটিকে ফ্রেমলআউটতে রাখুন এবং উপরের মত পৃষ্ঠের বিন্যাসের উচ্চতা এবং প্রস্থ সেট করুন

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

ঠিক আছে, কাজগুলি শেষ হয়েছে, আশা করি এটি আপনাকে সহায়তা করতে পারে।


0

আমার প্রয়োজনীয়তা হ'ল ক্যামেরার পূর্বরূপটি পূর্ণস্ক্রিন হওয়া এবং দিক অনুপাত রাখা উচিত। হেসাম এবং ইউসুফের সমাধানটি দুর্দান্ত ছিল তবে আমি কোনও কারণে উচ্চতর জুম সমস্যা দেখতে পাচ্ছি।

ধারণাটি একই, প্যারেন্টে পূর্বরূপ ধারক কেন্দ্র রাখুন এবং পুরো স্ক্রিনটি coverাকা না আসা পর্যন্ত দিক অনুপাতের উপর নির্ভর করে প্রস্থ বা উচ্চতা বৃদ্ধি করুন।

একটি বিষয় লক্ষণীয় যা পূর্বরূপের আকার ল্যান্ডস্কেপে রয়েছে কারণ আমরা প্রদর্শন ওরিয়েন্টেশনটি সেট করি।

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);

ক্যামেরাপ্রিভিউ শ্রেণীর ভিতরে:

@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

আপনি যে দিকটি চান তার অনুপাত অনুসারে আপনাকে অবশ্যই ক্যামেরাভিউ.গেটলয়েটপ্যারামস () উচ্চতা এবং ক্যামেরাভিউ.সেটলয়েটপ্যারাম ()। প্রস্থ সেট করতে হবে।


আমার ক্যামেরা ভিউর প্যারামিটারটি এইভাবে সেট করার চেয়ে আলাদা (যা আমি বর্তমানে করছি): পরামিতি.সেটপ্রিভিউসাইজ (অপটিমাল সাইজ.উইউথ, অপ্টিমালসাইজ.হাইট); 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
}

অ্যান্ড্রয়েড ডক বলেছেন: পূর্বরূপ আকার নির্ধারণ করার সময়, আপনাকে getSupportedPreviewSizes () থেকে মানগুলি ব্যবহার করতে হবে। সেটপ্রিভিউসাইজ () পদ্ধতিতে স্বেচ্ছাচারিত মান সেট করবেন না।
জি স্টিগার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.