机器视觉 -3.2- 简单几何性质

122 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情


title: 机器视觉 -3.2- 简单几何性质 mathjax: true date: 2021-08-27 17:09:19 tags: [Image_Processing, Robot_vision] categories: [Image_Processing, Robot_vision]

本文记录《机器视觉》 第三章第二节 —— 简单几何性质,一些学习笔记和个人理解,其中核心内容为二值图的转动惯量求解。

我们已经有了一组二值图,我们可以根据二值图来确定其表示物体的简单几何性质。

特征函数

二值图的特征函数 b(x,y)b(x, y)比较简单,当[x,y][x, y]处有物体时值为1,否则为0

面积

  • 可以用特征函数求得二值图的面积AA:
A=Ib(x,y)dxdy(1)A=\iint_{I} b(x, y) d x d y \tag{1}

可以认为是二值图的 0 阶矩的物理意义。

质心

空间位置按照密度加权平均即是质心的位置 (xˉ,yˉ)(\bar{x}, \bar{y})

xˉIb(x,y)dxdy=Ixb(x,y)dxdy(2)\bar{x} \iint _ { I } b ( x , y ) d x d y = \iint _ { I } x b ( x , y ) d x d y \tag{2}
yˉIb(x,y)dxdy=Iyb(x,y)dxdy(3)\bar { y } \iint _ { I } b ( x , y ) d x d y = \iint _ { I } y b ( x , y ) d x d y\tag{3}

可以认为是二值图的 1 阶矩(静力矩)物理意义。

朝向

  • 如果我们想要知道二值图物体表示的朝向,则需要用到转动惯量的概念。如果找到了使得物体转动惯量最小的轴,那么这个轴向就是物体的朝向。

  • 在当前图像为二维的情况下,转动惯量是物体针对某条直线,将物体上的每个点到直线距离的平方按照密度计算积分,即得到了图像关于该轴向的转动惯量值。

  • 我们的任务是为给定的二值图物体找到使得其转动惯量最小的直线。

  • 转动惯量计算方法:

E=Ir2b(x,y)dxdy\label4(4)E=\iint_{I} r^{2} b(x, y) d x d y \tag{4} \label{4}
  • 其中 rr 表示二值图上的点到直线的距离,虽然还没有这条直线

直线建模

  • 为我们的目标直线建模,取2个参数

    • 原点到直线的距离 ρ\rho
    • 直线和 xx 轴之间(沿逆时针方向)的夹角 θ\theta
  • 这种建模方式有一些方便之处:

    • 当坐标系平移或旋转时,这两个参数的变化是连续的
    • 当直线平行(或近似平行)于某个坐标轴时,用这两个参数来表示直线也不会产生问题(相比于:使用斜率和截距来表示直线的情况)
  • 使用这两个参数,可以将直线方程写为如下形式:

xsinθycosθ+ρ=0\label5(5)x \sin \theta-y \cos \theta+\rho=0 \tag{5} \label{5}
  • 在直线上,距离原点最近的点(ρsinθ,+ρcosθ)(-\rho \sin \theta,+\rho \cos \theta),通过这个点,沿着夹角 θ\theta 运动任意距离ss 的点仍在直线上,因此可以将直线上任意一点(x0,y0)(x_0,y_0)表示为:
x0=ρsinθ+scosθy0=+ρcosθ+ssinθ\label6(6)\begin{array} { l } { x _ {0 } = - \rho \sin \theta + s \cos \theta } \\ { y _ {0} = + \rho \cos \theta + s \sin \theta } \end{array} \tag{6} \label{6}

最短距离

  • 回到我们的二值图,在给定直线方程的情况下,二值图上一点(x,y)(x,y),直线上距离其最近的点(x0,y0)(x_0,y_0),二者距离显然可以表示为:

{%raw%}

r2=(xx0)2+(yy0)2\label7(7)r^{2}=\left(x-x_{0}\right)^{2}+\left(y-y_{0}\right)^{2} \tag{7} \label{7}

{%endraw%}

  • 将直线上点公式\eqref6\eqref{6}代入,得到:

{%raw%}

r2=x2+y2+ρ2+2ρ(xsinθycosθ)2s(xcosθ+ysinθ)+s2\label8(8)r^{2}=x^{2}+y^{2}+\rho^{2}+2 \rho(x \sin \theta-y \cos \theta)-2 s(x \cos \theta+y \sin \theta)+s^{2} \tag{8} \label{8}

{%endraw%}

  • 对于每个点,我们都需要解\eqref8\eqref{8}这样的优化方程
  • 即给定了x,y,ρ,θx,y,\rho,\theta,求解使得rr最小的s,我们在$$\eqref{8}中对ss求导,可得:
s=xcosθ+ysinθ\label9(9)s=x \cos \theta+y \sin \theta \tag{9} \label{9}
  • \eqref9\eqref{9}带入\eqref6\eqref{6},二值图上(x,y)(x,y)到直线上距离最近的点(x0,y0)(x_0,y_0)可得到关系为:

{%raw%}

xx0=+sinθ(xsinθycosθ+ρ)yy0=cosθ(xsinθycosθ+ρ)\label10(10)x-x_{0}=+\sin \theta(x \sin \theta-y \cos \theta+\rho) \\ y-y_{0}=-\cos \theta(x \sin \theta-y \cos \theta+\rho) \tag{10} \label{10}

{%endraw%}

  • \eqref10\eqref{10}带入 \eqref7\eqref{7}可得:
r2=(xsinθycosθ+ρ)2\label11(11)r^{2}=(x \sin \theta-y \cos \theta+\rho)^{2} \tag{11} \label{11}
  • 此处可以看到,将某点(x,y)(x,y)带入\eqref5\eqref{5},得到值的绝对值即为该点到直线的垂线(最短)距离。

二阶矩轴向通过质心

  • 我们已经得到了二值图上一点到任意直线的距离计算方法,将\eqref11\eqref{11}带入\eqref4\eqref{4},得到:

{%raw%}

E=I(xsinθycosθ+ρ)2b(x,y)dxdy=I[(xsinθycosθ)2+ρ2+2ρ(xsinθycosθ)]b(x,y)dxdy=[(xsinθycosθ)2+ρ2]Ib(x,y)dxdy+2ρsinθIxb(x,y)dxdy2ρcosθIyb(x,y)dxdy(12)\begin{aligned} E&=\iint_{I}(x \sin \theta-y \cos \theta+\rho)^{2} b(x, y) d x d y \\ &=\iint_{I}[{(x\sin \theta - y\cos \theta )^2} + {\rho ^2} + 2\rho (x\sin \theta - y\cos \theta )]b(x,y)dxdy\\ &=[{(x\sin \theta - y\cos \theta )^2} + {\rho ^2}]\iint_{I}b(x,y)dxdy + 2\rho \sin \theta \iint_{I}xb(x,y)dxdy - 2\rho \cos \theta \iint_{I}{yb(x,y)dxdy} \end{aligned} \tag{12}

{%endraw%}

  • ρ\rho求导,并令倒数为0,得到:
(xˉsinθyˉcosθ+ρ)A=0(13)(\bar{x} \sin \theta-\bar{y} \cos \theta+\rho) A=0\tag{13}
  • 其中,A是区域面积,而是区域质心。因此,我们得到了结论:
最小二阶矩所对应的轴一定经过区域重心!最小二阶矩所对应的轴一定经过区域重心!

确定轴向倾角

我们已经确定该轴经过一个确定的点(xˉ,yˉ)(\bar{x}, \bar{y})了,仅需要再确定直线倾角即可。

  • 将二值图平移到原点与质心重合的位置,那么我们要求得的就是一条穿过原点的直接倾角
  • 也就是直接去除 ρ\rho 参数的影响
  • 转动惯量计算方式如下:
E=I(xsinθycosθ)2b(x,y)dxdy(14)E=\iint_{I}(x' \sin \theta-y' \cos \theta)^{2} b(x', y') d x' d y' \tag{14}

其中,我们定义平移后的二值图II'上点的坐标为(x,y)({x'}, {y'})

  • 可以表示为:

{%raw%}

E=asin2θbsinθcosθ+ccos2θ其中:a=I(x)2b(x,y)dxdyb=2I(xy)b(x,y)dxdyc=I(y)2b(x,y)dxdy\label15(15)\begin{array}{l} E=a \sin ^{2} \theta-b \sin \theta \cos \theta+c \cos ^{2} \theta \\ 其中: a=\iint_{I^{\prime}}\left(x^{\prime}\right)^{2} b\left(x^{\prime}, y^{\prime}\right) d x^{\prime} d y^{\prime} \\ b=2 \iint_{I^{\prime}}\left(x^{\prime} y^{\prime}\right) b\left(x^{\prime}, y^{\prime}\right) d x^{\prime} d y^{\prime} \\ c=\iint_{I^{\prime}}\left(y^{\prime}\right)^{2} b\left(x^{\prime}, y^{\prime}\right) d x^{\prime} d y^{\prime} \\ \end{array} \tag{15} \label{15}

{%endraw%}

  • 即:
E=12(a+c)12(ac)cos2θ12bsin2θ(16)E=\frac{1}{2}(a+c)-\frac{1}{2}(a-c) \cos 2 \theta-\frac{1}{2} b \sin 2 \theta \tag{16}
  • 上式对θ\theta求导,并令求导结果等于零
  • 假设aca≠c,我们可以得到:
tan2θ=bac\label17(17)\tan 2 \theta=\frac{b}{a-c} \tag{17} \label{17}
  • 因此除非出现b=0b=0 并且 a=ca=c 的情况, 否则, 我们最终可以得到:

{%raw%}

sin2θ=±bb2+(ac)2cos2θ=±acb2+(ac)2(18)\begin{array}{l} \sin 2 \theta=\pm \frac{b}{\sqrt{b^{2}+(a-c)^{2}}} \quad \\ \cos 2 \theta=\pm \frac{a-c}{\sqrt{b^{2}+(a-c)^{2}}} \end{array} \tag{18}

{%endraw%}

  • 至此我们已经求出了使得该二值图转动惯量最小和最大的两个轴
  • EE​ 的的最小值和最大值的比值,给出了一些关于物体有“多么圆”的信息。对于直线,这个比值是0对于圆,这个比值是1。

拉格朗日

从式\eqref15\eqref{15}开始,事实上我们要解的就是一个带约束的优化方程组,可以使用拉格朗日乘数法求解:

{%raw%}

E=ax2bxy+cy2s.t.x2+y21=0\label19(19)\begin{array}{l} E = a{x^2} - bxy + c{y^2}\\ s.t.{x^2} + {y^2}-1 = 0 \end{array} \tag{19} \label{19}

{%endraw%}

  • EE设为f(x,y)f(x,y),约束条件设为g(x,y)=0g(x,y)=0,构建拉格朗日方程:
L(x,y)=ax2bxy+cy2+λ(x2+y21)(20)L(x,y) = a{x^2} - bxy + c{y^2} + \lambda ({x^2} + {y^2}-1) \tag{20}
  • 构造拉格朗日方程组:

{%raw%}

{fx+λgx=0fy+λgy=0g(x,y)=0{2axby+2λx=02bybx+2λy=0x2+y2=1(21)\left\{ \begin{array}{l} \frac{{\partial f}}{{\partial x}} + \lambda \frac{{\partial g}}{{\partial x}} = 0\\ \frac{{\partial f}}{{\partial y}} + \lambda \frac{{\partial g}}{{\partial y}} = 0\\ g(x,y) = 0 \end{array} \right. \to \left\{ \begin{array}{l} 2ax - by + 2\lambda x = 0\\ 2{\rm{by}} - bx + 2\lambda y = 0\\ {x^2} + {y^2} = 1 \end{array} \right. \tag{21}

{%endraw%}

  • 重新令 x=sinθ,y=conθx = sin\theta, y=con\theta可得:

{%raw%}

2ab1tanθ=2cbtanθb(tan2θ1)+2(ac)tanθ=0bac=2tanθtan2θ1=tan2θ(22)\begin{array}{l} 2a - b\frac{1}{{\tan \theta }} = 2c - b\tan \theta \\ b(ta{n^2}\theta - 1) + 2(a - c)tan\theta = 0\\ \frac{b}{{a - c}} = \frac{{2\tan \theta }}{{{{\tan }^2}\theta - 1}} = \tan 2\theta \end{array} \tag{22}

{%endraw%}

  • 即推出\eqref17\eqref{17}相同结论。

特征向量

可以将\eqref19\eqref{19}看作是一个二次型优化问题,原带约束的方程可以写成:

{%raw%}

\begin{array}{*{20}{l}} {E = {{\bf{s}}^T}{\bf{As}}}\\ {s.t.1-{{\bf{s}}^T}{\bf{Is}} = 0} \end{array} \tag{23}

{%endraw%}

  • 其中: {%raw%}s=(xy){\bf{s}} = \left( \begin{array}{l} x\\ y \end{array} \right){%endraw%},{%raw%}{\bf{A}} = \left( \begin{array}{l} \begin{array}{*{20}{c}} a&{\frac{b}{2}} \end{array}\\ \begin{array}{*{20}{c}} {\frac{b}{2}}&c \end{array} \end{array} \right){%endraw%},I\bf{I}为二阶单位阵
  • 那么拉格朗日方程可以写成:

{%raw%}

L=sTAsλ(1sTIs)(24){L = {{\bf{s}}^T}{\bf{As}} - \lambda(1- {{\bf{s}}^T}{\bf{Is}}}) \tag{24}

{%endraw%}

  • LLs\bf{s}的偏导数为0:

{%raw%}

Ls=2As2λIs=0As=λs\label25(25)\begin{array}{l} \frac{{\partial L}}{{\partial {\bf{s}}}} = 2{\bf{As}} - 2\lambda {\bf{Is}} = 0\\ {\bf{As}} = \lambda {\bf{s}} \end{array} \tag{25} \label{25}

{%endraw%}

  • 而式\eqref25\eqref{25}就是在寻找矩阵A\bf{A}的特征向量和特征值。
  • 也就是说,对于给定的二值图,求解其对应的a,b,ca,b,c,构造出矩阵A\bf{A},求解A\bf{A}的特征向量即是寻找最大、最小转动惯量的方向。
  • 二者大小的比值也类似于特征值的比值,也就是矩阵的条件数。

参考示例

  • 示例图像:

  • 示例程序
import math
import cv2

import numpy as np

import matplotlib.pyplot as plt
from numpy.lib.function_base import iterable


def vvd_round(num):
    if iterable(num):
        return np.round(np.array(num)).astype('int32').tolist()
    return int(round(num))


def show_image(image):
    plt.imshow(image.astype('uint8'))
    plt.show()
    pass


def gravity_center(mask):
    Ys, Xs = mask.nonzero()
    A = (mask > 0).sum()
    C_X = (Xs).sum() / A
    C_Y = (Ys).sum() / A
    return C_X, C_Y


def load_gray_image(image_path):
    image = cv2.imread(image_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image = (image == 0).astype('uint8') * 255
    return image


def moment_of_inertia(mask, center):
    temp_image = mask.copy().astype('uint8') * 128

    C_X, C_Y = center

    Ys, Xs = mask.nonzero()

    Ys = (Ys - C_Y) / 100
    Xs = (Xs - C_X) / 100

    a = (Xs * Xs).sum()
    b = 2 * (Xs * Ys).sum()
    c = (Ys * Ys).sum()

    if b == 0:
        theta = 0
    elif a == c:
        theta = - np.pi * 0.5 * 0.5
    else:
        theta = - math.atan(b / (a - c)) / 2

    point_1 = vvd_round([C_X + math.cos(theta) * 200, C_Y - math.sin(theta) * 200])
    point_2 = vvd_round([C_X - math.cos(theta) * 200, C_Y + math.sin(theta) * 200])

    temp_image = cv2.line(temp_image.astype('uint8'), point_1, point_2, 255, 2)

    point_1 = vvd_round([C_X + math.cos(theta + 0.5 * np.pi) * 200, C_Y - math.sin(theta + 0.5 * np.pi) * 200])
    point_2 = vvd_round([C_X - math.cos(theta + 0.5 * np.pi) * 200, C_Y + math.sin(theta + 0.5 * np.pi) * 200])

    temp_image = cv2.line(temp_image.astype('uint8'), point_1, point_2, 200, 2)

    theta_1 = theta
    theta_2 = theta + 0.5 * np.pi

    E_1 =(math.sin(theta_1)) ** 2 * a - b * math.sin(theta_1) * math.cos(theta_1) + c * (math.cos(theta_1)) ** 2
    E_2 =(math.sin(theta_2)) ** 2 * a - b * math.sin(theta_2) * math.cos(theta_2) + c * (math.cos(theta_2)) ** 2

    return temp_image, min(E_2, E_1) / max(E_2, E_1, 1)


if __name__ == '__main__':
    image_path = 'test.png'
    image = load_gray_image(image_path)
    center = gravity_center(image)
    temp_image, rate = moment_of_inertia(image, center)
    show_image(temp_image)
    pass

  • 示例效果

参考资料

  • 伯特霍尔德・霍恩著BERTHOLDKLAUSPAULHORN. 机器视觉[M]. 中国青年出版社, 2014.