【OpenCV 例程200篇】222. 特征提取之弗里曼链码(Freeman chain code)

OpenCV 例程200篇 总目录

【youcans 的 OpenCV 例程 300篇】222. 特征提取之弗里曼链码(Freeman chain code)

目标特征的基本概念

通过图像分割获得多个区域,得到区域内的像素集合或区域边界像素集合。我们把感兴趣的人或物称为目标,目标所处的区域就是目标区域。
特征通常是针对于图像中的某个目标而言的。图像分割之后,还要对目标区域进行适当的表示和描述,以便下一步处理。
“表示”是直接具体地表示目标,以节省存储空间、方便特征计算。目标的表示方法,有链码、多边形逼近(MPP)、斜率标记图、边界分段、区域骨架。
“描述”是对目标的抽象表达,在区别不同目标的基础上,尽可能对目标的尺度、平移、旋转变化不敏感。

边界特征描述子

目标的边界描述符(Boundary descriptors),也称为边界描述子。
轮廓就是对目标边界的描述,轮廓属性是基本的边界描述子。

例如:

  • 边界的长度,轮廓线的像素数量是边界周长的近似估计;
  • 边界的直径,边界长轴的长度,等于轮廓最小矩形边界框的长边长度;
  • 边界的偏心率,边界长轴与短轴之比,等于轮廓最小矩形边界框的长宽比;
  • 边界的曲率,相邻边界线段的斜率差;
  • 链码,通过规定长度和方向的直线段来表示边界;
  • 傅里叶描述符,对二维边界点进行离散傅里叶变换得到的傅里叶系数,对旋转、平移、缩放和起点不敏感;
  • 统计矩,把边界视为直方图函数,用图像矩对边界特征进行描述,具有平移、灰度、尺度、旋转不变性。

例程 12.11:闭合曲线的弗里曼链码

链码表示基于线段的 4连通或 8连通。弗里曼链码(Freeman chain code)使用一种编号方案来对每个线段的方向进行编号。

通过对闭合边界曲线向下降采样,简化了初始轮廓。例程中最大轮廓的像素点 1361,简化后轮廓的像素点 34,对应的弗里曼链码长度 34。即用 34位 Freeman 链码可以描述该最大轮廓的边界特征,显著降低了数据量。

相关算法的详细内容,参见 R.C.Gonzalez 《数字图像处理(第四版)》P587-590 例11.1。


import cv2
import numpy as np
from matplotlib import pyplot as plt

def FreemanChainCode(cLoop, gridsep=1):

    dictFreeman = {(1, 0): 0, (1, 1): 1, (0, 1): 2, (-1, 1): 3, (-1, 0): 4, (-1, -1): 5, (0, -1): 6, (1, -1): 7}
    diff_cLoop = np.diff(cLoop, axis=0) // gridsep
    direction = [tuple(x) for x in diff_cLoop.tolist()]
    codeList = list(map(dictFreeman.get, direction))
    code = np.array(codeList)
    return code

if __name__ == '__main__':

    img = cv2.imread("../images/Fig1105.tif", flags=1)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    blur = cv2.boxFilter(gray, -1, (5, 5))
    _, binary = cv2.threshold(blur, 200, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    imgCnts = np.zeros(gray.shape[:2], np.uint8)
    imgCnts = cv2.drawContours(imgCnts, contours, -1, (255, 255, 255), thickness=2)

    cnts = sorted(contours, key=cv2.contourArea, reverse=True)
    cnt = cnts[0]
    maxContour = np.zeros(gray.shape[:2], np.uint8)
    cv2.drawContours(maxContour, cnt, -1, (255, 255, 255), thickness=2)
    print("len(contours) =", len(contours))
    print("area of max contour: ", cv2.contourArea(cnt))
    print("perimeter of max contour: {:.1f}".format(cv2.arcLength(cnt, True)))

    gridsep = 50
    cntPoints = np.squeeze(cnt)
    subPoints = boundarySubsample(cntPoints, gridsep)
    print("subsample steps:", gridsep)
    print("points of contour:", cntPoints.shape[0])
    print("points of subsample:", subPoints.shape[0])

    subContour = np.zeros(gray.shape[:2], np.uint8)
    [cv2.circle(subContour, point, 1, 160, -1) for point in cntPoints]
    [cv2.circle(subContour, point, 4, 255, -1) for point in subPoints]
    cv2.polylines(subContour, [subPoints], True, 255, thickness=2)

    cntPoints = np.squeeze(cnt)
    pointsLoop = np.append(cntPoints, [cntPoints[0]], axis=0)
    chainCode = FreemanChainCode(pointsLoop, gridsep=1)
    print("Freeman chain code:", chainCode.shape)
    subPointsLoop = np.append(subPoints, [subPoints[0]], axis=0)
    subChainCode = FreemanChainCode(subPointsLoop, gridsep=50)
    print("Down-sampling Freeman chain code:", subChainCode.shape)
    print("youcans code:", subChainCode)

    plt.figure(figsize=(9, 6))
    plt.subplot(231), plt.axis('off'), plt.title("Origin")
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.subplot(232), plt.axis('off'), plt.title("Blurred")
    plt.imshow(cv2.cvtColor(blur, cv2.COLOR_BGR2RGB))
    plt.subplot(233), plt.axis('off'), plt.title("Binary")
    plt.imshow(binary, 'gray')
    plt.subplot(234), plt.axis('off'), plt.title("Contour")
    plt.imshow(imgCnts, 'gray')
    plt.subplot(235), plt.axis('off'), plt.title("Max contour")
    plt.imshow(maxContour, 'gray')
    plt.subplot(236), plt.axis('off'), plt.title("Down sampling")
    plt.imshow(subContour, 'gray')
    plt.tight_layout()
    plt.show()

运行结果:

len(contours) = 24
area of max contour: 152294.5
perimeter of max contour: 1525.4
subsample steps: 50
points of contour: 1361
points of subsample: 34
Freeman chain code: (1361,)
Down-sampling Freeman chain code: (34,)
[4 2 4 2 2 4 2 2 2 2 2 0 2 0 0 0 2 0 0 6 0 6 6 6 6 6 6 6 6 4 6 4 4 4]

【OpenCV 例程200篇】222. 特征提取之弗里曼链码(Freeman chain code)

【本节完】

说明:本文的案例来自 R.C.Gonzalez 《数字图像处理(第四版)》,本文的程序为作者原创。

版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125534118)
Copyright 2022 youcans, XUPT
Crated:2022-6-30
欢迎关注『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
194.寻找图像轮廓(cv.findContours)
222. 特征提取之弗里曼链码

Original: https://blog.csdn.net/youcans/article/details/125534118
Author: YouCans
Title: 【OpenCV 例程200篇】222. 特征提取之弗里曼链码(Freeman chain code)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/701917/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球