图形像素原理
每张图片都可以表示为由像素值组成的矩阵。
分辨率决定单位面积的像素个数
像素矩阵:像素点的值 – 颜色表达
RGB图像又称为真彩图像,它使用R、G、B 3个分量标识一个像素的颜色,R、G、B分别代表红、绿、蓝3种不同的基础颜色,通过3基色可以合成出任意颜色。所以对一个尺寸nxm的彩色图像来说,MATLAB中则存储为一个nxmx3 的多维数据数组,其中数组中的元素定义了图像中每一个像素的红、绿、蓝颜色值。图形文件格式把RGB图像存储为24位的图像,红、绿、蓝分量分别占用8位,因而理论上可以有2^24种颜色。
R G B:
0-255 256个 8bit 256 256 256
像素值的存储
1.创建一个二维数组来表示像素组成的矩阵
把三个byte 存入一个int
RGB
0000 0000 32位
1000 0000 24位 R
1000 0000 16位 G
1000 0000 低八位 B
0表示黑色 255 表示白色
Java的位移运算
为什么二进制1000等于-8
也就是说,对于4位整数1000,最高位为1符号位,说明是一个负数。那么它的计算方式是:
- -1 * 2^3 + 0 * 2^2 + 0 * 2^1 + 0 * 2^0=-8+0+0+0=-8
再例如二进制的1111,按照这个计算方式结果是:
- -1 * 2^3 + 1 * 2^2 + 1 * 2^1 + 1 * 2^0=-8+4+2+1=-1
Java中的int类型占32位,因此能表示的范围为-2^31 ~ 2^31-1,
int类型的十进制范围表示为:-2147483648~2147483647
int类型的二进制表示范围为: 10000000 00000000 00000000 00000000 ~ 01111111 11111111 11111111 11111111
左移<<
二进制数向左移动k位,丢弃最高的k位,并在有右边补k个0
01111111 11111111 11111111 11111111左移一位,符号位变成1,低位用0填充
所以结果位11111111 11111111 11111111 11111110,通过补码编码得出结果为-2
10000000 00000000 00000000 00000000左移一位,符号位变为0,代表正数,低位同样用0填充,结果位00000000 00000000 00000000 00000000,因此结果为0
右移>>
-
算术右移到方式比较微妙,二进制右移动k位,丢弃低k位,并在高k位补最高位的值。其目的是为了负数的运算
如下:算术右移动后,高位原本是几就用几补充
- 01111111 11111111 11111111 11111111 算术右移1位
- 00111111 11111111 11111111 11111111
- 10000000 00000000 00000000 00000000 算术右移1位
- 11000000 00000000 00000000 00000000
可以看到十进制无论是正还是负数,逻辑右移一位相当于除以二。
首先我们要都知道, &表示按位与,只有两个位同时为1,才能得到1, 0x代表16进制数,0xff表示的数二进制1111 1111 占一个字节.和其进行&操作的数,最低8位,不会发生变化.
我们只关心二进制的机器数而不关注十进制的值,那么byte &0xff只是对其最低8位的复制,通常配合逻辑或 ‘’|’'使用,达到字节的拼接
int vaule = ((255 & 0XFF) << 24) | ((red & 0XFF) << 16) | ((green & 0XFF) << 8) | ((blue & 0XFF) << 0);
此时代码终于看懂了
改进分析
package Image;
import jdk.management.resource.internal.inst.FileOutputStreamRMHooks;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
/**
* 1: 讲清楚图形像素原理
* 2: 位移运算 以及位运算
* 3: 完成像素图 - 基础效果 尝试比如调色板实现
*/
public class ImagePad extends JFrame {
public static int[][] res;
public static int width;
public static int height;
public ImagePad() {
setTitle("像素画");
setSize(100 + width, height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
@Override
public void paint(Graphics g) {
super.paint(g);
//ranDom(g);
draWing(g);
}
public static void ranDom(Graphics g) {
Color color = new Color(255, 255, 255);
g.setColor(color);
g.fillRect(100, 100, 500, 500);
Random random = new Random();
random.nextInt(256);// [0 bound)
// 随机一个数组的像素值
int[][] cloloArr = new int[500][500];
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 500; j++) {
int red = random.nextInt(256);
int green = random.nextInt(256);
int blue = random.nextInt(256);
int vaule = ((255 & 0XFF) << 24) | ((red & 0XFF) << 16) | ((green & 0XFF) << 8) | ((blue & 0XFF) << 0);
cloloArr[i][j] = vaule;
}
}
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 500; j++) {
Color color1 = new Color(cloloArr[i][j]);
g.setColor(color1);
g.fillRect(100 + i, 100 + j, 1, 1);
}
}
for (int i = 0; i < 500; i++) {
for (int j = 0; j < 500; j++) {
int value = cloloArr[i][j];
int red = (value >> 16) & 0xFF;
int green = (value >> 8) & 0xFF;
int blue = (value >> 0) & 0xFF;
int gray = (red + green + blue) / 5;
Color color1 = new Color(red / 2, green / 2, blue / 2);
g.setColor(color1);
g.fillRect(610 + i, 100 + j, 1, 1);
}
}
}
public static void draWing(Graphics gr) {
File file = new File("D:\\壁纸\\1.jpg");
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
width = bi.getWidth();
height = bi.getHeight();
res = new int[width][height];
int minx = bi.getMinX();
int miny = bi.getMinY();
for (int i = minx; i < width; i++) {
for (int j = miny; j < height; j++) {
int pixel = bi.getRGB(i, j);
res[i][j] = pixel;
}
}
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int value = res[i][j];
int red = (value >> 16) & 0xFF;
int green = (value >> 8) & 0xFF;
int blue = (value >> 0) & 0xFF;
int gray=(red+green+blue)/3;
Color color1 = new Color(red/3,green/3,blue);
Color color2 = new Color(gray,gray,gray);
gr.setColor(color1);
//gr.setColor(color2);
gr.fillRect(minx + i, miny + j, 1, 1);
}
}
}
public static void main(String[] args) {
new ImagePad();
}
}
分析
int value = res[i][j];
int red = (value >> 16) & 0xFF;
int green = (value >> 8) & 0xFF;
int blue = (value >> 0) & 0xFF;
int gray=(red+green+blue)/3;
Color color1 = newColor(red/3,green/3,blue);
Color color2 = new Color(gray,gray,gray);
原图:
当new Color(red/2,green/2,blue/2)
效果如下:
当new Color(red/3,green/3,blue/3)
效果如下:
当int gray=(red+green+blue)/3;
效果如下:
当int gray=(red+green+blue)/6;
效果如下: