Python實(shí)現(xiàn)二值掩膜影像去噪與邊緣強(qiáng)化方法詳解
前言
這篇博客主要解決的一個(gè)問題是掩膜圖像的噪聲去除和邊緣強(qiáng)化,如下圖1所示。可以看到掩膜圖像上有很多的斑點(diǎn)噪聲,而且掩膜的輪廓也不夠清晰。所以我們的目標(biāo)就是一方面盡可能把這些斑點(diǎn)噪聲去除,另一方面盡量突出掩膜邊界。另外處理后的掩膜可以比真值大一些,但最好不能小。
圖1 原始二值化影像
一、方法
因?yàn)橹坝凶鲞^相關(guān)的工作,所以對(duì)于保留邊界的斑點(diǎn)噪聲消除第一反應(yīng)是使用中值濾波。但很顯然對(duì)于我們這個(gè)應(yīng)用,單純中值濾波是不夠的。所以就想著那就采用多步處理,融合形態(tài)學(xué)操作。因此設(shè)計(jì)了一種如下圖所示的方法。
圖2 二值掩膜影像去噪與邊緣強(qiáng)化技術(shù)路線圖
中值濾波比較好理解,就是為了消除斑點(diǎn)噪聲。而腐蝕操作這是為了處理一些稍大的面狀的噪聲,通過多次的腐蝕,盡可能消除它們。而后續(xù)的3次膨脹操作則是對(duì)應(yīng)3次腐蝕,恢復(fù)成“原樣”。然后是一個(gè)二值化,目的在于進(jìn)一步去除一些噪聲并且強(qiáng)調(diào)輪廓。因?yàn)橛幸恍┹^暗的像素經(jīng)過3次膨脹就會(huì)形成很大一塊區(qū)域。因此,通過二值化可以過濾掉。最后膨脹一方面是為了滿足要求“比真值大一些”,另一方面是填充由于腐蝕或者二值化帶來的一些空洞。
二、代碼
Python版本代碼實(shí)現(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) # 主要流程:先做一次中值濾波,去除零碎像素噪聲點(diǎn) # 然后再做3次腐蝕操作去除一些噪聲塊,再做3次膨脹操作填充回來 # 然后,做個(gè)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))
三、效果測(cè)試
為了測(cè)試效果,輸出了中間過程的結(jié)果。如下是輸入的原始影像。
然后首先進(jìn)行中值濾波,結(jié)果如下。
然后進(jìn)行3次腐蝕操作,以去除一些噪聲,如下。
為了保證掩膜和輸入一樣,再膨脹3次,結(jié)果如下。
由于掩膜是0-1影像,為了過濾掉一些中間值,進(jìn)行一次二值化,結(jié)果如下。
二值化以后難免會(huì)有一些空洞,因此使用膨脹操作進(jìn)行填充,最終生成的掩膜如下。
將生成的掩膜范圍繪制到輸入影像上(紅色框線)如下圖所示。
到此這篇關(guān)于Python實(shí)現(xiàn)二值掩膜影像去噪與邊緣強(qiáng)化方法詳解的文章就介紹到這了,更多相關(guān)Python二值掩膜影像去噪內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python函數(shù)的返回值、匿名函數(shù)lambda、filter函數(shù)、map函數(shù)、reduce函數(shù)用法實(shí)例分析
這篇文章主要介紹了Python函數(shù)的返回值、匿名函數(shù)lambda、filter函數(shù)、map函數(shù)、reduce函數(shù)用法,結(jié)合實(shí)例形式分析了Python函數(shù)的返回值、匿名函數(shù)lambda、filter函數(shù)、map函數(shù)、reduce函數(shù)相關(guān)功能、原理與使用技巧,需要的朋友可以參考下2019-12-12Python函數(shù)__new__及__init__作用及區(qū)別解析
這篇文章主要介紹了Python函數(shù)__new__及__init__作用及區(qū)別解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08pytorch torch.nn.AdaptiveAvgPool2d()自適應(yīng)平均池化函數(shù)詳解
今天小編就為大家分享一篇pytorch torch.nn.AdaptiveAvgPool2d()自適應(yīng)平均池化函數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-01-01python實(shí)現(xiàn)支付寶轉(zhuǎn)賬接口
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)支付寶轉(zhuǎn)賬接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-0515個(gè)應(yīng)該掌握的Jupyter Notebook使用技巧(小結(jié))
這篇文章主要介紹了15個(gè)應(yīng)該掌握的Jupyter Notebook使用技巧(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09簡單介紹Python的Tornado框架中的協(xié)程異步實(shí)現(xiàn)原理
這篇文章主要介紹了簡單介紹Python的Tornado框架中的協(xié)程異步實(shí)現(xiàn)原理,作者基于Python的生成器講述了Tornado異步的特點(diǎn),需要的朋友可以參考下2015-04-04