目录
- 引言
- 链码
- 编程实现
- 轮廓提取
- 链码计算
- 总结
引言
本文介绍了图像的形状特征–链码,以及通过python和opencv实现的链码提取方法。所有opencv的版本为3.4.2,已经移除了直接返回链码的选项。
链码
链码用于描述图像的形状特征,首先需要获得图像的轮廓,而后从轮廓上某一点开始,沿着顺时针方向或逆时针方向巡游轮廓上的每一点,记录下后续点相对于当前的方向,并将相对方向量化为具体的数值,常用的方向描述为八连通描述符如下:
编程实现
链码求取的编程实现可以分为两个部分,第一部分为图像轮廓的提取,使用opencv中的findcontous()
实现;第二部分为轮廓差分后映射为链码。具体代码如下:
轮廓提取
值得注意的是,链码的求取对象为二值化的图像,因此在求取之前需要使用大津法(其他阈值化方法也可)对原始图像二值化,求得的轮廓也可能是多个轮廓的集合,需要分开提取链码,具体代码如下:
blurred_img=ndimage.gaussian_filter(img,radius)
threshold, binarized_img = cv2.threshold(blurred_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # 大于OTSU的为噪声,设置为255
_,cnts,_ = cv2.findContours(binarized_img.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE) # 需要使用cv2.CHAIN_APPROX_NONE,否则不是链码for c in cnts:cnt=np.squeeze(c)cnt=np.insert(cnt,0,cnt[-1],axis=0) # 循环填补freeman_code=chain_code(cnt)
链码计算
链码计算方式为简单的前向差分加映射,为了避免使用多个if语句,使用了dict.get()方法和map进行了直接的映射。
def chain_code(cnt):diff_cnt=np.diff(cnt,axis=0)dic={(1,0):0,(1,1):1,(0,1):2,(-1,1):3,(-1,0):4,(-1,-1):5,(0,-1):6,(1,-1):7}direction=[tuple(x) for x in diff_cnt.tolist()]code=list(map(dic.get,direction))code=np.array(code)return code
总结
本文利用opencv给出了图像链码的计算方法,弥补了网络上相关代码稀少或非python语言实现的不足。