IRCForumları - IRC ve mIRC Kullanıcılarının Buluşma Noktası

IRCForumları - IRC ve mIRC Kullanıcılarının Buluşma Noktası (https://www.ircforumlari.net/)
-   JavaScript (https://www.ircforumlari.net/javascript/)
-   -   Java Image Manipulation (https://www.ircforumlari.net/javascript/537172-java-image-manipulation.html)

SeckiN 13 Temmuz 2013 22:00

Java Image Manipulation
 
Java Image Manipulation

İçerik
x Temel “Image” Bilgileri
-- Java’da Image
-- Loading Image
-- Graphics2D Kullanarak Image objesini çizdirme
-- Kendi Image objemizi oluşturmak ve kullanmak
-- Resim/Image Kaydetmek
Işe Yarar Image Işlemleri
x Şeffaflaştırma
-- Belirli bir rengi şeffaflaştırma
-- Resmi çevirmek
-- Resmi döndürmek
-- Resmi yeniden boyutlandırmak

Başlamadan önce, şunu söyleyeyim... Yazıyı bir yabancı siteden çeviri yapacaktım fakat, sitenin yetersiz olduğunu gördüm ve bazı kısımları hariç kendim değiştirip anlattım. Bu yüzden benzer kod parçalarını internette kolayca bulabilirsiniz.


Resimler grafik arayüzlü birçok programda kullanılıyor olmaları sebebiyle önemlidir. Bu resimleri kontrol etme ve işleme becerisi çok önemli bir beceridir ve herhangi bir grafik tasarımcı veya oyun tasarımcısı için olmazsa olmazlardandır. Bu yazı, hobisiyle uğraşan bir amatör de olsanız, profesyonel bir tasarımcı da olsanız, Java’da resimlerle uğraşmanız için gerekli temelleri vermeyi amaçlamaktadır. Yazının sonuna kadar uyguladığınızda, “küçük ama çok etkili”, resimlerle ilgili en yaygın birkaç işlemi yapabilen bir sınıfa sahip olacaksınız. jpg, .png, .gif, and bmp resim dosyaları üzerinde işlem yapabileceksiniz. Bu yazı sadece, Java’da temel bilgilere sahip olduğunuz düşünülerek yazılmıştır. (Tabii birazcık da resimlerle uğraşma tecrübeniz varsa yardımı olacaktır.) Bu yazıda tabii ki olabildiğince sizi matematiksel detaylarla uğraştırmayacağım. Yani, hadi başlayalım kodlamaya...

Java’da Image

Java’da Image sınıfı java.awt.image.Image adresindedir. Bu sınıf, temel resim kontrollerini sağlar. Yani iskelet diyebiliriz. Fakat asıl sistem, kan ve etler, java.awt.image.BufferedImage sınıfındadır. BufferedImage dediğimiz şey, bir resim verisinin erişilebilir ara belleğidir. (Aslına bakarsanız, piksellerin ve RGB renklerinin demek daha doğru olur.) Bu sınıf, resimler üzerinde çalışma adına çok güçlü bir yöntem sağlar. Bir BufferedImage, ColorModel ve Raster’dan oluşmuştur. Çok derinlemesine bilmek gerekmese de,
ColorModel objesi, resmin piksel verilerini renk parçalarına dönüştürecek metodları sağlar.
Raster ise, piksellerin dikdörtgenler dizilimini gösterir. Raster, resmin ham verisini tutan DataBuffer ve bu buffer’daki verinin nasıl organize edileceğini açıklayan SampleModel sınıflarından oluşur.

Temel bilgi olarak bunlar yeterli..

Image Yükleme(Loading Image)


Muhtemelen resimlerle ilgili en çok kullanılan işlem budur. Programa resim açma/yükleme (load kelimesinin tam karşılığı olarak ne kullanacağımı bilemedim :/ ) aslına bakarsanız yeterincebasit bir işlemdir ve bunu yapmanın birçok yöntemi vardır. Ben en basit olarak gördüğüm bir yöntemi sizinle paylaşacağım. bunun için, javax.imageio.ImageIO sınıfını kullanacağız.
Temel olarak, yapmak istediğimiz şey, bir resim dosyasındaki tüm veriyi load ederek, (Kusura bakmayın Türkçe’de buna karşılık kullanabileceğim bir kelime gelmiyor aklıma) , bunu bir BufferedImage objesine aktarmaktır ki bir daha sonra bunu gösterebilelim. Bunu ImageIO kullanarak şu şekilde yapabiliriz:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Burada, ilk olarak bir BufferedImage referansı oluşturuyoruz. Ardından bunu bir kaynak dosyadan okumayı deniyoruz. (Hata vermezse, ) elde ettiğimiz resmi return ediyoruz.
Ve tabii ki, siz bir resmi, en azından görüntülemiyorsanız, bir objeye yüklemek tam anlamıyla faydasızdır. Bu yüzden, şimdi size bu resmi nasıl çizdirebileceğimizi anlatmak lazım bir de...


Graphics2D Kullanarak Image Objesini Çizdirme



İşte tam olarak burası, eğlencenin yavaş yavaş başladığı yer. Bir resmi çizdirmek için, ilk önce onu çizebileceğimiz bir yüzeye ihtiyacımız vardır. Bunun için de AWT ve Swing kaynakları kullanmamız gerekiyor. Bununla alakalı daha geniş bilgi için, “Grafik Dersleri 1” konusuna bakınız. Daha da geniş bilgi için Java Documentation sayfalarını inceleyin. Swing içindeki her üst düzey container -JPanel, JFrame Canvas gibi- kendi Graphics objesine sahiptir. Bu Graphics objesi bize, kendi ata yüzeyine çizim yapmamıza izin verir. Örneğin page.drawLine(int x1,inty1,int x2,int y2); veya page.drawImage(Image img,int x,int y,ImageObserver ob); gibi...
Graphics2D objesi ise, Graphics objesinin güçlü bir alt sınıfıdır anlayacağınız üzere... BufferedImage çizimlerine izin veren daha fazla metod sağlar.
BufferedImage load edip ekrana çizdiren bir örnek inceleyelim:
Öncelikle şunu belirtmeliyim. Ben Eclipse kullanıyorum ve buradaki örnekleri denemeniz sırasında kullanmak üzere ŞU RESiMLERi indirip oluşturduğunuz projenin içine kaydetmenizi öneriyorum.


[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Not:Bu şekilde normalde çalışıyor ama bazı durumlarda çalışmayabiliyor... Graphics nesnesine ulaşmaya çalıştığı anda o null olabiliyor.


Bu yöntemle çizdiğinizde, ekran boyutuyla oynadığınızda resmin yok olduğunu göreceksiniz.
Bunun önüne geçmek için, JPanel’in subclass’ı olan bir başka class yapıp; bunu,resmi ne durumda olursa olsun ekrana çizdirecek bir hale getirmemiz lazım. Bunun için de [RED}paintComponent(Graphics g); metodunu override etmemiz lazım. Bu class için aşağıya doğru devam edin.
Bir parça kod daha ekliyorum. Ben böyle kullanmayı tercih ediyorum genellikle.

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu Main birkaç şeyi açıklamakta fayda var... Bu class’taki loadImage metodunu çağırmadım. O, ImageApp class’ındaki yöntem için orada duruyordu. Bu class’ın sadece main metoduna baksanız yeterli bu yöntem için...

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Burada da şunu söylemekte fayda var. size ayarlarken +20 dedim, çizdirirken de (10,10) koordinatından başlattım ki pencerenin tam ortasına yerleştireyim resmi...


Not: bu metod için Graphics2D kullanmamıza gerek yoktu.. Onun yerine direkt olarak “g” üzerine çizim de yapabilirdik.
Fakat bu sefer metodumuz:
g.drawImage(image,10,10,null);
şeklinde olacaktı. (Evet bu iki class’ta drawImage parametre sistemi farklı...=)


Bu değişiklik sonuç olarak bize bir dünya farklılık oluşturuyor. Yeniden boyutlandırma,buffering, vs. gibi arkaplan işlemlerinde olay kendi içinde halledilecek. Biz de ilerlemeye devam edelim bu sırada...


Kendi Image objemizi oluşturmak ve kullanmak


Bunu yapmanın da yeterince kolay birkaç yöntemi var. En bariz yöntem haliyle,
BufferedImage bi=new BufferedImage(320, 240,BufferedImage.TYPE_3BYTE_BGR);
şeklinde oluştururuz.
Fakat bunun üzerinde bir çizim yapabilmek için bunun Graphics objesini oluşturmamız gerekir.
BufferedImage bi=new BufferedImage(320, 240,BufferedImage.TYPE_3BYTE_BGR);
bi.createGraphics();

Şimdi üzerine çizim yapabileceğimiz nur topu gibi bir yüzeyimiz oldu. Hayırlı olsun.
Not:createGraphics metodu Graphics2D objesi return eder ve sizin bunu bir şeye eşitlemeniz gerekir. sadece bunu yapıp bırakamazsınız.


Şimdi sizinle basit bir çizim yapalım.


Ya da bir dakika... Once şu ImagePanel class’ını biraz daha genişkapsamlı/genelgeçer hale getirelim.

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Kısaca söylemek gerekirse, bu class, BufferedImage objesi, 2 tane de sayı alır. ve bunu (x,y) itibariyle çizdirir.


Şimdi basit çizimimizi yapabiliriz. :)

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu örnek basit olarak Graphics2D üzerine nasıl çizim yapabileceğimizi gösteriyor. İsterseniz g.drawString, drawOval vs. metodları kullanarak farklı şeyler tecrübe edebilirsiniz.


Resim/Image Kaydetmek


Bu da daha önce bahsettiğimiz çoğu şey gibi yeterince basit bir metod... Temel olarak, yapılacak tek şey, RAM’deki resim verisinin dosyaya yazılması.. Aşağıdaki kodda bunun JPG ve PNG için yapılışı var. Java henüz Sun’a aitken eklenen ImageIO, bize büyük kolaylık sağlıyor.
ImageIO.write(RenderedImage ri,String format,File output);

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu metodu da Main class’ımıza ekledim.


Resmi Şeffaflaştırma

Bazen bir resmi veya onun bir kısmını geçirgen/şeffaf yapmamız gerekebilir. Photoshop, Gimp veya bunlara benzer bir resim düzenleme programı kullandıysanız, resmin “alpha” değerini değiştirme veya resme alpha katmanı uygulamanın bu işi yaptığını tahmin edebilirsiniz. Burada da tam olarak bunun nasl yapıldığını göreceğiz.


Her resmin bir parçası olan Graphics2D objesi ve JFrame gibi container’lar bizim, bunların nasıl çizileceğine karışmamıza izin verir. Temel olarak, setComposite(Composite comp), setStroke(Stroke stroke) and setPaint(Paint paint) vs. hepsi bizim Graphics2D objemizin çizimini etkiler. Composite bizim bu başlıkta yapmak istediğimiz işlem olan şeffaflık ayarlama gibi şeyleri etkilemeye yarar. Genellikle sadece resmin AlphaComposite’i ile ilgilenilir onu çizdirdiğimiz panele bulaşmamıza gerek yok. Main class’ımıza bu metodu da ekleyelim (tabii ki resim üzerinde uygulayıp ekleyelim, tüm container’ı etkilemeye gerek yok). Örnek kod parçası:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu kod parçası, once resmi alır, sonra resmi şeffaflaştırma işlemi için hazır hale getirilmiş yeni BufferedImage objesini oluşturur ve bunun Graphics2D objesini alarak belirlenen şeffaflık değerini AlphaComposite ile uygular. Ardından resmi çizer. Son olarak, kullanılan kaynakları serbest bırakır ve bitirir. AlphaComposite içinde kullanılan değer, 0.0 ile 1.0 arasında herhangi bir şey olabilir. (Not: Hatırlayınız, yazdığınız bir ondalık sayının float olarak alınmasını istiyorsanız, sayının sonuna “f” harfi eklemelisiniz.)
Main metodumuzun içindeki her şeyi silip yerine bunları yazabilirsiniz:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Outputumuz:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Belirli Bir Rengi Şeffaflaştırma

Birçok resim düzenleme programında olan işe yarar bir özellik de, belirli bir rengi şeffaf hale getirebilme özelliğidir. Buna maske (mask) uygulamak deniliyor. Bunu GIMP programı, tüm pikselleri teker teker test edip, belirli renkteki piksellerin RGB değerini sıfırlayıp alpha değerini de 0.0’a eşitleyerek yaptığını biliyorum. Bunu Java’da yapmak için:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu kısım, resmi aldıktan sonra, yeni bir renk tipinde (ARGB/ RGBA) bir hedef obje oluşturur. Sonraki kısım da asıl işi yapacak olan kısım.

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]
Bu, hedefin Graphics2D objesini alır, Composite değerini Alpha’ya çevirir. Resmi çizer ve Graphics2D objesini sistemden temizler. Sonra, resimdeki tüm pikselleri gezerek, rengi kontrol eder. Eğer renkler aynıysa, bunu alpha RGB değeriyle değiştiriyoruz. Son olarak, maske uygulanmış hedef resmi return ediyoruz.


Bunu uygulayıp ImagePanel ile gösterdiğimizde çıkan output:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Fark ettiğiniz üzere burada gayet güzel çalışıyor programımız. Bir de şunda deneyelim:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Eveeeeet... Gördüğünüz üzere, beyazın bir kısmını silemedi.. Siyahın daha büyük bir kısmını silemedi... Bunun sebebi, seçtiğimiz rengi biz siyah olarak görsek de, saygıdeğer programımız kendilerini farklı görüyor.
Bunun için de, işin içine threshold denilen bir kavram giriyor. Yani, manuel olarak, belirli miktardaki farkı yok saymasını sağlayacağız.


Bu kısım biraz karmaşık görünüyor fakat temel olarak yaptığım şey, rengi R, Gve B olarak ayırıp, hepsini bir threshold ile kontrol ediyorum. buna Photoshop’ta “tolerance” diyor hatırlayanlar olur...
kod parçasını paylaşıyorum:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bu kısmı biraz aceleye geldi.. Bunu çoğu kişi zaten okumayacağı için birisi hakkında soru sorana kadar açıklama ihtiyacı duymuyorum. Açıklanması gereken yerler, gelen soruya göre daha anlaşılır olacak...
Bir de sonuç paylaşayım:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bununla alakalı çok konuştum.. Diğer kısımlara geçeyim.


Resmi Çevirmek/Ters Yüz Etmek


Bir resmi ters yüz etmek, bir eksene göre ayna görüntüsünü almak demektir.
bunu yapmak için Graphics2D’nin daha çok parametre alan bir metodunu kullanacağız.
drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer);
parametreleri sırasıyla, çizim yapılacak hedef dikdörtgenin sol üst köşe, sağ alt köşe koordinatları ve kaynağın sol-üst ve sağ-alt köşeleri... Biz kaynağın köşelerinde sağ-üst ve sol-alt verirsek, bunu tersyüz etmiş oluruz. Aynı şekilde diğer ikisini de değiştirerek farklı bir eksene göre ters yüz etmiş oluruz:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Resmi Döndürmek

Normalde resmi döndürme işlemi, trigonometrik hesaplar ve image processing bilgisi gerektiren karmaşık sayılabilecek bir olaydır. Java’da sağlanan bir metod sayesinde biz bunu kolaylıkla yapıyoruz. Kod parçası:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

burada verdiğimiz w/2 ve h/2 değerleri referans noktası oluyor. yani 0,0 derseniz, bir kağıdın sol üst köşesini bir parmağınızla tutup bir köşesinden tutup çevirdiğinizde elde edeceğiniz şekil oluyor.
Örnek resimler vereyim. 45 derece çevrilmiş hal. Tabii ki renklerde bir miktar bozulmalar oldu. Resmin formatına bağlı olarak bunları yaşamazsınız. “kirby.jpg” ile deneyin.

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Resmi Yeniden Boyutlandırmak


Bunu yapmak için değişik yöntemler var. Ben bunu kullanmıyorum genelde fakat siz bunu bilin.
Olayın bütün matematiksel kısmını yine Graphics2D hallediyor. Fakat yine de işin içine çoğumuzun daha önce duymamış olduğu bir sınıf giriyor. “RenderingHints”. Bununla alakalı açıklama yapamayacağım çünkü ben de bilmiyorum :)

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Output diyelim:

[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...] [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Bunu kullanmanızı önerme sebebim hızlı ve sistemli oluşu..
Bir de şöyle bir şey varmış:
Image.getScaledInstance(int newWidth, int newHeight, int renderHints)


fakat bunun yavaş olduğunu söylüyorlar.. [Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Unutmadan ekleyeyim:
[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]

Alıntı


Tüm Zamanlar GMT +3 Olarak Ayarlanmış. Şuanki Zaman: 14:57.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions, Inc.
Search Engine Friendly URLs by vBSEO
Copyright ©2004 - 2025 IRCForumlari.Net Sparhawk