Perhatikan 10 gambar ini dari berbagai jumlah beras putih yang belum dimasak.
INI HANYA THUMBNAIL. Klik gambar untuk melihatnya dalam ukuran penuh.
Hitungan Gandum: A: 3, B: 5, C: 12, D: 25, E: 50, F: 83, G: 120, H:150, I: 151, J: 200
Perhatikan itu...
- Biji-bijian dapat saling menyentuh tetapi mereka tidak pernah tumpang tindih. Tata letak biji-bijian tidak pernah lebih dari satu butir.
- Gambar memiliki dimensi yang berbeda tetapi skala beras di semuanya konsisten karena kamera dan latar belakangnya diam.
- Butir tidak pernah keluar dari batas atau menyentuh batas gambar.
- Latar belakang selalu sama dengan warna kekuningan-putih.
- Biji-bijian kecil dan besar masing-masing dihitung sebagai satu butir.
5 poin ini adalah jaminan untuk semua gambar semacam ini.
Tantangan
Tulis sebuah program yang menghasilkan gambar-gambar tersebut dan, seakurat mungkin, menghitung jumlah butiran beras.
Program Anda harus mengambil nama file gambar dan mencetak jumlah butir yang dihitungnya. Program Anda harus bekerja untuk setidaknya satu dari format file gambar ini: JPEG, Bitmap, PNG, GIF, TIFF (sekarang semua gambar adalah JPEG).
Anda dapat menggunakan pemrosesan gambar dan perpustakaan visi komputer.
Anda tidak boleh membuat hardcode output dari 10 contoh gambar. Algoritme Anda harus berlaku untuk semua gambar padi-padian yang serupa. Seharusnya dapat berjalan dalam waktu kurang dari 5 menit pada komputer modern yang layak jika area gambar kurang dari 2000 * 2000 piksel dan ada kurang dari 300 butir beras.
Mencetak gol
Untuk masing-masing dari 10 gambar, ambil nilai absolut dari jumlah butir aktual dikurangi jumlah butir yang diprediksi program Anda. Jumlahkan nilai absolut ini untuk mendapatkan skor Anda. Skor terendah menang. Skor 0 sempurna.
Dalam hal ikatan, jawaban dengan suara terbanyak menang. Saya dapat menguji program Anda pada gambar tambahan untuk memverifikasi validitas dan akurasinya.
sumber
Jawaban:
Mathematica, skor: 7
Saya pikir nama fungsi cukup deskriptif:
Memproses semua gambar sekaligus:
Skornya adalah:
Di sini Anda dapat melihat sensitivitas skor wrt ukuran butir yang digunakan:
sumber
EdgeDetect[]
,DeleteSmallComponents[]
danDilation[]
diterapkan di tempat lain)Python, Skor:
2416Solusi ini, seperti solusi Falko, didasarkan pada pengukuran area "foreground" dan membaginya dengan area butiran rata-rata.
Sebenarnya, yang coba dideteksi oleh program ini adalah latar belakangnya, tidak sebanyak latar depan. Menggunakan fakta bahwa butiran beras tidak pernah menyentuh batas gambar, program dimulai dengan mengisi putih di sudut kiri atas. Algoritme banjir-isi mengecat piksel yang berdekatan jika perbedaannya dan kecerahan piksel saat ini berada dalam ambang tertentu, sehingga menyesuaikan dengan perubahan bertahap pada warna latar belakang. Pada akhir tahap ini, gambar mungkin terlihat seperti ini:
Seperti yang Anda lihat, ini cukup baik dalam mendeteksi latar belakang, tetapi tidak ada area yang "terperangkap" di antara butir. Kami menangani area ini dengan memperkirakan kecerahan latar belakang pada setiap piksel dan membuat semua piksel sama atau lebih cerah. Estimasi ini berfungsi seperti itu: selama tahap pengisian banjir, kami menghitung kecerahan latar belakang rata-rata untuk setiap baris dan setiap kolom. Perkiraan kecerahan latar belakang pada setiap piksel adalah rata-rata kecerahan baris dan kolom pada piksel tersebut. Ini menghasilkan sesuatu seperti ini:
EDIT: Akhirnya, area masing-masing daerah latar depan kontinu (yaitu non-putih) dibagi dengan rata-rata, pra-perhitungan, area biji-bijian, memberi kami perkiraan jumlah biji-bijian di wilayah tersebut. Jumlah dari jumlah ini adalah hasilnya. Awalnya, kami melakukan hal yang sama untuk seluruh area latar depan secara keseluruhan, tetapi pendekatan ini, secara harfiah, lebih berbutir halus.
Mengambil nama file input melalui baris perintah.
Hasil
sumber
avg_grain_area = 3038.38;
berasal?hardcoding the result
?The images have different dimensions but the scale of the rice in all of them is consistent because the camera and background were stationary.
Ini hanyalah nilai yang mewakili aturan itu. Hasilnya, bagaimanapun, berubah sesuai dengan input. Jika Anda mengubah aturan, maka nilai ini akan berubah, tetapi hasilnya akan sama - berdasarkan input.Python + OpenCV: Skor 27
Pemindaian garis horizontal
Ide: memindai gambar, satu baris setiap kali. Untuk setiap baris, hitung jumlah butiran beras yang ditemui (dengan memeriksa apakah piksel berubah menjadi hitam menjadi putih atau sebaliknya). Jika jumlah butir untuk baris meningkat (dibandingkan dengan baris sebelumnya), itu berarti kami mengalami butir baru. Jika angka itu berkurang, itu berarti kita melewati sebutir biji-bijian. Dalam hal ini, tambahkan +1 ke hasil total.
Karena cara algoritma bekerja, penting untuk memiliki gambar yang bersih, b / w. Banyak kebisingan menghasilkan hasil yang buruk. Latar belakang utama pertama dibersihkan menggunakan flofill (solusi mirip dengan jawaban Ell) kemudian ambang diterapkan untuk menghasilkan hasil hitam dan putih.
Ini jauh dari sempurna, tetapi menghasilkan hasil yang baik mengenai kesederhanaan. Mungkin ada banyak cara untuk memperbaikinya (dengan memberikan gambar b / w yang lebih baik, memindai ke arah lain (misalnya: vertikal, diagonal) dengan mengambil rata-rata dll ...)
Kesalahan per gambar: 0, 0, 0, 3, 0, 12, 4, 0, 7, 1
sumber
Python + OpenCV: Skor 84
Ini adalah upaya naif pertama. Ini menerapkan ambang adaptif dengan parameter yang disetel secara manual, menutup beberapa lubang dengan erosi dan pengenceran berikutnya dan memperoleh jumlah butir dari area latar depan.
Di sini Anda dapat melihat gambar biner menengah (hitam untuk latar):
Kesalahan per gambar adalah 0, 0, 2, 2, 4, 0, 27, 42, 0 dan 7 butir.
sumber
C # + OpenCvSharp, Nilai: 2
Ini adalah usaha kedua saya. Ini sangat berbeda dari upaya pertama saya , yang jauh lebih sederhana, jadi saya mempostingnya sebagai solusi terpisah.
Ide dasarnya adalah untuk mengidentifikasi dan memberi label setiap butir individu dengan fit elips iteratif. Kemudian hapus piksel untuk butiran ini dari sumber, dan coba temukan butir berikutnya, hingga setiap piksel dilabeli.
Ini bukan solusi yang paling cantik. Ini adalah babi raksasa dengan 600 baris kode. Perlu 1,5 menit untuk gambar terbesar. Dan saya benar-benar minta maaf atas kode yang berantakan.
Ada begitu banyak parameter dan cara untuk berpikir dalam hal ini sehingga saya cukup takut overfitting program saya untuk 10 sampel gambar. Skor akhir 2 hampir pasti adalah kasus overfitting: Saya memiliki dua parameter
average grain size in pixel
, danminimum ratio of pixel / elipse_area
, dan pada akhirnya saya hanya menghabiskan semua kombinasi dari dua parameter ini sampai saya mendapatkan skor terendah. Saya tidak yakin apakah ini halal dengan aturan tantangan ini.average_grain_size_in_pixel = 2530
pixel / elipse_area >= 0.73
Tetapi bahkan tanpa cengkeraman overfitting ini, hasilnya cukup bagus. Tanpa ukuran butir tetap atau rasio piksel, hanya dengan memperkirakan ukuran butir rata-rata dari gambar pelatihan, skor masih 27.
Dan saya mendapatkan sebagai output tidak hanya angka, tetapi posisi aktual, orientasi dan bentuk setiap butir. ada sejumlah kecil biji-bijian berlabel salah, tetapi secara keseluruhan sebagian besar label secara akurat cocok dengan biji-bijian asli:
A B C D E
F G H I J
(klik pada setiap gambar untuk versi ukuran penuh)
Setelah langkah pelabelan ini, program saya melihat setiap butir individu, dan perkiraan berdasarkan jumlah piksel dan rasio piksel / ellipse-area, apakah ini
Skor kesalahan untuk setiap gambar adalah
A:0; B:0; C:0; D:0; E:2; F:0; G:0 ; H:0; I:0, J:0
Namun kesalahan yang sebenarnya mungkin sedikit lebih tinggi. Beberapa kesalahan dalam gambar yang sama membatalkan satu sama lain. Gambar H khususnya memiliki beberapa butir yang salah label, sedangkan pada gambar E sebagian besar label benar
Konsepnya sedikit dibuat-buat:
Pertama latar depan dipisahkan melalui otsu-thresholding pada saluran saturasi (lihat jawaban saya sebelumnya untuk detail)
ulangi hingga tidak ada lagi piksel yang tersisa:
pilih 10 piksel tepi acak pada gumpalan ini sebagai posisi awal untuk sebuah butir
untuk setiap titik awal
anggap sebutir dengan tinggi dan lebar 10 piksel pada posisi ini.
ulangi sampai konvergensi
pergi secara radial ke luar dari titik ini, pada sudut yang berbeda, hingga Anda menemukan piksel tepi (putih-ke-hitam)
piksel yang ditemukan semoga menjadi piksel tepi dari satu butir. Cobalah untuk memisahkan inliers dari outlier, dengan membuang piksel yang lebih jauh dari elips yang diasumsikan daripada yang lain
berulang kali mencoba menyesuaikan elips melalui subset inliers, jaga elips terbaik (RANSACK)
perbarui posisi butir, orientasi, lebar dan tinggi dengan elips yang ditemukan
jika posisi butiran tidak berubah secara signifikan, hentikan
di antara 10 butir pas, pilih butir terbaik sesuai dengan bentuk, jumlah piksel tepi. Buang yang lain
hapus semua piksel untuk butir ini dari gambar sumber, lalu ulangi
akhirnya, lihat daftar butir yang ditemukan, dan hitung setiap butir baik sebagai 1 butir, 0 butir (terlalu kecil) atau 2 butir (terlalu besar)
Salah satu masalah utama saya adalah bahwa saya tidak ingin menerapkan metrik jarak elips penuh, karena menghitung itu sendiri merupakan proses berulang yang rumit. Jadi saya menggunakan berbagai solusi menggunakan fungsi OpenCV Ellipse2Poly dan FitEllipse, dan hasilnya tidak terlalu cantik.
Rupanya saya juga melanggar batas ukuran untuk codegolf.
Jawabannya terbatas pada 30000 karakter, saya saat ini di 34000. Jadi saya harus mempersingkat kode di bawah ini.
Kode lengkap dapat dilihat di http://pastebin.com/RgM7hMxq
Maaf untuk ini, saya tidak tahu bahwa ada batas ukuran.
Saya agak malu dengan solusi ini karena a) Saya tidak yakin apakah ini sesuai dengan semangat tantangan ini, dan b) terlalu besar untuk jawaban codegolf dan tidak memiliki keanggunan dari solusi lain.
Di sisi lain, saya cukup senang dengan kemajuan yang saya capai dalam pelabelan biji-bijian, tidak hanya menghitungnya, jadi ada itu.
sumber
C ++, OpenCV, skor: 9
Ide dasar metode saya cukup sederhana - cobalah untuk menghapus butiran tunggal (dan "butiran ganda" - butir 2 (tetapi tidak lebih!), Berdekatan satu sama lain) dari gambar dan kemudian menghitung sisanya menggunakan metode berdasarkan area (seperti Falko, Ell dan belisarius). Menggunakan pendekatan ini sedikit lebih baik daripada "metode area" standar, karena lebih mudah untuk menemukan nilai rata-rataPixelsPerObject yang baik.
(Langkah 1) Pertama-tama kita perlu menggunakan binarisasi Otsu pada saluran S gambar di HSV. Langkah selanjutnya adalah menggunakan operator dilatasi untuk meningkatkan kualitas latar depan yang diekstraksi. Daripada kita perlu menemukan kontur. Tentu saja beberapa kontur bukanlah butiran beras - kita perlu menghapus kontur yang terlalu kecil (dengan luas yang lebih kecil dari rata-rataPixelsPerObject / 4.. Sekarang akhirnya kita dapat mulai menghitung butiran :) (langkah ke-2) Menemukan butir tunggal dan ganda cukup sederhana - lihat saja daftar kontur untuk kontur dengan area dalam rentang tertentu - jika area kontur berada dalam jangkauan, hapus dari daftar dan tambahkan 1 (atau 2 jika itu butir "ganda") ke counter butir. (Langkah 3) Langkah terakhir tentu saja membagi area kontur yang tersisa dengan nilai rata-rataPixelsPerObject dan menambahkan hasil ke penghitung butir.
Gambar (untuk gambar F.jpg) harus menunjukkan ide ini lebih baik daripada kata-kata:
langkah pertama (tanpa kontur kecil (noise)):
langkah kedua - hanya kontur sederhana:
langkah ketiga - kontur yang tersisa:
Ini kodenya, ini agak jelek, tetapi harus bekerja tanpa masalah. Tentu saja OpenCV diperlukan.
Jika Anda ingin melihat hasil dari semua langkah, batalkan komentar semua fungsi panggilan imshow (.., ..) dan setel variabel fastProcessing menjadi false. Gambar (A.jpg, B.jpg, ...) harus dalam gambar direktori. Atau tentu saja Anda dapat memberikan nama satu gambar sebagai parameter dari baris perintah.
Tentu saja jika ada sesuatu yang tidak jelas saya dapat menjelaskannya dan / atau memberikan beberapa gambar / informasi.
sumber
C # + OpenCvSharp, skor: 71
Ini sangat menjengkelkan, saya mencoba untuk mendapatkan solusi yang benar-benar mengidentifikasi setiap butir menggunakan DAS , tetapi saya hanya. tidak bisa. mendapatkan. saya t. untuk. kerja.
Saya memilih solusi yang setidaknya memisahkan beberapa butir individu dan kemudian menggunakan biji-bijian itu untuk memperkirakan ukuran butir rata-rata. Namun sejauh ini saya tidak bisa mengalahkan solusi dengan ukuran butir hardcoded.
Jadi, sorotan utama dari solusi ini: tidak mengandaikan ukuran piksel yang tetap untuk biji-bijian, dan harus bekerja bahkan jika kamera dipindahkan atau jenis beras diubah.
Solusi saya berfungsi seperti ini:
Pisahkan latar depan dengan mengubah gambar menjadi HSV dan menerapkan ambang batas Otsu pada saluran saturasi. Ini sangat sederhana, berfungsi sangat baik, dan saya akan merekomendasikan ini untuk semua orang yang ingin mencoba tantangan ini:
->
Ini dengan bersih akan menghapus latar belakang.
Saya kemudian juga menghapus bayangan gandum dari latar depan, dengan menerapkan ambang batas tetap ke saluran nilai. (Tidak yakin apakah itu benar-benar banyak membantu, tapi itu cukup sederhana untuk ditambahkan)
Lalu saya menerapkan transformasi jarak pada gambar latar depan.
dan temukan semua maxima lokal dalam transformasi jarak ini.
Di sinilah ide saya rusak. untuk menghindari mendapatkan maxima lokal mutiple dalam butir yang sama, saya harus banyak menyaring. Saat ini saya hanya menyimpan maksimum terkuat dalam radius 45 piksel, yang berarti tidak setiap butir memiliki maksimum lokal. Dan saya tidak benar-benar memiliki pembenaran untuk radius 45 piksel, itu hanya nilai yang berfungsi.
(seperti yang Anda lihat, itu hampir tidak cukup biji untuk menjelaskan setiap butir)
Lalu saya menggunakan maxima tersebut sebagai seed untuk algoritma DAS:
Hasilnya meh . Saya berharap sebagian besar biji-bijian individu, tetapi rumpunnya masih terlalu besar.
Sekarang saya mengidentifikasi gumpalan terkecil, menghitung ukuran piksel rata-rata, dan kemudian memperkirakan jumlah butir dari itu. Ini bukan apa yang saya rencanakan untuk dilakukan di awal, tetapi ini adalah satu-satunya cara untuk menyelamatkan ini.
Sebuah tes kecil menggunakan pixel-per-grain ukuran hard-coded dari 2544,4 menunjukkan total kesalahan 36, yang masih lebih besar dari kebanyakan solusi lainnya.
sumber
HTML + Javascript: Skor 39
Nilai pastinya adalah:
Itu rusak (tidak akurat) pada nilai yang lebih besar.
Penjelasan: Pada dasarnya, menghitung jumlah piksel beras dan membaginya dengan rata-rata piksel per butir.
sumber
Upaya dengan php, Bukan jawaban skor terendah tetapi kode yang cukup sederhana
SCORE: 31
Penilaian diri
95 adalah nilai biru yang sepertinya berfungsi saat pengujian dengan GIMP 2966 adalah ukuran butir rata-rata
sumber