Python實現(xiàn)二值掩膜影像去噪與邊緣強化方法詳解
前言
這篇博客主要解決的一個問題是掩膜圖像的噪聲去除和邊緣強化,如下圖1所示??梢钥吹窖谀D像上有很多的斑點噪聲,而且掩膜的輪廓也不夠清晰。所以我們的目標就是一方面盡可能把這些斑點噪聲去除,另一方面盡量突出掩膜邊界。另外處理后的掩膜可以比真值大一些,但最好不能小。

圖1 原始二值化影像
一、方法
因為之前有做過相關(guān)的工作,所以對于保留邊界的斑點噪聲消除第一反應(yīng)是使用中值濾波。但很顯然對于我們這個應(yīng)用,單純中值濾波是不夠的。所以就想著那就采用多步處理,融合形態(tài)學(xué)操作。因此設(shè)計了一種如下圖所示的方法。

圖2 二值掩膜影像去噪與邊緣強化技術(shù)路線圖
中值濾波比較好理解,就是為了消除斑點噪聲。而腐蝕操作這是為了處理一些稍大的面狀的噪聲,通過多次的腐蝕,盡可能消除它們。而后續(xù)的3次膨脹操作則是對應(yīng)3次腐蝕,恢復(fù)成“原樣”。然后是一個二值化,目的在于進一步去除一些噪聲并且強調(diào)輪廓。因為有一些較暗的像素經(jīng)過3次膨脹就會形成很大一塊區(qū)域。因此,通過二值化可以過濾掉。最后膨脹一方面是為了滿足要求“比真值大一些”,另一方面是填充由于腐蝕或者二值化帶來的一些空洞。
二、代碼
Python版本代碼實現(xiàn)如下,非常簡單。
import cv2
import numpy as np
import os
def findFiles(root_dir, filter_type, reverse=False):
print("Finding files ends with \'" + filter_type + "\' ...")
separator = os.path.sep
paths = []
names = []
files = []
for parent, dirname, filenames in os.walk(root_dir):
for filename in filenames:
if filename.endswith(filter_type):
paths.append(parent + separator)
names.append(filename)
for i in range(paths.__len__()):
files.append(paths[i] + names[i])
print(names.__len__().__str__() + " files have been found.")
paths.sort()
names.sort()
files.sort()
if reverse:
paths.reverse()
names.reverse()
files.reverse()
return paths, names, files
if __name__ == '__main__':
root_dir = "./mask" # 影像的輸入路徑
out_dir = "./mask/refine" # 結(jié)果的輸出路徑
file_type = ".jpg" # 文件類型
median_kernel = 7 # 中值濾波卷積核大小
morph_kernel1 = 5 # 形態(tài)學(xué)操作卷積核大小1
morph_kernel2 = 5 # 形態(tài)學(xué)操作卷積核大小2
morph_iter1 = 3 # 形態(tài)學(xué)操作迭代次數(shù)1
morph_iter2 = 3 # 形態(tài)學(xué)操作迭代次數(shù)2
paths, names, files = findFiles(root_dir, file_type)
kernel1 = np.ones((morph_kernel1, morph_kernel1), np.uint8)
kernel2 = np.ones((morph_kernel2, morph_kernel2), np.uint8)
for i in range(len(files)):
img_gray = cv2.imread(files[i], cv2.IMREAD_GRAYSCALE)
# 主要流程:先做一次中值濾波,去除零碎像素噪聲點
# 然后再做3次腐蝕操作去除一些噪聲塊,再做3次膨脹操作填充回來
# 然后,做個Otsu二值化,把一些潛在的噪聲去除
# 最后,為了使掩膜盡可能包含真值,再做一次膨脹操作
img_median = cv2.medianBlur(img_gray, ksize=median_kernel)
img_erode = cv2.erode(img_median, kernel1, iterations=morph_iter1)
img_dilate = cv2.dilate(img_erode, kernel1, iterations=morph_iter1)
ret, img_threshold = cv2.threshold(img_dilate, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
img_mask = cv2.dilate(img_threshold, kernel2, iterations=morph_iter2)
# 繪制輪廓,可視化,以及保存
_, contours, _ = cv2.findContours(img_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img_rgb = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)
img_contours = cv2.drawContours(img_rgb, contours, -1, (0, 0, 255))
cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_refine.jpg", img_mask)
cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_range.jpg", img_contours)
# 如果需要查看每一步結(jié)果,可以把下面這些注釋掉
# cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_median.jpg", img_median)
# cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_erode.jpg", img_erode)
# cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_dilate.jpg", img_dilate)
# cv2.imwrite(out_dir + "/" + names[i].split(".")[0] + "_threshold.jpg", img_threshold)
print(i + 1, "/", len(files))三、效果測試
為了測試效果,輸出了中間過程的結(jié)果。如下是輸入的原始影像。

然后首先進行中值濾波,結(jié)果如下。

然后進行3次腐蝕操作,以去除一些噪聲,如下。

為了保證掩膜和輸入一樣,再膨脹3次,結(jié)果如下。

由于掩膜是0-1影像,為了過濾掉一些中間值,進行一次二值化,結(jié)果如下。

二值化以后難免會有一些空洞,因此使用膨脹操作進行填充,最終生成的掩膜如下。

將生成的掩膜范圍繪制到輸入影像上(紅色框線)如下圖所示。

到此這篇關(guān)于Python實現(xiàn)二值掩膜影像去噪與邊緣強化方法詳解的文章就介紹到這了,更多相關(guān)Python二值掩膜影像去噪內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python去除字符串中的空格、特殊字符和指定字符的三種方法
本文主要介紹了python去除字符串中的空格、特殊字符和指定字符的三種方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Python使用socket實現(xiàn)組播與發(fā)送二進制數(shù)據(jù)
在工作中經(jīng)常會用到socket傳輸數(shù)據(jù),例如客戶端給服務(wù)器發(fā)送數(shù)據(jù)(雙方約定了數(shù)據(jù)格式),本文主要介紹了Python使用socket實現(xiàn)組播與發(fā)送二進制數(shù)據(jù),感興趣的可以了解一下2021-06-06
教你怎么用python實現(xiàn)字符串轉(zhuǎn)日期
今天教各位小伙伴怎么用python實現(xiàn)字符串轉(zhuǎn)日期,文中有非常詳細的代碼示例,對正在學(xué)習(xí)python的小伙伴很有幫助,需要的朋友可以參考下2021-05-05

