ismailari.com

İsmail Arı'nın anasayfası

‘opencv’ etiketi için arşiv.

Erguvan yeniden!

3 yorum yapıldı

Kısa bir süre önce,  istediğimiz renkler dışındaki pikselleri MATLAB kullanarak nasıl siyah-beyaz yapabiliriz konusunda bir yazı yazmıştım. Yazıda erguvan rengini geçiren, diğer renkleri ise söndüren bir kod yazmıştık. Hatırlarsanız, yazıyı önemli bir uyarı ile bitirmiştik. Uyarıya uymayıp da denemek isteyen ama MATLAB'ı olmadığı için bu kodu çalıştıramayan çılgın maşuklar varsa üzülmesinler; okurlarımızdan A. Tahir İnce'nin önerisi üzerine bu yazıda aynı işlemi OpenCV'yi kullanarak yapacağız.

OpenCV diyorum ama aslında OpenCV2'yi, yani C++ arayüzünü kastediyorum. Zira, OpenCV'nin C fonksiyonlarından oluşan eski haliyle yazmayı hiç özlemiyorum. Neyse, Boğaziçi'nin simgesi dediğimiz erguvan resmimizi hatırlayalım:

Önceki yazıda ne yaptığımızı tekrar edelim. RGB uzayında çalışmak yerine, öncelikle resmi HSV uzayına attık. H (renk) kanalının değerlerine bakarak bir maske oluşturduk. H kanalının değerleri 0-360 derece arasında ise, erguvan rengine ait değerler 300-340 derece arasındaydı. Bunu da renklerin histogramını çizerek görmüştük. Daha sonra, oluşturduğumuz maskeyi kullanarak S (doygunluk) kanalındaki erguvan olmayan pikselleri sıfırlamış, yani bu pikselleri siyah beyaz yapmıştık. Ardından resmi özgün uzaya geri çevirmiştik. OpenCV'de de aynı işlemi yapacağız. Tek fark, S kanalının 0-360 derece arasında olması yerine 0-180 derece arasında olması. Dolayısıyla bizim istediğimiz sınırlar da öncekilerin yarısı olacak.

Lafı fazla uzatmadan kodu toptan vereyim, yorumlar da açıklamaları olsun:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

void erguvan(cv::Mat& resim) {

    // Renk uzayını HSV'ye dönüştürelim.
    cv::cvtColor(resim, resim, CV_BGR2HSV);

    // Renkli resmi kanallara ayıralım: Hue (renk tonu),
    //  Saturation (doygunluk), Value (aydınlık).
    std::vector kanallar;
    cv::split(resim, kanallar);

    // Maskeyi oluşturalım
    //  Renk tonu (ilk kanal) 0-180 derecelik bir açı içinde olacak. 0-360 derece
    //  arasında düşünürken 300-340 arası erguvan rengiydi, dolayısıyla burada tam
    //  yarısı olacak. Resimler için aşırıyüklü (overloaded) mantıksal işlemleri
    //  kullanarak tek satırda bu işi halledebildik.
    cv::Mat maske = (kanallar[0] < 150) | (kanallar[0] > 170);

    // Maske, erguvan dışında renge sahip olan pikseller için doğru (true),
    //  diğerleri için yanlış (false) oldu. Maskenin doğru olduğu yerlerin
    //  doygunluğunu 0'a çektik, yani bu pikselleri siyah-beyaz yaptık.
    kanallar[1].setTo(cv::Scalar(0), maske);

    // Kanalları geri birleştirelim ve resmi özgün uzayına geri çevirelim.
    cv::merge(kanallar,resim);
    cv::cvtColor(resim, resim, CV_HSV2BGR);
}

void main() {

    // Resmi okuyalım.
    cv::Mat resim = cv::imread("erguvan.jpg");

    // Ekrana çizdirelim.
    cv::namedWindow("Resim");
    cv::imshow("Resim", resim);

    // Erguvan dışındaki renkleri söndürelim.
    erguvan(resim);

    // Güncel resmi ekrana çizelim.
    cv::namedWindow("Resim 2");
    cv::imshow("Resim 2", resim);

    // Sonucu kaydedelim.
    cv::imwrite("erguvan2.jpg", resim);

    cv::waitKey();
}

Kod biraz uzun gibi görünse de çoğu satır yorumdan ibaret. Ve sonuç yine şahane!

6 Temmuz 2011, Kategori: Programlama, Etiketler: ,

OpenCV ile PCA (Temel Bileşenler Analizi)

Yorum yapılmadı

Bu yazı temel bileşenler analizinin OpenCV/C++ ile kodlanması üzerinedir. Temel bileşenler analizi hakkında detaylı teorik bilgi için tıklayınız.

Son zamanlarda en çok kullandığım yöntem Temel Bileşenler Analizi olabilir! MATLAB ve Python ile yapılan kodlamaları paylaşmıştım. Bugün C++ ile yazmam gerekiyordu. OpenCV'nin içinde olduğunu öğrenince ve kolaylıkla kullanıverince çok iyi oldu. Buradaki dokümantasyon bölümünde anlatılmış. Henüz Python'a port etmemişler, yeni OpenCV'nin C++ kısmında mevcut. Dokümantasyondaki örnek kod gayet anlaşılır:

PCA compressPCA(const Mat& pcaset, int maxComponents,
                const Mat& testset, Mat& compressed)
{
    PCA pca(pcaset, // veri
            Mat(), // önceden hesaplanmış bir ortalama vektörümüz yok,
                   // o halde PCA sınıfımız onu hesaplasın
            CV_PCA_DATA_AS_ROW, // vektörlerin matrisin satırlarında olduğunu bildir
                                // (sütunlarda olursa CV_PCA_DATA_AS_COL kullanın
            maxComponents // en çok kaç tane temel bileşen olduğunu ver
            );
    // eğer test verisi yoksa, hesaplanan baz vektörleri kullanım için döndür
    if( !testset.data )
        return pca;
    CV_Assert( testset.cols == pcaset.cols );

    compressed.create(testset.rows, maxComponents, testset.type());

    Mat reconstructed;
    for( int i = 0; i < testset.rows; i++ )
    {
        Mat vec = testset.row(i), coeffs = compressed.row(i);
        // vektörü sıkıştır. Sonuç çıktı matrisinin i. satırına yazılacak
        pca.project(vec, coeffs);
        // ve sonra geri oluştur
        pca.backProject(coeffs, reconstructed);
    }
    return pca;
}

PCA ile ilgili teorik bilgi için Google'a başvurabilirsiniz. Jonathon Shlens'in anlatımı çok güzel. Yayın hakkım olmadığı için burada paylaşamıyorum.

30 Temmuz 2010, Kategori: Programlama, Etiketler: , ,

Nümerik işlemler ve bilgisayarla görmek için Python

Yorum yapılmadı

Uzun süredir nümerik hesaplarım için IPython kabuğu ile Python'ın numpy modülünü kullanıyorum ve çok memnunum. Hele Opencv'nin güzel sürümündeki (svn'deki sürümü oluyor) matris yapısını numpy dizisine (ndarray) çevirebilince işlem kolaylığı ve çokluğu arttı, daha da şık oldu.

Bunun ne faydası var konusunda bir fikir vereyim. Opencv, içinde birçok bilgisayarla görme algoritmasını barındıran muhteşem bir açık kaynak kütüphane. Numpy, Matlab'ın Python muadili. Numpy neredeyse standart oldu ve tüm nümerik kütüphaneler onu destekliyor. Benim kullandığım en temel kütüphaneler grafik kütüphaneleri (matplotlib gibi) de Numpy destekli. Numpy'ın en güçlü yanı, dilimleme ("slicing") operatörü. Matlab kullananlar bunu bilir ve sever. Ayrıca işleri vektörlemek de mümkün. Kullanımı çok esnek. Opencv'de hazır fonksiyonları kullanmak çok kolay ama resimlerden istatistik falan toplayacaksanız işiniz Numpy sözdiziminde olduğu kadar kolay değil. Böyle bir çevirme işlemiyle ikisinin gücü birleşiyor. Bu arada, tüm bahsettiğim kütüphaneler platformdan bağımsız.

Şu anlık yalnızca float32 ve uint8 veri türlerini çevirdim.

def opencv2numpy(matIn):
    """Convert opencv matrix to numpy matrix (supports 1 and 3 channels currently)"""
    if matIn[0].type == cv.CV_8UC1 or matIn[0].type == cv.CV_8UC3:
        dtype = 'uint8'
    elif matIn[0].type == cv.CV_32FC1 or matIn[0].type == cv.CV_32FC3:
        dtype = 'float32'
    else:
        print "No support except float32 and uint8 yet"
        return 0

    if matIn[0].type == cv.CV_8UC3 or matIn[0].type == cv.CV_32FC3:
        matOut = np.fromstring(matIn.tostring(), dtype=dtype).reshape(matIn.height, matIn.width, 3)
    else:
        matOut = np.fromstring(matIn.tostring(), dtype=dtype).reshape(matIn.height, matIn.width)

    return matOut
def numpy2opencv(matIn):
    if matIn.ndim == 3 and matIn.shape[2] == 3:
        nChannels = 3
    else:
        nChannels = 1

    h,w = matIn.shape[0], matIn.shape[1]
    if matIn.dtype == "uint8":
        if nChannels == 1:
            dtype = cv.CV_8UC1
        else:
            dtype = cv.CV_8UC3
    elif matIn.dtype == "float32":
        if nChannels == 1:
            dtype = cv.CV_32FC1
        else:
            dtype = cv.CV_32FC3
    else:
        print "No support except float32 and uint8 yet"
        return 0

    matOut = cv.CreateMatHeader(h, w, dtype)
    if nChannels == 1:
        cv.SetData(matOut, matIn.data, w*matIn.itemsize)
    else:
        cv.SetData(matOut, matIn.data, w*4*matIn.itemsize)

    return matOut

Güncel işimi görmesi için yazdığımdan hataları olabilir, biraz da verimsiz oldu. Örneğin bir tarafa iyiyken, diğer tarafa verimsiz çeviriyor. Fakat benim için şu an bu öncelik konusu değil. "Exception" fırlatmam lazım ama hariçten gazel okumak zor geldi, işimi görüyor.

Kullanırsanız, genellerseniz veya geliştirirseniz lütfen benimle de paylaşın.

Güncelleme:

Opencv Python arayüzünde zaten hazırmış bu kod. Hem diğer veritipleri için de genellenmiş. Yenisi dönüşümler şöyle:

def cv2array(im):
    depth2dtype = {
        cv.IPL_DEPTH_8U: 'uint8',
        cv.IPL_DEPTH_8S: 'int8',
        cv.IPL_DEPTH_16U: 'uint16',
        cv.IPL_DEPTH_16S: 'int16',
        cv.IPL_DEPTH_32S: 'int32',
        cv.IPL_DEPTH_32F: 'float32',
        cv.IPL_DEPTH_64F: 'float64',
    }

    arrdtype=im.depth
    a = np.fromstring( im.tostring(),
                              dtype=depth2dtype[im.depth],
                              count=im.width*im.height*im.nChannels)
    a.shape = (im.height,im.width,im.nChannels)
    return a

def array2cv(a):
    dtype2depth = {
        'uint8':   cv.IPL_DEPTH_8U,
        'int8':    cv.IPL_DEPTH_8S,
        'uint16':  cv.IPL_DEPTH_16U,
        'int16':   cv.IPL_DEPTH_16S,
        'int32':   cv.IPL_DEPTH_32S,
        'float32': cv.IPL_DEPTH_32F,
        'float64': cv.IPL_DEPTH_64F,
    }
    try:
        nChannels = a.shape[2]
    except:
        nChannels = 1
    cv_im = cv.CreateImageHeader((a.shape[1], a.shape[0]),
                                                dtype2depth[str(a.dtype)],
                                                nChannels)
    cv.SetData(cv_im, a.tostring(),
    a.dtype.itemsize*nChannels*a.shape[1])
    return cv_im

8 Nisan 2010, Kategori: Programlama, Etiketler: , ,

MATLAB ile OpenCV'yi birlikte kullanmak

5 yorum yapıldı

Joaquim Luis tarafından yazılan ve benim de eklemeler yaparak geliştirdiğim bir kodu paylaşacağım. Önceki bir yazıda MPT araçkutusunu kullanarak bir resimdeki yüzleri ve gözleri bulmuştuk. Şimdi sadece yüzleri bulacağız ama bu sefer öyle saniyelerce beklemeden, bir saniyeden çok daha kısa bir sürede! Bunu da OpenCV'nin yüz bulma fonksiyonunu MATLAB'ten çağırarak başaracağız. Bunun dışında OpenCV'ye ait olan cvAbsDiff, cvAdd, cvAddS, cvAddWeighted, cvCanny, cvCircle, cvCvtColor, cvFindContours, cvCvtScale, cvDilate, cvDiv, cvApproxPoly, cvEllipseBox, cvErode, cvExp, cvFilter2D, cvFillPoly, cvFlip, cvFloodFill, cvGoodFeaturesToTrack, cvHoughLines2, cvHoughCircles, hypot, cvInpaint, cvLaplace, cvLine, cvLog, cvMatchTemplate, cvMorphologyEx, cvMul, cvPolyLine, cvPow, cvPyrDown, cvPyrUp, cvRectangle, cvResize, cvSmooth, cvSobel, cvSub, cvSubS ve cvPutText fonkiyonlarını da kullanabileceğiz. Bunların hepsini denemedim, garantisi yok. Neyse konuyu pek dağıtmayalım ve yüz bulmak için adımlara geçelim. O kısmını ben ekledim. Diğer fonksiyonların kullanımı için kaynaklarına bakarsınız.

Yazının tamamını okuyun »

10 Haziran 2008, Kategori: Programlama, Etiketler: ,