BMP ile ilgili teorik bilgileri bir önceki yazımda vermiştim. Bu yazımda ise C++ ile bir BMP resmini açıp,resme ait temel bilgilere erişmeye çalışacağız. Yazacağımız kodda bir BMP resmi ikili (binary) olarak açılacak ve imleç konumlandırılarak resme ait bilgiler okunacaktır. Görüntü işleme kütüphanesi projesine de ufak ufak başladığımdan yazacağımız programı fonksiyon olarak vermeye karar verdim. Fonksiyon *filename adında bir dosya yolu ile çağrılır. Bu dosya yolu ifstream fonksiyonu kullanılarak binary olarak açılır. BMP resminde daha önceki yazımda söylediğim üzere ilk iki bayt BM karakterlerini tutar. Read fonksiyonu ile 'BM' karakterleri bftype adlı değişkene atanır.
Bu değişken okuduğumuz dosyanın bir bmp resmi olup olmadığını anlamamıza yarayacak olduğundan hatasız bir program için mutlaka okunup içeriği incelenmelidir. Bundan sonra seekg fonksiyonu ile imleç istenilen adrese konumlandırılarak içerisindeki değer okunur ve ilgili değişkene atanır. Resimdeki gerekli büyüklükler okunduktan sonra imleç renklerin başlangıç adresi olan bfoffset adresine yerleştirilir. Bu değer BMP resmi içerisinde 10.baytta yazılıdır(24 bit BMP için bfoffset=54). İmleç yerleştirildikten sonra iç içe 2 for döngüsü ile resim boyu ve eni boyunca pixel pixel taranır ve okunan her pixel değeri oluşturulan matrise atanır. Bu aşamadan sonra artık elimizde resim değil,içerisinde red,green,blue ve alpha değerlerini tutan 4 adet matris vardır ve yapılacak tüm işlemler bu matris üzerinden yapılır.
NOT: RGB değerlerini okurken her satırın sonunda imleci kaldığı yerden padding değeri kadar kaydırdığımızı farketmişsinizdir.Bunun nedeni daha önce bahsetmediğim BMP formatına ait Padding kavramı.Bmp formatı bir satırın uzunluğunu 4 bayt ve katları uzunluğunda olmasını ister.Mesala biz 3x3 pixellik bir resmi kaydetmeye çalıştığımızda her pixel için 3 bayt(RGB) tutulduğundan(24-BMP) bir satırın uzunluğu 3*3=9 bayt olacaktır.Ancak BMP her satırın 4 bayt ve katı uzunlukta olması için 9 bayta 3 bayt daha ekler.Eklenen bu baytlar 00 00 00 içeriklidir ve padding olarak adlandırılır.Eğer okuma yaparken bu baytlarıda renk değeri olarak okursak ciddi bir hata yapmış oluruz.
bool BMPF::openbmp(char *filename) {
ifstream bmp(filename,ios::binary);
bmp.read((char*)&header.bftype,2);
bmp.seekg(2,ios::beg);
bmp.read((char*)&header.bfsize,4);
bmp.seekg(10,ios::beg);
bmp.read((char*)&header.bfoffset,4);
bmp.seekg(18,ios::beg);
bmp.read((char*)&bminfo.width,4);
bmp.seekg(22,ios::beg);
bmp.read((char*)&bminfo.height,4);
bmp.seekg(28,ios::beg);
bmp.read((char*)&bminfo.bppixel,2);
int i=0,j=0;
byte padding=4-(3*bminfo.width)%4;
if(padding==4) { padding=0; }
bmp.seekg((int)header.bfoffset,ios::beg);
for(j=bminfo.height-1;j>=0;j--) {
for(i=0;i< bminfo.height;i++) {
bmp.read((char*)&pixels[i][j],3); }
bmp.seekg(padding,ios::cur);
}
bmp.close();
return true; }
Bu kod çalıştırılacak olursa zaman açısından çokta verimli olmadığı görülür. Çünkü bu kodla her bir pixeli tek tek okuduk (Mavi ile yazılı satırlarda). Yani resmi bir cümle olarak düşünecek olursak her bir kelimeden sonra durarak okuduk. Bu da bizi yavaşlattı. Şimdi bir tampon tanımlayalım ve tüm satırı bir kerede okuyalım. 24 bit BMP için bir satırdaki toplam byte sayısı=genişlik*3+padding kadardır.(Her R,G,B için bir byte). Yani bir defada bu kadar byte'lık bir alan okuyacağız.
int buffersize=bminfo.width*3+padding;
byte *buffer;
buffer=new byte [buffersize];
j=bminfo.height-1;
while(j>-1) {
bmp.read((char*)buffer,buffersize);
Artık resim matrisimizin bir satırı buffer adlı adreste. Bu adresdeki değerleri pixels[m][n] matrisine almak için memcpy(1,2,sayi) adlı fonksiyonu kullanacağız. Bu fonksiyon ile 2. bellek bölgesinden sayi kadar byte 1.bellek bölgesine kopyalanır.
for( i=0 ; i < bminfo.width ; i++ )
{ memcpy( (char*) &(pixels[i][j]), buffer+3*i, 3 ); }
j--; }
delete [] buffer;
Her satır için işlem tekrar edildikten sonra tüm veiler pixels[m][n] matrisimize yazılmış olur. Artık tampon dosyamız ile işimiz kalmadığından buffer ı silebiliriz. Bu düzenleme sonrasında kod yeniden çalıştırılırsa bir 5100x3300 bir resim için 120 kat daha hızlı çalıştığı görülür. Resmin genişliği arttıkça bu oranda artacaktır.
Gönderen Bahri ABACI
Bunu E-postayla GönderBlogThis!Twitter'da PaylaşFacebook'ta PaylaşPinterest'te Paylaş
Etiketler: BMP, Goruntu Isleme, Programlama
26 yorum:
Unknown 3 Temmuz 2012 21:39
Bu güzel bilgiler için teşekkürler
YanıtlaSil
Yanıtlar
Yanıtla
Unknown 17 Nisan 2014 22:34
hocam paylaşım için teşekkürler. inceledim ancak kodları derleyemedim bana örnek bir proje dosyası gönderebilirmisiniz.
YanıtlaSil
Yanıtlar
Yanıtla
Bahri ABACI 17 Nisan 2014 23:21
Anlatılan fonksiyonu kullanarak basit bir resim açma ve kaydetme örneğine https://dl.dropboxusercontent.com/u/52989937/cescript/Projeler/ornek.zip adresinden ulaşabilirsiniz.
YanıtlaSil
Yanıtlar
sait 26 Kasım 2016 22:59
Bu yorum yazar tarafından silindi.
Sil
Yanıtlar
Yanıtla
sait 6 Aralık 2016 01:02
Merhabalar hocam mail olarak attığınız kodlarla problemim çözüldü. Teşekkür ederim.
Sil
Yanıtlar
Yanıtla
Yanıtla
Unknown 19 Nisan 2014 01:46
hocam tamam kodu derledim. başlangıc olarak ktüphanede sorun oldu ama calıştı sanırım yani yazılan diye bir bmp oluşturdu. kodun yapacağı buydu heralde..:) yanlız benim söyle bir calışmam var elimdeki bir bmp resmin piksel değerlerine ulaşıp bunları filtreledikten sonra tekrardan her pikseli kendi yerine koyup filtrelenmiş resmi oluşturmak istiyorum.(yani konvolasyon yapıcam) cbmp kütüphanesini kullanarak bunu nasıl yapabilirim yardımcı olabilirmisiniz. mesela fileopen foksiyonlarını kullanarak belirli bir ölcüde yapmayı başardım ancak resmi okuma ve yazmada sorunlar oluyor. ben cbmp yi kullanırsam daha iyi olcağını düşünüyorum.
YanıtlaSil
Yanıtlar
Yanıtla
Bahri ABACI 20 Nisan 2014 13:59
Merhabalar, cbmp ile söylediğiniz işlemi kolayklıkla yapabilirsiniz. http://www.cescript.com/2012/07/c-ile-konvolusyon-islemi.html yazımda konvolüsyon işlemi için bir fonksiyon hazırlamıştım (resim_kon). Yazıda verdiğim örnek kod ise tam olarak sizin isteğinizi gerçekleştiriyor.
YanıtlaSil
Yanıtlar
Yanıtla
Unknown 22 Nisan 2014 01:04
hocam linkteki konuyuda daha önce incelemiştim ancak derleyememiştim. ön calişmalarımı yapmak için ide olarak DevC++ kullanıyorum ben. derlemek için epeyde bi uğraşmıştım (kütüphaneler vs)ancak sürekli hata aldım zaten bu yüzden fileopen komutlarına yönelmiştim. simdi fileopende ilerleme kaydettim ancak filtrelediğim görüntü istediğim gibi olmuyor hatta bazılarında cok alakasız sonuclar cıkıyo..:) ben acıkcası okuma ve ara işlemlerde değilde yazma esnasında bir sıkıntı olduğunu düşünüyorum ancak suan kadar bulamadım. read ve write işlemlerinde gene sizin paylaştığınız bmp formatınıda dikkate aldığım halde sorunu cözemedim. mümkünse eğer bu kodu bir proje olarak alabilirmiyim sizden. yada eğer bilginiz varsa yazma esnasında neyi kacırıyor olabilirim. hazırladığım koduda gönderebilirim isterseniz.
YanıtlaSil
Yanıtlar
Yanıtla
Bahri ABACI 22 Nisan 2014 07:37
Merhabalar, Ben sorunun yazma konusunda olacağını sanmıyorum. Konvolüsyon hesabında çoğu zaman düştüğümüz hata değerlerin normalize olmaması. Yani defter ve kitaplarda yer alan ve yumuşatma çekirdeği olarak geçen f=[1,1,1...] tarzı filtreler resmin maksimum değerinin 255 den büyük (beyaz) veya f=[-1,-2,-1,0,..] gibi filtreler ise düşük (siyah) olmasına neden oluyor. Bir diğer konu ise filtreler normalize dahi olsa bu şekilde değerlerin oluşabileceğidir, bunu döngüler yardımıyla kontrol etmez isek -5 (10000101) yazılması gereken yere, türümüz unsigned (işaretsiz char) olduğu için 250 (10000101) yazıılacaktır. Linkte verdiğim örnek resim üzerinde dik kenarları bulmaya çalışan bir sobel filtreleme işlemi. Sizin kodunuzdaki farklılıkları da bu kodu referans alarak bulabilirsiniz. https://dl.dropboxusercontent.com/u/52989937/cescript/Projeler/ornek2.zip
YanıtlaSil
Yanıtlar
Yanıtla
Unknown 22 Nisan 2014 23:52
hocam merhabalar kodunuzu denedim. gercekten kütüphanesini cok iyi hazırlamışsınız ama sanırım kodları kullanırken extradan bazı kodarda eklemek gerekiyor. cünki farklı bir kac filtrede biraz sıkınıtılı calıştı. buda benim hazırladığın kod yukarda dediğim gibi nerde hata yaptığımı bir türlü anlayamıyorum bahsettiğiniz durumuda ayrıca sorgulatıyorum ama değişen bişey yok ne yazıkki, vektiniz varsa eğer inceleyip hatamı söylerseniz cok sevinirim şimdiden teşekkürler. https://www.dropbox.com/s/k4pzbe2d9bdv9om/convulation.rar
YanıtlaSil
Yanıtlar
Bahri ABACI 23 Nisan 2014 16:22
Merhabalar, kodunuza hızlı bir bakma şansı buldum. Üst kısımda neler olduğunu çok anlayamadım ama muhtemel hata olan 3x3 içerisinde dönen 181. satırdaki for döngüsüne "{" açmayı ve 191. satırda "}" kapatmayı unutmuş olmanız. Bunu düzelterek denediğimde resimde keskinleştirme işleminin yapıldığını gördüm.
Kütüphane fonksiyonunda muhtemelen gördüğünüz hata filtre={1/9,1/9,....} olduğu durumda oluşan siyah imge hatası veya benzer bir hatadır. Bu aslında 1/9 un c standartlarında 0.11 yerine integer olarak 0 almasından kaynaklanıyor. O nedenle genelde örneklerimi tam sayılar üzerinden yapıyorum, eğer 1/9, 1/4 gibi değerler kullanılacaksa 1.0/9, 1/4.0 diyerek işlemin double türünde yapıldığını belirtebilirsiniz. Bunun haricinde bir hata var ise belirtmeniz durumunda fonksiyonu düzenlemek isterim.
Sil
Yanıtlar
Yanıtla
Yanıtla
Unknown 26 Nisan 2014 01:18
merhabalar hocam vizelerim başladıda ondan biraz gec cevap yazdım kusura bakmayın. şimdi ben sizin kodlarınızla bir kac deneme yaptım aynı zamanda basic te yazılmış konvolasyon yapan başka bir filtre örneği ile karşılaştırdım. sonuclar birbirinden cok farklı cıkıyor. aynı filte değerlerini sizin kodunuzda kullandığımda yada kendi yazdığım kodda kullandığımda birbirinden cok farklı değerler oluyor. söyle bir durumu merak ettim acaba filtre değerleri yazılan kodlara göre özel olarak ayarlanması mı gerekiyor örneğin benim kodumdaki kenar bulma filtresini sizin yazdığınız kodda kullanıldığımda beklenen filteyi yapmaması normal bir durum mu. benim yazdığım koda özel filtre matrisleri mi belirlemem lazım. bide hocam sizin kullandığınız filtere değerlerinden birkac örnek verebilirmisiniz örneğin siz odaklamayı yada kabartmayı yaparken hangi değerleri kullanıyosunuz filtenizde. ben yukarda belirttiğiniz için sizin yazdığınız kodla birkac deneme yaptım onları size gönderiyorum aynı zamanda aynı değerler kullanarak diğer filtrenin sonuclarıda koydum bakıp farklılığın sebebini söylerseniz sevinirim. yani sizin kodda filtreleme için extra işlemler mi gerekiyo acaba farklı olmasının sebebi budur belkide. hocam bide unutmadan keskinleştirme için hangi değerleri kullandınız siz onuda verebilirmisiniz bana. teşekkür ederim ayrıca zamanınızı ayırdığınız için..:)
https://www.dropbox.com/s/s5cjxhlnfg5m8t4/FİLTELEME.rar
YanıtlaSil
Yanıtlar
Yanıtla
Bahri ABACI 28 Nisan 2014 17:35
Merhabalar, ben de işlerin yoğunluğundan vakit ayıramadım pek. Öncelikle konvolüsyon tek bir işlemdir ve resimden resime farklılıklar göstermez. Yalnız burada kullanılan çekirdek matrisine dikkat etmek gerekir. Gönderdiğiniz dosyada dikka ederseniz renkler ya çok beyaz yada çok siyah olmuş. Bu kullanılan çekirdek matrisin normalize olmadığını gösterir. Mesela yumuşatma için filtre[0]=1.0/9;
filtre[1]=1.0/9;
filtre[2]=1.0/9;
filtre[3]=1.0/9;
filtre[4]=1.0/9;
filtre[5]=1.0/9;
filtre[6]=1.0/9;
filtre[7]=1.0/9;
filtre[8]=1.0/9;
Şeklinde bir çekirdek kullanırsanız, referans imgeleriniz ile aynı sonucun çıktığını görebilirsiniz. Dikkat etmeniz gereken nokta filtrenin toplamının ya 0 yada 1 olması gerektiğidir. Basic dosyasında verilen çekirdekler küsüratlı olmaması için tamsayı olarak verilmiş. filtre=[1 1 1...] gibi. cbmp verilen çekirdeğin normalize olduğunu varsaydığından farklılıklar oluşmuş.
Diğer bir kaç çekirdek ile de
filtre[0]=-1.0/3;
filtre[1]=0.0;
filtre[2]=-1.0/3;
filtre[3]=0.0;
filtre[4]= 7.0/3;
filtre[5]=0.0;
filtre[6]=-1.0/3;
filtre[7]=0.0;
filtre[8]=-1.0/3;
Odaklanma gibi programı test ettim ve GIMP programını referans alarak gözle görülür bir fark olmadığını gördüm. Unsharp mask filtresi içinse de GIMP ile aynı sonuçları almama rağmen gönderdiğiniz referans imgeye benzer bir sonuç elde edemedim.
YanıtlaSil
Yanıtlar
Yanıtla
Unknown 7 Mayıs 2014 23:15
hacam merhabalar, cok teşekkür ederim yardımlarınız için. suan söylediklerinizi dikkate alarak yeni bişeyler üzerinde çalışıyorum.
YanıtlaSil
Yanıtlar
Yanıtla
Unknown 14 Aralık 2014 23:48
Hocam merhabalar rahatsız ettim. biz C++ da fotoğrafı işleyip içerisindeki sayıları bulup onlarla ilgili işlemler yapacağız. bunun için neyi araştırmamız gerekiyo ne ile yapılıyo biliyorsanız yardım edebilir misiniz. şimdiden teşekkür ederiz iyi akşamlar
YanıtlaSil
Yanıtlar
Bahri ABACI 15 Aralık 2014 12:48
Merhabalar,
Öncelikle hangi programlamaa aracını kullanacağınız önemli.
OpenCV de http://opencv-code.com/tutorials/how-to-read-the-digits-from-a-scratchcard/ projesi sizin için başlangıç olabilir.
CBMP kütüphanesi kullanacak iseniz adımlar Okuma->Eşikleme->Bağlantılı Bileşen Etiketleme->Kapalı Bölge Bulma->En Yakın Komşu Sınıflandırması şeklinde verilebilir.
Örnek olarak sudoku üzerinden rakamları bulup tanıyan bir sistem http://www.aishack.in/tutorials/sudoku-grabber-with-opencv-extracting-grid/ bloğunda anlatılmakta.
Hazır kütüphane olarak da http://jocr.sourceforge.net/ ve https://code.google.com/p/tesseract-ocr/ yaygın kullanılan kütüphaneler.
Sil
Yanıtlar
Yanıtla
Unknown 15 Aralık 2014 15:01
hocam öncelikle cevap verdiğiniz için çok teşekkür ederim.acaba hangi programlama aracında yazmamızı önerirsiniz.biz raspberry pi da kullanacağız.yardımcı olursanız çok seviniriz.iyi günler dilerim
Sil
Yanıtlar
Yanıtla
Bahri ABACI 15 Aralık 2014 17:25
Konuyla ilgili daha önce yapmış olduğunuz çalışmalar var ve konuya hakimseniz CBMP yi kullanabilirsiniz. Ben çalışmalarımda bu kütüphaneyi kullanıyorum ve Raspberry üzerinde performans açısından iyi sonuçlar yakaladım.
Diğer yandan OpenCV yi RaspberryPi üzerinde derlemek 10 saate yakın bir süre gerektiriyor.
Ancak kolay ve hızlı bir şekeilde kodlamak istiyorsanız OpenCV yi tercih edin derim. 3-4 tane temel fonksiyonu kullanarak OCR işlemini kolaylıkla yapabilirsiniz.
Sil
Yanıtlar
Yanıtla
Yanıtla
Adsız 5 Şubat 2017 02:21
"Bu değer BMP resmi içerisinde 10.baytta yazılıdır(24 bit BMP için bfoffset=54)." demişsiniz hocam. Doğrusu 11.bayt olmalı sanırım. Kolay gelsin.
YanıtlaSil
Yanıtlar
Adsız 5 Şubat 2017 04:30
Düzeltme: baytlar sayılırken 0'dan başlanıyormuş.
Sil
Yanıtlar
Yanıtla
Yanıtla
Unknown 12 Şubat 2017 04:05
Hocam öncelikle merhaba, byte padding=4-(3*bminfo.width)%4; burada padding değerini bulurken neden 3 bayta göre hesap yaptık? Neden 3 ile çarptık 4 ile çarpmamız gerekmez miydi? Alpha kanalını neden gözardı ettik? Aydınlatırsanız sevinirim. Kolay gelsin...
YanıtlaSil
Yanıtlar
Bahri ABACI 12 Şubat 2017 11:06
Merhabalar, yukarıda verdiğim kod sadece 24 bit bmp resimleri okumak için geçerli. Resim 32 bit olarak kaydedilmişse yapı tamamamen değiştiğinden farklı bir kod yazmak gerekmekte. O yüzden fonksiyonları yazarken resmin kesinlikle 24 bit olduğunu varsayarak bazı basitlestirmeler yapmaya çalıştım.
Sil
Yanıtlar
Yanıtla
Yanıtla
Unknown 12 Şubat 2017 13:14
Tekrar merhaba, sorum zaten sizin kodunuzla alakalı idi.
typedef struct RGBA {
byte blue;
byte green;
byte red;
byte alpha;
};
Burada tanımladığınız yapıda alpha'yı da tanımlamışsınız. Fakat hesaplarda veya okumada alpha'yı gözardı etmişsiniz. Ben görüntü işleme alanında yeniyim; bu olay kafamı karıştırdı. Acaba kodda ileriye dönüklük amacı mı güdüldü? (ufak değişiklikler yapılarak 32-bit bmp resimleri de okusun gibi.)
YanıtlaSil
Yanıtlar
Bahri ABACI 12 Şubat 2017 13:49
Evet aynen söylediğiniz gibi daha sonra alpha kanalına ihtiyaç duyabilirim diye alpha kanalını eklemiştim. Amacım 32 bit imgeleri okumaktan veya yazmaktan ziyade imgeye efekt uygularken kullanmaktı bu kanalı ama sanırım hiç kullanmadım. Bu haliyle dediğiniz gibi sadece kafa karıştırıcı olmuş.
Sil
Yanıtlar
Yanıtla
Unknown 12 Şubat 2017 16:34
Kafamdaki karmaşıklığa son verdiğiniz için teşekkürler :)
Sil
Yanıtlar
Yanıtla
Yanıtla
Unknown 10 Eylül 2018 14:55
Merhaba Hocam,
Daha öncesinde örnek projeler paylaşmışsınız ama onlara erişemiyorum. Kodları derlemede bende sorun yaşadım. Rica etsem örnekleri tekrar paylaşabilir misiniz? Bu arada paylaştığınız bilgiler için teşekkür ederim.
YanıtlaSil
Yanıtlar
Yanıtla
Yorum ekle
Daha fazlasını yükle...
Sonraki Kayıt Önceki Kayıt Ana Sayfa
Faydalı Bloglar
Google Research Blog
General and Scalable Parallelization for Neural Networks - Posted by Yuanzhong Xu and Yanping Huang, Software Engineers; Google Research, Brain Team Scaling neural networks, whether it be the amount of training da...
Kaggle | Yapay Öğrenme Yarışmaları
Triple GM Abhishek Thakur Answers Qs from the Kaggle Community - Last week we crowned the world’s first-ever Triple Grandmaster, Abhishek Thakur. In a video interview with Kaggle Data scientist Walter Reade, Abhishek ans...
Wolfram Alpha | Bilgi Motoru
Find All Wolfram News in One Place—The Wolfram Blog - This is the final post here at the Wolfram|Alpha Blog. Approximately six and a half years ago our launch team started the Wolfram|Alpha blog just prior to ...
Kelimeler Benim | Keyifli Vakit
-
Popüler Yayınlar
Piksel Kavramı ve Bmp Formatı
Piksel : Picture Element birleşik kelimesinden türetilmiş ve sayısal görüntülerin en küçük noktasını tanımlayan bir kelimedir. Resim : Orga...
Morfolojik Görüntü İşleme
Morfolojik görüntü işleme şekillerin biçimsel yapısı ile ilgilenerek nesneleri ayırt etmemize ve gruplayabilmemize olanak sağlar. Yöntem gri...
C++ BMP Okuma
BMP ile ilgili teorik bilgileri bir önceki yazım da vermiştim. Bu yazımda ise C++ ile bir BMP resmini açıp,resme ait temel bilgilere eriş...
Histogram İşlemleri
Histogram, sayısal bir resim içerisinde her renk değerinden kaç adet olduğunu gösteren grafiktir. Bu grafiğe bakılarak resmin parlaklık ...
Otsu Metodu ile Adaptif Eşikleme
Eşikleme yada ikili tonlama gri tonlanmış bir resmin siyah-beyaz (ikili) uzaya dönüştürülmesi işlemidir. Siyah-beyaz görüntüler, görüntü üze...
Gelecek Yayınlar
Temel Bileşen Analizi (PCA)
İmge Filtre Çeşitleri (Sobel, Prewitt, DoG, vs.)
Algoritma Hızlandırma Yöntemleri
Hough Dönüşümü ile Yuvarlak Bulma
Optimizasyon Yöntemleri
Parmak İzi Tanıma
Genetik Algoritmalar
Görüntü işleme ile ilgili yeni yazıları ve bu sitede yer alan yazıların güncellenmiş sürümlerini www.imlab.io veya cescript.github.io adreslerinden takip edebilirsiniz.