序:
几年前,看到6H猎人在网上做的动态世界各国领土变化的视频,被深深的吸引了,那个视频也特别火,被各大知名媒体引入,本想向作者询问视频制作软件,却被告之是一帧帧画出来的,作为一个资深地图迷和程序员自然不能忍。其实看视频的时候就已经在想这些算法该怎么写了,后来偶然看到了一个网站,调出了他的JS代码,学习了一下,又结合各种因素想了想,基本所有问题都已经解决了,就差开始动手了。于是今天就开始解决第一个问题,分析出空白地图中的区域。搞了一天,最终完成了。在网上不知道是不是自己的关键字搜索的不正确,总是找不到好方法。于是自己想了这个方法,效率不是很高,但是可以完美实现,后续用C++的话再看看怎么优化。
零、过程总述:
1、初步填充:这一步会首先一次将地图填充完毕,因为在自上而下用不同的颜色填充可能区域的时候,并不能准确知道那一部分和那一部分是一个区域,所以很容易出现一个区域多种颜色的情况。
2、颜色归类:分析出哪些颜色是其实是一个颜色,将他们归类。
3、最终填充:在依然像第一步一样遍历一遍图片,这次根据第二次的颜色归类,将属于同一区域的颜色,填充为同一种颜色。最终实现我们的目标
一、初步填充
填充规则,每个格子如果上面符合填充规则的话(列入上格既不是边界,也不是水,而且格子存在)颜色等于上面,否则判断左侧格子。如果上和左都不符合,则随机一种颜色填充。很显然A1是是随机出的颜色。B1颜色从A1来,A2颜色也从A1来。到了H1则再次随机颜色。
填充后会发现如下问题
侧视图效果:
我的效果颜色是因为,我的颜色并不是随机的,而是初始颜色为(0,0,0),每次换颜色就+1 (0,0,1) 蓝色满了就进一,以此类推。所以效果看起来又黑又蓝。其实只要不是同一区域内的绝对不是同一种颜色。只是颜色变化太小,人的眼睛分辨不出,之所以黑蓝交替出现,是因为出现了进位比如(0,1,0) 在人眼睛里依然是黑色。如果地图很大,则会看到绿色逐步出现。过度感很强。
也许你会发现,很多区域都别细长条所填充。并不是我们想要的样子。接下来我们需要进入第二步,颜色归类。
二、颜色归类
虽然说是第二步,其实我们可以在第一步中进行,当我们对G3颜色进行判断后,虽然确定了G3的颜色,可是不需要那么快结束,接着判断一下他的左边是否为合法相邻块。如果是,那么就查看一下颜色是否和自己相同,如果不同,则他两个是属于同一区域的不同颜色,将这两种颜色归为一类。
三、最终填充
最后一步,最后一次遍历地图,将属于同一区域的颜色,填充为为同一颜色。就得到了效果。
代码如下
from PIL import Image
import random
#im = Image.open('./org-s.bmp')
im = Image.open('./org.bmp')
def isVaildColor(color):
return color!=(102,102,102) and color!=(153,204,255)
def randMapColor():
color=(random.randint(0,255),random.randint(0,255),random.randint(0,255))
while(not isVaildColor(color)):
color=(random.randint(0,255),random.randint(0,255),random.randint(0,255))
return color
def findAncestors(colFather):
while(colorFatherDir[colFather]!=colFather):
#print("不是祖元素,下一个!",colFather)
colFather=colorFatherDir[colFather]
return colFather
def MapColorP(color):
r=color[0]
g=color[1]
b=color[2]+1
if b>255:
b=0
g=g+1
if g>255:
g=0
r=r+1
print("红色进位")
if r>255:
print("颜色不够用")
r=0
color=(r,g,b)
if isVaildColor(color):
return color
else:
return MapColorP(color,1)
print("-------------------------------处理中----------------------------------")
color=(0,0,0)
color=MapColorP(color)
colorFatherDir={}
colorFatherDir[color]=color
for i in range(im.size[0]):
if isVaildColor(im.getpixel((i,0))):
im.putpixel((i,0),color)
else:
color=MapColorP(color)
colorFatherDir[color]=color
for j in range(1,im.size[1]):
if isVaildColor(im.getpixel((0,j))):
if isVaildColor(im.getpixel((0,j-1))):
colorMate=im.getpixel((0,j-1))
im.putpixel((0,j),colorMate)
else:
color=MapColorP(color)
colorFatherDir[color]=color
im.putpixel((0,j),color)
for i in range(1,im.size[0]):
if isVaildColor(im.getpixel((i,j))):
if isVaildColor(im.getpixel((i,j-1))):
colorMate=im.getpixel((i,j-1))
im.putpixel((i,j),colorMate)
#归属集处理
if isVaildColor(im.getpixel((i-1,j))):
if findAncestors(im.getpixel((i,j)))!=findAncestors(im.getpixel((i-1,j))):
colorFatherDir[findAncestors(im.getpixel((i,j)))]=findAncestors(im.getpixel((i-1,j)))
elif isVaildColor(im.getpixel((i-1,j))):
colorMate=im.getpixel((i-1,j))
im.putpixel((i,j),colorMate)
else:
color=MapColorP(color)
colorFatherDir[color]=color
im.putpixel((i,j),color)
print("颜色总数",len(colorFatherDir))
realColor={}
for father in colorFatherDir:
realColor[findAncestors(father)]=randMapColor()
for j in range(1,im.size[1]):
for i in range(1,im.size[0]):
if isVaildColor(im.getpixel((i,j))):
colFather=im.getpixel((i,j))
im.putpixel((i,j),realColor[findAncestors(colFather)])
im.show()
im.save("./tmp.bmp","BMP") #保存图像为gif格式
我这张图的边界颜色为(102,102,102),水的颜色为(153,204,255)
如果自己手里有待填充地图,请改为适合自己的颜色。