OpenGL ile ikili görüntülerdeki köşeleri nasıl tespit edebilirim?


13

Ben gibi ikili 160x120 görüntüler var:

gerçek görüntü

Bu beyaz lekelerin köşelerini tespit etmek istiyorum. Daha önce matematiksel morfoloji ile kapatılmışlardır, bu nedenle iç köşeleri olmamalıdır. Bu özel durumda, 16 köşe istiyorum, örneğin:

köşe algılama örneği

İlk denemem goodFeaturesToTrack veya FAST gibi bazı OpenCV işlevlerini kullanmaktı, ancak özellikle yavaşlar (artı FAST çok kararsız). Benim fikrim GPU'da böyle bir hesaplama yapmak olurdu, çünkü kaynak imajım ondan geliyor. Web'de bu tür gölgelendiricilerin nasıl yazılacağı konusunda fikirler aradım (OpenGL ES 2.0 kullanıyorum), ancak somut bir şey bulamadım. Böyle bir algoritmayı nasıl başlatabileceğim hakkında bir fikrin var mı?


2
HIZLI yavaş mı? :)
22'de endolit

1
evet, komik değil mi? aslında, SURF veya SIFT gibi emsal algoritmalardan daha hızlıdır, ancak daha az hassastır, bir görüntüden diğerine oldukça kararsızdır ve CPU'da yapılacak kadar hızlı değildir
Stéphane Péchard

Bunları her karede doğru bir şekilde tespit etmek ne kadar önemlidir? Dikdörtgenler ne kadar hızlı hareket ediyor? Çoğu karedeki köşeleri tespit etmek ve algoritmanın kaçırdığı karelere enterpolasyon uygulamak uygun mudur?
justis

@justis iyi, şu anda bunu yapma şeklim (OpenCV'nin cvFindContours () ve cvApproxPoly () işlevlerini kullanarak) zamanla çok kararlı değil, bu yüzden sonucu gecikme getiren düşük geçişli bir filtreyle filtreliyorum. İnterpolasyonla daha kararlı bir sonuç elde edebileceğimi düşünüyor musunuz?
Stéphane Péchard

Yanıtlar:


3

Hangi boyutta görüntüler üzerinde çalışıyorsunuz? Hangi kare hızında? Hangi donanımda? HIZLI güzel, erm, hızlı benim deneyim.

Ayrıca FAST'ın tüm görüntüde gFTT'nin cezasını çalıştırmadan daha iyi istikrar sağlamak için tanımlanan ROI'larda goodFeaturesToTrack ile çalışan bir ROI dedektörü olarak kullanıldığını gördüm.

"Harris" köşe dedektörü çok basit operasyonlar oluşur gibi potansiyel çok hızlı da (örneğin piksel başına hiçbir sqrt ()!) - değil gFTT olarak istikrarlı olarak, ama muhtemelen daha çok FAST daha.

(GPU uygulaması açısından, Google'da gpu corneroldukça fazla bağlantı var gibi görünüyor, ancak ne kadar uygun olabilecekleri hakkında hiçbir fikrim yok - FPGA'da uygulama eğilimindeyim.)


Resimlerim 160x120, sözde bir iPhone'da 30 fps'de, ancak elbette, uygulamanın yapacak çok daha fazlası var :-) Böyle bir cihazda HIZLI oldukça hızlı bir şekilde bir uygulama gördüm, ama sadece bir demo oldu bunu yapıyorum ... Bu yüzden gpu tabanlı çözümlere bakıyorum.
Stéphane Péchard

15

Harris köşe algılamasını kullanarak OpenGL ES 2.0'da böyle bir şey uyguluyordum ve tamamen bitmemişken, şimdiye kadar sahip olduğum gölgelendirici tabanlı uygulamayı paylaşacağımı düşündüm. Bunu iOS tabanlı açık kaynak çerçevesinin bir parçası olarak yaptım , böylece belirli bir adımın nasıl çalıştığını merak ediyorsanız kodu kontrol edebilirsiniz.

Bunu yapmak için aşağıdaki adımları kullanıyorum:

  • Vektörle (0.2125, 0.7154, 0.0721) RGB değerlerinin bir nokta ürününü kullanarak görüntüyü parlaklık değerlerine düşürün.
  • Geçerli kanalın solunda, sağında ve üstünde ve altındaki piksellerden kırmızı kanal değerlerini çıkararak X ve Y türevlerini hesaplayın. Daha sonra kırmızı kanalda bulunan x türevini, yeşil kanalda bulunan Y türevini ve mavi kanalda X ve Y türevlerinin ürününü saklarım. Bunun için parça gölgelendirici aşağıdaki gibi görünür:

    precision highp float;
    
    varying vec2 textureCoordinate;
    varying vec2 leftTextureCoordinate;
    varying vec2 rightTextureCoordinate;
    
    varying vec2 topTextureCoordinate; 
    varying vec2 bottomTextureCoordinate;
    
    uniform sampler2D inputImageTexture;
    
    void main()
    {
     float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
     float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
     float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
     float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
    
     float verticalDerivative = abs(-topIntensity + bottomIntensity);
     float horizontalDerivative = abs(-leftIntensity + rightIntensity);
    
     gl_FragColor = vec4(horizontalDerivative * horizontalDerivative, verticalDerivative * verticalDerivative, verticalDerivative * horizontalDerivative, 1.0);
    }
    

    Burada varyasyonlar her yöndeki ofset doku koordinatlarıdır. Bu mobil GPU'larda kötü bir şekilde yavaş olan bağımlı doku okumalarını ortadan kaldırmak için tepe gölgeleyicisinde bunları önceden hesaplıyorum.

  • Bu türev görüntüye bir Gauss bulanıklığı uygulayın. Ayrılmış bir yatay ve dikey bulanıklık kullandım ve her geçişte yalnızca beş doku okuması ile dokuz vuruşlu bir bulanıklık yapmak için donanım doku filtrelemesinden faydalandım. Bu gölgelendiriciyi bu Stack Overflow yanıtında açıklıyorum .

  • Bulanık giriş türevi değerlerini kullanarak gerçek Harris köşe algılama hesaplamasını çalıştırın. Bu durumda, aslında Alison Noble tarafından Ph.D. tez "Görüntü Yüzeylerinin Tanımları". Bunu işleyen gölgelendirici aşağıdaki gibi görünür:

    varying highp vec2 textureCoordinate;
    
    uniform sampler2D inputImageTexture;
    
    const mediump float harrisConstant = 0.04;
    
    void main()
    {
     mediump vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;
    
     mediump float derivativeSum = derivativeElements.x + derivativeElements.y;
    
     // This is the Noble variant on the Harris detector, from 
     // Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45.     
     mediump float harrisIntensity = (derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z)) / (derivativeSum);
    
     // Original Harris detector
     //     highp float harrisIntensity = derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z) - harrisConstant * derivativeSum * derivativeSum;
    
     gl_FragColor = vec4(vec3(harrisIntensity * 10.0), 1.0);
    }
    
  • Yerel maksimum olmayan baskılama gerçekleştirin ve geçen pikselleri vurgulamak için bir eşik uygulayın. Merkezi bir pikselin mahallesindeki sekiz pikseli örneklemek ve bu gruplamada maksimum olup olmadığını belirlemek için aşağıdaki parça gölgelendiriciyi kullanıyorum:

    uniform sampler2D inputImageTexture;
    
    varying highp vec2 textureCoordinate;
    varying highp vec2 leftTextureCoordinate;
    varying highp vec2 rightTextureCoordinate;
    
    varying highp vec2 topTextureCoordinate;
    varying highp vec2 topLeftTextureCoordinate;
    varying highp vec2 topRightTextureCoordinate;
    
    varying highp vec2 bottomTextureCoordinate;
    varying highp vec2 bottomLeftTextureCoordinate;
    varying highp vec2 bottomRightTextureCoordinate;
    
    void main()
    {
        lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;
        lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
        lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
        lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
        lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;
        lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;
        lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;
        lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;
        lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
    
        // Use a tiebreaker for pixels to the left and immediately above this one
        lowp float multiplier = 1.0 - step(centerColor.r, topColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);
        multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);
    
        lowp float maxValue = max(centerColor.r, bottomColor);
        maxValue = max(maxValue, bottomRightColor);
        maxValue = max(maxValue, rightColor);
        maxValue = max(maxValue, topRightColor);
    
        gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);
    }
    

Bu işlem, nesnelerinizden şöyle görünen bir mısır haritası oluşturur:

Mısır haritası

Aşağıdaki noktalar, maksimum olmayan bastırma ve eşiklemeye dayalı köşeler olarak tanımlanır:

Tanımlanmış köşeler

Bu filtre için uygun eşikler ayarlandığında, köşeleri nesnenin gerçek kenarlarının içine piksel veya benzeri yerleştirme eğiliminde olmasına rağmen, bu görüntüdeki 16 köşenin tümünü tanımlayabilir.

Bir iPhone 4'te, bu köşe algılama, kameradan gelen 640x480 video karelerinde 20 FPS'de çalıştırılabilir ve bir iPhone 4S, bu boyuttaki videoları 60+ FPS'de kolayca işleyebilir. Bu gibi bir görev için CPU'ya bağlı işlemeden daha hızlı olmalı, ancak şu anda noktaları okuma işlemi CPU'ya bağlı ve olması gerekenden biraz daha yavaş.

Bunu eylemde görmek istiyorsanız, çerçevem ​​için kodu alabilir ve onunla birlikte gelen FilterShowcase örneğini çalıştırabilirsiniz. Harris köşe algılama örneği, cihaz kamerasından canlı videoda çalışıyor, ancak bahsettiğim gibi, şu anda CPU'da köşe noktalarının okunması gerçekten yavaşlıyor. Bunun için de GPU tabanlı bir sürece geçiyorum.


1
Çok hoş! Github'daki çerçevenizi takip ediyorum, gerçekten ilginç görünüyor, tebrikler!
Stéphane Péchard

Köşe koordinatlarını gerçekten CPU'ya nasıl geri alabileceğiniz bir yerde bir örneğiniz var mı? Bazı akıllı GPU yolu var mı veya işaretli pikselleri arayan bir bitmap aracılığıyla CPU üzerinde bir geri okuma ve daha sonra döngü gerektiriyor mu?
Quasimondo

@Quasimondo - Köşe algılaması için pikseller üzerinde CPU'ya bağlı yinelemeyi önlemek için nokta çıkarma için histogram piramitleri kullanmaya çalışıyorum: tevs.eu/files/vmv06.pdf . Son zamanlarda biraz dikkatim dağıldı, bu yüzden bunu bitirmedim, ama yakında istiyorum.
Brad Larson

Merhaba @BradLarson, bunun çok eski bir konu olduğunu biliyorum ve cevabınız için teşekkür ederim. GPUImage çerçevesinde KGPUImageHarrisCornerDetection.m dosyasını kontrol ettim. Görüntüden köşe konumunu ayıklamak için, görüntüyü arabelleğe okumak için glReadPixels'i kullandınız ve daha sonra, bir Array'da colotByte> 0 ile noktaları depolamak için buffer üzerinde döngü oluşturdunuz. Bunları GPU'da arabellek ve döngüde görüntüyü okumak zorunda olmadığımız bir şekilde yapmanın bir yolu var mı?
Sahil Bajaj

1
@SahilBajaj - Gördüğüm (ve henüz uygulama zamanı olmayan) bir teknik, bunun gibi seyrek görüntülerden noktaların hızlı bir şekilde çıkarılması için histogram piramitlerini kullanmaktır . Bu bunu önemli ölçüde hızlandıracaktır.
Brad Larson

3

Shi-Tomasi ve Moravec gibi "sağlam" köşe dedektörleri çok yavaştır. buradan kontrol edin - http://en.wikipedia.org/wiki/Corner_detection FAST muhtemelen yeterince iyi olan tek hafif köşe dedektörüdür. Maksimum olmayan baskılama yaparak FAST'ı geliştirebilirsiniz - en iyi "cornerness" skoru ile FAST çıktısını seçin (bunu hesaplamanın birkaç sezgisel yolu vardır, bunlara Mısırlılık skoru olarak Shi-Tomasi ve Moravec de dahildir) Ayrıca birkaç FAST dedektöründen de seçim yapabilirsiniz - FAST-5'ten FAST-12'ye ve FAST_ER'e (sonuncusu muhtemelen mobil cihazlar için çok büyük) Başka bir yol da FAST oluşturmanın FAST - yazar sitesinden FAST kod üreteci alması ve olası görüntüler kümesi üzerinde eğitilmesidir. http://www.edwardrosten.com/work/fast.html


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.