rangercyh / sprite_sheet_slice

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

install

pip install PyQt5
pip install opencv-python
pip install olefile  # for tga
pip install imageio

intro

通过 opencv 识别图像边缘,把 sprite sheet 切割成单独的图。

在网上找了一些工具,发现这么常用的事情居然没有合适的工具做,简直不可思议,有一些工具可以实现,但是并不太满足我的要求,比如我要求导出图片需要相同大小,然后需要核心要素居中之类的操作,所以还是自己写比较方便。

逻辑细节:

  1. 加载图片(最好是带透明通道的,如果不带透明通道最后保存需要自己写一个通道信息,当然也可以不写),因为 opencv 的 imread 函数不支持比较常见的 tga 格式图片,所以引入 imageio 库来代替它加载图片,这样支持的图片格式更多。

  2. 因为 opencv 处理的图片格式是 BGR 的,跟常见的 RGB 不一样所以用 cv2.cvtColor(np.array(image), cv2.COLOR_RGBA2BGRA) 转一下。

  3. 为了识别出边缘,首先得处理一下图像,先取图像的灰度图,然后用 Sobel 算子做一下梯度减法,这样可以过滤到低水平梯度的图,让图像更干净。

  4. 要是图像噪点比较多,还可以用低通滤波器函数平滑图像来去掉高频噪点,不过因为一般 sprite sheet 都比较干净,所以这一步可以省略。

  5. 接下来把灰度图处理成二值图,也就是黑白图。这里 opencv 提供了两个函数,一个是强制全图平均的二值化函数,一个是自适应的二值化函数。前者就是按照全图设置一个阈值来翻转像素,后者就是根据一个范围内的像素点来翻转。因为 sprite sheet 一般比较干净,所以用全图的就够了。

  6. 接下来一般还需要做一些形态学处理,使最后识别边缘更加准确,其实是因为二值化处理灰度图之后基本上有内容的区域中间都会留下一些黑点像素,这个时候就可以利用形态学处理来去掉这些地方。对于我想要识别 sprite 边缘来说主要是 4 类形态学处理:腐蚀、膨胀、开、闭。其实开闭就是腐蚀+膨胀,顺序不同。腐蚀可以想象成缩小边缘的像素点,膨胀就是往外扩,所以一缩一扩就可以把内部的小点点吞掉,就去掉了。不过我这里没有加,主要是我测试的效果不太好,容易把一些比较紧凑的 sprite sheet 内容连到一起了,不利于区分边缘。如果一张图只需要扣一个元素出来还是很有必要处理一下的,这样后续的计算边缘性能要好一些。

  7. 最后就是用 findContours 函数识别出边缘了,有个细节就是这个函数的返回值是没有顺序的,但我想要的 sprite sheet 当然最好是按照从上到下,从左到右排序的,这样方便我后续用。所以我对结果做了个排序,当然这里也有细节,就是即使是同一行的切分出来的元素,也不见得 y 坐标就相同,还是会有一定的波动的,所以我加了一个容忍范围,在容忍范围内波动都认为是同一行。

  8. 另一个细节就是最识别出来的结果我做了一步过滤,就是如果识别出来的边缘框起来的区域面积过小,那么对于 sprite sheet 来说通常就意味着识别错了,所以我过滤了比较小的区域,实际用起来其实识别正常的情况下是不会有过滤的。

  9. 因为我需要导出相同尺寸的图,所以最后就是找到所有图最大的宽高,然后按照这个尺寸把原图拷贝进去,居中对齐。

package

pip install pyinstaller
pyinstaller -F -w 1.py

About


Languages

Language:Python 100.0%