数据可视化-统计电影海报颜色

目标

实现和ppt上类似的效果,对电影海报进行颜色统计并展现出来
ppt上的效果:
1

1.0版本

1.0版本首先绘制每幅电影海报的色彩图,然后再扩充到整个月份、年度等
我们获取到的海报都是彩色图像,所以总共的色彩会有256X256X256个,这个数量是庞大的,所以我们在R、G、B三色中分别抽取4个,最后会有4X4X4=64个色彩,这个是比较适中的
我们对0-255分为4组,每组取其平均数,即:
0-63–>32
64-127–>96
128-191–>160
192-255–>224
比如我们有个色彩是[35,230,180],分别对应R、G、B
那这个色彩对应我们选取的64个色彩的第几个呢?
我们作出规定:先B、后G,最后R
64色彩中的第n个,n=(B/64)+(G/64)4+(R/64)16
所以我们这个色彩就对应[32,224,160],是64色彩中的第14个(从0开始)
64色彩按顺序依次如下:
0[32,32,32] 1[32,32,96] 2[32,32,160] 3[32,32,224]
4[32,96,32] 5[32,96,96] 6[32,96,160] 7[32,96,224]
8[32,160,32] 9[32,160,96] 10[32,160,160] 11[32,160,224]
12[32,224,32] 13[32,224,96] 14[32,224,160] 15[32,224,224]
16[96,32,32]……依次类推
然后将图片中的所有色彩分配到这64种颜色中,为了让最后的结果更加明显,64的颜色中的每种颜色的像素数扩充10倍,即达到640
最后将这64种颜色按序填充至640X10的jpg图像中

代码

因为之前在学习图像加密时,使用的java,所以依然使用java

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package graphic;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class poster {
public static void readThePoster(File ImageFile,int month,int postNum) throws IOException {
BufferedImage image=ImageIO.read(ImageFile);
int height=image.getHeight();
int width=image.getWidth();
int sum=height*width;
int count=0;
int colorNum[]=new int[64];
for(int x=0;x<width;x++) {
for(int y=0;y<height;y++) {
int pixel=image.getRGB(x, y);
int R=(pixel&0xff0000)>>16;
int G=(pixel&0xff00)>>8;
int B=pixel&0xff;
int suoshuKind=(R/64)*16+(G/64)*4+B/64;
colorNum[suoshuKind]++;
}
}
int fenpeideNum[]=new int[64];
int fenpeiSum=0;
for(int i=0;i<64;i++) {
fenpeideNum[i]=(colorNum[i]*640/sum);
fenpeiSum+=fenpeideNum[i];
}
if(fenpeiSum!=640) {
if(fenpeiSum>640) {
int chazhi=fenpeiSum-640;
int j=0;
for(int i=0;i<chazhi;) {
if(fenpeideNum[j%64]>1) {
fenpeideNum[j%64]--;
j++;i++;
}else {
j++;
}
}
}else {
int chazhi=640-fenpeiSum;
int j=0;
for(int i=0;i<chazhi;) {
if(fenpeideNum[j%64]>0) {
fenpeideNum[j%64]++;
j++;i++;
}else {
j++;
}
}
}
}
//统计完毕后,开始绘图
int paintColor[]= {32,96,160,224};
int paintCount=0;
//不要使用image.getType因为有些图像可能有些问题
BufferedImage outImage=new BufferedImage(640,10,BufferedImage.TYPE_3BYTE_BGR);
for(int x=0;x<64;x++) {
for(int i=0;i<fenpeideNum[x];i++) {
for(int y=0;y<10;y++) {
int B=paintColor[x%4];
int G=paintColor[(x/4)%4];
int R=paintColor[(x/16)%4];
Color pixel=new Color(R,G,B);
outImage.setRGB(paintCount+i, y, pixel.getRGB());
}
}
paintCount+=fenpeideNum[x];
}
String path="E:/大学课程/大三下学期/数据可视化/电影海报色谱图jpg/"+String.valueOf(month)+"月/"+String.valueOf(postNum)+".jpg";
File outFile=new File(path);
ImageIO.write(outImage, "jpg", outFile);
}
public static void main(String[] args) throws IOException {
int monthNum[]= {51,19,42,44,54,51,34,55,53,45,69,57};
for(int m=1;m<=12;m++) {
for(int i=0;i<monthNum[m-1];i++) {
File f=new File("E:/大学课程/大三下学期/数据可视化/电影海报/"+String.valueOf(m)+"月/"+String.valueOf(i)+".jpg");
readThePoster(f,m,i);
}
System.out.println(""+m+"月生成完毕!");
}
}
}

注意事项

注意BufferedImage outImage=new BufferedImage(640,10,BufferedImage.TYPE_3BYTE_BGR);设置输出图像的类型要设置成TYPE_3BYTE_BGR,不要使用image.getType,因为使用了image.getType后,有些生成jpg图像不行,生成png都可以,这可能和图像自身有关,所以统一使用BufferedImage.TYPE_3BYTE_BGR,表示一个具有8位RGB颜色分量的图像,具有三字节存储的R、G、B三种颜色

实现效果

选《一条狗的回家路》这部电影的海报,海报如下:
2
生成的颜色分布图如下所示:
3
可以发现效果还是不错的

2.0版本

实现了单个电影的后,实现按月统计的2019全年的色彩图,原理和单条的是相同的,只不过将单条的像素量调整为一个月里所有海报的

代码

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package graphic;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class posterTotal {
static int monthNum[]= {51,19,42,44,54,51,34,55,53,45,69,57};
static int totalPixel[][]=new int[12][64];
static int monthTotalSum[]=new int[12];
static int fenpeideNum[][]=new int[12][64];
static BufferedImage outImage=new BufferedImage(640,120,BufferedImage.TYPE_3BYTE_BGR);
public static void readThePoster(int month) throws IOException {
for(int i=0;i<monthNum[month];i++) {
File f=new File("E:/大学课程/大三下学期/数据可视化/电影海报/"+String.valueOf(month+1)+"月/"+String.valueOf(i)+".jpg");
BufferedImage image=ImageIO.read(f);
int height=image.getHeight();
int width=image.getWidth();
monthTotalSum[month]+=height*width;
for(int x=0;x<width;x++) {
for(int y=0;y<height;y++) {
int pixel=image.getRGB(x, y);
int R=(pixel&0xff0000)>>16;
int G=(pixel&0xff00)>>8;
int B=pixel&0xff;
int suoshuKind=(R/64)*16+(G/64)*4+B/64;
totalPixel[month][suoshuKind]++;
}
}
}
}
public static void dividen(int month) {
int fenpeiSum=0;
for(int i=0;i<64;i++) {
fenpeideNum[month][i]=(totalPixel[month][i]*640/monthTotalSum[month]);
fenpeiSum+=fenpeideNum[month][i];
}
System.out.println(""+month+"月像素分配总数:"+fenpeiSum);
if(fenpeiSum!=640) {
if(fenpeiSum>640) {
int chazhi=fenpeiSum-640;
int j=0;
for(int i=0;i<chazhi;) {
if(fenpeideNum[month][j%64]>1) {
fenpeideNum[month][j%64]--;
j++;i++;
}else {
j++;
}
}
}else {
int chazhi=640-fenpeiSum;
int j=0;
for(int i=0;i<chazhi;) {
if(fenpeideNum[month][j%64]>0) {
fenpeideNum[month][j%64]++;
j++;i++;
}else {
j++;
}
}
}
}
}
public static void paintPic(int month) {
int paintColor[]= {32,96,160,224};
int paintCount=0;
for(int x=0;x<64;x++) {
for(int i=0;i<fenpeideNum[month][x];i++) {
for(int y=month*10;y<(month+1)*10;y++) {
int B=paintColor[x%4];
int G=paintColor[(x/4)%4];
int R=paintColor[(x/16)%4];
Color pixel=new Color(R,G,B);
outImage.setRGB(paintCount+i,y,pixel.getRGB());
}
}
paintCount+=fenpeideNum[month][x];
}
}
public static void outPutTheImage() throws IOException {
String path="E:/大学课程/大三下学期/数据可视化/测试.jpg";
File outFile=new File(path);
ImageIO.write(outImage, "jpg", outFile);
}
public static void main(String[] args) throws IOException {
for(int m=0;m<12;m++) {
readThePoster(m);
System.out.println(""+m+"月像素总数:"+monthTotalSum[m]);
//统计完该月后,分配像素
dividen(m);
//分配完后,在图上绘制
paintPic(m);
}
outPutTheImage();
System.out.println("绘制完成!");
}
}

效果

4
图像大小为640X120,从上到小为2019年1-12月电影海报颜色分布,每一个月高度为10,宽度为640