不會吧?不會吧?不會吧?不會有人忘記我還會寫圖像處理的代碼吧?別說了,我知道你忘了,沒關系,我會在這篇文章寫一些很簡短的代碼實現常見的圖像處理工作。
如何提取深度圖像的邊緣信息?
Sobel算子:Sobel算子是一種基于圖像梯度的邊緣檢測算法,可以在x方向和y方向上計算圖像的梯度,然后將兩個梯度值合并成一個邊緣強度值。通常可以使用Sobel算子來檢測深度圖像中的水平和垂直邊緣。 Scharr算子是一種改進的Sobel算子,它使用了更大的卷積核來平滑圖像,并在計算梯度時使用更準確的權重。Scharr算子在處理低對比度圖像時表現更好。 Laplacian算子:Laplacian算子是一種基于二階微分的邊緣檢測算法,可以檢測出深度圖像中的較強的邊緣。該算子計算圖像的拉普拉斯變換,并尋找其中的極值點作為邊緣點。 深度邊緣檢測算法:除了基于梯度或微分的算法,還有一些專門針對深度圖像的邊緣檢測算法。這些算法通常利用深度圖像的信息來檢測物體表面的變化,例如深度跳變或斜率變化等。 Canny算子是一種廣泛使用的邊緣檢測算法,它采用了多步驟的邊緣檢測過程。首先,使用高斯濾波器平滑圖像,然后計算圖像的梯度和梯度方向。接下來,應用非極大值抑制和雙閾值處理來提取邊緣。最后,通過連接具有強度邊緣的像素來獲得完整的邊緣。Canny算子在抑制噪聲和保留真實邊緣方面表現良好,通常被認為是一種比Sobel算子更優秀的邊緣檢測算法。 如何使用Python實現一個抽幀算法? 為啥會有這種東西?原因就是因為圖像幀太多又不需要都處理~
import cv2
def extract_frames(video_path, interval):
# 打開視頻文件
cap = cv2.VideoCapture(video_path)
# 計算視頻總幀數和幀率
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
# 計算抽幀間隔
interval_frames = int(interval * fps)
# 初始化幀計數器和關鍵幀列表
count = 0
frames = []
# 逐幀遍歷視頻
while True:
ret, frame = cap.read()
if not ret:
break
count += 1
# 如果是關鍵幀,將其添加到關鍵幀列表中
if count % interval_frames == 0:
frames.append(frame)
# 關閉視頻文件
cap.release()
????return?frames
? 照指定的時間間隔從視頻中抽取關鍵幀 上述代碼中,extract_frames()函數接受視頻文件路徑和抽幀間隔作為輸入參數,返回一個包含關鍵幀的列表。在函數內部,首先使用cv2.VideoCapture()函數打開視頻文件,并使用cv2.CAP_PROP_FRAME_COUNT和cv2.CAP_PROP_FPS獲取視頻總幀數和幀率。然后,根據指定的抽幀間隔計算需要保留的關鍵幀,在逐幀遍歷視頻時根據幀計數器來判斷當前幀是否為關鍵幀,如果是,則將其添加到關鍵幀列表中。最后,使用cap.release()函數關閉視頻文件。 可以使用以下代碼調用extract_frames()函數來從視頻文件中抽取關鍵幀:
frames = extract_frames('video.mp4', 1) # 抽取間隔為1秒的關鍵幀
for frame in frames:
cv2.imshow('frame', frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
? 上述代碼將抽取間隔設置為1秒,然后遍歷返回的關鍵幀列表,使用cv2.imshow()函數顯示每個關鍵幀,并在用戶按下鍵盤后繼續顯示下一個關鍵幀。最后,使用cv2.destroyAllWindows()函數關閉所有顯示窗口。 讓我們使用一個算子來提取深度圖像的邊緣信息的函數: Sobel算子是一種常用的邊緣檢測算子,它利用圖像的灰度值變化來檢測邊緣。
import cv2
import numpy as np
def extract_depth_edges(depth_img):
# 計算Sobel算子的卷積核
sobelx = cv2.Sobel(depth_img, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(depth_img, cv2.CV_64F, 0, 1, ksize=3)
# 計算梯度幅值和方向
grad_mag = np.sqrt(sobelx ** 2 + sobely ** 2)
grad_dir = np.arctan2(sobely, sobelx)
# 將梯度幅值歸一化到0-255之間
grad_mag_norm = cv2.normalize(grad_mag, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
# 將梯度方向轉換為角度
grad_dir_deg = (grad_dir * 180 / np.pi) % 180
# 應用非極大值抑制
grad_mag_nms = cv2.Canny(grad_mag_norm, 100, 200)
????return?grad_mag_nms
? 上述代碼中,extract_depth_edges()函數接受深度圖像作為輸入參數,返回提取的邊緣信息。在函數內部,首先使用cv2.Sobel()函數計算x和y方向上的Sobel算子的卷積核,然后計算梯度幅值和方向。接下來,將梯度幅值歸一化到0-255之間,并將梯度方向轉換為角度。最后,應用非極大值抑制(Canny邊緣檢測算法)來提取邊緣信息,并返回結果。 可以使用以下代碼調用extract_depth_edges()函數來提取深度圖像的邊緣信息:
depth_img = cv2.imread('depth_image.png', cv2.IMREAD_GRAYSCALE)
edges = extract_depth_edges(depth_img)
cv2.imshow('depth_edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
? 上述代碼將讀取深度圖像并將其作為輸入參數傳遞給extract_depth_edges()函數,然后顯示提取的邊緣信息。 有時候會有這樣的需求,把提取的圖像邊緣保存在一個txt文件中: 假設我們已經提取了深度圖像的邊緣信息,存儲在名為edge_img的NumPy數組中,邊緣值的范圍在0到255之間。
import numpy as np # 假設我們已經提取了深度圖像的邊緣信息,存儲在名為edge_img的NumPy數組中 # 將邊緣值縮放到0到1之間 edge_img = edge_img / 255.0 # 將邊緣信息轉換為字符串格式 edge_str = np.array2string(edge_img, separator=',', formatter={'float_kind':lambda x: "%.5f" % x}) # 將字符串寫入txt文件 with open('edge_info.txt', 'w') as f: ????f.write(edge_str)在上面的代碼中,我們將邊緣值縮放到0到1之間,并將其轉換為字符串格式。我們使用NumPy的array2string函數將數組轉換為字符串,并使用逗號作為分隔符。我們還設置了formatter參數,將浮點數的小數位數限制為5位。最后,我們將字符串寫入名為edge_info.txt的txt文件中。 請注意,在讀取txt文件時,需要使用適當的代碼將字符串轉換回NumPy數組格式。 雖然一直寫不了長代碼,但是不妨礙我寫在一起: 接下來把抽幀算法和保存邊緣到txt的函數寫在一起
import cv2
import numpy as np
def extract_edge(frame, threshold):
# 使用高斯模糊平滑圖像
blurred = cv2.GaussianBlur(frame, (3, 3), 0)
# 轉換為灰度圖像
gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)
# 使用Canny算法提取邊緣
edges = cv2.Canny(gray, threshold, threshold * 2)
return edges
def save_edges_to_txt(edges, filename):
# 將邊緣值縮放到0到1之間
edges = edges / 255.0
# 將邊緣信息轉換為字符串格式
edge_str = np.array2string(edges, separator=',', formatter={'float_kind':lambda x: "%.5f" % x})
# 將字符串寫入txt文件
with open(filename, 'w') as f:
f.write(edge_str)
# 讀取深度圖像
depth_img = cv2.imread('depth_img.png')
# 指定抽幀間隔
interval = 10
# 提取深度圖像邊緣
edges = extract_edge(depth_img, 50)
# 抽幀,保留每隔interval個像素
sampled_edges = edges[::interval, ::interval]
# 將邊緣信息保存到txt文件中
save_edges_to_txt(sampled_edges,?'edge_info.txt')
在上面的代碼中,我們定義了一個extract_edge函數來提取深度圖像的邊緣,該函數使用高斯模糊平滑圖像并使用Canny算法提取邊緣。我們還定義了一個save_edges_to_txt函數,將邊緣信息保存到txt文件中。 在主函數中,我們首先讀取深度圖像,然后指定抽幀間隔。我們使用extract_edge函數提取深度圖像邊緣,并使用抽幀算法保留每隔interval個像素。最后,我們使用save_edges_to_txt函數將提取的邊緣信息保存到txt文件中。 應該是可以直接運行的,如果運行不了你再改改? 上面鄙人已經教了你把圖像轉換成txt的文件,如何把保存在txt文件里面的邊緣信息恢復成圖像呢? 你會不?
import cv2
import numpy as np
def load_edges_from_txt(filename, shape):
# 從txt文件中讀取邊緣信息
edge_str = np.loadtxt(filename, delimiter=',')
# 創建全零數組
edges = np.zeros(shape)
# 將邊緣信息復制到全零數組的對應位置上
np.put(edges, np.arange(shape[0]*shape[1]), edge_str)
# 對全零數組進行插值操作
edges = cv2.resize(edges, (shape[1], shape[0]))
# 對插值后的邊緣圖像進行二值化處理
ret, edges = cv2.threshold(edges, 0, 255, cv2.THRESH_BINARY)
return edges
# 讀取深度圖像
depth_img = cv2.imread('depth_img.png')
# 獲取深度圖像大小
height, width = depth_img.shape[:2]
# 從txt文件中加載邊緣信息,并恢復成圖像
edges = load_edges_from_txt('edge_info.txt', (height//10, width//10))
# 顯示原始深度圖像和恢復的邊緣圖像
cv2.imshow('depth_img', depth_img)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
? ? 在上面的代碼中,我們定義了一個load_edges_from_txt函數,該函數從txt文件中加載邊緣信息,并將其恢復成圖像。該函數首先使用numpy.loadtxt函數從文件中加載數據,并將其轉換為NumPy數組。然后,該函數根據指定的圖像大小創建一個全零數組,并使用numpy.put函數將邊緣信息數組的值復制到全零數組的對應位置上。接下來,該函數對全零數組進行插值操作,并使用cv2.threshold函數對插值后的邊緣圖像進行二值化處理,生成二值圖像。 最后一個代碼,把1000x1000的圖像信息轉換到10x10的圖像里面,應該怎么做? 使用圖像縮放操作。可以使用OpenCV中的cv2.resize函數對原始圖像進行縮放操作。該函數的輸入參數包括原始圖像、目標圖像大小和插值方法等。
import cv2
# 讀取原始圖像
img = cv2.imread('original_image.png')
# 縮放圖像
new_img = cv2.resize(img, (10, 10), interpolation=cv2.INTER_AREA)
# 顯示原始圖像和縮放后的圖像
cv2.imshow('original', img)
cv2.imshow('new', new_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上面的代碼中,我們使用cv2.imread函數讀取原始圖像,然后使用cv2.resize函數對原始圖像進行縮放操作,將其縮放為10x10的圖像。在cv2.resize函數中,我們將目標圖像大小設置為(10, 10),并將插值方法設置為cv2.INTER_AREA。最后,我們使用cv2.imshow函數顯示原始圖像和縮放后的圖像。 ?
?
?
電子發燒友App


















評論