OpenCV图像藏密--将图像隐藏到另一张图像中

2020-12-03 11:47:43 浏览数 (1)

文章目录

  • 加密
  • 解密

密码学的应用流行多年并且技巧繁多。本文所有介绍的是图像藏密(image steganography)的隐藏技术。而密码学分为加密和解密,本文先介绍加密再介绍解密。1

加密

代码语言:javascript复制
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
    Mat image1, image2, image3;
    image1 = imread("D:\C  \openCV\images\5.jpg", IMREAD_COLOR);
    image2 = imread("D:\C  \openCV\images\4.jpg", IMREAD_COLOR);
    namedWindow("Org image", WINDOW_AUTOSIZE);
    namedWindow("Hide image", WINDOW_AUTOSIZE);
    namedWindow("Steged image", WINDOW_AUTOSIZE);

    //检查两个图的大小与类型
    if (image1.type() != image2.type() || image1.size() != image2.size()){
        cout << "两图类型或大小不同" << endl;
        return 1;
    }

    //图像的高,行数
    int numberRows = image1.rows;
    //图像的宽,列数
    int numberCols = image1.cols;

    //产生加密文件
    image3.create(numberRows, numberCols, image1.type());
    Mat tFront_image, tHidden_image;
    //要显示的图像
    Mat front_mask(numberRows, numberCols, image1.type(), Scalar(0xF0, 0xF0, 0xF0));
    //要隐藏得图像
    Mat hidden_mask(numberRows, numberCols, image1.type(), Scalar(0xF0, 0xF0, 0xF0));

    //前两图进行位的相加(and)处理,结果放入第三张图
    //因为之前声明资料为0xF0,相加之后只保留前4个位
    bitwise_and(image1, front_mask, tFront_image);
    bitwise_and(image2, hidden_mask, tHidden_image);
    //处理每个颜色通道,将左侧4个位移到右侧
    for (int j = 0; j < numberRows; j  ) {
        for (int i = 0; i < numberCols; i  ) {
            tHidden_image.at<Vec3b>(j, i)[0] = tHidden_image.at<Vec3b>(j, i)[0] >> 4;
            tHidden_image.at<Vec3b>(j, i)[1] = tHidden_image.at<Vec3b>(j, i)[1] >> 4;
            tHidden_image.at<Vec3b>(j, i)[2] = tHidden_image.at<Vec3b>(j, i)[2] >> 4;
        }
    }
    //前两图进行位的互补(or)处理,结果放入第三张图
    //要隐藏的图就是右侧的四个位
    bitwise_or(tFront_image, tHidden_image, image3);
    imshow("Org image", image1);
    imshow("Hide image", image2);
    imshow("Steged image", image3);
    imwrite("D:\C  \openCV\images\staged-lena.jpg", image3);
    waitKey(0);

    return 0;
}

1、bitwise_and(lnputArray src1 , lnputArray src2, OutputArray dst, lnputArray mask=noArray()): 计算两个图像内每个元素( per-element )位的连接( conjuction ) (1) src1:第一输入图像或Scalar 颜色值。 (2) src2 :第二输入图像或Scalar 颜色值。 (3) dst : 输出图像,与输入图像同大小与类型。 (4) mask:可有可无的掩码。

2、bitwise_ or(lnputArray src1 , lnputArray src2, OutputArray dst, lnputArray mask=noArray()): 计算两个图像内每个元素位的分离( disjuction ) (1) src1:第一输入图像或Scalar 颜色值。 (2) src2 :第二输入图像或Scalar 颜色值。 (3) dst : 输出图像,与输入图像同大小与类型。 (4) mask:可有可无的掩码。

执行结果 (a)原图:

(b)要隐藏的图:

©原图加隐藏图:

程序中的加密原则,是认为每个字节(byte)的各个位都有其重要性。而重要性是从左到右降序,左侧是重要的位,称为最高有效位(Most Significant Bit, MSB);右侧是不重要的位,称为最低有效位(Least Significant Bit, LSB)。所以本程序要将隐藏得重要位放到另一个字节的最低有效位。 本程序只是示范,所以加密前后两个文件的大小(这里的大小不是指文件的大小,而是像素:700x700)与图文件的类型都必须相同。例如,使用同一台相机或手机拍摄的图像大小一般是相同的,除了手机横拍或直拍的差异。不过相信读者已知道要被隐藏得图像其长宽一定要较小,因为在两层的for循环处理中,超过隐藏文件的长或宽就不进行处理了。

解密

代码语言:javascript复制
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat image2, image3;
    image3 = imread("D:\C  \openCV\images\staged-lena.jpg");
    //图像的高,行数
    int numberRows = image3.rows;
    //图像的宽,列数
    int numberCols = image3.cols;
    //产生解密文件
    image2.create(numberRows, numberCols, image3.type());
    Mat tHidden_image;
    Mat hidden_mast(numberRows, numberCols, image3.type(), Scalar(0x0F, 0x0F, 0x0F));
    bitwise_and(image3, hidden_mast, image2);
    //换原加密处理
    for (int j = 0; j < numberRows; j  ) {
        for (int i = 0; i < numberCols; i  ) {
            image2.at<Vec3b>(j, i)[0] = image2.at<Vec3b>(j, i)[0] << 4;
            image2.at<Vec3b>(j, i)[1] = image2.at<Vec3b>(j, i)[1] << 4;
            image2.at<Vec3b>(j, i)[2] = image2.at<Vec3b>(j, i)[2] << 4;
        }
    }
    imshow("Staged Image", image3);
    imshow("Hidden Image", image2);
    waitKey(0);

    return 0;
}

执行结果 (a)原图加隐藏图:

(b)解密出的图像:

也许你认为图片有失真,其实隐藏图像并不一定是要传送真实的图片,而只是为了传递图像中的信息。


  1. 《OpenCV和Visual Studio图像识别应用开发》 ↩︎

0 人点赞