App的icon颜色跟App类别的关系

手机里的app有一百多个吧,不太喜欢用ios的app文件夹,觉得有点难看,所以一般用页来分类,每个类别一页或者几个类别一起拼成一页。于是就很容易发现购物那一页全线飘红(无视下面的视频类)。

很容易想到这不是偶然,大家都心知肚明暖色可以激发人买买买的欲望。那么其他app呢?微信是绿色的,支付宝是蓝色的,网易云音乐是红色的,这些颜色是如何选择的?这几个app的颜色选择可能有一定的偶然性,但是一个类别比如购物类有明显暖色倾向的话,颜色的选择就不是偶然了,那么除了购物类之外其他类别有没有颜色倾向呢?
碰巧会爬虫也会opencv,刚好也知道描述视觉感觉的话可以用Lab空间计算距离……既然已经想到这一步了就来做一下吧!

大致思路就是

  • 把App Store上的app图标按类别爬下来
  • 选择常见的几种颜色比如红、绿、蓝、黄、品红、青作为标准色
  • 用OpenCV分析一下图片的颜色,转换到Lab空间,计算出到哪个标准色距离最短
  • 把结果可视化方便得出结论

爬取图片

以下是代码,加了非常详细的注释,App Store的网站非常友好哈哈哈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# coding:utf8
import requests
from bs4 import BeautifulSoup

# 浏览器请求头(大部分网站没有这个请求头会报错)
headers = {'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"}
all_url = 'http://itunes.apple.com/cn/genre/ios-%E5%9B%BE%E4%B9%A6/id6018?mt=8' # 开始的URL地址
start_html = requests.get(all_url, headers=headers) # 加了头的地址
Soup = BeautifulSoup(start_html.text, 'lxml') # 解析HTML

# 找到类别列表 <div id="genre-nav" class="nav">
all_lei = Soup.find('div', class_='nav').find_all('a')

for lei in all_lei: # 取一个类别
lei_url = lei['href'] # 取该类别的链接
lei_html = requests.get(lei_url, headers=headers) # 加了头的地址
lei_soup = BeautifulSoup(lei_html.text, 'lxml') # 解析HTML

# 找到类别网址里的app排行榜 <div id="selectedcontent" class="grid3-column">
all_app = lei_soup.find('div', class_='grid3-column').find_all('a')

f = open('图书'+'.txt', 'w') # 以类别名称命名txt
for a in all_app: # 取出app排行榜中的一个app
title = a.get_text() # 取类别名称
print(title)
app_url = a['href'] # 取出该app的链接
app_html = requests.get(app_url, headers=headers) # 加了头的地址
app_soup = BeautifulSoup(app_html.text, 'lxml') # 解析HTML

# 找到app页面中的icon <div class="product-hero__media l-column small-5 medium-4 large-3 small-valign-top">
icon = app_soup.find('div',class_='product-hero__media l-column small-5 medium-4 large-3 small-valign-top').find_all('img')

for img in icon:
src = img['src']
print(src)
f.write(src + '\n') # 将icon地址写到以类别命名的txt文件中
f.close()
# 得到一个以某个类别命名的txt文件 里面有该类别240个app的icon的地址
# 得到所有类别的txt

爬完之后就得到了每个类别前240个icon图片的链接,用下载器下载下来就搞定了

分析颜色

批量读取图片
1
2
3
4
5
width = 246
height = 246
size = height * width # icon尺寸
path = '/Users/Jinnm/Desktop/pic/'
dirs = os.listdir(path) # 导入该路径中的所有文件名
颜色空间转换

图片里每个像素转换

1
2
3
4
5
6
7
for i in dirs:
img = cv2.imread(path + i, cv2.IMREAD_COLOR) # 导入文件
img2 = []
for j in range(0, width):
for k in range(0, height):
# 存储每个像素点的lab值, trans为转换函数
img2.append(trans(img[i][j][2], img[i][j][1], img[i][j][0]))

标准颜色的转换

1
2
3
4
5
6
# 设定标准的13种颜色的rgb值
rule = [[255, 0, 0], [255, 147, 0], [255, 255, 0], [0, 255, 0], [0, 255, 255], [0, 0, 255], [148, 32, 146], [255, 64, 255], [171, 69, 0], [171, 121, 66], [165, 165, 165], [0, 0, 0], [255, 255, 255]];
rule2 = [];
# 储存13种颜色的lab值
for i in range(0, 13):
rule2.append(trans(rule[i][0], rule[i][1], rule[i][2]));

转换函数(依照rgb转lab公式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def trans(r,g,b): #根据公式把rgb数据转到lab
def calV(V):
if V <= 0.04045:
return V / 12.92
else:
return ((V + 0.055) / 1.055) ** 2.4
def calXYZ(R, G, B):
sR = calV(R / 255.0)
sG = calV(G / 255.0)
sB = calV(B / 255.0)
x = 100 * (0.4124564 * sR + 0.3575761 * sG + 0.1804375 * sB)
y = 100 * (0.2126729 * sR + 0.7151522 * sG + 0.0721750 * sB)
z = 100 * (0.0193339 * sR + 0.1191920 * sG + 0.9503041 * sB)
return [x, y, z]
def f(t):
if t > ((6.0 / 29) ** 3):
return t ** (1.0 / 3)
else:
return 1.0 / 3 * 29 * 29 / 6 / 6 * t + 16.0 / 116
def calLab(X, Y, Z):
X_n = 94.813
Y_n = 100.000
Z_n = 107.262
L = 116 * f(Y / Y_n) - 16
a = 500 * (f(X / X_n) - f(Y / Y_n))
b = 200 * (f(Y / Y_n) - f(Z / Z_n))
return [L, a, b]
R = int(r)
G = int(g)
B = int(b)
[x, y, z] = calXYZ(R, G, B)
[L, a, b] = calLab(x, y, z)
return [L, a, b]
量化图片颜色

计算在lab颜色空间中与标准色的距离,将每个像素点量化到距离最小的标准色,并记录一张图片中各个标准色的像素数量

1
2
3
4
5
6
7
8
for i in range(0, width * height):
dist = []
for j in range(0, 13):
# 记录下像素点与13种颜色在lab颜色空间中的距离
dist.append( (img2[i][0] - rule2[j][0]) ** 2 + (img2[i][1] - rule2[j][1]) ** 2 + ( img2[i][2] - rule2[j][2]) ** 2)
num = [0] * 13
pos = dist.index(min(dist)) # 读取距离最小的颜色序号作为该像素点的代表
num[pos] += 1 # 一张图中所有像素点的代表颜色的数量统计
保存结果

将结果保存到exel

1
2
3
4
5
6
7
8
import xlwt
book = xlwt.Workbook(encoding='utf-8');
sheet =book.add_sheet('test'); # 建立存储数据的excel表
flag = 0;
for j in range(0, 13):
sheet.write(flag, j, label=num[j]); # 把统计数据写入excel表中
flag += 1;
book.save('/Users/Jinnm/Desktop/result.xls'); # 保存excel表

结果大概是这个样子(13列是13种颜色)

可视化结果

刚好下个学期有可视化的课程,打算学习之后处理一下这个结果,目前先用最最普通的柱状图表示

结果分析

对结果的柱状图进行初步的分析。
发现结果跟自己预想的不太一样哈哈,原本感觉购物暖色,社交冷色,结果社交类中暖色的比例也非常高。

总体

现象一:白色在所有大类中均占最高的比例
猜测原因:
大部分icon喜欢采用白底+logo的配置,由于logo在icon中占的像素数少,导致大量的icon被归类于白色主色调。
至于为什么都喜欢采用白底,猜测是因为

  • 白色的icon背景带来更好的融合性和统一性,以ios系统为例,自带的系列图标很多都是这个形式,那么第三方也采用这个形式会使界面比较统一协调。
  • 白色可以为用户提供清新干净的视觉体验,去掉不必要的视觉干扰,从而更集中于logo。而五彩斑斓的杂色的图标往往容易让人有嘈杂的眩晕感。
  • 由于颜色带来的视觉效果是互相影响的,而白色一般不影响其他颜色观感,是一个非常好的“搭色”。

现象二:暖色在统计数据中比重较高
猜测原因:
现在每个用户都有大量app排列在手机中,暖色相较于冷色往往更为显眼,用红色与黄色作为icon的主颜色会使该icon更为醒目,从而增加用户的点击使用率。

现象三:配色选取大多数少于3种
这一块目前通过这个柱状图是看不出来的,但是观察exel的表格可以发现,一个icon在很多颜色上的像素数都是0或是数值很小,数值明显特别大的颜色一般在三种以内。另一方面也说明了目前这种数据可视化的方式有很多不足。
猜测原因:
icon是一个很小的图标,简洁的图案和配色会比较适合这种小区域猜测,清晰而又令人印象深刻。而且再观察之后可以发现,多种颜色一般是相近的颜色。采取色相接近的配色方案主要是为了使得icon整体观感统一和谐。

分类

在红色白色总体占比大的情况下,单纯的看一个类别的柱状图,那每一个类别都是红色白色是主要颜色了……所以分类的分析采用横向对比的方法,观察相对其他类别而言,哪些颜色比较突出,哪些颜色显得特别少。这一方面的分析目前的柱状图也很不合适,而且每张图的纵坐标比例是不一样的,所以不能直接比较高度……

种类:摄影
现象:
黑白两色的比例极高,彩色运用明显比较少,但在相对运用比较少的彩色中红色占比还是比较大的。
猜测原因:
多数的摄影app喜欢标榜个性,追求性冷淡的高端简洁风。除去这一些以外的摄影app往往是针对女性用户群的,故多用女性更偏好的红粉色调。

种类:商务
现象:
绿、青、蓝、紫的比例较高
猜测原因:
这一类冷色调的颜色往往给用户以平和安稳的感觉,会让用户更倾向去信赖。而且这些冷色调是没有性别偏好的颜色,男女中都有大量的用户群偏好这种颜色,所以这是一个非常容易使用户产生好感的颜色。

种类:社交
现象:
白色的比例较低
猜测原因:
大部分的社交软件更倾向于用彩底突出吸引力。而且相较于白底的平淡无奇,彩底更能使得这些社交软件显得活泼生动而愉悦,营造更为轻松的氛围。

种类:购物
现象:
红色比例极高
猜测原因:
红色等暖色可以给用户一种视觉上的刺激感,在使icon更具冲击力的同时,也某种程度上促进了用户的购买欲,从而促进快速消费。这也是为什么大多数快餐店会选择这类冲击性大的暖色。

总结

结果还是和自己平时的感受有挺多不一样的,看来数据是王道哈哈哈。目前最大的不足就是数据可视化,不合适的可视化使得直观地看出规律变得非常困难。