在这里我们将会简单了解到什么是卷积操作,并使用卷积对图像进行处理。
1.预备知识
我们需要知道的是,在计算机中,图像是由很多个像素点组合而成,我们对图像的卷积处理其实就是对这些像素点进行一定的运算处理。知道这一点我们就可以开始以下的学习了。
2.卷积操作
在图像处理中,卷积操作指的就是使用一个卷积核(kernel)对一张图像中的每个像素进行一系列操作。卷积核通常是一个四方形网格结构(例如2x2、3x3的方形区域),该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置于该像素上,翻转核之后再依次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是该位置的新像素值。
动态演示如下:
动态演示中我们会发现6 * 6的图经过卷积处理后我们得到了4 * 4的图,这是因为我们在处理图像边界的时候有两种选择。其一,我们可以把最外围的像素“丢弃”掉,这是最直接的;其二,我们在最外围再添加一圈0像素,这样我们就可以同样使用卷积得到边界像素。
3.卷积的应用
在了解了卷积操作后,我们来实际地使用卷积处理原图,得到有趣的图片吧!
(1)锐化
(2)浮雕
(3)强调边缘
代码如下:
(注:以下代码还实现了图像的灰白化、黑白化、镜像等,有兴趣可以参考了解一下)
package imagePro;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class Pro {
Graphics g;//画布
public void showUI(){
//窗口基本属性
JFrame jf=new JFrame();
jf.setSize(1100, 1100);
jf.setDefaultCloseOperation(jf.DISPOSE_ON_CLOSE);
jf.setLocationRelativeTo(null);
//监听器对象
ImgListener lis=new ImgListener();
//菜单栏
JMenuBar bar=new JMenuBar();
//菜单选项
JMenu menu1=new JMenu("图片处理");
//子选项
JMenuItem loadPic=new JMenuItem("加载图片");
JMenuItem drawPic=new JMenuItem("绘制图片");
JMenuItem grayPic=new JMenuItem("灰度化");
JMenuItem blackPic=new JMenuItem("黑白化");
JMenuItem mirrorPic=new JMenuItem("镜像");
JMenuItem guessPic=new JMenuItem("高斯模糊");
JMenuItem relievoPic=new JMenuItem("浮雕");
JMenuItem sharpenPic=new JMenuItem("锐化");
JMenuItem edgePic=new JMenuItem("强调边缘");
//添加监听器
loadPic.addActionListener(lis);
drawPic.addActionListener(lis);
grayPic.addActionListener(lis);
blackPic.addActionListener(lis);
mirrorPic.addActionListener(lis);
guessPic.addActionListener(lis);
relievoPic.addActionListener(lis);
sharpenPic.addActionListener(lis);
edgePic.addActionListener(lis);
//菜单添加选项
menu1.add(loadPic);
menu1.add(drawPic);
menu1.add(grayPic);
menu1.add(blackPic);
menu1.add(mirrorPic);
menu1.add(guessPic);
menu1.add(relievoPic);
menu1.add(sharpenPic);
menu1.add(edgePic);
//添加菜单
bar.add(menu1);
//设置菜单栏
jf.setJMenuBar(bar);
jf.setVisible(true);//窗体可见
g=jf.getGraphics();//获取窗体的画布
lis.setGraphics(g);
}
public static void main(String[] args){
Pro pro=new Pro();
pro.showUI();
}
}
监听器类
package imagePro;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImgListener implements ActionListener{
BufferedImage image;//图片
BufferedImage img;//临时图片
BufferedImage img_1;//图片黑白化
Graphics temp_g;//临时画布
Graphics g;
public void actionPerformed(ActionEvent e) {
String str=e.getActionCommand();
System.out.println(str);
if("加载图片".equals(str)){
load();
}
if("绘制图片".equals(str)){
draw();
}
if("灰度化".equals(str)){
huidu();
}
if("黑白化".equals(str)){
heibai();
}
if("镜像".equals(str)){
mirror();
}
if("高斯模糊".equals(str)){
Guess();
}
if("浮雕".equals(str)){
fudiao();
}
if("锐化".equals(str)){
ruihua();
}
if("强调边缘".equals(str)){
edge();
}
}
public void load(){
try {
image =ImageIO.read(new File("DVA.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw(){
g.drawImage(image, 100, 100, null);
}
public void huidu(){
img=new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
temp_g=img.getGraphics();
//分别获取R/G/B值
for(int i=0;i<image.getWidth();i++){
for(int j=0;j<image.getHeight();j++){
int RGB=image.getRGB(i, j);
int R=(RGB>>16)&0xff;
int G=(RGB>>8)&0xff;
int B=RGB&0xff;
//绘制该点
int gray=(int)(0.3*R+0.59*G+0.11*B);
temp_g.setColor(new Color(gray,gray,gray));
temp_g.drawLine(i, j, i, j);
}
}
g.drawImage(img, 100, 100, null);
}
public void heibai(){
img=new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);
temp_g=img.getGraphics();
//分别获取R/G/B值
for(int i=0;i<image.getWidth();i++){
for(int j=0;j<image.getHeight();j++){
int RGB=image.getRGB(i, j);
int R=(RGB>>16)&0xff;
int G=(RGB>>8)&0xff;
int B=RGB&0xff;
//绘制该点
int ave=(R+G+B)/3;
if(ave<78){
temp_g.setColor(Color.BLACK);
}else
temp_g.setColor(Color.WHITE);
temp_g.drawLine(i, j, i, j);
}
}
img_1=img;
g.drawImage(img, 100, 100, null);
}
public void mirror(){
img=new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);
temp_g=img.getGraphics();
//分别获取R/G/B值
for(int i=0;i<image.getWidth();i++){
for(int j=0;j<image.getHeight();j++){
int RGB=image.getRGB(i, j);
int R=(RGB>>16)&0xff;
int G=(RGB>>8)&0xff;
int B=RGB&0xff;
//绘制该点
temp_g.setColor(new Color(R,G,B));
temp_g.drawLine(image.getWidth()-i-1, j, image.getWidth()-i-1, j);
}
}
g.drawImage(img, 100, 100, null);
}
public void Guess(){
double value[]={0.075,0.124,0.075,0.124,0.204,0.124,0.075,0.124,0.075};
drawPic(img, value);
}
private void fudiao() {
double value[]={1,0,-1,1,0,-1,1,0,-1};
drawPic(img, value);
}
private void edge() {
double value[]={1,1,1,1,-7,1,1,1,1};
drawPic(img, value);
}
private void ruihua() {
double value[]={-1,-1,-1,-1,9,-1,-1,-1,-1};
drawPic(img, value);
}
public void drawPic(BufferedImage img,double[] value){
img=new BufferedImage(image.getWidth(),image.getHeight(),BufferedImage.TYPE_INT_RGB);
temp_g=img.getGraphics();
int pix[]=new int[9];
for(int i=1;i<img.getWidth()-1;i++){
for(int j=1;j<img.getHeight()-1;j++){
readPix(image, i, j, pix);//获取图像该点周围的像素值
temp_g.setColor(changePix(pix, value));//设置该点的颜色
temp_g.drawLine(i, j, i, j);
}
}
g.drawImage(img, 100, 100, null);
}
public void readPix(BufferedImage img,int x,int y,int[]pix){
int start=0;
for(int i=x-1;i<x+2;i++){
for(int j=y-1;j<y+2;j++){
pix[start++]=img.getRGB(i, j);//3*3的数组转化为1*9的数组
}
}
}
public Color changePix(int[] pix,double[] value){
double R=0;
double G=0;
double B=0;
//分别获取R、G、B的值
for(int i=0;i<pix.length;i++){
R+=((pix[i]>>16)&0xff)*value[i];
G+=((pix[i]>>8)&0xff)*value[i];
B+=(pix[i]&0xff)*value[i];
}
if(R>255)R=255;
if(R<0)R=0;
if(G>255)G=255;
if(G<0)G=0;
if(B>255)B=255;
if(B<0)B=0;
return new Color((int)R,(int)G,(int)B);
}
public void setGraphics(Graphics g){
this.g=g;
}
}
参考:(图像处理基本知识)https://zhuanlan.zhihu.com/p/55013828