关于程序对图片的识别与再现以及马赛克和滤镜的生成

前言

图像,是我们对环境认知的最基础的最直观的基本方式。存在既会表示,表示则会被理解,被“看”到。人眼能看到周围的环境吗,靠的是自然光的反射与衍射,若是想让程序显示出我们能看到的图片,需要其生成一张能放出各种颜色光的点阵图

电脑的屏幕

在内存中

在内存中可以使用一个int表示一个像素的数值 记录下来

屏幕的结构

多个灯珠组成的一个矩阵结构

灯珠

颜色: 电子三原色 红 绿 蓝,每种颜色的变化阶梯有256阶

亮度: 明暗度 每个灯珠都可以显示出 256^3 种不同的颜色

一个1980*1080的屏幕有多少颗200万左右的灯珠

一个灯珠表示一个像素

在内存中可以使用一个int表示一个像素的数值 记录下来

像素值

int 作为一个像素存储单位 ,自身内部所占内存空间是 32bit

最高八位 表示透明度 其次: 是 Red Green Blue 各占八位 像素:

Red        0-255

Green    0-255

Blue       0-255

透明度:0-255

00000000//透明值00000000//红00000000//绿00000000//蓝

程序中图像的实现

颜色的定义

Color 类:

创建颜色对象:

1: Color color1 = new Color(r //red,g //green,b //blue);

2: Color color2 = new Color(r,g,b,a);

3: Color color3 = new Color(p //rgb);

将 透红绿蓝 8位依次排列,就能构成一个32位二进制数,将其存储为int类型的值,这就是其像素的颜色值,所以创建颜色类的方法有三种,分别为提供r,g,b的值,或a,r,g,b的值,或颜色值p

程序的实现

首先,完成一个窗体的创建,用以绘制图片

public void showUI() {
setTitle("图像处理");
setSize(1900, 900);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

继承父类用以重写刷新代码并显示自定义的生成方法

public class ImageProUI extends JFrame {
// 直接使用继承的方法 创建界面

public void showUI() {
setTitle("图像处理");
setSize(1900, 900);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

// 改造父类的刷新界面的方法 重写方法 用于在窗体可视化时直接显示咱们的照片

@Override
public void paint(Graphics g) {
super.paint(g);
// 绘制图片
drawMyPixMatrix(g);

}
}

接下来编写自定义的图形生成方法drawMyPixMatrix

public void drawMyPixMatrix(Graphics g){
// 原图
for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {

                int pixNum = arr[i][j];
                Color color = new Color(pixNum);
                g.setColor(color);
                g.fillRect(100+i,200+j,1,1);

            }
        }

}

我们已经知道,颜色的本质是一个int类型的数字,可以通过还原成二进制数来调控灯光的亮度来进行操作。由此我们可以直接读取初始化的二维数组中的初始数据绘制成一个底盘,也可以叫原图

接着,我们便可以对原图进行调色处理,比如在绘画方法中加入这样的循环,可以使新的自定义规律数字重新填充到二维数组中,使其存储的rgb数发生改变

for (int i = 0; i < w; i++) {
          for (int j = 0; j < h; j++) {
              arr[i][j]=i*j;
          }
      }

运行后可以得到这样一个美丽的图形:

放大后还有一些美丽的花纹

这仅仅只是一种计算rgb值的方法:[i][j] = i * j

还有其他的无数的规律同样也可以使用,比如: = i + j, = i % j 等,还可以将color中的r,g,b的值提取出来再处理:

  Color color = new Color(pixNum);
  Color color1 = new Color( 255-color.getGreen() , 255-color.getBlue() , 255-color.getRed() );

然后再用新生成的color1进行绘制,这样也不唯是一种规律用以绘画

马赛克的生成

如何将图片打上马赛克?这看起来好像有点无从下手,其实自习观察马赛克就可以发现,马赛克的本质其实是将某一部分色块只用一个像素点的颜色表示出来,这样,我们就能够写出对应代码了

我们可以将行列数的自加变成跳跃性的,同时生成一个具有一种颜色的大色块,从而形成遮蔽整张图片的马赛克结构。

我们可以在绘图方法中加入这样一段循环

 for (int i = 0; i < w; i+=10) {
            for (int j = 0; j < h; j+=10) {

                int pixNum = arr[i][j];
                Color color = new Color(pixNum);
                g.setColor(color);
                g.fillRect(650+i,200+j,10,10);

            }
        }

运行程序后会形成这样的图形:

初见马赛克的结构,但是由于是规则图形,并不是很明显

为了更方便更直观的看出马赛克,我们可以改写一下图形的生成逻辑,生成一些不规律的图形用以观测:我们可以生成一个随机数并将随机数填充至矩阵中,

Random rand = new Random();

        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                //防止生成的随机数大于整形的最大值
                int pix = rand.nextInt(Integer.MAX_VALUE);
                arr[i][j] = pix;

            }
        }

将代码放入绘图方法中并取代原有的矩阵数字生成规则( arr [i][j] = i * j )

运行后可以得到这样的图形:

这样就能更直观的看出这一点。

对传入图像的转化和投射

为了将我们传入的图像进行处理,使其转换成程序能够处理的矩阵图列,我们编写一段获取照片像素的方法

    //获取一张照片像素的方法
    public int[][] getImagePixArr() {
        //这里是照片的存储位置
        String path = "C:"; 
        File file = new File(path);
        try {
            BufferedImage img = ImageIO.read(file);
            int w = img.getWidth();
            int 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);
                }
            }
            return arr;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

别忘记导包

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.Random;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.awt.image.BufferedImage;

为了接收返回的矩阵值,我们改造之前的绘图方法

private void drawMyImage(Graphics g) {

        int[][] arr = getImagePixArr();
        int w = arr.length;
        int h = arr[0].length;


        //原图
        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {

                int pixNum = arr[i][j];
                Color color = new Color(pixNum);
                g.setColor(color);
                g.fillRect(100+i,200+j,1,1);

            }
        }

        //马赛克
        for (int i = 0; i < w; i+=10) {
            for (int j = 0; j < h; j+=10) {

                int pixNum = arr[i][j];
                Color color = new Color(pixNum);
                g.setColor(color);
                g.fillRect(650+i,200+j,10,10);

            }
        }

    }

并且

public void paint(Graphics g) {
        super.paint(g);

        drawMyImage(g);
//        drawMyPixMatrix(g);
    }

随便传入一张照片并运行,可以得到以下结果

我们可以通过改变文件地址来更改图片,

其实,规律更改图片提取的rgb数,可以做到使图片蒙上不同的滤镜

滤镜

比如在绘图方法中加入这样的循环:

//反转色滤镜
for (int i = 0; i < w; i+=1) {
            for (int j = 0; j < h; j+=1) {

                int pixNum = arr[i][j];
                Color color = new Color(pixNum);
                Color color1 = new Color(255-color.getGreen(),255-color.getBlue(),255-color.getRed());
                g.setColor(color1);
                g.fillRect(1200+i,200+j,1,1);

            }
        }

运行后,可得到这样的图片:

这样,滤镜也能实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值