图像的编码原理
图像是由一个个带有颜色的小格组成的,每个小格的颜色都是唯一的。一张图片的像素个数=长*宽。所以不难理解,为什么一张图片的像素(像素点个数)越高,图片就越清晰,因为图片的精密度更高。下图显示的是一个分辨率为 900
×
\times
× 600的图片。
而每个像素的颜色取值是通过RGB模式确定的,RGB色彩就是常说的光学三原色,R代表Red(红色),G代表Green(绿色),B代表Blue(蓝色)。自然界中肉眼所能看到的任何色彩都可以由这三种色彩混合叠加而成,因此也称为加色模式。R、G、B各自的取值都是0~255,用 8bit一个字节就可以存储。所以用int数据类型就可以把RGB所需三个字节存储起来,最后还剩一个字节可以添加额外的信息。然后通过相应的位移运算和与运算就可以获得所需的RGB分量。
// 0000 0000 1000 0000 1000 0000 1000 0000 = 8421504
R G B
int value = 8421504;
int red = (value >> 16) & 0xFF;
int green = (value >> 8) & 0xFF;
//0000 0000 1000 0000 1000 0000 1000 0000
//右移八位: 0000 0000 1000 0000 1000 0000
// 0xFF: 1111 1111
// 最后做与运算获得分量:green:
int blue = (value >> 0) & 0xFF;
绘制图像
接下来就可以将图片的像素存储到二维数组里,
Image是一个抽象类,BufferedImage是其实现类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中(BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便地操作这个图片)
流程如下:
1.首先根据提供的图片路径path创建一个文件对象
String path="E:\\java\\eclipse\\eclipse javaee\\workspace\\Yu java\\66.jpg"
File file =new File(path);//java.io.File
2.再次具体化file是什么类型的文件,
以便于调用不同类型文件所具有的不同方法,这里是image文件
那么就可以调用getRGB(i, j)来获取像素。
//读取文件数据
//java.awt.image.BufferedImage;
BufferedImage buffimage=null;
try {
buffimage=ImageIO.read(file);//javax.imageio.ImageIO
}catch (IOException e) {
e.printStackTrace();
System.err.println("图像读取失败");
}
3.通过循环将buffimage.getRGB(i, j)获得像素存放在数组中
详细实现如下:
//读取文件,获得图片像素
public int[][] getImagePixel(String path)
{
//读取文件的数据
File file =new File(path);
//imageIO操作将图片文件的输入输出,
//读取文件数据
BufferedImage buffimage=null;
try {
buffimage=ImageIO.read(file);
}catch (IOException e) {
e.printStackTrace();
System.err.println("图像读取失败");
}
//获取缓冲图片的大小,初始化保存像素值得二维数组
int w=buffimage.getWidth();
int h=buffimage.getHeight();
int [][]arrPixel=new int[w][h];
for(int i=0;i<w;i++)
{
for(int j=0;j<h;j++)
{
int pixel=buffimage.getRGB(i, j);
arrPixel[i][j]=pixel;
}
}
return arrPixel;
}
以上是原图重绘效果。除此之外,根据像素的重绘间隔和色彩RGB设置我们可以获得不同的图片渲染效果。例如:马赛克(间隔取像素,不一个一个重绘),二值化(根据计算出来的灰度值定一个阈值 100 ,大于画白, 小于画黑色)。
//马赛克 间距取像素值 绘制成间距大小的方块
public void paint2(Graphics g,String path)
{
int [][]arrpixel=getImagePixel(path);
for(int i=0;i<arrpixel.length;i+=20)
{
for(int j=0;j<arrpixel[i].length;j+=20)
{
int pixel=arrpixel[i][j];
int red=(pixel>>16&0xFF);
int green=(pixel>>8&0xFF);
int blue =(pixel>>0&0xFF);
Color color=new Color(red,green,blue);
g.setColor(color);
g.fillRect(i, j+200, 20,20);
}
}
}
//灰度
public void paint3(Graphics g ,String path)
{
int [][]pixel=getImagePixel(path);
for(int i=0;i<pixel.length;i++)
{
for(int j=0;j<pixel[i].length;j++)
{
int value =pixel[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
int gray =(red+green+blue)/3;
// int gray =(int)(red*0.4+green*0.28+blue*0.31);
//Color color=new Color(red/2,green/2,blue/2);
Color color=new Color(gray,gray,gray);
g.setColor(color);
g.fillRect(i,j+200,1,1);
}
}
}
//二值化手绘
public void paint4(Graphics g ,String path)
{
int [][]pixel=getImagePixel(path);
for(int i=0;i<pixel.length;i++)
{
for(int j=0;j<pixel[i].length;j++)
{
int value =pixel[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
int gray=(int)(red*0.4+green*0.5+blue*0.6);
//以gray<100为分界线,大于这个数的全部是白色
if(gray<150)
{
g.setColor(Color.black);
}
else
{
g.setColor(Color.white);
}
g.fillRect(i, j+200,1, 1);
}
}
}
//轮廓检测
//相邻之间的像素点进行比较
public void paint5(Graphics g ,String path)
{
int [][]pixel=getImagePixel(path);
for(int i=0;i<pixel.length-2;i++)
{
for(int j=0;j<pixel[i].length-2;j++)
{
int value =pixel[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
int valuen=pixel[i+2][j+2];
int redn=(valuen>>16)&0xFF;
int greenn=(valuen>>8)&0xFF;
int bluen=(valuen>>0)&0xFF;
//int gray =(red+green+blue)/3;
int gray =(int)(red*0.41+green*0.28+blue*0.31);
int grayn =(int)(redn*0.41+greenn*0.28+bluen*0.31);
if(Math.abs(gray-grayn)>15){
g.setColor(Color.PINK);
}else{
g.setColor(Color.white);
}
g.fillRect(i, j+200, 1, 1);
}
}
}
//绘制油画
public void paint6(Graphics g ,String path)
{
Random random = new Random();
int [][]pixel=getImagePixel(path);
for(int i=0;i<pixel.length;i+=3)
{
for(int j=0;j<pixel[i].length;j+=3)
{
Color color=new Color(pixel[i][j]);
g.setColor(color);
int size = random.nextInt(5)+5;
g.fillOval(i,j+200,size,size);
}
}
}
马赛克
灰度
二值化