神经网络预测书本模型基础上的透视投影

0.前言

上一篇博客里确定了书本模型的系数范围,本篇在这个的基础上编写代码,包括:1)生成在书本变形模型下的x,z坐标;2)确定书本模型上的坐标之后,对其进行透视投影变换;3)训练神经网络;4)测试网络的性能;

1 书本变形模型下的x,z坐标

上篇确定了三阶多项式的系数范围,最终通过找规律如下:

if x3+x2+x1 == -0.4079999999999999 or x3+x2+x1 == -0.3979999999999999 or x3+x2+x1 == -0.4179999999999999:

符合这个规律的系数完美符合如下图形


确定了系数之后,进行定积分求坐标的工作

已知两点之间的弧长值,求弧长公式和第一个点的x坐标,要求出定积分公式中的上限。第一个坐标就是左侧空白后的值,即0.025.


由于在手工标定的过程中,从书的边缘开始,所以应在标定的结果里去掉两侧空白处。暂定左右空白为0.025,总弧长为1,于是除去空白后,每个文字间的距离应占0.024,即字与字间的弧长为0.024.

leftBlankDist = 0.025
rightBlankDist = 0.025

col0PosX = 0.025

allArcLen = 1

rowNum = 11
colNum = 39

PerTextArcLen = (allArcLen- leftBlankDist - rightBlankDist)/(colNum-1)

利用python求定积分函数进行不断地逼近求值,穷举法。

Fx = lambda x: math.sqrt(1+(3*a3*x**2+2*a2*x+a1)**2)
calu, err = integrate.quad(Fx, prevPosX, nextPosX)

快捷求下个坐标的方法是,利用曲线在点上的斜率,算出直线方程,再根据勾股定理算出下个坐标。

def getNextColX(prevColX):
    zX = lambda x: a3*x**3 + a2*x**2 + a1*x**1 + a0
    zDiff = lambda x: 3*a3*x**2 + 2*a2*x**1 + a1    
    k_prevColX = zDiff(prevColX)
    b =  zX(prevColX) - k_prevColX*prevColX   
    
    return quadratic(-(k_prevColX**2+1), 2*prevColX-2*k_prevColX*b, prevColX**2-b**2+PerTextArcLen**2)    
#a*x**2+b*x**+c=0
def quadratic(a,b,c):
    if a == 0:
        return -1
    if not isinstance(a,(int,float)) or  not isinstance(b,(int,float)) or not isinstance(c,(int,float)):
        return -2
    delta = math.pow(b,2) - 4*a*c
    if delta < 0:
        return -3
    x1= (math.sqrt(delta)-b)/(2*a)
    x2=-(math.sqrt(delta)+b)/(2*a)
    
    if x1 >0:
        return x1
    else:
        return x2    

就这样,不停地逼近,直到求得下个坐标与上个坐标的弧长近似于0.024即可。

如此这般重复39个,得到了所有的x坐标,利用之前得到的多项式,算出z的坐标。

将x的坐标从0到1映射到-190到190.

posX = []
    for x in posXLst:        
        posX.append((x-0.5)*380) 

y坐标和之前的是一致的,从50到-50。

验证一下得到的坐标对不对,画出三维图

  

2. 透视投影

在得到了书本变形的文字坐标后,对其进行透视投影变换,生成神经网络训练数据库。

for pitchIndex in range(len(pitchAngleList)):
        for rollIndex in range(len(rollAngleList)):
            for headingIndex in range(len(headingAngleList)):
                fileIndex = strModelName+"_"+str(samplesIndex)
                pitch_generate = pitchAngleList[pitchIndex]
                roll_generate = rollAngleList[rollIndex]
                heading_generate = headingAngleList[headingIndex]
                #get result
                totalGenerateResult(fileIndex, worldPosArray, coeffLst, pitch_generate, roll_generate, heading_generate)
                samplesIndex = samplesIndex + 1

验证得到的透视投影是否正确,画图如下:

  

3. 训练神经网络

在进行透视投影后生成的大量数据之上,进行神经网络的训练。网络结构如下:

batch_size = 200
epochs = 400
#2*429=858
firstLayerInputDim = 858
firstLayerOutput = 572

secondLayerOutput = 572

thirdLayerOutput = 335

fourthLayerOutput = 75

lastLayerOutput = 6

训练网络的时候,感觉很奇怪。没训练多长时间,acc直接干到了1,我的天爷,真是不知道该说啥。


92800/97200 [===========================>..] - ETA: 0s - loss: 1.8241e-05 - acc: 1.0000
94200/97200 [============================>.] - ETA: 0s - loss: 1.8278e-05 - acc: 1.0000
95400/97200 [============================>.] - ETA: 0s - loss: 1.8281e-05 - acc: 1.0000
96800/97200 [============================>.] - ETA: 0s - loss: 1.8281e-05 - acc: 1.0000
97200/97200 [==============================] - 4s 43us/step - loss: 1.8269e-05 - acc: 1.0000
Epoch 00157: early stopping

Testing ------------

  200/24300 [..............................] - ETA: 2s
 2200/24300 [=>............................] - ETA: 0s
 4800/24300 [====>.........................] - ETA: 0s
 6800/24300 [=======>......................] - ETA: 0s
 9200/24300 [==========>...................] - ETA: 0s
11200/24300 [============>.................] - ETA: 0s
13600/24300 [===============>..............] - ETA: 0s
15600/24300 [==================>...........] - ETA: 0s
18200/24300 [=====================>........] - ETA: 0s
20400/24300 [========================>.....] - ETA: 0s
22800/24300 [===========================>..] - ETA: 0s
24300/24300 [==============================] - 1s 24us/step
test cost: [1.827156896522813e-05, 1.0]
不知道为啥会这样。

在这个过程中,发现一个问题,网络不能预测出数量级不同的label值,比如说,前三个值都是0到1之间的,后面一个直接大于1了,那这个大于1的label值最多预测到0.9999,不能达到1.所有我感觉label值必须都在一个数量级上,然后我对label值中大于1的值进行了归一化。

def maxMinNormalization(num):
    return (num+1.47)/(1.3+1.47)

后来发现0,他也预测不出来,所以0和1都不能取。

归一化的值应该只是在网络训练的时候,而不是直接在求得坐标的时候进行归一化。

4.测试网络

随机选取3个样本进行测试,得以下结果。

predictValueArray [[  5.45609236e-01  -5.45512736e-02  -4.89583574e-02   7.42099364e-04
    9.96643126e-01  -2.19673872e-01]
 [  5.08703649e-01  -1.53725430e-01  -1.81550622e-01  -1.36820215e-03
    9.96155620e-01  -2.19944909e-01]
 [  4.37749803e-01  -1.53838143e-01  -4.46817018e-02   1.61321252e-03
    9.96471167e-01  -2.16794565e-01]]
testData_label [[ 0.54105207 -0.05597847 -0.04537996  0.          0.99637681 -0.218     ]
 [ 0.50614548 -0.15391273 -0.18274901  0.          0.99637681 -0.218     ]
 [ 0.43633231 -0.15391273 -0.04537996  0.          0.99637681 -0.218     ]]

看起来还是蛮准的嘛。

5 插曲

在整个过程中,遇到了一个问题就是:如何验证得到的书本变形的坐标是正确的呢。只有画图了。然后画图结果是这样:


这就有一个问题就是,看起来,明明点与点的之间的弧长根本不相等,后面开始变长了。经过老师的指导,最后发现原因是分辨率问题,即:x坐标显示的量级都是十。而z的却是0,01。这就造成了错觉。所以使用如下语句即可解决这个问题:

pylab.axis("equal")

6.后言

在完成以上工作后,下一步的任务是:

1)完成逆映射的相关工作

2)如何提取真实世界文字的坐标呢


猜你喜欢

转载自blog.csdn.net/qq_35546153/article/details/80786711