文章目录
密码学的应用流行多年并且技巧繁多。本文所有介绍的是图像藏密(image steganography)的隐藏技术。而密码学分为加密和解密,本文先介绍加密再介绍解密。1
加密
#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循环处理中,超过隐藏文件的长或宽就不进行处理了。
解密
#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)解密出的图像:
也许你认为图片有失真,其实隐藏图像并不一定是要传送真实的图片,而只是为了传递图像中的信息。
-
《OpenCV和Visual Studio图像识别应用开发》 ↩︎