[python]图像处理的方式找出使用颜色突出显示的内容

本文介绍了一种通过图像处理技术在自动化测试中识别APP内颜色突出内容的方法。首先,利用UI自动化框架获取特定控件截图并进行min马赛克处理,然后使用KMeans进行颜色聚类,找出最突出的颜色。接着,通过计算颜色点与拟合曲线的距离确定目标颜色。最后,应用目标颜色识别突出内容的坐标。这种方法对于不同颜色突出的文本识别有效,简化了自动化测试中的颜色识别问题。
摘要由CSDN通过智能技术生成

目录

[python]图像处理的方式找出使用颜色突出显示的内容

问题描述

解决思路

后续

具体实现

引用


问题描述

在一些文本描述页面中,通常会出现使用于正文不同的(通常选用比较鲜明的)颜色对一些超链接或其他内容进行突出显示,如图所示:

这边选用了两个APP的弹窗显示作为案例

图中《用户服务协议》和《隐私政策》都使用了与正文不同的颜色作为突出显示。

与web页面不同,现有自动化测试脚本无法识别出<red>或者<blue>标签(实际上在app开发过程中也不一定使用html语言),我能拿到的仅有这张图片、文本内容、还有一些简单的布局信息

很明显,不同APP用于突出显示的颜色和正文的颜色甚至底色都可不尽相同,我要做的是使代码能够自动识别哪个颜色是突出显示的颜色,并且进一步把突出显示的部分的坐标标注出来。

解决思路

受限于自动化测试框架的限制,直接使用框架获取坐标的方案是行不通的;

于是尝试使用图像处理的方案

精简图片

我们要找的是上面文本描述中颜色突出的部分,但是整个页面上颜色突出的明显不止《隐私协议》,下方的“同意”按钮同样非常鲜明,因此需要精简一下要处理的图片

幸运的是,自动化测试框架(我用的是UIAutoMator2)已经提供了相应功能,可以针对控件单独截图,效果大概是这样

搞定!

提取颜色

粗瞄一眼,图片中存在的有蓝色、黑色、白色,下面还有特效造成的灰色

但代码是不懂这个的,图片中实际存在的颜色远不止这几个

所以这里找了个用KMeans计算色卡的方案,为了保证效果,在此之前对图像打了个马赛克

需要注意的是,这里的打码用的方式是计算方圆一定范围内的最小值(正常的马赛克好像是平均值来着,没研究过),效果大概这样

对,还是那张图片,但是糊了,就想墨水湮开一样,这样处理是为了方便后续进行聚类计算的时候减少干扰(意识流,不加这一步到底效果如何没测试过,有兴趣的可以试试)

然后聚类,使用KMeans的时候我设置了分成5类,一般这种场景下5个颜色是比较合适的,基本的就三个(底色、正文颜色、突出正文的颜色),在留俩余量用于辅助后续计算。

叮!获得色卡

找到那只特立独行的猪(~~

可以看出,我们要的蓝色已经包含在里面了,其他的白色、黑色、灰色跟它比起来都显得那么平淡,虽然已经一眼就能看出来了,但代码还是需要计算才能“看到”这个异端。

现在把五种颜色的RGB值作为坐标输入坐标系(没找到好用的三维坐标系工具,用二维分别显示xy关系和xz关系也一样)

图中蓝点就是五个颜色在每个坐标系中的对应位置,绿线是使用numpy计算的的拟合曲线,

原理很简单,拟合曲线表达的是散点的整体趋势,而离拟合曲线距离最远的点就是跟大家最格格不入的那个。

最终距离用两个坐标系的距离加起来就好,硬要转换成三维坐标系再计算“真正”的距离也行,反正都是正相关,我们要的也只是排名而非具体数值。

距离分别是

[28.230040762072576, 122.2510082584425, 181.78840487811084, 79.90634236787547, 7.861095013861184]

距离最大的是第三个,cv2打印一下RGB值(cv2的RGB顺序应该是BGR):

[255.0, 171.44061303, 1.33333333]

检查一下

冇问题

后续

接下来就简单了,知道了具体的颜色,遍历也好,用其他什么工具也好,可以很容易的找出原图中颜色为#01ABFF的区域,再代入控件的左边计算一下,该颜色区域在整个页面的绝对坐标也不难算出。


具体实现

这里只给了计算突出颜色的方法,从截图到计算全部过程

关于UIAutoMator2的用法请参考github官方文档

# coding: utf-8
#
import copy
from collections import Counter
import cv2
import matplotlib.pyplot as plt
import numpy as np
import uiautomator2 as u2
from PIL import Image
from sklearn.cluster import KMeans


def msk(img,size):
    '''
    将图片进行min马赛克处理
    方便对颜色进行提取聚类
    '''
    ret=copy.copy(img)
    for index_1 in range(0,max(len(img),size),size):
        for index_2 in range(0,max(len(img[index_1]),size),size):
            index_1_s=index_1 if index_1+size<len(img) else len(img)-size
            index_2_s=index_2 if index_2+size<len(img[index_1]) else len(img[index_1])-size
            index_1_f=index_1_s+size
            index_2_f=index_2_s+size
            item=[255,255,255]
            for i in range(index_1_s,index_1_f):
                for j in range(index_2_s,index_2_f):
                    for itemi in range(3):
                        item[itemi]=min(item[itemi],img[i][j][itemi])
                        #item[itemi]+=img[i][j][itemi]
            #for index_item in range(3):
            #    item[index_item]=item[index_item]/(size*size)
            for i in range(index_1_s,index_1_f):
                for j in range(index_2_s,index_2_f):
                    for itemi in range(3):
                        ret[i][j][itemi]=item[itemi]
    return ret
def special_colors(color_list):
    '''
    返回一组颜色中最为突出(相较其他颜色更为显著)的颜色
    '''
    x=np.array([i[0] for i in color_list])
    y=np.array([i[1] for i in color_list])
    z=np.array([i[2] for i in color_list])

    xy = np.polyfit(x, y, 1) 
    xz = np.polyfit(x, z, 1) 

    def point_distance_line(point,line_point1,line_point2):
    	#计算
        vec1 = line_point1 - point
        vec2 = line_point2 - point
        distance = np.abs(np.cross(vec1,vec2)) / np.linalg.norm(line_point1-line_point2)
        return distance
    
    xy_p0_x=0
    xz_p0_x=0
    xy_p0_y=xy[1]
    xz_p0_y=xz[1]

    xy_p1_x=1
    xz_p1_x=1
    xy_p1_y=xy[0]+xy[1]
    xz_p1_y=xz[0]+xz[1]

    distance_xy=[]
    distance_xz=[]
    for i in color_list:
        param_point=np.array([i[0],i[1]])
        param_line_point1=np.array([xy_p0_x,xy_p0_y])
        param_line_point2=np.array([xy_p1_x,xy_p1_y])
        distance_xy.append(point_distance_line(param_point,param_line_point1,param_line_point2))

        param_point=np.array([i[0],i[2]])
        param_line_point1=np.array([xz_p0_x,xz_p0_y])
        param_line_point2=np.array([xz_p1_x,xz_p1_y])
        distance_xz.append(point_distance_line(param_point,param_line_point1,param_line_point2))
    
    # print('xy距离 - {}'.format(distance_xy))
    # print('xz距离 - {}'.format(distance_xz))
    # print('距离 - {}'.format([distance_xy[index]+distance_xz[index] for index in range(len(distance_xy))]))

    max_distance=max([distance_xy[index]+distance_xz[index] for index in range(len(distance_xy))])
    ret_index=[distance_xy[index]+distance_xz[index] for index in range(len(distance_xy))].index(max_distance)
    return color_list[ret_index]

# cv2.imshow("OpenCV",palette_perc(clt_1))
# cv2.waitKey()
# cv2.destroyAllWindows()



def work():
    d = u2.connect()
    # image = d(resourceId="cn.youth.news:id/are").screenshot()
    image = d.xpath('//android.widget.ScrollView').screenshot()
    img = cv2.cvtColor(np.asarray(image),cv2.COLOR_RGB2BGR)
    img2=msk(img,10)
    clt=KMeans(n_clusters=5) # 定义聚类器,预设聚5类
    clt_1 = clt.fit(img2.reshape(-1, 3)) # 计算聚类
    that_color=special_colors(clt_1.cluster_centers_)
    print(that_color)

if __name__ == '__main__':
    work()
    

引用

使用KMeans计算图片的色卡:使用KMeans计算图片主要颜色

python计算拟合曲线:python计算拟合曲线

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值