كؤوس رؤية الشفق. واجهة برمجة تطبيقات Android Camera2 من برنامج Maker Part 5 Flash



نعيش في حقبة من الإنجازات والإنجازات التكنولوجية ، بالنظر إلى كيفية اندفاع صواريخ Mask و Bezos في السماء ، فنحن ، نحن الأشخاص العاديين الحاصلين على تعليم تقني عالٍ ، غالبًا لا نلاحظ إمكانية تحقيق اختراق ليس هناك ، بعيدًا في الفضاء ، ولكن هنا بجوارنا حرفياً لا تنهض من الأريكة من على الطاولة.

احكم بنفسك على الاكتشاف الذي يمكن أن يؤدي إلى قراءة مقال منتظم حول الهواتف الذكية الحديثة. لن أعطي المصدر ، حتى لا نتقاسم الدخل المستقبلي.
, , . « » Google Pixel. IT RAW, HDR-, «», . Pixel 4 «Night Sight» . : , . , .

شيء آخر هو أن المشي ليلًا والتنظيف على شاشة الهاتف المحمول غير مريح إلى حد ما ، حتى في الوضع الليلي. ثم سقطت عيني عن طريق الخطأ على سماعة رأس VR لهاتف ذكي ، مستلقية على الرف. لقد تحقق الاختراق! يبقى فقط ، باستخدامه والمعرفة المتراكمة على أربع منشورات حول Android Camera2 API ، لتوجيه الصورة من "Night Sight" مباشرة إلى العين. في نفس الوقت ، ستكون اليدين حرة في الإمساك بقط أسود في غرفة مظلمة. بدون ضوء ، بالطبع ، لن يعمل ، الفوتونات ، على الأقل قليلاً ، لكنه ضروري. لكن على الأقل يجب أن نصل (أو حتى نتفوق) على مستوى نظارة كوتان في الظلام.

لذلك ، لمعرفة كيفية الرؤية في الظلام ، نحتاج إلى:

1: سماعة رأس الواقع الافتراضي



لهاتف ذكي ، (أرخص هاتف ممكن) 2: هاتف ذكي يدعم guglofich الحديث للكاميرا (حسنًا ، بالتأكيد لن يكون أرخص)



3: معرفة أساسيات واجهة برمجة تطبيقات Android Camera2 (لدينا بالفعل)

الجزء الأول
الجزء الثاني
الجزء الثالث
الجزء الرابع

نحن نفتح مشروعًا جديدًا في Android Studio ونبدأ في نحت الرمز.

أول شيء يجب فعله هو تجميع سطح الواقع الافتراضي الفعلي الذي سوف يتألق في سماعة الرأس.

نسق
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#03061B"
    tools:context=".MainActivity">

    <TextureView
        android:id="@+id/textureView"
        android:layout_width="240dp"
        android:layout_height="320dp"
        android:layout_marginTop="28dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextureView
        android:id="@+id/textureView3"
        android:layout_width="240dp"
        android:layout_height="320dp"
        android:layout_marginTop="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textureView" />

    <LinearLayout
        android:layout_width="165dp"
        android:layout_height="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textureView3"
        app:layout_constraintVertical_bias="0.838">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="36dp"
            android:backgroundTint="#3F51B5"
            android:text=""
            android:textColor="#1A87DD" />

        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="37dp"
            android:backgroundTint="#3F51B5"
            android:text=""
            android:textColor="#2196F3" />
    </LinearLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

يجب أن يحتوي الإخراج على شيء مثل هذا:



كما ترون ، تبين أن القوام مستطيل ، بينما في أي لعبة VR لهاتف ذكي ، يتمكن المطورون بطريقة ما من جعلها مستديرة. لكننا لن نتطرق إلى هذا الأمر. سوف تظهر المزيد من الخبرة أنها ستفعل.

لهذا ، في الواقع ، نكتب نشاطًا متواضعًا ، حيث كل شيء مألوف لنا بالفعل من المقالات السابقة.

package com.example.twovideosurfaces;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.StrictMode;
import android.util.Log;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import java.util.Arrays;
public class MainActivity extends AppCompatActivity  {
    public static final String LOG_TAG = "myLogs";
    public static Surface surface1 = null;
    public static Surface surface2 = null;
    CameraService[] myCameras = null;
    private CameraManager mCameraManager = null;
    private final int CAMERA1 = 0;
    private Button mOn = null;
    private Button mOff = null;
    public static TextureView mImageViewUp = null;
    public static TextureView mImageViewDown = null;
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler = null;
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }
    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.activity_main);
        Log.d(LOG_TAG, " ");
        if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                ||
                (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
        ) {
            requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
        mOn = findViewById(R.id.button1);
        mOff = findViewById(R.id.button3);
        mImageViewUp = findViewById(R.id.textureView);
        mImageViewDown = findViewById(R.id.textureView3);
        mOn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myCameras[CAMERA1] != null) {//  
                    if (!myCameras[CAMERA1].isOpen()) myCameras[CAMERA1].openCamera();
                }
            }
        });
        mOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            //     
            myCameras = new CameraService[mCameraManager.getCameraIdList().length];
            for (String cameraID : mCameraManager.getCameraIdList()) {
                Log.i(LOG_TAG, "cameraID: " + cameraID);
                int id = Integer.parseInt(cameraID);
                //    
                myCameras[id] = new CameraService(mCameraManager, cameraID);
            }
        } catch (CameraAccessException e) {
            Log.e(LOG_TAG, e.getMessage());
            e.printStackTrace();
        }
    }
    public class CameraService {
        private String mCameraID;
        private CameraDevice mCameraDevice = null;
        private CameraCaptureSession mSession;
        private CaptureRequest.Builder mPreviewBuilder;
        public CameraService(CameraManager cameraManager, String cameraID) {
            mCameraManager = cameraManager;
            mCameraID = cameraID;
        }
        private CameraDevice.StateCallback mCameraCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice camera) {
                mCameraDevice = camera;
                Log.i(LOG_TAG, "Open camera  with id:" + mCameraDevice.getId());
                startCameraPreviewSession();
            }
            @Override
            public void onDisconnected(CameraDevice camera) {
                mCameraDevice.close();
                Log.i(LOG_TAG, "disconnect camera  with id:" + mCameraDevice.getId());
                mCameraDevice = null;
            }
            @Override
            public void onError(CameraDevice camera, int error) {
                Log.i(LOG_TAG, "error! camera id:" + camera.getId() + " error:" + error);
            }
        };
        private void startCameraPreviewSession() {
            SurfaceTexture texture = mImageViewUp.getSurfaceTexture();
            texture.setDefaultBufferSize(1280, 1024);
            surface1 = new Surface(texture);
            SurfaceTexture texture2 = mImageViewDown.getSurfaceTexture();
            surface2 = new Surface(texture2);
            texture2.setDefaultBufferSize(1280, 1024);
            try {
                mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                mPreviewBuilder.addTarget(surface1);
                mPreviewBuilder.addTarget(surface2);
                mCameraDevice.createCaptureSession(Arrays.asList(surface1,surface2),
                        new CameraCaptureSession.StateCallback() {
                            @Override
                            public void onConfigured(CameraCaptureSession session) {
                                mSession = session;

                                try {
                                    mSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
                                } catch (CameraAccessException e) {
                                    e.printStackTrace();
                                }
                            }
                            @Override
                            public void onConfigureFailed(CameraCaptureSession session) {
                            }
                        }, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
        public boolean isOpen() {
            if (mCameraDevice == null) {
                return false;
            } else {
                return true;
            }
        }
        public void openCamera() {
            try {
                if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                    mCameraManager.openCamera(mCameraID, mCameraCallback, mBackgroundHandler);
                }
            } catch (CameraAccessException e) {
                Log.i(LOG_TAG, e.getMessage());
            }
        }
        public void closeCamera() {
            if (mCameraDevice != null) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
        }
    }
    @Override
    public void onPause() {
        if (myCameras[CAMERA1].isOpen()) {
            myCameras[CAMERA1].closeCamera();
        }
        stopBackgroundThread();
        super.onPause();
    }
    @Override
    public void onResume() {
        super.onResume();
        startBackgroundThread();
    }
}

نعم ، ولا تنسى

البيان
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.twovideosurfaces">
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.NoActionBar"
        >
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


الآن ندفع الهاتف الذكي إلى سماعة الرأس VR ونتجول في المنزل ، مستمتعين برؤية السايبورج مع دقة تبلغ 1280 × 1024 لكل عين. الأحاسيس ، بالطبع ، غريبة ، مع فقدان عمق الرؤية ، لكنها لا تزال باردة. الشيء الوحيد هو أنها تبدو مظلمة قليلاً ، ولكن هذا بسبب تداخل لوحة سماعة الرأس الشفافة الأمامية. لذلك ، من الضروري عمل فتحة أمام كاميرا الهاتف الذكي. ولكن مرة أخرى ، في معظم نماذج الواقع الافتراضي ذات الميزانية ، قد لا تكون هذه اللوحة موجودة على الإطلاق ، ومن المحتمل أنك لن تضطر إلى دحر نفسك بالعمل اليدوي.

كل ما تبقى الآن هو إقناع واجهة برمجة تطبيقات كاميرا Google بأن لدينا ظلمة كاملة ، وسيكون من الرائع استخدام وضع الرؤية الليلية ، ومع كل هذه RAW ، و HDR-stacking والتعرف على المشهد من خلال الشبكات العصبية .

للقيام بذلك ، فقط اكتب في الجلسة:

mPreviewBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
                                            CaptureRequest.CONTROL_SCENE_MODE_NIGHT);


وفك التعرض والحساسية الضوئية إلى أقصى حد

 mPreviewBuilder.set(CaptureRequest.CONTROL_AE_MODE,
        CaptureRequest.CONTROL_AE_MODE_OFF);
mPreviewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME,Long.valueOf("100000000"));
 mPreviewBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 30000);


أوه ، أنا أعمى!



هذا ما اتضح أن القطة تراه عندما يتم طرده من غرفة النوم ، حيث يمنع الناس من ممارسة الجنس في غرفة المعيشة.

ولكن بالطبع ، هذا تعداد ومعلمات (وهناك الكثير منها في واجهة برمجة التطبيقات ، وهنا فقط زوجين) تحتاج إلى تعديله لاحقًا تجريبيًا.

الآن يمكننا فقط انتظار الليل. ليس بلا قمر ، بالطبع ، مع غطاء سحابي كثيف في مكان ما في التايغا ، لكن ليلة عادية مع فوتونات طيران عشوائية. وإليك ما سيحدث ... على

الرغم من أنه يبدو أنه مع التصوير العادي ، لا يوجد شيء مرئي تقريبًا.



لكن الكاميرات الحديثة تعمل العجائب ولا تزال تجد قطة سوداء ...



الآن يمكنك المشي ليلا ، لأنه خلال النهار لا يمكنك بسبب الحجر الصحي. من الناحية النظرية ، من المستحيل أيضًا في الليل ، ولكن من سيراك ، يطارد في ظلام الليل مع سماعات VR على رؤوسهم ...

All Articles