Bu yayında yabancı bir kaynağı direkt olarak Türkçeye çevirerek sunmayı uygun buldum.
AnaSayfa'da da yazdığım gibi, sizlere henüz özgün bir kaynak sunamıyorum çünkü ben de sizin gibi öğrenmeye çalışıyorum ve öğrendikçe de Türkçe kaynak oluşturarak İngilizcesi olmayanların da bilgiden yararlanmasını sağlamayı hedefliyorum. Gerçi daha önce JavaFX kullanmadıysanız bu yayında sıkıntı yaşayabilirsiniz ama yine de en azından JavaFX'e bir başlangıç yapmış olursunuz. :)
Daha detaylı bilgi için buyurun: Kaynak Site

Projenize bir isim seçin ve
JavaFX ile bir OpenCV uygulaması
Bu eğitimde Eclipse'de OpenCV kütüphanesi kullanılarak basit bir JavaJX GUI uygulaması oluşturulabilmesi için size rehberlik edilecektir.
- Bu yayınımızda yapacaklarımız:
e(fx)clipse
plugin'i ve Scene Builder kurulumu.- Scene Builder ile çalışmak.
- Uygulamamızı yazmak ve çalıştımak.
İlk JavaFX uygulamanız
Bu yayını takip ederek yazacağımız uygulama ile bir web kamerasının video akışını (kare kare) yakalayarak bir kullanıcı arayüzü (GUI) üzerinde göstereceğiz. Scene Builder ile şunlara sahip bir GUI oluşturacağız:
~ Görüntü akışını başlatmak-durdurmak için bir buton
~ Görüntüleri göstereceğimiz bir görüntü kapsayıcı.
~ Görüntü akışını başlatmak-durdurmak için bir buton
~ Görüntüleri göstereceğimiz bir görüntü kapsayıcı.
e(fx)clipse plugin ve Scene Builder kurulumu
Eclipse'ye,
http://www.eclipse.org/efxclipse/install.html#fortheambitious
JavaFX Scene Builder2.0 adlı programı şu linkten indirin ve kurun:http://www.oracle.com/technetwork/java/javafxscenebuilder-1x-archive-2199384.html
e(fx)clipse
plugin'i kurmak için şu kılavuzu takip edin:http://www.eclipse.org/efxclipse/install.html#fortheambitious
JavaFX Scene Builder2.0 adlı programı şu linkten indirin ve kurun:http://www.oracle.com/technetwork/java/javafxscenebuilder-1x-archive-2199384.html
Şimdi bir JavaFX projesi oluşturabilrsiniz.
File > New > Project...
ve JavaFX project...
seçin.
Projenize bir isim seçin ve
Next
'e tıklayın. (MyFirstJFXApp)
Library sekmesinden OpenCV kütüphanenizi projeye dahil edin ve
(İlk Java yayınımda bunun nasıl yapılacağını yazmıştım. Library sekmesinde, Add Library... butonuna tıklayıp, User Library seçip OpenCV-2.4.13'ü işaretleyip Finish dedikten sonra ortaya eklenen OpenCV-2.4.13'ün yanındaki oka tıklayıp Native Library Location bölümüne C:/OpenCV-2.4.13/build/java/x64 (veya siz OpenCV'nizi nereye koyduysanız o adresi belirtin) yazıyorsunuz)
Next
deyin.(İlk Java yayınımda bunun nasıl yapılacağını yazmıştım. Library sekmesinde, Add Library... butonuna tıklayıp, User Library seçip OpenCV-2.4.13'ü işaretleyip Finish dedikten sonra ortaya eklenen OpenCV-2.4.13'ün yanındaki oka tıklayıp Native Library Location bölümüne C:/OpenCV-2.4.13/build/java/x64 (veya siz OpenCV'nizi nereye koyduysanız o adresi belirtin) yazıyorsunuz)

FXML dosyası ve Controller Class'ın dahil olacağı Package Name girin (application). Language olarak FXML deyin. FXML dosyanız için bir isim verin (FirstJFX). Son olarak da bir Controller Name ile bu FXML dosyanızdaki bileşenlerle işlemler yapacağınız controller sınıfı için isim verin (FXController).
(Bence fxml dosyası ve controller aynı isimle olursa daha iyi olur ama bu örnekde farklı isim verilebileceği de gösterilmek istenmiş sanırım.)
Son olarak Finish diyerek projenizi oluşturun...
(Bence fxml dosyası ve controller aynı isimle olursa daha iyi olur ama bu örnekde farklı isim verilebileceği de gösterilmek istenmiş sanırım.)
Son olarak Finish diyerek projenizi oluşturun...

Scene Builder ile çalışmak
Eğer Scene Builder'i yüklediyseniz şimdi Eclipse'de soldaki Package Explorer'da projenin altında src altında package adı altındaki FXML dosyanıza sağ tıklayıp
Open with SceneBuilder
'ı seçebilirsiniz.
Scene Builder grafik arayüz oluşturmanıza yardımcı olur. Anlık ön izleme ile çalışmanıza, bileşenlerin yerlerini değiştirmenize izin verir. Şimdi neden bahsettiğime bir göz atalım.
İlk olarak FXML dosyanızda sadece AnchorPane olsun. (Not: SceneBuilder ilk açıldığında, ortada aslında bir BorderPane vardır ama boyutları ayarlanmadığı için görünmemektedir. Fareniz ile ortaları seçmeye çalışırsanız göreceksiniz.) AnchorPane, çocuk (child) bileşenlerinin (üzerine koyacağınız bileşenler onun çocuk bileşenleridir), kendisinin kenarlarından hiza alıp konumlanmasına olanak tanır. Eğer AnchorPane bir kenarlığa veya dolguya(padding) sahipse, hizalanmalar bunların iç taraflarından itibaren yapılır. AnchorPange, çocuk bileşenlerini belli bölümlere hizalamaya izin verdiği gibi, bileşenlerin düzensiz durmalarına da izin verir.
Şimdi de AnchorPane'yi silin ve yerine bir BorderPane koyun. BorderPane'in çocukları üst, sol, sağ, alt ve merkez pozisyonlara hizalanabilirler.

Soldaki 
Butonumuza kod tarafında erişebilmek için de bir kimlik (id) vermemiz gerekiyor. Bunun için de yine sağ taraftaki
Container
menüsünden sürükleyip ortaya bırakarak sahneye bir BorderPane ekleyebilirsiniz. Bunu yaptığınızda, soldaki Hierarchy
menüsünde onun bölümlerini (top, bottom, center...) göreceksiniz. Şimdi bu BorderPane'mize, görüntüyü başlatıp durdurma özelliği vereceğimiz butonumuzu ekleyelim. Bunun için sağdaki Controls
menüsünden Button'u seçip sürükleyin ve Hierarchy
bölümündeki BOTTOM alanına bırakın. Bunu yaptığınızda buton seçili iken sağ tarafta Properties, Layout ve Code bölümlerinin dolduğunu göreceksiniz. Buradan butonumuzun özelliklerini ayarlayabiliyoruz. Örnek olarak Properties
menüsünü açıp Text
kutusuna Start Camera yazabilirsiniz. 
Butonumuza kod tarafında erişebilmek için de bir kimlik (id) vermemiz gerekiyor. Bunun için de yine sağ taraftaki
Code
menüsündeki fx:id
kutusuna buton için bir id verin (örn: start_btn).
Eğer butonun kenara çok yakın olduğunu düşünüyorsanız, sağdaki
Butona tıklandığında bir eylem gerçekleşmesini istiyoruz. Bu yüzden, yine butona id verdiğimiz
Layout
menüsündeki margin özelliklerini artırarak butonun dışına doğru görünmez bir dolgu alanı oluşturabilirsiniz.Butona tıklandığında bir eylem gerçekleşmesini istiyoruz. Bu yüzden, yine butona id verdiğimiz
Code
menüsündeki OnAction
kutusuna, butona tıklandığında controller sınıfımızda çalışacak bir fonksiyon adı verin (örn: startCamera). (Bana sorarsanız butonun adını startButton, bu fonksiyonun adını da startButton_onAction vermek daha anlaşılır olurdu.)
Şimdi de 
Controls
menüsünden bir ImageView bileşeni ekleyerek görüntülerimizi sunacağımız bileşenimizi de eklemiş olalım. ImageView'i alıp BorderPane'misin CENTER kısmına sürükleyip bırakın. Kod tarafında bu bileşenimize erişebilmemiz için de bir id verin (Yine sağdaki Code menüsündeki fx:id kutusundan) (örn: currentFrame), ve isterseniz margin de ekleyebilirsiniz...
Son olarak GUI'mize eklediğimiz bileşenlerin hepsine, hangi controller sınıfıyla birlikte çalışacağını da belirtmemiz gerekiyor. Sol alt taraflarda kalan
Her bileşende bunun belirtilmesi gerekiyor. Eğer en başta BorderPane'mizde bunu belirttikten sonra diğer bileşenleri (button, imageview) ekleseydik, onlara bu otomatik olarak yazılırdı. Ama öğrenmiş olmak için şimdi tek tek yazmak daha faydalı olur...
Controller
menüsündeki Controller class
kutusuna, controller'ınızın adını (paketAdı.controllerAdı şeklinde) yazmanız gerekiyor. Bizim örneğimizde buraya yazmamız gereken: application.FXControllerHer bileşende bunun belirtilmesi gerekiyor. Eğer en başta BorderPane'mizde bunu belirttikten sonra diğer bileşenleri (button, imageview) ekleseydik, onlara bu otomatik olarak yazılırdı. Ama öğrenmiş olmak için şimdi tek tek yazmak daha faydalı olur...
Scene Builder programınızı kaydettiğinizde, Eclipse'deki fxml dosyasınızın, bizim yaptığımız değişikliklerin kodlarıyla otomatik olarak doldurulduğunu göreceksiniz.
Temel JavaFX Kavramları
Stage, uygulamanın nerede gösterileceğidir (örn. Windows'un bir penceresi).Scene, uygulamanın bir "sayfa"sını oluşturan Node'lerin (bileşenlerimizin) kapsayıcısıdır.Node, Scene'nin görsel bir görünüm ve interaktif bir davranış elemanıdır.Node'ler hiyerarşik olarak iç içe olabilirler. (Butonun, BorderPane'nin içinde olması gibi)
main sınıfında, start fonksiyonu ile birincil Stage'mizi belirtmeliyiz.
public void start(Stage primaryStage)
ve fonksiyonumuz içinde fxml dosyamızı stage'mize dolduruyoruz:
// Grafik arayüzümüzü oluşturduğumuz dosyayı ana dosyamız olarak yüklüyoruz:
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("FirstJFX.fxml"));
// Sahnemizi oluşturuyoruz, ana sahnemizi ve sahne boyutlarını belirtiyoruz:
Scene scene = new Scene(root,640,480);
// Sahnenin stillerini ayarlayan dosyayı da get'iriyoruz :)
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
// Yukarıda çağırılanlarla sahnenin kurulmasını istiyoruz:
primaryStage.setScene(scene);
// Bu otomatik oluşturulmuş komutlar arasında yok. Pencereye başlık ekledim:
primaryStage.setTitle("Merhaba");
// Sahneyi göster:
primaryStage.show();
GUI bileşenlerininin Controller sınıfı ile yönetimi
Bizim uygulamamız için iki basit şeye ihtiyacımız var: butona basılmasının kontrolü ve buna bağlı olarak ImageView durumundaki değişiklik. Öncelikle controller sınıfımızı açıp, sınıfımız içine şunları yazarak nesnelerimize id'leri ile ulaşabiliriz:
@FXML
private Button start_btn;
@FXML
private ImageView currentFrame;
@FXML
tagı, sıradaki komutun fxml dosyasıyla bağlantılı olduğunu belirtiyor.@FXML
tagı ile, fxml dosyamızdaki elemanların aksiyonlarına da ulaşabiliriz. Hatırlarsanız butona tıklandığında startCamera diye bir fonksiyon çalışsın istemiştik. fxml dosyamızda bu, onAction parametresinde aşağıdaki gibi belirtilmiştir:<Button fx:id="button" mnemonicParsing="false" onAction="#startCamera" text="Start Camera" BorderPane.alignment="CENTER">
ve biz de controller sayfamıza gelerek aşağıdaki şekilde bu aksiyona ulaşabiliyoruz:
@FXML
protected void startCamera(ActionEvent event) { ... }
Video Yakalamak
Öncelikle geçen yayında söylediğim, OpenCV komutlarının çalışması için gerekli bir kütüphaneyi çağırma işini yapmamız gerekiyor. Bunun için main.java dosyanızı açın ve main fonksiyonunun içine System.loadLibrary(Core.NATIVE_LIBRARY_NAME); yazın. Böylece OpenCV komutlarımız hata vermeden çalışabilecek...
Video yakalamak için gerekli nesne türümüz VideoCapture'dir.
VideoCapture capture = new VideoCapture();
Bu, FFmpeg açık kaynak kütüphanesi oluşturur. Bir video, arka arkaya kareler şeklinde oluşur. İki kare arasında beklenen çok kısa bir süre vardır. Video kameraların saniyede kaç kare gösterebileceğinin sınırı vardır. Biz bunu saniyede 30 kare olarak ayarlayacağız. Bunu yapmak için, arkaplanda her 33 milisaniyede bir çalışacak bir zamanlayıcı (yani bir
`ScheduledExecutorService`
) ayarlayacağız.Runnable frameGrabber = new Runnable() { ... }
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
Eğer videonun başarılı bir şekilde alınıp alınamadığını öğrenmek isiyorsanız,
isOpened
fonksiyonu:if (this.capture.isOpened()) { ... }
Yıkıcı nesne çağırıldığında video otomatik olarak kapanır. Siz bundan önce kapatmak istiyorsanız, onun release (bırakmak/salıvermek) fonksiyonunu çağırmanız gerekir:
this.capture.release();
Video kareleri, basit görüntülerden (images) oluşur. Bu nedenle, onları işleyebilmek için Mat nesnesine almamız gerekir.
Mat frame = new Mat();
Video akışı sıralıdır. VideoCapture nesnesinin read() fonksiyonunu her kullandığınızda, sıradaki karenin görüntüsünü alırsınız ve fonksiyonun parametresi olan Mat nesnesine yazmış olursunuz:
this.capture.read(frame);
Şimdi görüntümüzü BGR (BlueGreenRed) formatından GrayScale (GriSkala) formatına çevirelim. OpenCV bunu aşağıdaki fonksiyon ile kolayca yapmaktadır:
Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY);
- cvtColor fonksiyonunun aldığı parametrelere bakalım:
- kaynak görüntü (frame)
- hedef görüntü (frame), dönüşümden sonra görüntünün aktarılacağı Mat nesnesi.
- Dönüşümün hangi türler arasında yapılacağını belirten parametre. Biz bu örneğimizde
COLOR_BGR2GRAY
kullandık. (Çünküimread
, görüntüyü BGR türünde alır).
Şimdi elimizdeki bu Mat nesnesini ImageView'e koyabilmek için dönüştürmek gerekir. Öncelikle Mat nesnemizi saklamak için bir tampon (buffer) oluşturalım.
MatOfByte buffer = new MatOfByte();
Sonra
imencode
fonksiyonu ile bu tamponumuza Mat türü karemizi (frame) koyabiliriz.Imgcodecs.imencode(".png", frame, buffer);
Bu fonksiyon, ara belleğe bir görüntü kodlamaktadır. Görüntü sıkıştırılır ve ara bellekte bu sıkıştırılmış haliyle saklanır.
imencode
, CV_8UC1
tipinde tek satırlı, byte'ler dizisi halinde kodlanmış bir matris dizi döndürür.- Üç paremetre alır:
- (”.png”) Çıkış biçimini tanımlayan dosya uzantısı.
- (frame) Görüntüsü yazılacak olan Mat nesnesi.
- (buffer) Yeniden boyutlandırılıp sıkıştırılmış olan resmin saklanacağı nesne..
Artık görüntüyü
ByteArrayInputStream
fonksiyonu ile tampondaki diziyi okuyarak ImageView'de gösterilebilecek formatta oluşturabiliriz.new Image(new ByteArrayInputStream(buffer.toArray()));"
Şimdi yeni görüntümüzü ImageView'e koyabiliriz. Java 1.8 ile hem ana işlemler devam ederken hem de görüntüleri kare kare gösterme işini aynı anda yapamazsınız; bu yüzden, başka bir thead oluşturarak bizim ana thead'ımızdaki ImageView görüntülerini güncelleştirmesini sağlamalıyız.
Image imageToShow = grabFrame();
Platform.runLater(new Runnable() {
@Override public void run() { currentFrame.setImage(imageToShow); }
});

Bu eğitimde anlatılanlar için kaynak kodu şuradan indirebilirsiniz: GitHub.
Hiç yorum yok:
Yorum Gönder