以一张脸部皮肤切片中的毛孔作为研究对象,使用模式匹配寻找到该切片中所有的毛孔
from skimage.feature import match_template
img_gray = cv2.cvtColor(img_o,cv2.COLOR_BGR2GRAY)
img_kernel = img_gray[255:295,460:500]
plt.subplot(131),plt.imshow(img_o)
plt.title('original'),plt.xticks([]),plt.yticks([])
plt.subplot(132),plt.imshow(img_gray,'gray')
plt.title('gray'),plt.xticks([]),plt.yticks([])
plt.subplot(133),plt.imshow(img_kernel,'gray')
plt.title('template'),plt.xticks([]),plt.yticks([])
plt.show()
如上图所示,左边图为皮肤切片原图,中间为灰度图,右边为选中的匹配对象
result = match_template(img_gray, img_kernel, pad_input=True, mode='constant', constant_values=0)
plt.subplot(121),plt.imshow(img_gray,'gray')
plt.title('img_gray')
plt.subplot(122),plt.imshow(result,'gray')
plt.title('match_template'),plt.xticks([]),plt.yticks([])
plt.show()
匹配结果如上图右所示,其中亮度较高的部分即我们所寻找的部分
接下来我们要让这张图看起来,更加明显,所以进行二值化操作,并降噪
mask = np.ones_like(result)
mask[result > 0.4] = 255
mask[result < 0.4] = 0
plt.subplot(121),plt.imshow(mask,'gray'),plt.title('threshold')
# open
kernel = np.ones((2,2),np.uint8)
th_mor = cv2.morphologyEx(mask,cv2.MORPH_OPEN,kernel, iterations = 3)
plt.subplot(122),plt.imshow(th_mor,'gray'),plt.title('open'),plt.xticks([]),plt.yticks([])
plt.show()
如此我们已经得到毛孔的轮廓图,不过这样看是不是太抽象了,ok,那么我们就把它画到原图上看一下
# 寻找轮廓
_, contour_total, _ = cv2.findContours(th_mor, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 绘制筛选后的轮廓
img_ground = img_o.copy()
cv2.drawContours(img_ground,new_contours,-1,(0,255,255),2)
fig = plt.figure(figsize=(12, 9))
axes = np.zeros((3, 3), dtype=np.object)
axes[0, 0] = plt.subplot(231),plt.imshow(img_o),plt.title('original image')
axes[0, 1] = plt.subplot(232),plt.imshow(img_ground),plt.title('contours')
plt.show()
至此模式匹配的简单应用就算结束了。准确率什么的仅仅凭借我们肉眼观察是无法断定的,在此我们可以人工在原图上标注出毛孔的轮廓,然后与模式匹配结果进行比较,下面贴上作者尝试标注的图与模式匹配结果的对比(人工标注比较随意)
其中第二部分,模式匹配方法应用及二值化操作过程中,参数设置决定匹配结果。
另外,在各种方法使用过程中,发现LBP效果也挺好。
补充:上述第二部分方法是采用skimage的match_template,最近因为工作需要,又做了一份opencv的方法,具体如下:
import cv2
img_match = cv2.matchTemplate(img_gray, img_kernel, cv2.TM_CCOEFF_NORMED)
# 给匹配图补黑边,解决cv2匹配过程中边缘忽略问题
img_match = cv2.copyMakeBorder(img_match,0,img_kernel.shape[0]-1,0,img_kernel.shape[1]-1,cv2.BORDER_CONSTANT,value=(0, 0, 0))
经检测发现,两者效果接近,skimage效果稍优。
本人邮箱:[email protected],欢迎讨论。