segmentasi gambar gambar RGB dengan K berarti pengelompokan dalam python


8

Saya ingin mengelompokkan gambar RGB untuk tutupan lahan menggunakan k means clustering sedemikian rupa sehingga berbagai daerah gambar ditandai oleh warna yang berbeda dan jika batas yang mungkin dibuat memisahkan daerah yang berbeda. Saya menginginkan sesuatu seperti:

masukkan deskripsi gambar di sini

dari ini :

masukkan deskripsi gambar di sini

Apakah mungkin untuk mencapai ini dengan pengelompokan K-means? Saya telah mencari di seluruh internet dan banyak tutorial melakukannya dengan k berarti pengelompokan tetapi hanya setelah mengkonversi gambar ke skala abu-abu. Saya ingin melakukannya dengan gambar RGB saja. Apakah ada sumber yang bisa membantu saya memulainya? Tolong sarankan sesuatu.


Hai, coba tautan ini. Saya mencobanya beberapa waktu lalu, tetapi hanya memiliki keberhasilan yang terbatas. Mungkin Anda bisa membuatnya bekerja sedikit lebih baik. Semoga berhasil. opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/…
Jcstay

Hai, terima kasih atas saran Anda @ Jcstay tetapi saya sudah mencoba tautannya dan itu tidak membantu. Terima kasih.
rach

3
Saya akan menunjukkan bahwa algoritma K-means, seperti semua metode pengelompokan lainnya, kebutuhan dan kecocokan optimal k. Karena semua yang ada dalam data referensi akan diberikan sebuah kelas, jika k tidak dioptimalkan, hasilnya dapat keliru tanpa dukungan untuk kelas yang dihasilkan. Dalam kasus ini, kelas yang diberikan dapat mewakili tidak lain dari efek noise atau marginal dalam data. Umumnya, nilai-nilai siluet margin digunakan untuk memilih k yang optimal.
Jeffrey Evans

Jawaban:


9

Saya meretas solusi untuk ini dan menulis artikel blog beberapa waktu lalu pada topik yang sangat mirip, yang akan saya rangkum di sini. Script ini dimaksudkan untuk mengekstraksi sungai dari gambar NAIP 4-band menggunakan pendekatan segmentasi dan klasifikasi gambar.

  1. Konversi gambar ke array numpy
  2. Lakukan segmentasi pergeseran cepat (Gambar 2)
  3. Konversi segmen ke format raster
  4. Hitung NDVI
  5. Lakukan statistik zona rata-rata menggunakan segmen dan NDVI untuk mentransfer nilai NDVI ke segmen (Gambar 3)
  6. Klasifikasi segmen berdasarkan nilai NDVI
  7. Evaluasi hasil (Gambar 4)

Contoh ini mengelompokkan gambar menggunakan pengelompokan quickshift dalam ruang warna (x, y) dengan 4-band (merah, hijau, biru, NIR) daripada menggunakan pengelompokan K-means. Segmentasi gambar dilakukan menggunakan paket scikit-image . Rincian lebih lanjut tentang berbagai algoritma segmentasi gambar di scikit-image di sini . Demi kenyamanan, saya biasa arcpymelakukan banyak pekerjaan GIS, meskipun ini seharusnya cukup mudah untuk dipindahkan ke GDAL.


masukkan deskripsi gambar di sini


from __future__ import print_function

import arcpy
arcpy.CheckOutExtension("Spatial")

import matplotlib.pyplot as plt
import numpy as np
from skimage import io
from skimage.segmentation import quickshift

# The input 4-band NAIP image
river = r'C:\path\to\naip_image.tif'

# Convert image to numpy array
img = io.imread(river)

# Run the quick shift segmentation
segments = quickshift(img, kernel_size=3, convert2lab=False, max_dist=6, ratio=0.5)
print("Quickshift number of segments: %d" % len(np.unique(segments)))

# View the segments via Python
plt.imshow(segments)

# Get raster metrics for coordinate info
myRaster = arcpy.sa.Raster(river)

# Lower left coordinate of block (in map units)
mx = myRaster.extent.XMin
my = myRaster.extent.YMin
sr = myRaster.spatialReference

# Note the use of arcpy to convert numpy array to raster
seg = arcpy.NumPyArrayToRaster(segments, arcpy.Point(mx, my),
                               myRaster.meanCellWidth,
                               myRaster.meanCellHeight)

outRaster = r'C:\path\to\segments.tif'
seg_temp = seg.save(outRaster)
arcpy.DefineProjection_management(outRaster, sr)

# Calculate NDVI from bands 4 and 3
b4 = arcpy.sa.Raster(r'C:\path\to\naip_image.tif\Band_4')
b3 = arcpy.sa.Raster(r'C:\path\to\naip_image.tif\Band_3')
ndvi = arcpy.sa.Float(b4-b3) / arcpy.sa.Float(b4+b3)

# Extract NDVI values based on image object boundaries
zones = arcpy.sa.ZonalStatistics(outRaster, "VALUE", ndvi, "MEAN")
zones.save(r'C:\path\to\zones.tif')

# Classify the segments based on NDVI values
binary = arcpy.sa.Con(zones < 20, 1, 0)
binary.save(r'C:\path\to\classified_image_objects.tif')

2
Ini adalah solusi yang fantastis dan menghindari beberapa masalah dengan k-means dan menemukan k yang optimal.
Jeffrey Evans

Ini sangat bagus, kerja bagus !!
Jcstay

7

Anda bisa melihat pengelompokan di scikit-belajar . Anda perlu membaca data menjadi array numpy (saya sarankan rasterio ) dan dari sana Anda dapat memanipulasi data sehingga setiap band adalah variabel untuk klasifikasi. Misalnya, dengan asumsi Anda memiliki tiga band membaca ke python sebagai red, green, dan bluearray numpy:

import numpy as np
import sklearn.cluster

original_shape = red.shape # so we can reshape the labels later

samples = np.column_stack([red.flatten(), green.flatten(), blue.flatten()])

clf = sklearn.cluster.KMeans(n_clusters=5)
labels = clf.fit_predict(samples).reshape(original_shape)

import matplotlib.pyplot as plt

plt.imshow(labels)
plt.show()

Perhatikan bahwa pengelompokan KMeans tidak memperhitungkan konektivitas akun dalam dataset.


+1 Jawaban bagus. Akan sangat bagus untuk menunjukkan contoh konversi gambar warna ke array numpy menggunakan rasterio;)
Aaron

1
@ Harun, terima kasih! Saya telah memposting contoh yang sedikit lebih panjang termasuk membaca data menggunakan rasterio.
om_henners

@ Tom_henners solusi Anda luar biasa tapi saya punya pertanyaan. Gambar tersegmentasi yang dikembalikan oleh program Anda menggunakan k means clustering adalah 2D. Sekarang saya perlu menghitung koefisien kemiripan dadu antara gambar asli (gambar 3D sebelum dipecah menjadi R, G, B band) dan gambar tersegmentasi tetapi itu membutuhkan keduanya untuk memiliki dimensi yang sama. Bagaimana saya mengatasi masalah ini?
rach
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.