UNITY’de Bir Webcam’e Erişerek Onun Görüntüsünü Objeye Texture Olarak Atamak

Yayınlandı: 01 Temmuz 2013 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

Merhaba,

Bu derste, Unity’de bir webcam’e (ya da bir kameraya) erişip onun görüntüsünü oyun motoru içinde kullanmayı göstermeye çalıştım. Kodları comment’leyerek neyin ne olduğunu kısaca açıkladım. Zaten tek bir script yeterli; o da oldukça kısa bir script.

NOT: Bu webcam olayı tüm cihazlarda (cep telefonları dahil) çalışıyor ancak eğer webcam kullanan bir Android uygulaması yaparsanız uygulama kurulmadan önce uygulamanın istediği izinler arasında “Hardware controls : take pictures and videos” da gözüküyor.

Kodu görmek için yazının devamını okuyabilirsiniz…

WebcamTest adında yeni bir C# script oluşturup içeriğini aşağıdaki gibi değiştirmeniz ve bu objeyi webcam görüntüsünü hangi objede göstermek istiyorsanız ona component olarak vermeniz yeterli. Bu objede Mesh Renderer gibi bir component olmalı ve objenin z ekseni (mavi eksen), webcam görüntüsünün görünmesini istediğiniz yöne doğru bakmalı.

using System.Collections;
using UnityEngine;

public class WebcamTest : MonoBehaviour
{
	private WebCamTexture webcam;
	private int mevcutWebcam; // Cihazda birden çok webcam varsa aralarında geçiş yapmak için kullanacağımız bir kod
	private WebCamDevice[] webcamCihazlari; // Aygıttaki tüm webcam'leri depolayan bir değişken
	private Quaternion anaRotasyon; // Kameranın ekrana yamuk yumuk açılarla yansımasını engellemek için bir değişken

	IEnumerator Start()
	{
		// Webcam'e erişmek için kullanıcıdan izin istememiz gerekiyor mu kontrol et
		if( !Application.HasUserAuthorization( UserAuthorization.WebCam ) )
		{
			// Kullanıcının izni gerekiyor, izin iste ve bekle
			yield return Application.RequestUserAuthorization( UserAuthorization.WebCam );

			// Kullanıcı izin vermezse script'i objeden kaldır
			if( !Application.HasUserAuthorization( UserAuthorization.WebCam ) )
				Destroy( this );
		}

		webcamCihazlari = WebCamTexture.devices;

		// Eğer cihazda en az 1 tane webcam varsa, 0. indexteki webcam cihazını "webcam" değişkenine ata; eğer webcam yoksa hata mesajı ver
		if( webcamCihazlari.Length != 0 )
		{
			webcam = new WebCamTexture( webcamCihazlari[0].name );
			mevcutWebcam = 0;
		}
		else
		{
			Debug.LogError( "Hata! Cihazda webcam bulunamadı." );

			// Hata mesajının ardından bu scripti objeden kaldır
			Destroy( this );
		}

		// Objeye texture olarak webcam görüntüsünü ata
		GetComponent<Renderer>().material.mainTexture = webcam;

		// Webcam'den veri almaya başla (webcam'i çalıştır)
		webcam.Play();

		anaRotasyon = transform.rotation;
	}

	void Update()
	{
		// Her kameranın kendine has bir çekim açısı olabilir. Bu kod, objeyi kameranın çekim açısına göre otomatik olarak döndürüyor (benim de tam anlamadığım bir şekilde)
		transform.rotation = anaRotasyon * Quaternion.AngleAxis( webcam.videoRotationAngle, Vector3.forward );
	}

	void OnGUI()
	{
		// Webcam'i duraklatmak/devam ettirmek ya da durdurmak için ekranın sol üstüne butonlar ekle
		if( webcam.isPlaying )
		{
			if( GUI.Button( new Rect( 10, 10, 100, 50 ), "DURAKLAT" ) )
				webcam.Pause();

			if( GUI.Button( new Rect( 10, 70, 100, 50 ), "DURDUR" ) )
				webcam.Stop();
		}
		else
		{
			if( GUI.Button( new Rect( 10, 10, 100, 50 ), "OYNAT" ) )
				webcam.Play();
		}

		// Görüntüyü ters çevirmek için butonlar ekle
		if( GUI.Button( new Rect( 10, 150, 100, 50 ), "DİKEY ÇEVİR" ) )
		{
			Vector3 scale = transform.localScale;
			scale.y = -scale.y;
			transform.localScale = scale;
		}

		if( GUI.Button( new Rect( 10, 210, 100, 50 ), "YATAY ÇEVİR" ) )
		{
			Vector3 scale = transform.localScale;
			scale.x = -scale.x;
			transform.localScale = scale;
		}

		// Eğer varsa başka kameralara geçmek için buton ekle
		if( webcamCihazlari.Length > 1 )
		{
			if( GUI.Button( new Rect( 120, 10, 100, 50 ), "KAMERA DEĞİŞ" ) )
				WebcamDegistir( ( mevcutWebcam + 1 ) % webcamCihazlari.Length );
		}

		// Eğer cihazda ön kamera varsa ilk ön kameraya geçiş yapmayı sağlar
		if( GUI.Button( new Rect( 230, 10, 120, 50 ), "ÖN KAMERA" ) )
		{
			for( int i = 0; i < webcamCihazlari.Length; i++ )
			{
				// Eğer bu webcam öne bakıyorsa mevcut kamerayı buna ayarla
				if( webcamCihazlari[i].isFrontFacing )
				{
					WebcamDegistir( i );
					return;
				}
			}
		}

		// Eğer cihazda arka kamera varsa ilk arka kameraya geçiş yapmayı sağlar
		if( GUI.Button( new Rect( 360, 10, 120, 50 ), "ARKA KAMERA" ) )
		{
			for( var i = 0; i < webcamCihazlari.Length; i++ )
			{
				// Eğer bu webcam arkaya bakıyorsa mevcut kamerayı buna ayarla
				if( !webcamCihazlari[i].isFrontFacing )
				{
					WebcamDegistir( i );
					return;
				}
			}
		}
	}

	private void WebcamDegistir( int yeniWebcam )
	{
		// Mevcut webcam'den görüntü almayı bırak
		webcam.Stop();

		// Artık kullanmayacağımız webcam görüntüsünü yok ederek hafızayı boşalt
		Destroy( webcam );

		// Yeni webcam'e geçiş yap
		mevcutWebcam = yeniWebcam;
		webcam = new WebCamTexture( webcamCihazlari[mevcutWebcam].name );
		GetComponent<Renderer>().material.mainTexture = webcam;

		// Yeni webcam'i çalıştır
		webcam.Play();
	}
}
yorum
  1. Anıl dedi ki:

    Hocam iyi günler. Ben çok sahneli bir projede çalışıyorum. Bu işlemi, yaptığım sahneyi açtığımda webcamden aldığım görüntü ekrana yansıyor. Ama başka bir sahneden o sahneye geldiğimde webcam görüntüsü yansımıyor. Bu sorunu nasıl çözebilirim

    • yasirkula dedi ki:

      Hmm daha önce bu senaryoyu denememiştim. Aslına bakarsanız WebCamTexture’u da bu ders haricinde hiç kullanmadım. Senaryonuzda webcam sahnesinden X sahnesine geçip sonra geri webcam sahnesine dönüyorsanız, o zaman webcam sahnesinden X sahnesine geçmeden önce (örneğin OnDestroy fonksiyonu içerisinde) webcam.Stop() fonksiyonunu çağırmayı deneyebilirsiniz. Eğer işe yaramazsa, webcam’i çalıştırmadan önce birkaç saniye beklemeyi deneyebilirsiniz.

  2. Yusuf Benli dedi ki:

    Merhabalar unityi yeni kurdum youtubedaki bir çok videyu izleyerek ekrana AR camera ekliyorum.Fakat run yaptığımda kamera çalışmıyor.Şöyle bir hata alıyorum:
    Exception in callback: Failed to create ImageTargetObserver: DATABASE_LOAD_ERROR.
    UnityEngine.Debug:LogErrorFormat (string,object[])
    Vuforia.Internal.Utility.UnityLogger:LogError (string,object[])
    Vuforia.Internal.Utility.Log:Error (string,object[])
    Vuforia.Utility.ExtensionMethods.DelegateHelper:InvokeDelegate (System.Delegate,object[])
    Vuforia.Utility.ExtensionMethods.DelegateHelper:InvokeWithExceptionHandling (System.Action`1,Vuforia.VuforiaInitError)
    Vuforia.Internal.Core.Engine:InitOnCameraReady ()
    Vuforia.WebCam:HandleFirstWebCamFrame ()
    Vuforia.WebCam:b__33_0 (bool)
    Vuforia.Internal.Utility.VuforiaCoroutineUtility/d__1:MoveNext ()
    UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)

    PC webcami AR kamerayı desteklemiyor olabilir mi?

    • yasirkula dedi ki:

      PC webcam’inin sorun çıkarmaması lazım. Hatayı arattığımda Vuforia’yı yeniden kurunca düzeldiğini söyleyen de buldum, Vuforia sürümünü 10.0’dan 9.8‘e çekince düzeldiğini söyleyen de. Maalesef daha fazla yardımcı olamıyorum çünkü Vuforia ile en son çalışalı çok uzun zaman oldu.

  3. Yasir dedi ki:

    Hocam merhaba bir uygulama yaptım pc için build aldım ama .exe açıyorum açılıyor sıkıntı yok. Fakat uygulamanın bir kısmın da kameranın açılması gerekiyor ama açılmıyor. Büyük ihtimal build alırken kamera izni falan vermem gerekiyor ama bulamadım. Fikriniz varsa yardımcı olur musunuz?

  4. Altay Olcay dedi ki:

    Merhaba. Görüntüyü istediğim gibi alıyorum. Texture olarak maretiale verip ekrana verebiliyorum sorun yok. Bir kaç gündür bu materiali bayt a çevirip İnternette bir mssql veritabanına yazdırıp, başka cihazdan almayı deniyorum. Fakat başaramadım. Yani yapmaya çalıştığım karşılıklı iki kişi canlı bir şekilde görüntü paylaştırmak, sonraki adımda sesi paylaştırmaya çalışacağım. Bu sistem Veritabanı yöntemi ile sağlıklımı? Değilse firmalar hangi yöntemi kullanıyor? Eğer sağlıklı ise nasıl yapabilirim? Bir fikriniz var mı?

    • yasirkula dedi ki:

      WebCamTexture’u byte[]’a çevirerek yollamayın çünkü bu çok yavaş olur ve byte[]’ta bir sıkıştırma işlemi yapılmadığı için, çok fazla veri aktarımı anlamına gelir (15 fps’te yollasanız ve her frame 100KB olsa, saniyede 1.5 MB oluyor). Onun yerine, hazır plugin’ler kullanın. “unity video chat” şeklinde arama yaparak birkaç alternatif plugin görebilir ve bunları kendiniz kıyaslayabilirsiniz (benim tecrübem olmadığından bir öneride bulunamıyorum).

      • Altay dedi ki:

        Cevabınız için teşekkür ederim. Pluginleri inceleyeceğim. Peki farklı bir alternatif olarak, resim olarak kayıt etsem servera sonrada sadece karşı cihazın resmini mevcut cihaza yükleyip ekrana bassam sizce şişme veya perfonmans açısından sorun yaratır mı? Tabi denemek lazım ama sadece mantık ve tecrübe açısından düşünürsek diye mantık yürütüyorum.

      • yasirkula dedi ki:

        Resimden kastınız WebCamTexture’u her saniye 15 kere JPEG veya PNG’e çevirip karşıya yollamaksa, cevabımda bahsettiğim sıkıştırma işlemi olmaması olayı bu; yani yine çok şişer. MP4 videolar nasıl sıkıştırılıyor bilmiyorum ama her frame ayrı bir resim olarak sıkıştırılmıyordur diye düşünüyorum, öyle olsa videolar aşırı yer kaplardı.

      • Altay dedi ki:

        Haklısınız. Bir eklenti buldum. 10.000 dakika ücretsiz veriyor. Onu bir deneyeceğim. Yardımlarınız için teşekkür ederim.

  5. Mehmet ŞENGÜL dedi ki:

    Merhaba hocam. Kodları bir plane bağladım görüntü alıyorum fakat ön kamerada sağa yatırınca sola sola yatırınca sağa dönüyor. Rotation ayarlarıyla oynadım ama bi sonuç alamadım. Yardımcı olabilir misin?

    • yasirkula dedi ki:

      Derste webcam.videoRotationAngle’dan faydalanıyorum. Eğer bu sizde bir işe yaramadıysa, plane’i elle 90 derece döndürmekten başka bir seçenek olmayabilir.

  6. bunyaminyakut dedi ki:

    hocam hayırlı akşamlar,
    ben bir objenin üzerindeki dokuyu slider ile nasıl kontrol ederek döndürebilirim?
    daha anlaşılır olsun diye şu şekilde örnek vereyim; Duvara tuğla dokusunu ekledim ve duvara tıkladığımda tuğla dokusunu duvar oynamadan istediğim gibi nasıl döndürebilirim.

    • yasirkula dedi ki:

      Materyalin mainTextureOffset değerini değiştirebilirsiniz: https://docs.unity3d.com/ScriptReference/Material-mainTextureOffset.html

      • UV Rotation değerini nasıl değiştirebilirim? Ve bunu bir slidere nasıl bağlayabilirim.

      • yasirkula dedi ki:

        Kendi shader’ınızı yazmadan bunu yapmanız mümkün değil diye biliyorum, örnek shader’lar için: https://forum.unity.com/threads/rotation-of-texture-uvs-directly-from-a-shader.150482/

      • çok teşekkür ederim halletmeye çalışırım

      • Properties
        {
        _MainTex(“Texture”, 2D) = “white” {}
        _UvRotation(“UV Rotation”, float) = 0
        }

        SubShader
        {
        Tags { “Queue” = “Transparent” “RenderType” = “Transparent” }
        Blend SrcAlpha OneMinusSrcAlpha
        ZTest on
        ZWrite off

        Pass
        {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include “UnityCG.cginc”

        struct appdata
        {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
        fixed4 color : COLOR;
        };

        struct v2f
        {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
        fixed4 color : COLOR;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST;
        fixed _UvRotation;

        v2f vert(appdata v)
        {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);

        fixed cosr = cos(_UvRotation);
        fixed sinr = sin(_UvRotation);
        fixed2x2 uvrotation = fixed2x2(cosr, -sinr, sinr, cosr);

        float2 uv = mul(UNITY_MATRIX_M, v.vertex).xz * _MainTex_ST.xy;
        o.uv = mul(uvrotation, uv);
        o.color = v.color;
        return o;
        }

        fixed4 frag(v2f i) : SV_Target
        {
        fixed4 col = tex2D(_MainTex, i.uv);
        return fixed4(col.rgb, i.color.a);
        }
        ENDCG
        }
        }

        //Bu şekilde shader kullandıktan sonra bunun UV Rotation değerine bir slider ile değişken nasıl yaratabilirim,?

      • yasirkula dedi ki:

        Slider’ın On Value Changed’inde materyal.SetFloat(“_UvRotation”, sliderDegeri); kodunu çağırabilirsiniz.

  7. Furkan emre dedi ki:

    (mevcutWebcam + 1 ) % webcamCihazlari.Length );

    Hocam ben bunu tam anlamadım

    • yasirkula dedi ki:

      mevcutWebcam değişkeni, webcamCihazlari array’inde kaçıncı sıradaki webcam cihazının şu anda aktif olduğunu belirtmekte. Bir sonraki webcam’i çalıştırırken mevcutWebcam’in değerinin, webcamCihazlari’nın sınırları dışına taşmadığından emin olmamız lazım. Koddaki % işareti “bölümden kalan” anlamına geliyor, yani “4 % 3” yazarsak bu 4’ün 3’e bölümünden kalanı döndürür. 4 yerine ne yazarsak yazalım sonuç [0,2] aralığında olur. Yazdığım kodda ise, %’un döndürdüğü değer daima [0,webcamCihazlari.Length-1] aralığında oluyor, yani webcamCihazlari’nın sınırları dahilinde oluyor.

Cevap Yazın

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.