Görüntüde zebra benzeri desen bulma (Fotoğraftan yapılandırılmış ışık saçak merkez çizgisinin algılanması)


12

Saçakların bir nesneye yansıtıldığı ve fotoğrafın çekildiği bir projede çalışıyorum. Görev, saçak düzlemi ile özne yüzeyi arasındaki 3B kavşak eğrisini matematiksel olarak temsil eden saçakların merkez çizgilerini bulmaktır.

Fotoğraf bir PNG (RGB) ve eski denemelerde gri tonlama ve daha sonra, her saçaktaki her bir piksel sütununun orta noktasını bulmanın kolay olduğu siyah beyaz, "zebra benzeri" bir fotoğraf elde etmek için fark eşiği kullanıldı. Sorun şu ki, eşikleme ve ayrı bir piksel sütununun ortalama yüksekliğini alarak, hiç arzu edilmeyen bazı hassas kayıplar ve nicemleme yapıyoruz.

İzlenimlerim, görüntülere bakarak, eşiksiz görüntüden (RGB veya gri tonlamalı) doğrudan bazı istatistiksel süpürme yöntemiyle tespit edilirse, merkez çizgilerinin daha sürekli (daha fazla nokta) ve daha pürüzsüz (nicelleştirilmemiş) olabileceğidir. (bazı sel / yinelemeli evrişim, her neyse).

Aşağıda gerçek bir örnek resim bulunmaktadır:

resim açıklamasını buraya girin

Herhangi bir öneri çok takdir edilecektir!


çok ilginç. Ama bu arada, 3d nesneyi tespit etmek için renk şeridini kullanarak biraz araştırma yapıyorum. Çünkü renk şeridi kullanarak, her şeridin yazışmalarını projektörden bulmak kolaydır. Böylece trigonometri kullanılarak 3d bilgi hesaplanabilir. Renk aynıysa yazışmayı nasıl bulursunuz? Sanırım projeniz de 3B yeniden yapılanma hakkında mı?

@johnyoung: Lütfen cevap olarak yorum eklemeyin. Yorum yapabilmeniz için itibara ihtiyaç duyduğunuzu anlıyorum, ancak lütfen mevcut hareket tarzınızdan kaçının. Temsilcinizi artırmak için kendi (ilgili) sorularınızı sormanızı veya başkalarının sorularını yanıtlamanızı öneririm.
Peter K.

Cevap vermek yerine bir soru daha için üzgünüm, Faz kaydırma yönteminde yansıtılan görüntüdeki her pikselde fazı hesaplıyoruz, ama burada neden saçak merkez çizgisini bulmamız gerekiyor, benim sorum çok aptalca olabilir ama yapmıyorum Hayır, bu yüzden lütfen bana kesin nedeni söyleyin. U cevap verdikten sonra sorumu silebilir

Bunlar farklı yöntemlerdir. Bir dizi beyaz çizgi (her biri 3B alanda bir "düzlem" oluşturur) yansıtarak bir dizi geometrik düzlemi modelleniyorum. Bu nedenle, saçakların merkez çizgisini bulmam gerekiyor, çünkü uçakların kalınlığı yok. Tabii ki faz kayması analizi yapabilirim, ama bir sorun var: projeksiyonum ikili (siyah ve beyaz şeritler değişiyor), yoğunluk sinüzoidal olarak değişmiyor ve bu yüzden faz kayması yapamıyorum (ve şu anda yapmam gerekmiyor) ).
heltonbiker

Yanıtlar:


13

Aşağıdaki adımları öneririm:

  1. Ön planı arka plandan ayırmak için bir eşik bulun.
  2. İkili görüntüdeki her bir damla için (bir zebra şeridi), her biri xiçin ağırlıklı merkezi (piksel yoğunluğuna göre) yyönde bulun .
  3. Muhtemelen, ygürültüyü gidermek için değerleri düzeltin .
  4. (x,y)Bir tür eğri takarak noktaları bağlayın . Bu makale size yardımcı olabilir. Bence daha da kötüsü, yüksek seviyeli bir polinom da sığabilir.

İşte adım 1,2 ve 4'ü gösteren bir Matlab kodu. Otomatik eşik seçimini atladım. Bunun yerine kılavuzu seçtim th=40:

Sütun başına ağırlıklı ortalama bularak bulunan eğriler şunlardır: resim açıklamasını buraya girin

Bunlar bir polinom takıldıktan sonraki eğrilerdir: resim açıklamasını buraya girin

İşte kod:

function Zebra()
    im = imread('http://i.stack.imgur.com/m0sy7.png');
    im = uint8(mean(im,3));

    th = 40;
    imBinary = im>th;
    imBinary = imclose(imBinary,strel('disk',2));
    % figure;imshow(imBinary);
    labels = logical(imBinary);
    props =regionprops(labels,im,'Image','Area','BoundingBox');

    figure(1);imshow(im .* uint8(imBinary));
    figure(2);imshow(im .* uint8(imBinary));

    for i=1:numel(props)
        %Ignore small ones
        if props(i).Area < 10
            continue
        end
        %Find weighted centroids
        boundingBox = props(i).BoundingBox;
        ul = boundingBox(1:2)+0.5;
        wh = boundingBox(3:4);
        clipped = im( ul(2): (ul(2)+wh(2)-1), ul(1): (ul(1)+wh(1)-1) );
        imClip = double(props(i).Image) .* double(clipped);
        rows = transpose( 1:size(imClip,1) );
        %Weighted calculation
        weightedRows  = sum(bsxfun(@times, imClip, rows),1) ./ sum(imClip,1);
        %Calculate x,y
        x = ( 1:numel(weightedRows) ) + ul(1) - 1;
        y = ( weightedRows ) + ul(2) - 1;
        figure(1);
        hold on;plot(x,y,'b','LineWidth',2);
        try %#ok<TRYNC>
            figure(2);
            [xo,yo] = FitCurveByPolynom(x,y);
            hold on;plot(xo,yo,'g','LineWidth',2);
        end
        linkaxes( cell2mat(get(get(0,'Children'),'Children')) )
    end        
end

function [xo,yo] = FitCurveByPolynom(x,y)
   p = polyfit(x,y,15); 
   yo = polyval(p,x);
   xo = x;
end

bunu çok ilginç buldum. Python kullanıyorum, ama yine de tüm bunların gerekçelerini incelemek zorunda kalacağım. Bağımsız bir yorum olarak, klasik görüntü işleme (doğrudan uint8 dizileri gibi nicelenmiş görüntü kapları üzerine) yapma eğiliminde değilim, ancak işlemleri uygulamadan önce her şeyi kayan diziler olarak belleğe yüklerim. Ayrıca, görüntünüzün alt yarısındaki sonuçlardan şaşırdım, mavi çizgiler beklenen saçak orta çizgileri boyunca akmıyor ... (?). Şimdilik teşekkürler, sonuç alır almaz bazı geri bildirimler getireceğim!
heltonbiker

@heltonbiker, lütfen güncellenmiş cevabı kontrol edin. Kayan nokta hakkında haklısın, ben dönüştürdüğümde kullandım double. Alt yarıdaki sonuçlar hakkında, kontrol etmem gerekiyor, bir yazılım hatası olabilir
Andrey Rubshtein

1
@heltonbiker, bitti. Aslında 1 tabanlı indeksleme ile ilgili bir hataydı.
Andrey Rubshtein

Mükemmel! Gerçekten şaşırtıcı. Bu teknikle ve benim amacım için, düzeltmeye sadece ihtiyaç duyulmakla kalmayacak, aynı zamanda zararlı da olacaktır. İlginiz için çok teşekkürler!
heltonbiker

3

RGB görüntüsünü kullanmam. Renkli görüntüler genellikle kamera sensörüne genellikle elde edebileceğiniz çözünürlüğü azaltan bir "Bayer Filtre" koyarak yapılır .

Gri tonlamalı görüntüyü kullanırsanız, açıkladığınız adımların ("zebra" görüntüsünü ikileştirin, orta çizgiyi bulun) iyi bir başlangıç ​​olduğunu düşünüyorum. Son adım olarak,

  • Bulduğunuz orta hatta her noktayı alın
  • yukarıdaki ve altındaki "zebra" satırındaki piksellerin gri değerlerini alın
  • en küçük kareler kullanarak bu gri değerlere bir parabol takmak
  • bu parabolün tepe noktası orta hat pozisyonunun geliştirilmiş bir tahminidir

Güzel düşünceler. Her piksel sütununun tepe değerleri boyunca bir çeşit parabol veya spline kullanmayı planlıyorum, ancak yine de bir piksel sütununu veya bunun yerine bir piksel "bölgesini" incelemeniz gerekip gerekmediğini merak ediyorum ... daha fazla cevap. Şimdilik teşekkürler!
heltonbiker

@heltonbiker - hızlı bir test olarak sadece yeşil kanalı kullanın. Renk sensöründe normalde 2 kat daha fazla yeşil piksel vardır ve kırmızı ve maviden daha az interpoalized
Martin Beckett

@MartinBeckett İlginiz için teşekkürler, zaten her kanalı analiz ettim ve aslında yeşil kanal, kırmızı kanaldan çok daha kararlı görünüyor. Her kanal için dikey enine kesitlerin yoğunluk değerlerini çizmekle birlikte, "şerit deseni" kanallar arasında çok fazla değişmiyor gibi görünüyor ve şu anda gri tonlamaya dönüştürüldüğünde eşit olarak karıştırıyorum. Yine de, en iyi kontrast sonucunu elde etmek için kanallar arasındaki en iyi doğrusal kombinasyonu incelemeyi planlıyorum, VEYA zaten gri tonlamalı görüntüler elde etmeyi planlıyorum. Tekrar teşekkürler!
heltonbiker

3

Sorunuzu bir 'yol optimizasyonu sorunu' olarak modelleyerek sorununuza alternatif bir çözüm burada. Basit binarizasyon ve sonra eğri uydurma çözümünden daha karmaşık olmasına rağmen, uygulamada daha sağlamdır.

Çok yüksek seviyeden, bu görüntüyü bir grafik olarak düşünmeliyiz,

  1. her görüntü pikseli bu grafikteki bir düğümdür

  2. her bir düğüm, komşu olarak bilinen diğer düğümlere bağlanır ve bu bağlantı tanımı genellikle bu grafiğin topolojisi olarak adlandırılır.

  3. her düğümün, bu düğümün aradığımız en uygun merkez hatta olma olasılığını yansıtan bir ağırlığı (özellik, maliyet, enerji veya ne demek istersen) vardır.

Bu olasılığı modelleyebildiğimiz sürece, 'saçakların merkez çizgilerini' bulma probleminiz , grafik üzerinde , örneğin Viterbi algoritması gibi etkili bir şekilde çözülebilen yerel optimal yolları bulmak için soruna dönüşür .

İşte bu yaklaşımı benimsemenin bazı artıları:

  1. tüm sonuçlarınız sürekli olacaktır (bir orta çizgiyi parçalara ayırabilecek eşik yönteminin aksine)

  2. böyle bir grafik oluşturmak için birçok özgürlük, farklı özellikler ve grafik topolojisi seçebilirsiniz.

  3. sonuçlarınız yol optimizasyonları açısından en uygunudur

  4. çözümünüz gürültüye karşı daha sağlam olacaktır, çünkü gürültü tüm pikseller arasında eşit olarak dağıtıldığı sürece, bu optimum yollar sabit kalır.

İşte yukarıdaki fikrin kısa bir gösterimi. Nodların başlangıç ​​ve bitiş neyin mümkün olduğunu belirtmek için önceden herhangi bir bilgi kullanmadığımdan, olası her başlangıç ​​düğümünün wrt kodunu çözerim. Kod Çözülmüş Viterbi Yolları

Bulanık sonlar için, olası her bitiş düğümü için en uygun yolları aradığımızdan kaynaklanır. Sonuç olarak, karanlık alanlarda bulunan bazı düğümler için, vurgulanan yol hala yerel optimal yoludur.

Bulanık yol için, bulduktan sonra düzeltebilir veya ham yoğunluk yerine bazı düzgünleştirilmiş özellikler kullanabilirsiniz.

Başlangıç ​​ve bitiş düğümlerini değiştirerek kısmi yolları geri yüklemek mümkündür.

Bu istenmeyen yerel optimal yolları budamak zor olmayacaktır. Çünkü viterbi kod çözme işleminden sonra tüm yolların olasılığına sahibiz ve çeşitli ön bilgileri kullanabilirsiniz (örneğin, aynı kaynağı paylaşanlar için sadece tek bir optimal yola ihtiyacımız olduğunu doğru olarak görüyoruz.)

Daha fazla ayrıntı için makaleye bakabilirsiniz.

 Wu, Y.; Zha, S.; Cao, H.; Liu, D., & Natarajan, P.  (2014, February). A Markov Chain Line Segmentation Method for Text Recognition. In IS&T/SPIE 26th Annual Symposium on Electronic Imaging (DRR), pp. 90210C-90210C.

Yukarıdaki grafiği yapmak için kullanılan kısa bir python kodu parçası.


import cv2
import numpy as np
from matplotlib import pyplot
# define your image path
image_path = ;
# read in an image
img = cv2.imread( image_path, 0 );
rgb = cv2.imread( image_path, -1 );

# some feature to reflect how likely a node is in an optimal path
img = cv2.equalizeHist( img ); # equalization
img = img - img.mean(); # substract DC
img_pmax = img.max(); # get brightest intensity
img_nmin = img.min(); # get darkest intensity
# express our preknowledge
img[ img > 0 ] *= +1.0  / img_pmax; 
img[ img = 1 :
    prev_idx = vt_path[ -1 ].astype('int');
    vt_path.append( path_buffer[ prev_idx, time ] );
    time -= 1;
vt_path.reverse();    
vt_path = np.asarray( vt_path ).T;

# plot found optimal paths for every 7 of them
pyplot.imshow( rgb, 'jet' ),
for row in range( 0, h, 7 ) :
    pyplot.hold(True), pyplot.plot( vt_path[row,:], c=np.random.rand(3,1), lw = 2 );
pyplot.xlim( ( 0, w ) );
pyplot.ylim( ( h, 0 ) );

Bu çok ilginç bir yaklaşım. "Grafikler" konusunun yakın zamana kadar (aynı projede) sadece grafikleri kullanarak başka bir sorunu çözebileceğim için belirsiz olduğunu itiraf ediyorum. "Anladım" sonra, bu en kısa yol algoritmalarının ne kadar güçlü olabileceğini anladım. Fikriniz çok ilginç ve eğer ihtiyacım / fırsatım varsa bunu yeniden uygulamak imkansız değil. Çok teşekkür ederim.
heltonbiker

Mevcut sonuçlarınıza gelince, deneyimlerime göre, grafiği oluşturmadan önce görüntüyü gauss ve / veya medyan filtreyle düzeltmek muhtemelen daha iyi olacaktır. Bu çok daha düzgün (ve daha doğru) çizgiler verecektir. Ayrıca, olası bir hile iki veya daha fazla piksel (örneğin, 8 veya 10 piksel belirli bir sınıra kadar) üzerinde "doğrudan atlama" sağlamak için mahalleyi genişletmektir. Elbette uygun bir maliyet fonksiyonu seçilmelidir, ancak ayarlamanın kolay olduğunu düşünüyorum.
heltonbiker

Oh evet. Elimde bir şey seçtim, kesinlikle diğer topoloji ve enerji işlevlerini kullanabilirsiniz. Aslında, bu çerçeve de eğitilebilir. Özellikle, ham yoğunluk ile başlarsınız, optimum yollar için kod çözersiniz, sadece yüksek güvenleri olan bu optimal düğümleri alırsınız ve bu şekilde 'etiketli veriler' elde edersiniz. Otomatik olarak etiketlenmiş verilerin bu küçük kısmı ile birçok yararlı şeyi öğrenebilirsiniz.
pitfall

3

Cevabımı diğer yaklaşımlardan biraz farklı olduğu için yayınlamam gerektiğini düşündüm. Bunu Matlab'da denedim.

  • tüm kanalları toplayın ve bir resim oluşturun, böylece tüm kanallar eşit olarak tartılır
  • bu görüntü üzerinde morfolojik kapanma ve Gauss filtrelemesi gerçekleştirin
  • elde edilen görüntünün her bir sütunu için yerel maksimumu bulun ve bir resim oluşturun
  • bu resmin bağlı bileşenlerini bul

Burada gördüğüm bir dezavantaj, bu yaklaşımın şeritlerin bazı yönleri için iyi performans göstermeyeceğidir. Bu durumda, yönünü düzeltmeli ve bu prosedürü uygulamalıyız.

İşte Matlab kodu:

im = imread('m0sy7.png');
imsum = sum(im, 3); % sum all channels
h = fspecial('gaussian', 3);
im2 = imclose(imsum, ones(3)); % close
im2 = imfilter(im2, h); % smooth
% for each column, find regional max
mx = zeros(size(im2));
for c = 1:size(im2, 2)
    mx(:, c) = imregionalmax(im2(:, c));
end
% find connected components
ccomp = bwlabel(mx);

Örneğin, görüntünün orta sütununu alırsanız, profili şöyle görünmelidir: (mavi renk profildir. Yeşil renk yerel maksimum değerdir) orta profil ve yerel maksimum

Ve tüm sütunlar için yerel maksimumu içeren resim şöyle görünür: resim açıklamasını buraya girin

Bağlı bileşenler şunlardır (bazı çizgiler kırılmış olsa da, çoğu sürekli bir bölge alır):

resim açıklamasını buraya girin


Aslında şu anda yaptığımız şey budur, tek fark her bir piksel sütunu için yerel maksimumları nasıl bulacağımızdır: maksimum değer ve üst ve alt komşularıyla pikselden geçen parabolün kesin tepe noktasını bulmak için parabolik enterpolasyon kullanırız . Bu, sonucun çizgilerin ince yumuşaklığını daha iyi temsil eden pikseller arasında "olmasını" sağlar. Cevabınız için teşekkürler!
heltonbiker
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.