不會吧?不會吧?不會吧?不會有人忘記我還會寫圖像處理的代碼吧?別說了,我知道你忘了,沒關系,我會在這篇文章寫一些很簡短的代碼實現常見的圖像處理工作。
如何提取深度圖像的邊緣信息?
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函數顯示原始圖像和縮放后的圖像。 ?
?
?
評論
查看更多