Menemukan pola seperti zebra pada gambar (Deteksi garis tengah terstruktur-cahaya dari foto)

12

Saya bekerja di proyek di mana pinggiran diproyeksikan terhadap subjek, dan foto diambil. Tugasnya adalah untuk menemukan garis tengah pinggiran, yang mewakili, secara matematis, kurva 3D persimpangan antara bidang pinggiran dan permukaan subjek.

Foto tersebut adalah PNG (RGB), dan upaya sebelumnya menggunakan skala abu-abu kemudian menentukan perbedaan untuk mendapatkan fotografi hitam-putih, "seperti zebra", dari mana mudah untuk menemukan titik tengah dari setiap kolom piksel di setiap pinggiran. Masalahnya adalah, dengan melakukan thresholding dan juga dengan mengambil tinggi rata-rata kolom piksel diskrit, kami mengalami beberapa kehilangan presisi dan kuantisasi, yang tidak diinginkan sama sekali.

Kesan saya, dengan melihat gambar, adalah bahwa garis tengahnya bisa lebih kontinu (lebih banyak titik) dan lebih halus (tidak dikuantisasi) jika terdeteksi langsung dari gambar yang tidak dibatasi (baik RGB atau skala abu-abu), dengan beberapa metode sapuan statistik (beberapa konvolusi banjir / iteratif, apa pun).

Di bawah ini adalah contoh gambar aktual:

masukkan deskripsi gambar di sini

Setiap saran akan sangat dihargai!

heltonbiker
sumber
itu sangat menarik. Tapi ngomong-ngomong, saya melakukan riset menggunakan strip warna untuk mendeteksi objek 3d. Karena menggunakan strip warna, mudah untuk menemukan korespondensi setiap strip dari proyektor. Jadi, dengan menggunakan trigonometri, informasi 3d dapat dihitung. Bagaimana Anda menemukan korespondensi jika warnanya sama? Saya kira proyek Anda juga tentang rekonstruksi 3d?
@johnyoung: Tolong jangan tambahkan komentar sebagai jawaban. Saya menyadari bahwa Anda memerlukan reputasi sebelum dapat berkomentar, tetapi tolong jangan melakukan tindakan apa pun saat ini. Saya sarankan untuk mengajukan pertanyaan Anda sendiri (terkait) atau menjawab pertanyaan orang lain untuk meningkatkan perwakilan Anda.
Peter K.
Maaf untuk satu pertanyaan lagi alih-alih memberikan jawaban, Dalam metode pergeseran fase kita menghitung fase pada setiap piksel dalam gambar yang diproyeksikan, tetapi di sini mengapa kita perlu mencari tahu garis tengah pinggiran, mungkin pertanyaan saya terlalu konyol tetapi saya tidak bukan itu, jadi tolong telepon aku alasan yang tepat. Anda dapat menghapus pertanyaan saya setelah memberikan jawaban
Ini adalah metode yang berbeda. Saya memodelkan serangkaian bidang geometris dengan memproyeksikan serangkaian garis putih (masing-masing membentuk "bidang" dalam ruang 3D). Jadi, saya perlu menemukan garis tengah pinggiran, karena pesawat tidak memiliki ketebalan. Tentu saya bisa melakukan analisis fase-shift, tetapi ada satu masalah: proyeksi saya adalah biner (garis-garis hitam dan putih berganti-ganti), intensitasnya tidak bervariasi secara sinusoidal, jadi saya tidak dapat melakukan pergeseran fase (dan tidak perlu, saat ini ).
heltonbiker

Jawaban:

13

Saya menyarankan langkah-langkah berikut:

  1. Temukan ambang untuk memisahkan latar depan dari latar belakang.
  2. Untuk setiap gumpalan dalam gambar biner (satu garis zebra), untuk masing-masing x, cari pusat yang ditimbang (dengan intensitas piksel) ke yarah.
  3. Mungkin, menghaluskan ynilainya, untuk menghilangkan noise.
  4. Hubungkan (x,y)titik - titik dengan memasang semacam kurva. Artikel ini mungkin membantu Anda. Anda juga dapat memuat polinomial tingkat tinggi, meskipun menurut saya lebih buruk.

Berikut adalah kode Matlab yang menunjukkan langkah 1,2 dan 4. Saya melewatkan pemilihan ambang otomatis. Sebagai gantinya saya memilih manual th=40:

Ini adalah kurva yang ditemukan dengan menemukan rata-rata tertimbang per kolom: masukkan deskripsi gambar di sini

Ini adalah kurva setelah pemasangan polinomial: masukkan deskripsi gambar di sini

Ini kodenya:

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
Andrey Rubshtein
sumber
Saya menemukan ini sangat menarik. Saya menggunakan Python, tapi saya harus mempelajari alasan dari semua ini. Sebagai komentar independen, saya cenderung tidak melakukan pemrosesan gambar klasik (langsung pada wadah gambar yang dikuantisasi seperti array uint8), tetapi memuat semuanya ke memori sebagai array float sebelum menerapkan operasi. Juga, saya terkejut dengan hasil dari bagian bawah gambar Anda, garis biru tidak berjalan di sepanjang garis tengah pinggiran yang diharapkan ... (?). Terima kasih untuk sekarang, saya akan membawa beberapa umpan balik segera setelah saya mendapatkan hasil!
heltonbiker
@heltonbiker, silakan periksa jawaban yang diperbarui. Anda benar tentang floating point, saya menggunakannya ketika saya dikonversi menjadi double. Tentang hasil di bagian bawah, saya perlu memeriksa, mungkin ada bug perangkat lunak
Andrey Rubshtein
1
@heltonbiker, sudah selesai. Itu memang bug yang terkait dengan pengindeksan berbasis 1.
Andrey Rubshtein
Sangat bagus! Luar biasa, memang. Dengan teknik ini, dan untuk tujuan saya, perataan tidak hanya tidak diperlukan, tetapi juga akan berbahaya. Terima kasih banyak atas minat Anda!
heltonbiker
3

Saya tidak akan menggunakan gambar RGB. Gambar berwarna biasanya dibuat dengan meletakkan "Bayer Filter" pada sensor kamera, yang biasanya mengurangi resolusi yang dapat Anda capai.

Jika Anda menggunakan gambar grayscale, saya pikir langkah-langkah yang Anda jelaskan (binarize "zebra" image, cari garis tengah) adalah awal yang baik. Sebagai langkah terakhir, saya akan melakukannya

  • Ambil setiap titik di garis tengah yang Anda temukan
  • ambil nilai abu-abu piksel dalam garis "zebra" di atas dan di bawah
  • paskan parabola dengan nilai-nilai abu-abu ini menggunakan kuadrat paling tidak berarti
  • puncak parabola ini adalah perkiraan posisi garis tengah yang lebih baik
Niki Estner
sumber
Pikiran yang bagus. Saya berencana untuk menggunakan semacam parabola atau spline di sepanjang nilai puncak dari setiap kolom piksel, tapi saya masih bertanya-tanya apakah saya harus memeriksa kolom piksel atau bukan "wilayah" piksel di sepanjang garis ... Akan menunggu beberapa saat lagi untuk lebih banyak jawaban. Terima kasih untuk sekarang!
heltonbiker
@heltonbiker - sebagai tes cepat hanya gunakan saluran hijau. Biasanya ada 2x lebih banyak piksel hijau pada sensor warna dan lebih sedikit interpoalted daripada merah dan biru
Martin Beckett
@ MartinBeckett Terima kasih atas minat Anda, saya sudah menganalisis setiap saluran, dan memang saluran hijau tampaknya jauh lebih terselesaikan daripada, katakanlah, saluran merah. Namun, merencanakan nilai intensitas penampang vertikal untuk setiap saluran, "pola garis" tampaknya tidak banyak berubah di antara saluran, dan saat ini saya mencampurkannya secara merata pada konversi ke skala abu-abu. Meskipun demikian, saya masih berencana untuk mempelajari kombinasi linear terbaik antara saluran untuk mendapatkan hasil kontras terbaik, ATAU untuk memperoleh gambar yang sudah dalam skala abu-abu. Terima kasih lagi!
heltonbiker
3

Inilah solusi alternatif untuk masalah Anda dengan memodelkan pertanyaan Anda sebagai 'masalah optimisasi jalur'. Meskipun lebih rumit daripada solusi binarization-dan-kemudian-kurva sederhana, itu lebih kuat dalam praktiknya.

Dari level yang sangat tinggi, kita harus mempertimbangkan gambar ini sebagai grafik, di mana

  1. setiap piksel gambar adalah simpul pada grafik ini

  2. setiap node terhubung ke beberapa node lain, yang dikenal sebagai tetangga, dan definisi koneksi ini sering disebut sebagai topologi dari grafik ini.

  3. setiap node memiliki bobot (fitur, biaya, energi, atau apa pun yang Anda ingin menyebutnya), mencerminkan kemungkinan bahwa node ini berada di garis tengah optimal yang kami cari.

Selama kita dapat memodelkan kemungkinan ini, maka masalah Anda menemukan 'garis tengah pinggiran' menjadi masalah untuk menemukan jalur optimal lokal pada grafik , yang dapat secara efektif diselesaikan dengan pemrograman dinamis, misalnya algoritma Viterbi.

Berikut adalah beberapa pro mengadopsi pendekatan ini:

  1. semua hasil Anda akan berkelanjutan (tidak seperti metode ambang batas yang mungkin memecah satu garis tengah menjadi beberapa bagian)

  2. banyak kebebasan untuk membangun grafik seperti itu, Anda dapat memilih fitur yang berbeda, dan topologi grafik.

  3. hasil Anda optimal dalam arti optimalisasi jalur

  4. solusi Anda akan lebih kuat terhadap noise, karena selama noise terdistribusi secara merata di antara semua piksel, jalur optimal tersebut tetap stabil.

Berikut ini demonstrasi singkat dari ide di atas. Karena saya tidak menggunakan pengetahuan sebelumnya untuk menentukan apa yang mungkin dimulai dan diakhiri node, saya cukup mendekodekan setiap node awal yang mungkin. Jalur Viterbi yang Didekodekan

Untuk akhiran fuzzy, ini disebabkan oleh fakta bahwa kami mencari jalur optimal untuk setiap simpul akhir yang mungkin. Akibatnya, meskipun untuk beberapa node yang terletak di daerah gelap, jalur yang disorot masih merupakan jalur lokal optimal.

Untuk jalur fuzzy, Anda bisa menghaluskannya setelah menemukannya atau menggunakan beberapa fitur yang dihaluskan alih-alih intensitas mentah.

Dimungkinkan untuk memulihkan jalur parsial dengan mengubah node awal dan akhir.

Tidak akan sulit untuk memangkas jalur optimal lokal yang tidak diinginkan ini. Karena kami memiliki kemungkinan semua jalur setelah decoding viterbi, dan Anda dapat menggunakan berbagai pengetahuan sebelumnya (misalnya kami melihat memang benar bahwa kami hanya memerlukan satu jalur optimal untuk mereka yang berbagi sumber yang sama.)

Untuk detail lebih lanjut, Anda bisa merujuk ke kertas.

 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.

Berikut ini adalah potongan pendek kode python yang digunakan untuk membuat grafik di atas.


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 ) );
batu sandungan
sumber
Ini adalah pendekatan yang sangat menarik. Saya mengakui bahwa topik "grafik" tidak jelas bagi saya sampai baru-baru ini ketika (pada proyek yang sama ini) saya hanya bisa menyelesaikan masalah lain menggunakan grafik. Setelah saya "mengerti", saya menyadari betapa kuatnya algoritma jalur terpendek ini. Ide Anda sangat menarik dan bukan tidak mungkin saya akan menerapkan kembali untuk yang satu ini jika saya memiliki kebutuhan / peluang. Terima kasih banyak.
heltonbiker
Adapun hasil Anda saat ini, dari pengalaman saya mungkin akan lebih baik untuk menghaluskan gambar terlebih dahulu dengan filter gaussian dan / atau median, sebelum membangun grafik. Ini akan memberikan garis yang lebih halus (dan lebih tepat). Juga, satu trik yang mungkin adalah memperluas lingkungan untuk memungkinkan "lompatan langsung" lebih dari dua piksel atau lebih (hingga batas tertentu, katakanlah, 8 atau 10 piksel). Tentu saja fungsi biaya yang sesuai harus dipilih, tetapi saya pikir itu mudah diatur.
heltonbiker
Oh ya. Saya hanya mengambil sesuatu di tangan, Anda pasti dapat menggunakan fungsi topologi dan energi lainnya. Sebenarnya, kerangka kerja ini juga bisa dilatih. Khususnya, Anda mulai dengan intensitas mentah, mendekode untuk jalur optimal, hanya mengambil node optimal dengan kepercayaan tinggi, dan dengan cara ini Anda mendapatkan 'data berlabel'. Dengan bagian kecil dari data berlabel otomatis ini Anda dapat mempelajari banyak hal bermanfaat.
perangkap
3

Pikir saya harus memposting jawaban saya karena agak berbeda dari pendekatan lain. Saya mencoba ini di Matlab.

  • jumlah semua saluran dan buat gambar, sehingga semua saluran diberi bobot yang sama
  • melakukan penutupan morfologis dan pemfilteran Gaussian pada gambar ini
  • untuk setiap kolom gambar yang dihasilkan, cari maxima lokal dan buat gambar
  • temukan komponen yang terhubung dari gambar ini

Satu kelemahan yang saya lihat di sini adalah bahwa pendekatan ini tidak akan bekerja dengan baik untuk beberapa orientasi garis. Dalam hal ini kita harus memperbaiki orientasinya dan menerapkan prosedur ini.

Berikut kode Matlab:

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);

Misalnya, jika Anda mengambil kolom tengah gambar, profilnya akan terlihat seperti ini: (warna biru adalah profil. Warna hijau adalah maksimum lokal) profil tengah dan maksimum lokal

Dan gambar yang mengandung maksimum lokal untuk semua kolom terlihat seperti ini: masukkan deskripsi gambar di sini

Berikut adalah komponen-komponen yang terhubung (meskipun beberapa garis putus-putus, sebagian besar dari mereka mendapatkan daerah kontinu):

masukkan deskripsi gambar di sini

dhanushka
sumber
Inilah sebenarnya yang sedang kami lakukan sekarang, dengan satu-satunya perbedaan adalah bagaimana menemukan maxima lokal untuk setiap kolom piksel: kami menggunakan interpolasi parabola untuk menemukan titik tepat parabola yang melewati piksel dengan nilai maksimum dan tetangganya yang atas dan bawah . Ini memungkinkan s untuk hasilnya menjadi "antara" piksel, yang lebih baik mewakili kelancaran garis halus. Terima kasih atas jawaban anda!
heltonbiker