import enum
import time
try:
from PIL import Image
from PIL import ImageDraw
except ImportError:
pass
from devicetest.utils.time_util import TS
class ImgLoc(enum.Enum):
'''
图片所在的枚举类
1左上 (North_West)
2中上 (North)
3右上 (Nort_East)
4左中 (West)
5全图 (All)
6右中 (East)
7左下 (South_West)
8中下 (South)
9右下(South_East)
'''
North_West = 1
North = 2
North_East = 3
West = 4
All = 5
East = 6
South_West = 7
South = 8
South_East = 9
class ImgUtils:
@staticmethod
def img2arr(arr_img, rect=None, convert=True):
'''
@将位图流转化为二维二值数组
@param arr_img: instance of Image
'''
if convert and arr_img.mode != 'L':
arr_img = arr_img.convert('L')
width, height = arr_img.size
pix = arr_img.load()
if rect:
rect_l, rect_t, rect_r, rect_b = rect
result_list = []
for pix_h in range(height):
if not rect_t <= pix_h <= rect_b + 1:
continue
temp_list = []
for pix_w in range(width):
if not rect_l <= pix_w <= rect_r + 1:
continue
temp_list.append(pix[pix_w, pix_h])
result_list.append(temp_list)
return result_list
result_list = []
for pix_h in range(height):
temp_list = []
for pix_w in range(width):
temp_list.append(pix[pix_w, pix_h])
result_list.append(temp_list)
return result_list
@staticmethod
def get_rect(rect_width, rect_height, location):
'''
根据方位对象,获取图片的方位
'''
rect = (0, 0, rect_width, rect_height)
if location == ImgLoc.East.value:
rect = (int(rect_width >> 1), 0, rect_width, rect_height)
elif location == ImgLoc.South.value:
rect = (0, int(rect_height >> 1), rect_width, rect_height)
elif location == ImgLoc.West.value:
rect = (0, 0, int(rect_width >> 1), rect_height)
elif location == ImgLoc.North.value:
rect = (0, 0, rect_width, int(rect_height >> 1))
elif location == ImgLoc.North_East.value:
rect = (int(rect_width >> 1), 0,
rect_width, int(rect_height >> 1))
elif location == ImgLoc.South_East.value:
rect = (int(rect_width >> 1),
int(rect_height >> 1), rect_width, rect_height)
elif location == ImgLoc.North_West.value:
rect = (0, 0, int(rect_width >> 1), int(rect_height >> 1))
elif location == ImgLoc.South_West.value:
rect = (0, int(rect_height >> 1),
int(rect_width >> 1), rect_height)
return rect
@staticmethod
def quick_find(fp1, fp2, similar=1, density=None,
rect=None, loc=ImgLoc.All.value, debug=False):
'''
快速查找图片,指定的similar越大,速度越快
1. 如果similar不等于1,则使用density来加快查找速度 density(x,y)
表示对比的时候 每个横坐标上只对比 (width / 2^x)个点
每个纵坐标上只对比 height / 2^y个点,相当于只对比原来的
(width + height) / 2^(x+y) 个点
@param fp1: 大图片的绝对路径
@param fp2: 小图片的绝对路径
@param similar: 对比的相似度;如 0.7, 0.9, 1
@param density: 小图中对比的密度: (2,3) 表示每行对比 width >> 2个点;
没列对比 height >> 3个点
@param rect: 大图中指定区域内查找 (left,top,right,bottom)
@param loc: 小图在大图中的什么部位,是一个枚举对象,ImgLoc,注意需要
加.value;如: ImgLoc.North.value 或者 直接输入 1 -9 的数字也行
@param debug: 是否打印debug信息
'''
if debug:
TS.start()
_m1 = Image.open(fp1)
_m2 = Image.open(fp2)
m1_w, m1_h = _m1.size
if not rect:
rect = ImgUtils.get_rect(m1_w, m1_h, loc)
data1 = ImgUtils.img2arr(_m1.crop(rect) if rect else _m1)
data2 = ImgUtils.img2arr(_m2)
if debug:
TS.stop("before find_arr")
return ImgUtils.find_arr(data1, data2, similar, density, rect, debug)
@staticmethod
def find_arr(im1, im2, similar=1, density=None, rect=None, debug=False):
'''
在大图中查找小图
注意:如果density值为None,则系统自动设置,保证特征点在9 - 16个左右
(即 3 * 3 或 4 * 4之间)
@param im1 大图的二维数组
@param im2 小图的二维数组
@param similar 相似度
@param density (x,y) x: 可以控制小图横坐标查找的点数
im2Width >> x 个点数
@param rect 在指定的区域中查找图片 (若指定,则可以大大节省时间)
(leftX,topY,rihgtX,bottomY)
@return (rect,similar) rect:找到的图片位置; similar:相似度
'''
if debug:
TS.start()
m2_width = len(im2[0])
m2_height = len(im2)
arr_width = len(im1[0]) - m2_width + 1
arr_height = len(im1) - m2_height + 1
denx, deny = 0, 0
if not density:
denx, deny = ImgUtils.get_density(m2_width, m2_height)
else:
denx, deny = density
den_yy = int(m2_height >> deny)
den_xx = int(m2_width >> denx)
total = den_yy * den_xx
if total == 0:
total = 1
max_fail_num = (1 - similar) * total
if debug:
print("denXX: %i; denYY: %i; total: %i" % (
den_xx, den_yy, total))
print("maxFailNum %i" % max_fail_num)
starttime = time.time()
endtime = starttime + 5.0 * 60.0
for arr_h in range(arr_height):
for arr_w in range(arr_width):
if time.time() <= endtime:
fail_num = 0
found = True
for _yy in range(den_yy):
for _xx in range(den_xx):
x_den = _xx << denx
y_den = _yy << deny
m2_val = im2[y_den][x_den]
m1_val = im1[arr_h + y_den][x_den + arr_w]
if m1_val != m2_val:
fail_num += 1
if max_fail_num <= fail_num:
found = False
break
if not found:
break
if found:
if debug:
TS.stop("find_arr")
if rect:
rect_l, rect_t, rect_r, rect_b = rect
return (1 - fail_num / total), (
arr_w + rect_l, arr_h + rect_t, arr_w +
m2_width + rect_l, arr_h + m2_height + rect_t)
return (1 - fail_num / total), (
arr_w, arr_h, arr_w + m2_width, arr_h + m2_height)
else:
return None, None
if debug:
TS.stop("find_arr")
return None, None
@staticmethod
def img_filter(filter_img, *filters):
last_img = filter_img
for _filter in filters:
last_img = last_img.filter(_filter)
return last_img
@staticmethod
def get_density(width, height, maxWNum=4, maxHNum=4):
denx, deny = 0, 0
while width > maxWNum:
denx += 1
width = int(width >> 1)
while height > maxHNum:
deny += 1
height = int(height >> 1)
return denx, deny