原理简介
在图像处理中,线性滤波是一种比较基本的处理方式。在进行滤波处理之前,我们首先需要一个滤波矩阵,改矩阵称为卷积核,通常情况下为 3×3、5×5、7×7... 大小的矩阵,这样该卷积核的最中心会有一个元素。
在简单的图像处理中,其一般的处理方式就是对某一个像素及其周围的像素的RGB值与卷积核对应的元素相乘后相加,最后将该值取代原来的像素值RGB值。
假设左边的矩阵代表着某一张图片,其元素表示的是其对应像素的RGB值,而右边的矩阵则是我们的卷积核。其处理过程就是针对某一像素及其周围像素,例如我们取绿色方框里的像素,然后向其周围取一个大小与卷积核相同的像素矩阵,即红色方框表示的矩阵。用该矩阵与卷积核对应的元素相乘之后求和,最后用该值作为绿色方框位置的像素的RGB值。再重复计算其他像素的RGB值即可。
可以看出用 3×3 的卷积核滤波之后,原来图片的最外围一圈的像素并没有计算到,但是对于一整张图片来说可以忽略不计。
还有一点就是在Java中,RGB值是作为一个整体用一个 int 类型的数据进行存储的,所以在进行计算时,要分别对 R、G、B 进行卷积运算,最后将计算后的 R、G、B 值作为对应位置的RGB值。此外还要判断计算过后的 R、G、B 值是否超过了 0 ~ 255 的范围。
示例代码
在示例中,我们以常见的锐化处理卷积核为例:
其他类型的卷积核大家可以去查阅相关资料,相关的实例代码如下:
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 TextFilter {
public static void main(String[] args) {
JFrame jf = new JFrame(); // 创建显示窗体
jf.setSize(800,800); // 设置窗体大小
jf.setLocationRelativeTo(null); // 窗体居中
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置退出进程
jf.setVisible(true); // 设置窗体可见
File file = new File("兵长.jpg"); // 建立图片文件对象
// 建立缓冲图片
BufferedImage image = null;
try {
image = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
if (image != null){
sharpen(jf.getGraphics(), image); // 调用锐化函数并绘出
}
}
// 锐化函数
public static void sharpen (Graphics g, BufferedImage image){
BufferedImage sharpenImage = new BufferedImage(image.getWidth(),image.getHeight(),image.getType()); // 建立新的缓冲图片用于保存
int[][] kernel = {{-1, -1, -1},{-1, 9, -1},{-1, -1, -1}}; // 建立卷积核
// 循环卷积计算
for (int i = 0; i < image.getWidth() - kernel.length + 1; i++){
for (int j = 0; j < image.getHeight() - kernel.length + 1; j++) {
int red = 0, green = 0, blue = 0;
for (int m = 0; m < kernel.length; m++) {
for (int n = 0; n < kernel.length; n++) {
red += (image.getRGB(i + m, j + n) >> 16 & 0xFF) * kernel[m][n];
green += (image.getRGB(i + m, j + n) >> 8 & 0xFF) * kernel[m][n];
blue += (image.getRGB(i + m, j + n) & 0xFF) * kernel[m][n];
}
}
// 判断 R、G、B 是否在 0 ~ 255 范围内
red = red > 255 ? 255 : Math.max(red, 0);
green = green > 255 ? 255 : Math.max(green, 0);
blue = blue > 255 ? 255 : Math.max(blue, 0);
int color = (255 << 24) + (red << 16) + (green << 8) + blue;
sharpenImage.setRGB(i+kernel.length/2, j+kernel.length/2, color); // 将计算后的RGB值保存到新图片中
}
}
g.drawImage(sharpenImage, 50, 50, null); // 绘制新图片
}
}
锐化效果如下:
原图
锐化处理后