我使用術語“矢量化”,因為這是用來描述我正在寫的程序的內容。我不知道它實際上叫什么,但我想要做的是獲取影像的元素并將它們分成不同的影像。
這是我試圖“矢量化”的示例圖片
我想要做的是(使用 opencv)將玉米芯與其連接的綠色原料分開,并將每個玉米芯塊分成自己的影像。
我嘗試過的是以下內容:
def kmeansSegmentation(path_to_images, image_name, path_to_save_segments):
img = cv2.imread(path_to_images image_name)
img_blur = cv2.GaussianBlur(img, (3,3), 0)
img_gray = cv2.cvtColor(img_blur, cv2.COLOR_BGR2GRAY)
img_reshaped = img_gray.reshape((-1, 3))
img_reshaped = np.float32(img_reshaped)
criteria = (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 5
attempts = 10
ret,label,center=cv2.kmeans(img_reshaped,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
v = np.median(res)
sigma=0.33
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 sigma) * v))
edges = cv2.Canny(img_gray, lower, upper)
contours, hierarchy = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
sorted_contours= sorted(contours, key=cv2.contourArea, reverse= True)
mask = np.zeros(img.shape[:2], dtype=img.dtype)
array_of_contour_areas = [cv2.contourArea(contour) for contour in contours]
contour_avg = sum(array_of_contour_areas)/len(array_of_contour_areas)
contour_var = sum(pow(x-contour_avg,2) for x in array_of_contour_areas) / len(array_of_contour_areas)
contour_std = math.sqrt(contour_var)
print("Saving segments", len(sorted_contours))
for (i,c) in tqdm(enumerate(sorted_contours)):
if (cv2.contourArea(c) > contour_avg-contour_std*2):
x,y,w,h= cv2.boundingRect(c)
cropped_contour= img[y:y h, x:x w]
cv2.drawContours(mask, [c], 0, (255), -1)
#tmp_image_name= image_name "-kmeans-" str(K) str(random.random()) ".jpg"
#cv2.imwrite(path_to_save_segments tmp_image_name, cropped_contour)
result = cv2.bitwise_and(img, img, mask=mask)
"""
scale_percent = 30 # percent of original size
width = int(edges.shape[1] * scale_percent / 100)
height = int(edges.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(result, dim, interpolation = cv2.INTER_AREA)
cv2.imshow("edges", resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
"""
#tmp_image_name= image_name "-kmeans-" str(K) str(random.random()) ".png"
#cv2.imwrite(path_to_save_segments tmp_image_name, result)
return result
請原諒注釋掉的代碼,我只是在修改演算法時觀察我對影像所做的更改。
uj5u.com熱心網友回復:
我相信你正在嘗試做的是一種叫做“實體分割”的東西。這個程序最好使用深度學習技術來完成,除非你能找到一個預先訓練好的模型,否則它可能不適合你。這是一篇關于如何做到這一點的文章:https : //www.analyticsvidhya.com/blog/2019/04/introduction-image-segmentation-techniques-python/
一個更簡單(但不太準確)的解決方案可能是找到使用 RGB 閾值來創建圖片的“輪廓”,然后使用泛光填充演算法來識別結果影像中的特定像素。要繪制影像的粗略輪廓,您必須嘗試不同的閾值。首先,將整個影像轉換為灰度 w。OpenCV ( cv2.imread('image-name', 0))。要測驗不同的閾值,只需檢查每個像素值是否高于或低于某個值(您選擇的值):
import numpy as np
import cv2
import matplotlib.pyplot as plt
def apply_threshold(img_array, threshold):
threshold_applied = []
for row in img_array:
threshold_applied.append([])
for pixel in row:
if pixel>threshold:
threshold_applied[len(threshold_applied)-1].append([255, 255, 255])
else:
threshold_applied[len(threshold_applied)-1].append([0, 0, 0])
new_img = np.array(threshold_applied, np.uint8)
cv2.imwrite(str(threshold) ".jpg", new_img)
img = cv2.imread("Ek1Dx.jpg", 0)
apply_threshold(img, 210)
如果您運行代碼,您會發現輸出極其不準確,并且幾乎看不到玉米棒和玉米粒。在過去十年左右的時間里,實體分割和分割影像實際上是一個非常大的計算機科學問題。可能還有其他過濾器可以用來獲得更準確的結果,但我認為識別閾值是一種基線影像分割技術。如果你愿意,你可以嘗試在程式中調整閾值,看看它是否會讓你得到一個更分割的影像。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/365635.html
