SynthText流程解读 - 不看代码不知道的那些事

1 概述

SynthText是OCR领域生成数据集非常经典,且至今看来无人超越的方法。整体可以分为三个大的步骤,分别是生成文字的mask,这里用到了图像的分割信息来选取区域,图像的深度信息来拟合该区域的3D平面,单应性变换来旋转平面;文字上色,用于选取适合背景色的文字颜色;图像融合,用来了泊松图像融合。

整体思路是非常棒的,挑不出毛病。目前有些文本贴图不真实,主要原因是分割的区域不是同一个平面内的区域,加之图像的深度信息也不准,导致了3D平面拟合不准,文字贴上去也就不准了。

2 流程解读

2.1 生成文字mask

这部分需要用到图像的分割信息和深度信息,示意图如图2-1所示。

分割和深度信息示意图

图2-1 分割和深度信息示意图

在当前的场景当中,最好的分割结果是可以把同一个物体的不同平面分割出来;次好的结果是把同一个平面分割出来,可以是不同物体。比如一座房子,不同的墙最好可以单独分开,两座平行的房子上平行的墙,分割在一起也是可以的。对于曲面,整个分割成一个instance就可以了,这个可以通过无法拟合成一个平面来删除。

最好的深度信息,就是准确的深度信息。

xyz = su.DepthCamera.depth2xyz(depth) 这步就是将深度信息转化为空间3D坐标。

regions = TextRegions.get_regions(xyz,seg,area,label) 会对分割区域进行筛选,得到可用于分割的区域。

筛选分为两步:
(1)regions = TextRegions.filter(seg,area,label) 筛除面积过小,或者长宽比极端的区域
(2)regions = TextRegions.filter_depth(xyz,seg,regions) 筛除区域内的点不能构成一个平面的区域,也就是曲面或者多个面,这里会得到平面的拟合结果

筛选后的区域示意图如下图2-2所示。
选择区域示意图

图2-2 选择区域示意图

regions = self.filter_for_placement(xyz,seg,regions) 对图2-2中的区域进行warp的变换,并获取warp变换所使用的单应性变换矩阵。

这部分有些难理解,我这里举个例子。比如我们有原图2-3。

例子原图

图2-3 例子原图

我们选取的区域为图2-4,也就是床下面那块黑影。
例子选取的区域

图2-4 例子选取的区域

该区域的部分截取下来为图2-5。
例子区域截图

图2-5 例子区域截图

该区域拟合的平面为图2-6。

例子区域拟合的平面

图2-6 例子区域拟合的平面

将图2-6中的平面绕中点转正,也就是转到平面的法向量对准我们,即法向量与Y轴平行。记录下这个变换过程所用到的单应性变换矩阵及其逆变换矩阵。转正后的图片如下图2-7所示。

例子区域变换结果图

图2-7 例子区域变换结果图

其mask如图2-8所示。
例子区域变换mask

图2-8 例子区域变换mask结果图

我们这里得到的单应性变换矩阵就是图2-4变为图2-8的矩阵。接下来只要往图2-8上贴上文字,然后整体变回图2-4就可以了。

这部分直接关系到了文字贴上图片能否有背景在同一个空间的效果。有许多的深度信息和分割信息是不准的,如果可以优化的话,可以有更好的效果。拿自动驾驶的数据集去当背景图应该是个不错的选择。

2.2 plane2xyz的bug

在将预估出来的平面转正的时候,发现转出来的z的值总是不同的,这和我们的理解是由偏差了。查了半天问题,发现是place2xyz代码中的两个系数写反了。修正后的代码为

@staticmethod
def plane2xyz(center, ij, plane):
    """
    converts image pixel indices to xyz on the PLANE.

    center : 2-tuple
    ij : nx2 int array
    plane : 4-tuple

    return nx3 array.
    """
    ij = np.atleast_2d(ij)
    n = ij.shape[0]
    ij = ij.astype('float')
    xy_ray = (ij-center[None,:]) / DepthCamera.f
    z = -plane[3]/(xy_ray.dot(plane[:2])+plane[2])
    # z = -plane[2]/(xy_ray.dot(plane[:2])+plane[3])
    xyz = np.c_[xy_ray, np.ones(n)] * z[:,None]
    return xyz

接下来解释一下为何如此。如下图2-9,我们的目的是将左边图像平面上的点,转换到右侧的实际平面上,中间的原点是小孔,原点到左侧图像的距离为焦距。实际平面就是代码中的plane,它有四个值,分别是 a , b , c , d a, b, c, d a,b,c,d,表示平面 a x + b y + c z + d = 0 ax+by+cz+d=0 ax+by+cz+d=0

plane

图2-9 图像平面和实际平面示意图

图像上点 ( x i , y i ) (x_i, y_i) (xi,yi)经过原点的直线可以表示为
x − 0 x i − 0 = y − 0 y i − 0 = z − 0 z i − 0 (2-1) \frac{x-0}{x_i - 0} = \frac{y-0}{y_i - 0} = \frac{z-0}{z_i - 0} \tag{2-1} xi0x0=yi0y0=zi0z0(2-1)

于是可以有

x = x i z z i , y = y i z z i , z i = f (2-2) x = \frac{x_iz}{z_i}, y = \frac{y_iz}{z_i}, z_i=f \tag{2-2} x=zixiz,y=ziyiz,zi=f(2-2)

将式 ( 2 − 2 ) (2-2) (22)代入 a x + b y + c z + d = 0 ax+by+cz+d=0 ax+by+cz+d=0,计算直线与planar scene的交点可以得到

z = − d a x i f + b y i f + c (2-3) z = -\frac{d}{a\frac{x_i}{f} + b\frac{y_i}{f} + c} \tag{2-3} z=afxi+bfyi+cd(2-3)

代码中plane[2]就是 c c cplane[3]就是 d d d,所有原来是反的。

代码中的xy_ray就是 x i f \frac{x_i}{f} fxi y i f \frac{y_i}{f} fyi。要求 x x x y y y,再利用式 ( 2 − 2 ) (2-2) (22)就可以了,这也就有了

xyz = np.c_[xy_ray, np.ones(n)] * z[:,None]

把这行代码改了,有奇效!

2.3 文字上色

我们往图2-8上贴文字的时候,需要确定文字的字体和颜色,字体随机即可,文字的颜色是需要根据背景色来确定的。

render_res = self.text_renderer.render_sample(font,collision_mask) 就是贴文字的过程。这部分的位置选取,字体选取,文字尺寸什么的就不说了,说一下这个文字颜色的选取。

选取颜色的过程在 def color_text(self, text_arr, h, bg_arr) 函数当中,这里依赖于一个文件 colors_new.cp ,这个文件中存储的是shape为 (4941, 12) 的array,为表示方便称为colorscolors[:, :6]表示颜色A的RGB值和各通道方差,colors[:, 6:12]表示颜色B的RGB值和各通道方差。表示背景色为A时,文字颜色可以用B;背景色为B时,文字颜色可以用A。

在寻找最匹配的背景色的时候,使用了LAB颜色空间,也就是将所有的RGB值转为到了LAB空间,然后取候选区域的所有LAB值的平均作为背景色LAB色,然后根据LAB色的距离来选取最合适的RGB值。方差就是取值的时候,加上方差,来得到多样性的作用。

这部分是可以优化的,背景色直接取LAB平均也太暴力了,万一颜色比较花,或者有极端值,就会影响很大。可以改成聚类或者mmcq的方式来获取主体色作为背景色。

2.4 图像融合

直到上述部分,文字仍旧还是和背景分离的,得到带有文本的图像和贴图的区域之后,使用了泊松融合的方式来自然融合两图,这里不推荐使用cv2.seamlessClone,因为cv2.seamlessClone暴露的参数太少了,作者自己写的blit_images就非常好,scale_grad 这个参数可以用来调整前景的梯度,也就是前景贴到背景上的明显程度。

比如有前景图和背景图,如图2-10所示。
前景图和背景图

图2-10 前景图和背景图

使用不同的 scale_grad 参数和 cv2.seamlessClone 的效果如下图2-11所示,cv2.seamlessClone甚至丢失掉了边界。
泊松融合对比图

图2-11 泊松融合对比图

将文本贴到warp过的区域之后,就可以使用单应性变换逆矩阵,把warp的区域还原回去,得到最终的效果图。

最终效果图

图2-12 泊松融合对比图

这么好的效果,其实是挑选过结果的,实际情况下,还是有很多都是效果没那么出色的。怪就怪分割和深度信息不准。

参考资料

[1] Synthetic Data for Text Localisation in Natural Images
[2] https://github.com/ankush-me/SynthText

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七元权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值