【Java编程】【计算机视觉】一种简单的图片加/解密算法

by Li y.c.

一、内容简介

本文介绍一种简单的图片加/解密算法,算法的基本原理十分简单,即逐个(逐行、逐列)地获取图片的像素点颜色值,对其进行一些简单的算数运算操作进行加密,解密过程则相应地为加密运算的逆运算。

二、图片表示基础

在计算机中,图片(我们使用.jpg文件作为示例)在内存中是使用RGB数组进行存储,举例:

以上图片中,每一个像素点用一个rgb值表示,一般为6位16进制数,例如0x123456,这里0x12表示红度(RED)值,0x34表示绿度(GREEN)值,0x56表示蓝度(BLUE)值。注意到,两位16进制数的取值范围为0~255(0x00到0xFF)。

三、R/G/B值的获取

假如我们知道当前像素点的rgb值为0x123456,如何从中获取到分离的r/g/b值呢?通过简单的位运算即可。如以下java代码:

java 复制代码
public class RGBTest {
    public static void main(String[] args) {
        String format1 = String.format("%x", (0x123456 >> 16));  // 获取red值(前两位)
        String format2 = String.format("%x", (0x123456 >> 8) & 0xFF);  // 获取green值(中间两位)
        String format3 = String.format("%x", (0x123456) & 0xFF);  // 获取blue值(末两位)
        String format = String.format("%x", (0x123456) & 0xFFFFFF);  // 不做改变
        System.out.println(format1);
        System.out.println(format2);
        System.out.println(format3);
        System.out.println(format);
    }
}

运行结果正是我们想要的:

四、获取整张图片的RGB数组

有了以上的基础,我们就可以将整张图片存储为一个RGB表示的数组,为之后的加/解密操作做基础。使用如下的Java代码:

java 复制代码
public List<Integer> getRGB(BufferedImage image, int x, int y) {

        List<Integer> rgb = new ArrayList<Integer>();
        if (image != null && x <= image.getWidth() && y <= image.getHeight()) {
            for (int h = 0; h < y; h++) {
                for (int w = 0; w < x; w++) {
                    //获得w,h坐标的颜色
                    int pixel = image.getRGB(w, h);
                    rgb.add(pixel);
                }
            }
        }
        return rgb;
    }

五、加密函数

我们使用简单的加密操作,即把图片的R/G/B值同时加50后模256(防止值溢出造成噪点【可以想见,若某一通道出现进位,后果是灾难性的】):

java 复制代码
// 加密函数
    public static void Encrypt(Integer[] rgb, int width, int height) {
        // 输出文件名
        File file = new File("image_out.jpg");
        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        for (int h = 0; h < height; h++) {
            for (int w = 0; w < width; w++) {
                int color = rgb[w + width * h];
                int red = color >> 16;
                int green = (color >> 8) & 0xFF;
                int blue = color & 0xFF;
                int red_ = (red + 50) % 256;
                int green_ = (green + 50) % 256;
                int blue_ = (blue + 50) % 256;
                Color c = new Color(red_ << 16 | green_ << 8 | blue_);
                g2.setColor(c);
                g2.drawLine(w, h, w + 1, h + 1);
            }
        }
        try {
            ImageIO.write(bi, "jpg", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

看看加密效果:(以下代码位于主函数中)

java 复制代码
// 加密部分:【image_1_1.jpg】---【image_out.jpg】
            Image_Encrypt r = new Image_Encrypt();
            File f = new File("image_1_1.jpg");
            BufferedImage bi = ImageIO.read(f);
            int width = bi.getWidth();
            int height = bi.getHeight();
            List<Integer> l = null;
            Integer[] rbg = new Integer[width * height];
            l = r.getRGB(bi, width, height);
//             查看rgb值:
//            System.out.print(l);
            for (int i = 0; i < width * height; i++) {
                rbg[i] = l.get(i);
            }
            Encrypt(rbg, width, height);

加密后的图像:

六、解密函数

解密函数应为加密函数的逆运算,考虑到边缘条件,代码如下:

java 复制代码
// 解密函数
    public static void Decrypt(Integer[] rgb, int width, int height) {
        // 输出文件名
        File file = new File("image_out_de.jpg");
        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        for (int h = 0; h < height; h++) {
            for (int w = 0; w < width; w++) {
                int color = rgb[w + width * h];
                int red = color >> 16;
                int green = (color >> 8) & 0xFF;
                int blue = color & 0xFF;

                int red_;
                if (red == 255){
                    red_ = 255;
                }
                else{
                    red_ = (red - 50 + 255) % 255;
                }

                int green_;
                if (green == 255){
                    green_ = 255;
                }
                else{
                    green_ = (green - 50 + 255) % 255;
                }

                int blue_;
                if (blue == 255){
                    blue_ = 255;
                }
                else{
                    blue_ = (blue - 50 + 255) % 255;
                }

                Color c = new Color(red_ << 16 | green_ << 8 | blue_);
                g2.setColor(c);
                g2.drawLine(w, h, w + 1, h + 1);
            }
        }
        try {
            ImageIO.write(bi, "jpg", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

解密后的图像却是这样的:

推测是由于边缘条件造成的,修改代码中......

【debug】

我们写一个测试类,看看从0到255的值里面,是否有不满足该逆运算关系的:

java 复制代码
public class Test {
    public static void main(String[] args){
        for (int i = 0;i <= 255;i ++){
            int j = (i + 50) % 256;
            int j_ = (j - 50 + 256) % 256;
            if (i != j_){
                System.out.print("errr");
            }
        }
    }
}

输出如下:

【没有报错】......??

基准测试

加/解密均不做任何操作,直接由三通道的值拼凑出rgb数组:

加密函数

java 复制代码
// 加密函数
    public static void Encrypt(Integer[] rgb, int width, int height) {
        // 输出文件名
        File file = new File("image_out.jpg");
        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        for (int h = 0; h < height; h++) {
            for (int w = 0; w < width; w++) {
                int color = rgb[w + width * h];
                int red = color >> 16;
                int green = (color >> 8) & 0xFF;
                int blue = color & 0xFF;

                // 基准测试
                int red_ = red;
                int green_ = green;
                int blue_ = blue;

//                int red_ = (red + 50) % 256;
//                int green_ = (green + 50) % 256;
//                int blue_ = (blue + 50) % 256;
                Color c = new Color(red_ << 16 | green_ << 8 | blue_);
                g2.setColor(c);
                g2.drawLine(w, h, w + 1, h + 1);
            }
        }
        try {
            ImageIO.write(bi, "jpg", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

解密函数

java 复制代码
// 解密函数
    public static void Decrypt(Integer[] rgb, int width, int height) {
        // 输出文件名
        File file = new File("image_out_de.jpg");
        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        for (int h = 0; h < height; h++) {
            for (int w = 0; w < width; w++) {
                int color = rgb[w + width * h];
                int red = color >> 16;
                int green = (color >> 8) & 0xFF;
                int blue = color & 0xFF;

                // 基准测试
                int red_ = red;
                int green_ = green;
                int blue_ = blue;
//                int red_;
//                if (red == 255){
//                    red_ = 255;
//                }
//                else{
//                    red_ = (red - 50 + 256) % 256;
//                }

//                int green_;
//                if (green == 255){
//                    green_ = 255;
//                }
//                else{
//                    green_ = (green - 50 + 256) % 256;
//                }

//                int blue_;
//                if (blue == 255){
//                    blue_ = 255;
//                }
//                else{
//                    blue_ = (blue - 50 + 256) % 256;
//                }

                Color c = new Color(red_ << 16 | green_ << 8 | blue_);
                g2.setColor(c);
                g2.drawLine(w, h, w + 1, h + 1);
            }
        }
        try {
            ImageIO.write(bi, "jpg", file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
相关推荐
TPBoreas3 小时前
Jenkins 改完端口号启动不起来了
java·开发语言
金斗潼关3 小时前
SpringCloud GateWay网关
java·spring cloud·gateway
JK0x073 小时前
代码随想录算法训练营 Day40 动态规划Ⅷ 股票问题
算法·动态规划
Feliz..3 小时前
关于离散化算法的看法与感悟
算法
水蓝烟雨4 小时前
1128. 等价多米诺骨牌对的数量
算法·hot 100
codists4 小时前
《算法导论(第4版)》阅读笔记:p11-p13
算法
秋名RG4 小时前
深入解析建造者模式(Builder Pattern)——以Java实现复杂对象构建的艺术
java·开发语言·建造者模式
eternal__day4 小时前
Spring Boot 实现验证码生成与校验:从零开始构建安全登录系统
java·spring boot·后端·安全·java-ee·学习方法
陈大爷(有低保)5 小时前
swagger3融入springboot
java
Kidddddult6 小时前
力扣刷题Day 43:矩阵置零(73)
算法·leetcode·力扣