Java图像处理(底层像素逻辑)
·
底层像素矩阵到位运算
一、图片的结构
-
- 像素值组成的矩阵
-
- 像素值:颜色的数值表达
- 计算机的颜色:RGB(三个通道)ARGB(四个通道)
- 三个通道:
- red : 16-23位
- green : 8-15位
- blue : 0-7位
- 四个通道:
- Alpha : 24-31
- red 16-23位
- green 8-15位
- blue 0-7位
- 一个int:4byte
- 会将四个通道之中的值按照顺序排进一个int数值中。
- 三个通道:
二、 拆解像素:位运算
- 四个颜色通道被塞进了一个int里,在做图像处理时,需要单独拆解出来。这里就需要用到执行效率高的位运算。
- 注意,这里是按位与运算(&),是对二进制位进行逐位计算的运算符,不要和判断布尔条件的逻辑与(&&)混淆!
- 向右位移:>>将二进制数向右边移动,高位缺失补0,低位溢出的位数丢失
- 向左位移:<< 将二进制数向左边移动,低位缺失补0,高位溢出的位数丢失
- 位运算:
- 与运算:相同保留源码,不同为0,两个都是1就是1,其他都是0;
- 或运算:有一个1就是1,都为0才是0.
- 异或运算:相同为0,不同为1.
- 拆数据:
- red = num>>16 & 0xff;
- green = num>>8 & 0xff;
- blue = num & 0xff;
- 将num向右移位,低位的数据直接抛弃,只将所需要的数据留在最右边。此时比如需要八位数据,八位已经位移到最后八位,如果使用0xff(0000 0000 1111 1111)。前面0的部分和位移后数据与运算之后,得到的就是0。最后8位的数据都是1,和位移后的数据进行与运算,就能提取出来所需要的几位数据。
- 合数据:
- rgb = red<<16 | green<<8 | blue;
- 此时red,green等数据都是最右边是八位是有效数据的一串数字,如果在此时将red向左移动16位,那么这个有效数据就回到了它原本应该在的部位,其他几个同理。
- 将这几个数据或运算,只要有1,结果就是1,那么这几个内容就会完美的拼在一起,并且保证数据正确。
- 注意,这里是按位与运算(&),是对二进制位进行逐位计算的运算符,不要和判断布尔条件的逻辑与(&&)混淆!
三、不同的绘画
1.基础图画还原
- 直接给出代码,代码之中包含注释
package picture01;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImagePro extends JFrame {
// 核心数据结构:保存图片每一个像素点的二维数组
int w, h;
int[][] imgArr;
public ImagePro() {
setTitle("Java 图像处理 - 基础原图还原");
setSize(800, 900);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 在窗口初始化时,提前将图片数据加载进内存
imgArr = getImage("D:\\study\\java\\新建文件夹\\mihu.jpg");
setVisible(true);
}
//将所画图纸变成实物
public static void main(String[] args) {
new ImagePro();
}
// 重绘方法:核心渲染逻辑
@Override
public void paint(Graphics g) {
//清理画板,JFram窗口在每次重绘时,如果不调用这几代码,画面上可可能会残留之前拖动窗口留下的
//重影或花屏
super.paint(g);
//防御性编程,如果读取图片错误或者未读到,立即返回防止空指针异常
if (imgArr == null) return;
// 遍历二维数组,逐个像素画出来
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pix = imgArr[i][j];
// 拆解出干净的 RGB 通道
int red = (pix >> 16) & 0xFF;
int green = (pix >> 8) & 0xFF;
int blue = pix & 0xFF;
// 设置画笔颜色
g.setColor(new Color(red, green, blue));
// 画出这个像素点(加上 50 的偏移量避免被窗口的标题栏遮挡)
// 使用 1x1 的矩形代表一个真实的像素点
g.fillRect(i + 50, j + 50, 1, 1);
}
}
}
// 数据提取:将物理图片转化为内存中的二维数组
/*try { ... } catch (IOException e) { ... }作用:涉及到硬盘文件io操作,,文件可能不存在
,路径写错,或者图片格式损坏,这是一道安全防线,如果读取失败,会打印错误信息并返回null,
防止整个程序直接崩溃*/
public int[][] getImage(String path) {
try {
//根据文件路径,将硬盘里的文件加载到内存之中,并且转换成BufferedImage对象。
//可以理解为图片已经脱离了物理文件的形态,变成了Java可以直接调用的内存对象
BufferedImage img = ImageIO.read(new File(path));
w = img.getWidth();
h = img.getHeight();
int[][] arr = new int[w][h];
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
//把该像素点的颜色提取出来
arr[i][j] = img.getRGB(i, j);
}
}
//经过循环之后,图片已经变成了一个装满int数字的数字矩阵。最后将这个二位数组返回给调用者(paint)
return arr;
} catch (IOException e) {
/*catch的意思是捕获,IOException 的全称是 Input/Output Exception(输入/输出异常)。
之前try之中的是我们希望正常执行的代码,如果在读取过程之中发生了任何io错误,程序不会立即闪退
二十生成一个IOException类型的错误对象
*/
//打印黑匣子记录
e.printStackTrace();
return null;
}
}
}
2.底片/反色
// 设置画笔颜色
g.setColor(new Color(255-red, 255-green, 255-blue));
-这是最简单的滤镜,视觉冲击力极强。原理是用最大值 255 减去当前的颜色值,得到它的互补色。
3.黑白/二值化滤镜
- 先计算灰度值,使得图像非黑即白,大于灰度值的一个颜色,反之另一个颜色
int Y = (int)(0.299*red+0.587*green+0.114*blue);
int threshold = 127;
if(Y>threshold){
g.setColor(Color.WHITE);
}else{
g.setColor(Color.BLACK);
}
4.复古滤镜
- 1.利用公式变换颜色
- 2.注意颜色溢出(最高到255)
//4.复古老照片滤镜
int R = (int)(0.393*red + 0.769*green + 0.189*blue);
int G = (int)(0.349*red + 0.686*green + 0.168*blue);
int B = (int)(0.272*red + 0.534*green + 0.131*blue);
int RED = Math.min(R, 255);
int GREEN = Math.min(G, 255);
int BLUE = Math.min(B, 255);
g.setColor(new Color(RED, GREEN, BLUE));
高对比度/色彩增强滤镜
- 1.色彩增强,利用公式来得到。
- 2.运用线性映射,将每个颜色通道归一化到【0,1】区间,进行缩放后再还原到[0,255]
- 3.contrast
- 大于1,对比度增强
- 小于1,对比度降低
- 4.需要设置边界,无论是大还是小。
//高对比度增强
double contrast = 1;
int R = (int)((red-128)*contrast+128);
int G = (int)((green-128)*contrast+128);
int B = (int)((blue-128)*contrast+128);
int RED = Math.max(0, Math.min(R, 255));
int GREEN = Math.max(0, Math.min(G, 255));
int BLUE = Math.max(0, Math.min(B, 255));
g.setColor(new Color(RED, GREEN, BLUE));
- 颜色对比
- (1)contrast = 1:原图

- (2)contrast = 2>1:饱和度增强

- (3)contrast = 0.5<1:饱和度降低

- (1)contrast = 1:原图
更多推荐
所有评论(0)