当前位置: 首页 > news >正文

【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代码:

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代码:

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(防止值溢出造成噪点【可以想见,若某一通道出现进位,后果是灾难性的】):

// 加密函数
    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();
        }
    }

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

// 加密部分:【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);

加密后的图像:

在这里插入图片描述

六、解密函数

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

// 解密函数
    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的值里面,是否有不满足该逆运算关系的:

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数组:

加密函数

// 加密函数
    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();
        }
    }

解密函数

// 解密函数
    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();
        }
    }

相关文章:

  • 麒麟高级服务器操作系统内核升级
  • Oracle WITH 子句(也称为 公共表表达式,Common Table Expression,CTE)
  • 终止进程kill和killall
  • 智能合约开发中13种最常见的漏洞
  • 队列的各种操作实现(数据结构C语言多文件编写)
  • 从零构建大模型之Transformer公式解读
  • 大联盟(特别版)双端互动平台完整套件分享:含多模块源码+本地部署环境
  • QT Sqlite数据库-教程002 查询数据-上
  • Java集合框架深度解析:核心接口、实现类与应用场景
  • Android基础入门、Android常见界面布局基础练习
  • 回溯-day65
  • Neovim安装及lazy配置
  • ADI的BF561双核DSP怎么做开发,我来说一说(十六)触摸屏的设计
  • QT Sqlite数据库-教程002 查询数据-下
  • 操作系统导论——第19章 分页:快速地址转换(TLB)
  • Vue.js 项目中 vue.config.js 常用配置项解析
  • bash的特性-命令和文件自动补全
  • Linux - 系统服务管理(Systemd)
  • qt中的正则表达式
  • 【记录】Docker 镜像
  • 佩斯科夫:俄美总统会晤正在筹备中,未设定停火最后期限
  • 福建海警位金门附近海域依法开展常态化执法巡查
  • 2025年一季度上海市生产总值
  • 湃书单|澎湃新闻编辑们在读的19本书:在工作中迷失
  • 全国双拥模范城(县)名单
  • 兰斯莫斯想在雅典卫城拍《拯救地球》,希腊官方:价值观不符