Unity Android Cihaz Kamerasıyla Resim/Video Çekmek

Yayınlandı: 04 Haziran 2018 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

Merhabalar,

Bu Unity dersinde, Android ve iOS platformlarda cihazın kamerasını kullanarak resim çekmeyi veya video kaydetmeyi göreceğiz.

O halde hadi başlayalım!

Kurulum

İlk önce şu adresteki NativeCamera.unitypackage‘ı Assets-Import Package yoluyla projenize import edin:  https://github.com/yasirkula/UnityNativeCamera/releases

Alternatif olarak, asset’i Asset Store’dan da import edebilirsiniz: https://assetstore.unity.com/packages/tools/integration/native-camera-for-android-ios-117802

Eğer iOS’a build alacaksanız, Plugins/NativeCamera/Editor/NCPostProcessBuild.cs scriptindeki CAMERA_USAGE_DESCRIPTION‘ın değerini dilerseniz değiştirin. Buraya girdiğiniz yazı, kameraya erişim izni isterken gözükecek. Android’e build alacaksanız özel bir şey yapmanız gerekmiyor.

Fonksiyonlar

A) Kameranın Durumunu Kontrol Etmek

  • NativeCamera.DeviceHasCamera()

Cihazın kamerası olup olmadığını döndürür. Bazı telefonlarda kamera olmadığı için, bu fonksiyon o cihazlarda false döndürür.

  • NativeCamera.IsCameraBusy()

Kameranın meşgul olup olmadığını döndürür. Eğer kamera meşgulse (true), o an kameraya erişmek mümkün değildir.

B) Resim Çekmek

  • NativeCamera.TakePicture( CameraCallback callback, int maxSize = -1, PreferredCamera preferredCamera = PreferredCamera.Default )

callback: Kullanıcı kamera ile bir resim çekince veya işlemi iptal edince bu fonksiyon çağrılır. Buraya vereceğiniz fonksiyon bir string parametre almak zorundadır. Eğer işlem iptal edildiyse bu parametrenin değeri null olurken aksi taktirde, çekilen resim dosyasının konumu bu string’de depolanır.

maxSize: Eğer resmin genişliği veya yüksekliği bu değerden büyük olursa, resmin bu boyuta küçültülmüş bir versiyonu döndürülür. Varsayılan olarak bir büyüklük limiti yoktur ancak resim ne kadar büyük olursa hafızada o kadar çok yer kaplayacağı için bu parametreye 512, 1024 vs. gibi işinizi görmeye yetecek bir değer vermeniz şiddetle önerilir.

preferredCamera: Varsayılan olarak arka kamera mı yoksa ön kamera mı açılsın belirlemeye yarar. Ancak Android’de her cihaz bu değişkeni desteklemediğinden bazı Android cihazlarında bir etkisi olmayabilir.

C) Video Kaydetmek

  • NativeCamera.RecordVideo( CameraCallback callback, Quality quality = Quality.Default, int maxDuration = 0, long maxSizeBytes = 0L, PreferredCamera preferredCamera = PreferredCamera.Default )

quality: Çekilen videonun kalitesini belirler. Değeri Default (varsayılan), Low, Medium veya High olabilir.

maxDuration: Çekilen videoya saniye cinsinden bir süre limiti koyar. Bu süre bitiminde video çekimi hâlâ devam ediyorsa, video otomatik olarak durdurulur. Varsayılan olarak bir süre limiti yoktur. Yalnız bu parametrenin doğru çalışabilmesi için, cihazın üreticisinin kamera yazılımına bu işlevselliği eklemiş olması gerekmektedir; yani bu parametre bazı cihazlarda bir işe yaramayabilir.

maxSizeBytes: Çekilen videoya byte cinsinden bir boyut limiti koyar. Video bu boyutu aşarsa, çekim otomatik olarak durdurulur. Varsayılan olarak bir boyut limiti yoktur. Bu parametrenin iOS’ta bir etkisi yoktur. Ayrıca bu parametrenin doğru çalışabilmesi için, cihazın üreticisinin kamera yazılımına bu işlevselliği eklemiş olması gerekmektedir; yani bu parametre bazı cihazlarda bir işe yaramayabilir.

D) Çalışma Zamanı İzinleri (Runtime Permissions) Hakkında

Android 6.0 sürümü itibariyle artık önemli bir Android fonksiyonuna erişmeden önce, çalışma zamanında bu fonksiyona erişim izni istemek zorundayız. NativeCamera fonksiyonları çalışmadan önce otomatik olarak izin isterler ancak dilerseniz kendi başınıza da izinlerin mevcut durumunu sorgulayabilir veya izin isteyebilirsiniz.

  • NativeCamera.CheckPermission()

İzinlerin durumunu sorgular ve bir NativeCamera.Permission enum‘u döndürür. Eğer kameraya erişim iznimiz varsa bu enum’un değeri Permission.Granted olurken eğer henüz iznimiz yoksa Permission.ShouldAsk olur. Eğer kullanıcı karşısına gelen izin ekranını “Bir daha sorma” seçili bir şekilde reddederse veya kullanıcının cihazında aktif olan bir ebeveyn kontrol sistemi bu iznin verilmesini engelliyorsa, Permission.Denied döndürülür. Bu durumda kullanıcı izni cihazın ayarlar menüsünden elle vermek zorundadır. Böyle bir durumla baş başa kalırsanız, kullanıcıya ayarlar menüsünden izin vermesini söyleyen bir uyarı penceresi göstermenizi öneririm.

  • NativeCamera.RequestPermission()

Kameraya erişim izni ister ve sonucu bir NativeCamera.Permission enum’unda döndürür. Resim/video çekmeye yarayan NativeCamera fonksiyonları bu fonksiyonu otomatik olarak çağırıp sonucu döndürürler.

E) Çekilen Resim Dosyasını Texture’a Çevirmek

  • NativeCamera.LoadImageAtPath( string imagePath, int maxSize = -1, bool markTextureNonReadable = true, bool generateMipmaps = true, bool linearColorSpace = false )

Bu fonksiyon vasıtasıyla bir resim dosyasını hızlıca bir Texture2D objesine çevirebilirsiniz.

imagePath: Texture2D olmasını istediğiniz resim dosyasının konumunu buraya girmelisiniz.

maxSize: Eğer resmin genişliği veya yüksekliği bu değerden büyük olursa, resmin bu boyuta küçültülmüş bir versiyonu döndürülür. Varsayılan olarak bir büyüklük limiti yoktur ancak resim ne kadar büyük olursa hafızada o kadar çok yer kaplayacağı için bu parametreye 512, 1024 vs. gibi işinizi görmeye yetecek bir değer vermeniz şiddetle önerilir.

markTextureNonReadable: Texture2D objesinin RAM’deki kopyasını silerek hafızayı rahatlatır. Bunun dezavantajı, artık resmin piksellerine elle erişemezsiniz; yani eğer GetPixel veya SetPixel fonksiyonlarını kullanıyorsanız bu parametreyi false yapın.

generateMipmaps: Texture’un mipmap’lerinin olup olmayacağını belirler.

linearColorSpace: Texture’un linear renk uzayını mı yoksa gamma renk uzayını mı (varsayılan) kullanacağını belirler.

Örnek Kod

Aşağıdaki örnek kodun iki işlevi bulunmaktadır:

  • ekranın sol yarısına tıklarsanız, kamera ile resim çekmeniz istenir ve çekilen resim geçici bir küp objesine texture olarak verilir
  • ekranın sağ yarısına tıklarsanız, kamera ile video kaydetmeniz istenir ve bu kaydedilen video daha sonra oynatılır
void Update()
{
	if( Input.GetMouseButtonDown( 0 ) )
	{
		// Eğer kamera meşgulse bir şey yapma
		if( NativeCamera.IsCameraBusy() )
			return;

		if( Input.mousePosition.x < Screen.width / 2 )
		{
			// Kamera ile resim çek
			// Eğer resmin genişliği veya yüksekliği 512 pikselden büyükse, resmi ufalt
			ResimCek( 512 );
		}
		else
		{
			// Kamera ile video kaydet
			VideoKaydet();
		}
	}
}

private void ResimCek( int maksimumBuyukluk )
{
	NativeCamera.Permission izin = NativeCamera.TakePicture( ( konum ) =>
	{
		Debug.Log( "Çekilen resmin konumu: " + konum );
		if( konum != null )
		{
			// Çekilen resmi bir Texture2D'ye çevir
			Texture2D texture = NativeCamera.LoadImageAtPath( konum, maksimumBuyukluk );
			if( texture == null )
			{
				Debug.Log( konum + " konumundaki resimden bir texture oluşturulamadı." );
				return;
			}

			// Texture'u geçici bir küp objesine ver
			GameObject kup = GameObject.CreatePrimitive( PrimitiveType.Cube );
			kup.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 5f;
			kup.transform.forward = -Camera.main.transform.forward;
			kup.transform.localScale = new Vector3( 1f, texture.height / (float) texture.width, 1f );

			Material material = kup.GetComponent<Renderer>().material;
			if( !material.shader.isSupported ) // eğer Standard shader desteklenmiyorsa Diffuse shader'ı kullan
				material.shader = Shader.Find( "Legacy Shaders/Diffuse" );

			material.mainTexture = texture;

			// 5 saniye sonra küp objesini yok et
			Destroy( kup, 5f );

			// Küp objesi ile birlikte Texture2D objesini de yok et
			// Eğer prosedürel bir objeyi (Texture2D) işiniz bitince yok etmezseniz,
			// mevcut scene'i değiştirene kadar obje hafızada kalmaya devam eder
			Destroy( texture, 5f );
		}
	}, maksimumBuyukluk );

	Debug.Log( "İzin durumu: " + izin );
}

private void VideoKaydet()
{
	NativeCamera.Permission izin = NativeCamera.RecordVideo( ( konum ) =>
	{
		Debug.Log( "Kaydedilen videonun konumu: " + konum );
		if( konum != null )
		{
			// Videoyu oynat
			Handheld.PlayFullScreenMovie( "file://" + konum );
		}
	} );

	Debug.Log( "İzin durumu: " + izin );
}

Böylece bu dersi de noktalamış olduk. Bir sonraki derste görüşmek dileğiyle!

yorum
  1. huseyin kulu dedi ki:

    boyutlandırmayı fotografın veya videonun pixelie göre yapıyorum pc de bulunan resimleri pixel i örnek veriyorum 1024*2048 bu dik bir resim oluyor normalde bunu aktardıgımda sorunsuz boyutlandırıyorum fakat telefondan cekilmiş bir resim oldugunda telefonda dik bir resmi 2048*1024 olarak kaydediyor yani yan olarak aktarma yapınca yan duruyor aynı durum tam tersi icinde gecerli bunun yötemi nedir sizce

    • yasirkula dedi ki:

      Resmi NativeCamera.LoadImageAtPath ile Texture’a yüklemeniz lazım, siz de öyle yapıyorsunuz değil mi? Kodunuzu kabaca görebilir miyim?

      • huseyin kulu dedi ki:

        public void ResimCekme()
        {
        krpmaEkranı = GameObject.Find(“Canvas”).gameObject.transform.GetChild(4).gameObject;
        foto = krpmaEkranı.gameObject.transform.GetChild(2).gameObject.transform.GetChild(0).gameObject.transform.GetChild(0).gameObject.GetComponent();
        this.transform.parent.gameObject.SetActive(false);
        if (NativeCamera.IsCameraBusy())
        return;

        NativeCamera.Permission izin = NativeCamera.TakePicture((pack) =>
        {
        string yazi = pack;
        string[] kelimeler = yazi.Split(‘.’);
        Debug.Log(kelimeler[kelimeler.Length – 1]);

        if (kelimeler[kelimeler.Length – 1] == “jpg” || kelimeler[kelimeler.Length – 1] == “png”)
        {
        WWW www = new WWW(“file://” + pack);
        krpmaEkranı.gameObject.SetActive(true);
        foto.texture = http://www.texture;

        }
        }, 4096);
        }

      • yasirkula dedi ki:

        Şunu deneyin:

        NativeCamera.Permission izin = NativeCamera.TakePicture((pack) =>
        {
        	if( pack != null )
        	{
        		Texture2D texture = NativeCamera.LoadImageAtPath( pack );
        		if( texture != null )
        		{
        			krpmaEkranı.gameObject.SetActive(true);
        			foto.texture = texture;
        		}
        	}
        }, 4096);
        
      • huseyin kulu dedi ki:

        tmm hocam bu oldu cok sagolun fakat videoda load işlemini nasıl kullanacaz onada bir örnek atarmısın size zahmet cok yardımcı oldunuz teşekkür ederim

      • yasirkula dedi ki:

        VideoKaydet() fonksiyonundaki gibi Handheld.PlayFullScreenMovie( "file://" + konum ); yapabilirsiniz. Eğer VideoPlayer kullanmayı planlıyorsanız, şuradaki kod işinize yarayabilir: https://github.com/yasirkula/UnityNativeGallery/issues/21#issuecomment-380409079

      • huseyin kulu dedi ki:

        public void VideoKaydet()
        {
        GameObject VideoPanel = GameObject.Find(“Canvas”).gameObject.transform.GetChild(5).gameObject;
        GameObject videoOynamaAlanı = GameObject.Find(“Canvas”).gameObject.transform.GetChild(5).gameObject.transform.GetChild(0).gameObject.transform.GetChild(0).gameObject;
        NativeCamera.Permission izin = NativeCamera.RecordVideo((pack) =>
        {
        if (pack != null)
        {

        VideoPanel.gameObject.SetActive(true);
        videoOynamaAlanı.GetComponent().url = “file://” + pack;
        videoOynamaAlanı.GetComponent().prepareCompleted += (VideoPlayer source) =>
        {
        CustomRenderTexture redertexture = new CustomRenderTexture((int)source.texture.width, (int)source.texture.height);
        videoOynamaAlanı.GetComponent().targetTexture = redertexture;
        videoOynamaAlanı.GetComponent().texture = redertexture;
        VideoPanel.gameObject.transform.GetChild(3).gameObject.GetComponent().sprite = VideoPanel.gameObject.transform.GetChild(3).gameObject.GetComponent().playIcon;
        VideoPanel.gameObject.transform.GetChild(3).gameObject.GetComponent().baslangıc = false;
        videoOynamaAlanı.GetComponent().Prepare();

        // deneme = videoOynamaAlanı.GetComponent().targetTexture;
        // Videodakika = (int)videoOynamaAlanı.GetComponent().length / 60;
        // VideoSaiye = (float)videoOynamaAlanı.GetComponent().length % 60;
        videoOynamaAlanı.GetComponent().Pause();
        videoOynamaAlanı.GetComponent().frame = 100;
        };
        }

        });

        }

        Hata Devam Ediyor Video Cekme Veya Video yükleme Sorusuz ilk ekran onay sahnesi falan sorunsuz texture aktarılınca yan duruyor

      • yasirkula dedi ki:

        videoOynamaAlanı objesinin Transform’unu NativeCamera.GetVideoProperties(pack).rotation kadar derece Rotate edebilirsiniz. X, Y veya Z eksenlerinden hangisinde çevireceğinizi deneye yanıla bulmanız lazım.

  2. hüseyin kulu dedi ki:

    selam bir sorunum var hic bir kaynakta bulamadım cevabını sizin assesti kullandım sorunsuz şekilde calısıyor bunun icin teşekkür ederim falan raw imageye foto veya video yüklendıgında yan olarak algılıyor genel bütün telefonlarda aynı sorun var fakat pc den aldıgım video veya fotolarda sorun olmuyor sadece telefondan cekilmiş genel olarak bütün video ve fotolarda ya gözükme sorunum var bunun kaynagı edir sizce yardımcı olursanız sevirinirim

  3. Ali dedi ki:

    Merhaba.Benim Problemim Küpün Collideri Var Ama Kendisi Mesh yani modeli yok.Sebebi Ne

  4. yasir bey iki provider ekledigim zaman ilk provider çalışıyor. ikinci ekledigim eklenmemiş gibi davranıyor. bunun çozumu nedir.

    boyle oldugu zaman sadece sosyal medya paylaşımı aktif oluyor. camera çalışmıyor.

    şimdiden teşekkurler ve iyi gunler.

    • yasirkula dedi ki:

      İki provider’a farklı android:authorities değerleri vermeyi deneyin. Eğer işe yaramazsa isterseniz AndroidManifest’inizi bana atın, bir de ben inceleyeyim.

      • yasir bey size bir sorum olacak. müsait olduğunuz bir zaman cevap verebilirseniz sevinirim.
        import ettigim bir asset i oyunumdan nasıl kaldırabilirim. fiziksel olarak silsem parçaları kalabileceğini düşünüyorum.
        yada o asseti oyunumda kullanmasam apk ya dahil olmaz mı acaba.
        şimdiden çok teşekkür ederim.

      • yasirkula dedi ki:

        Şu an için asset’i sadece fiziksel olarak silerek projenizden kaldırabilirsiniz. Kullanmadığınız asset’ler APK’ya dahil olmaz ama Resources veya StreamingAssets klasörleri içerisinde yer alan asset’leriniz varsa, onlar (ve onların kullandığı diğer asset’ler) her halükarda APK’ya dahil olur.

Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.