OpenCV和MFC的超混沌图像加密

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: OpenCV和MFC的超混沌图像加密

基于 openCV 和 MFC 的超混沌图像加密


项目链接


https://download.csdn.net/download/weixin_45525272/78561755


效果展示


加载图像



进行加密



进行解密



环境


  • 基于 openCV 与 MFC 的超混沌图像加密软件,openCV 提供图像读取、存储功能,通过 MFC 构建人机交互界面


  • 编译环境为 Visual Studio Community 2017


  • OpenCV 库版本 opencv-4.5.1-vc14_vc15


源代码


Encryption_MFCDlg.h: 头文件


// Encryption_MFCDlg.h: 头文件
//
#pragma once
// CEncryptionMFCDlg 对话框
class CEncryptionMFCDlg : public CDialogEx
{
// 构造
public:
  CEncryptionMFCDlg(CWnd* pParent = nullptr); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
  enum { IDD = IDD_ENCRYPTION_MFC_DIALOG };
#endif
  protected:
  virtual void DoDataExchange(CDataExchange* pDX);  // DDX/DDV 支持
// 实现
protected:
  HICON m_hIcon;
  // 生成的消息映射函数
  virtual BOOL OnInitDialog();
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  DECLARE_MESSAGE_MAP()
public:
  afx_msg void OnBnClickedChooseImg();
public:
  //添加成员变量行列标号
  int count_n;
  int count_m;
  //原图、加密、解密图像数据
  cv::Mat lena;
  cv::Mat encryption_lena;
  cv::Mat decryption_lena;
  CProgressCtrl EnProgress;
  CProgressCtrl DeProgress;
  //缩放窗体链表
  CList<CRect, CRect&> m_listRect;
  afx_msg void DrawMat(cv::Mat & img, UINT nID);
  afx_msg void OnBnClickedEncrypting();
  afx_msg void OnBnClickedDecrypting();
  afx_msg void EncrytingMat(cv::Mat & Enimg, const double Enx_chaos[], const double Eny_chaos[]);
  afx_msg void DecrytingMat(cv::Mat & Deimg, const double Enx_chaos[], const double Eny_chaos[]);
  afx_msg void OnBnClickedSaveEncrypting();
  afx_msg void OnBnClickedSaveDecrypting();
  afx_msg void OnBnClickedLoadencryption2enWindow();
  afx_msg void OnSize(UINT nType, int cx, int cy);
  afx_msg void OnBnClickedUnchangedChooseImg();
};
//数组循环右移函数声明
template <typename T>
void array_rightshift(std::vector<T> &a, int &N);
//数组循环右移函数定义
template <typename T>
void array_rightshift(std::vector<T> &a, int &N)
{
  //采用空间换时间,构建等长临时数组
  //将原数组后num_shift1位(移位位数)元素放置临时数组前面,将原数组前面的元素放置临时数组后面,将临时数组赋值给原数组
  int bitnum = static_cast<int>(a.size());
  int num_shift1 = N % bitnum;
  std::vector<T> temp(bitnum);
  for (int i = 0; i < num_shift1; i++)
  {
    temp[i] = a[bitnum - num_shift1 + i];
  }
  for (int j = 0; j < bitnum - num_shift1; j++)
  {
    temp[j + num_shift1] = a[j];
  }
  for (int k = 0; k < bitnum; k++)
  {
    a[k] = temp[k];
  }
}


Encryption_MFCDlg.cpp: 实现文件


// Encryption_MFCDlg.cpp: 实现文件
//
#include "stdafx.h"
#include "Encryption_MFC.h"
#include "Encryption_MFCDlg.h"
#include "afxdialogex.h"
#include <stdio.h>
#include<vector>
#include <cmath>
#include<algorithm>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#ifndef PI
#define PI 3.141592658
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
  CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
  enum { IDD = IDD_ABOUTBOX };
#endif
  protected:
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
// 实现
protected:
  DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialogEx::DoDataExchange(pDX);
}
//?
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CEncryptionMFCDlg 对话框
CEncryptionMFCDlg::CEncryptionMFCDlg(CWnd* pParent /*=nullptr*/)
  : CDialogEx(IDD_ENCRYPTION_MFC_DIALOG, pParent)
{
  m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CEncryptionMFCDlg::DoDataExchange(CDataExchange* pDX)
{
  CDialogEx::DoDataExchange(pDX);
  DDX_Control(pDX, IDC_EN_PROGRESS, EnProgress);
  DDX_Control(pDX, IDC_DE_PROGRESS, DeProgress);
}
BEGIN_MESSAGE_MAP(CEncryptionMFCDlg, CDialogEx)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDC_CHOOSE_IMG, &CEncryptionMFCDlg::OnBnClickedChooseImg)
  ON_BN_CLICKED(IDC_ENCRYPTING, &CEncryptionMFCDlg::OnBnClickedEncrypting)
  ON_BN_CLICKED(IDC_DECRYPTING, &CEncryptionMFCDlg::OnBnClickedDecrypting)
  ON_BN_CLICKED(IDC_SAVE_ENCRYPTING, &CEncryptionMFCDlg::OnBnClickedSaveEncrypting)
  ON_BN_CLICKED(IDC_SAVE_DECRYPTING, &CEncryptionMFCDlg::OnBnClickedSaveDecrypting)
  ON_BN_CLICKED(IDC_LOADENCRYPTION2EN_WINDOW, &CEncryptionMFCDlg::OnBnClickedLoadencryption2enWindow)
  ON_WM_SIZE()
  ON_BN_CLICKED(IDC_UNCHANGED_CHOOSE_IMG, &CEncryptionMFCDlg::OnBnClickedUnchangedChooseImg)
END_MESSAGE_MAP()
// CEncryptionMFCDlg 消息处理程序
BOOL CEncryptionMFCDlg::OnInitDialog()
{
  CDialogEx::OnInitDialog();
  // 将“关于...”菜单项添加到系统菜单中。
  // IDM_ABOUTBOX 必须在系统命令范围内。
  ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  ASSERT(IDM_ABOUTBOX < 0xF000);
  CMenu* pSysMenu = GetSystemMenu(FALSE);
  if (pSysMenu != nullptr)
  {
    BOOL bNameValid;
    CString strAboutMenu;
    bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
    ASSERT(bNameValid);
    if (!strAboutMenu.IsEmpty())
    {
      pSysMenu->AppendMenu(MF_SEPARATOR);
      pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
  }
  // 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
  //  执行此操作
  SetIcon(m_hIcon, TRUE);     // 设置大图标
  SetIcon(m_hIcon, FALSE);    // 设置小图标
  // TODO: 在此添加额外的初始化代码
  //设置进度条En颜色
  ::SendMessageA(EnProgress.GetSafeHwnd(),PBM_SETBARCOLOR,0,RGB(255, 250, 250));
  EnProgress.SetBarColor(RGB(67, 205, 128));
  //设置进度条De颜色
  ::SendMessageA(DeProgress.GetSafeHwnd(), PBM_SETBARCOLOR, 0, RGB(255, 250, 250));
  DeProgress.SetBarColor(RGB(67, 205, 128));
  //获取所有窗口位置大小
  CRect rect;
  GetWindowRect(&rect);
  m_listRect.AddTail(rect);//对话框的区域
  CWnd* pWnd = GetWindow(GW_CHILD);//获取子窗体
  while (pWnd)
  {
    pWnd->GetWindowRect(rect);//子窗体的区域
    m_listRect.AddTail(rect);           //CList<CRect,CRect> m_listRect成员变量
    pWnd = pWnd->GetNextWindow();//取下一个子窗体
  }
  return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
void CEncryptionMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
  if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  {
    CAboutDlg dlgAbout;
    dlgAbout.DoModal();
  }
  else
  {
    CDialogEx::OnSysCommand(nID, lParam);
  }
}
// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
void CEncryptionMFCDlg::OnPaint()
{
  if (IsIconic())
  {
    CPaintDC dc(this); // 用于绘制的设备上下文
    SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    // 使图标在工作区矩形中居中
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2;
    // 绘制图标
    dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
    CDialogEx::OnPaint();
    CDialog::UpdateWindow();
  }
}
HCURSOR CEncryptionMFCDlg::OnQueryDragIcon()
{
  return HCURSOR();
}
//选择图片控件响应函数
void CEncryptionMFCDlg::OnBnClickedChooseImg()
{
  // TODO: 在此添加控件通知处理程序代码
  CString picPath;   // 定义图片路径变量  
  CFileDialog dlg(true, _T("*.tiff;*.bmp; *.tif;*.jpg"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
    _T("image files (*.tiff;*.bmp ;*.jpg;)|*.tiff;*.bmp; *.jpg |ALL Files (*.*) |*.*||"), NULL);
  //打开文件对话框的标题名
  dlg.m_ofn.lpstrTitle = _T("选择图片");
  if (dlg.DoModal() == IDOK)
  {
    picPath = dlg.GetPathName();  //获取图片路径  
  }
  //CString to string  使用这个方法记得字符集选用“使用多字节字符”,不然会报错  
  std::string picpath = picPath.GetBuffer(0);
  lena = cv::imread(picpath, cv::IMREAD_COLOR);
  if (lena.empty())
  {
    MessageBox(_T("读取文件为空,请选择一张图像文件"));
    return;
  }
  else if (lena.rows*lena.cols < 1024 * 1024)
  {
    ;
  }
  else if (lena.rows*lena.cols < 2048 * 2048)
  {
    lena = cv::imread(picpath, cv::IMREAD_REDUCED_COLOR_2);
  }
  else if (lena.rows*lena.cols < 4096 * 4096)
  {
    lena = cv::imread(picpath, cv::IMREAD_REDUCED_COLOR_4);
  }
  else
  {
    lena = cv::imread(picpath, cv::IMREAD_REDUCED_COLOR_8);
  }
  SetDlgItemText(IDC_ImagePath, picPath);
  DrawMat(lena, IDC_ORIGINAL1);
  AfxMessageBox("图像读取完成");
}
void CEncryptionMFCDlg::OnBnClickedUnchangedChooseImg()
{
  // TODO: 在此添加控件通知处理程序代码
  CString picPath;   //定义图片路径变量  
  CFileDialog dlg(true, _T("*.tiff;*.bmp; *.tif;*.jpg"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
    _T("image files (*.tiff;*.bmp ;*.jpg;)|*.tiff;*.bmp; *.jpg |ALL Files (*.*) |*.*||"), NULL);
  //打开文件对话框的标题名
  dlg.m_ofn.lpstrTitle = _T("选择图片");
  if (dlg.DoModal() == IDOK)
  {
    picPath = dlg.GetPathName();  //获取图片路径  
  }
  //CString to string  使用这个方法记得字符集选用“使用多字节字符”,不然会报错  
  std::string picpath = picPath.GetBuffer(0);
  lena = cv::imread(picpath, cv::IMREAD_COLOR);
  if (lena.empty())
  {
    MessageBox(_T("读取文件为空,请选择一张图像文件"));
    return;
  }
  SetDlgItemText(IDC_ImagePath, picPath);
  DrawMat(lena, IDC_ORIGINAL1);
  AfxMessageBox("图像读取完成");
}
//加密控件响应函数
void CEncryptionMFCDlg::OnBnClickedEncrypting()
{
  // TODO: 在此添加控件通知处理程序代码
  CString str_encryp_password;
  //从输入密码控件获取密码,存入str_encryp_passward
  GetDlgItem(IDC_ENCRYPTION_PASSWORD)->GetWindowText(str_encryp_password);
  if (lena.empty())
  {
    AfxMessageBox("未载入图像,请先载入一张原始图像!");
    return;
  }
  else if (str_encryp_password.IsEmpty())
  {
    AfxMessageBox("密码为空,请重新输入8位密码!");
    return;
  }
  else if (str_encryp_password.GetLength()!=8)
  {
    AfxMessageBox("密码长度错误,请重新输入8位密码!");
    return;
  }
  for(int i=0;i< str_encryp_password.GetLength();++i)
  {
    if (str_encryp_password[i]<'0' || str_encryp_password[i]>'9')
    {
      AfxMessageBox("密码数据类型错误,请输入范围在0-9之间的数字!");
      return;
    }
  }
  //动态申请混沌数组内存
  double *x_chaos = new double[lena.rows * lena.cols * lena.channels()];
  double *y_chaos = new double[lena.rows * lena.cols * lena.channels()];
  //结合图像特征信息初始化初值
  double tempx_last = 0.1*(str_encryp_password[0]-'0')+ 0.01*(str_encryp_password[1] - '0');
  double tempy_last = 0.1*(str_encryp_password[2] - '0') + 0.01*(str_encryp_password[3] - '0');
  double tempz_last = 0.1*(str_encryp_password[4] - '0') + 0.01*(str_encryp_password[5] - '0');
  double tempw_last = 0.1*(str_encryp_password[6] - '0') + 0.01*(str_encryp_password[7] - '0');
  double tempx_new, tempy_new, tempz_new, tempw_new;
  //离散采样时间
  double tt0 = 0.001;
  //需舍去的元素个数
  int num_ignore = 100000;
  //迭代混沌序列
  for (int i = 0; i < lena.rows * lena.cols * lena.channels() + num_ignore; ++i)
  {
    tempx_new = tempx_last + tt0 * (24 * (tempy_last - tempx_last) + 4 * (1 + 0.02 * tempw_last * tempw_last) * tempy_last);
    tempy_new = tempy_last + tt0 * (19 * tempx_last - tempx_last * tempz_last);
    tempz_new = tempz_last + tt0 * (tempx_last * tempx_last - 9 * tempz_last);
    tempw_new = tempw_last + tt0 * tempy_last;
    //舍去前10000次迭代结果即忽略瞬态行为
    if (i >= num_ignore)
    {
      *(x_chaos + i - num_ignore) = tempx_new;
      *(y_chaos + i - num_ignore) = tempy_new;
    }
    tempx_last = tempx_new;
    tempy_last = tempy_new;
    tempz_last = tempz_new;
    tempw_last = tempw_new;
  }
  //对混沌序列进行处理
  double x_max = *std::max_element(x_chaos, x_chaos + lena.rows * lena.cols * lena.channels() - 1);
  double x_min = *std::min_element(x_chaos, x_chaos + lena.rows * lena.cols * lena.channels() - 1);
  double y_max = *std::max_element(y_chaos, y_chaos + lena.rows * lena.cols * lena.channels() - 1);
  double y_min = *std::min_element(y_chaos, y_chaos + lena.rows * lena.cols * lena.channels() - 1);
  for (int i = 0; i < lena.rows * lena.cols * lena.channels(); ++i)
  {
    //x归一化,三角变换,取模
    *(x_chaos + i) = (*(x_chaos + i) - x_min) / (x_max - x_min);
    *(x_chaos + i) = 1.0 / PI * asin(sqrt(*(x_chaos + i)));
    *(x_chaos + i) = int(floor(pow(10, 8)*(*(x_chaos + i)))) % 256;
    *(y_chaos + i) = (*(y_chaos + i) - y_min) / (y_max - y_min);
    *(y_chaos + i) = 1.0 / PI * asin(sqrt(*(y_chaos + i)));
    *(y_chaos + i) = int(floor(pow(10, 8)*(*(y_chaos + i)))) % 256;
  }
  //初始化加密标号
  count_n = 0;
  count_m = 0;
  //设置进度条范围、步长
  EnProgress.SetRange32(0, lena.rows * lena.cols * lena.channels() - 1);
  int nFirstStep = EnProgress.SetStep(1);
  //调用加密函数对图像进行加密
  EncrytingMat(lena, x_chaos, y_chaos);
  //绘制图形
  DrawMat(encryption_lena, IDC_ENCRYPTION1);
  AfxMessageBox("图像加密完成");
  //释放空间防止内存泄漏
    //置空指针
  delete[]x_chaos;
  delete[]y_chaos;
  x_chaos = nullptr;
  y_chaos = nullptr;
}
// 解密控件相应函数
void CEncryptionMFCDlg::OnBnClickedDecrypting()
{
  // TODO: 在此添加控件通知处理程序代码
  CString str_decryp_password;
  //从输入密码控件获取密码,存入str_encryp_passward
  GetDlgItem(IDC_DECRYPTION_PASSWORD)->GetWindowText(str_decryp_password);
  if (encryption_lena.empty())
  {
    AfxMessageBox("未载入加密图像,请先对原始图像进行加密!");
    return;
  }
  else if (str_decryp_password.IsEmpty())
  {
    AfxMessageBox("密码为空,请重新输入8位密码!");
    return;
  }
  else if (str_decryp_password.GetLength() != 8)
  {
    AfxMessageBox("密码长度错误,请重新输入8位密码!");
    return;
  }
  for (int i = 0; i < str_decryp_password.GetLength(); ++i)
  {
    if (str_decryp_password[i]<'0' || str_decryp_password[i]>'9')
    {
      AfxMessageBox("密码数据类型错误,请输入范围在0-9之间的数字!");
      return;
    }
  }
  //动态申请混沌数组内存
  double *x_chaos = new double[encryption_lena.rows * encryption_lena.cols * encryption_lena.channels()];
  double *y_chaos = new double[encryption_lena.rows * encryption_lena.cols * encryption_lena.channels()];
  //结合图像特征信息初始化初值
  double tempx_last = 0.1*(str_decryp_password[0] - '0') + 0.01*(str_decryp_password[1] - '0');
  double tempy_last = 0.1*(str_decryp_password[2] - '0') + 0.01*(str_decryp_password[3] - '0');
  double tempz_last = 0.1*(str_decryp_password[4] - '0') + 0.01*(str_decryp_password[5] - '0');
  double tempw_last = 0.1*(str_decryp_password[6] - '0') + 0.01*(str_decryp_password[7] - '0');
  double tempx_new, tempy_new, tempz_new, tempw_new;
  //离散采样时间
  double tt0 = 0.001;
  //需舍去的元素个数
  int num_ignore = 100000;
  //迭代混沌序列
  for (int i = 0; i < encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() + num_ignore; ++i)
  {
    tempx_new = tempx_last + tt0 * (24 * (tempy_last - tempx_last) + 4 * (1 + 0.02 * tempw_last * tempw_last) * tempy_last);
    tempy_new = tempy_last + tt0 * (19 * tempx_last - tempx_last * tempz_last);
    tempz_new = tempz_last + tt0 * (tempx_last * tempx_last - 9 * tempz_last);
    tempw_new = tempw_last + tt0 * tempy_last;
    //舍去前10000次迭代结果即忽略瞬态行为
    if (i >= num_ignore)
    {
      *(x_chaos + i - num_ignore) = tempx_new;
      *(y_chaos + i - num_ignore) = tempy_new;
    }
    tempx_last = tempx_new;
    tempy_last = tempy_new;
    tempz_last = tempz_new;
    tempw_last = tempw_new;
  }
  //对混沌序列进行处理
  double x_max = *std::max_element(x_chaos, x_chaos + encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() - 1);
  double x_min = *std::min_element(x_chaos, x_chaos + encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() - 1);
  double y_max = *std::max_element(y_chaos, y_chaos + encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() - 1);
  double y_min = *std::min_element(y_chaos, y_chaos + encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() - 1);
  for (int i = 0; i < encryption_lena.rows * encryption_lena.cols * encryption_lena.channels(); ++i)
  {
    //x归一化,三角变换,取模
    *(x_chaos + i) = (*(x_chaos + i) - x_min) / (x_max - x_min);
    *(x_chaos + i) = 1.0 / PI * asin(sqrt(*(x_chaos + i)));
    *(x_chaos + i) = int(floor(pow(10, 8)*(*(x_chaos + i)))) % 256;
    *(y_chaos + i) = (*(y_chaos + i) - y_min) / (y_max - y_min);
    *(y_chaos + i) = 1.0 / PI * asin(sqrt(*(y_chaos + i)));
    *(y_chaos + i) = int(floor(pow(10, 8)*(*(y_chaos + i)))) % 256;
  }
  //设置进度条范围、步长
  DeProgress.SetRange32(0, encryption_lena.rows * encryption_lena.cols * encryption_lena.channels() - 1);
  int nFirstStep = DeProgress.SetStep(1);
  //调用解密函数对图像进行解密
  DecrytingMat(encryption_lena, x_chaos, y_chaos);
  //绘制图形
  DrawMat(decryption_lena, IDC_DECRYPTION1);
  AfxMessageBox("图像解密完成");
  //释放空间防止内存泄漏
    //置空指针
  delete[]x_chaos;
  delete[]y_chaos;
  x_chaos = nullptr;
  y_chaos = nullptr;
}
// 保存加密控件响应函数
void CEncryptionMFCDlg::OnBnClickedSaveEncrypting()
{
  // TODO: 在此添加控件通知处理程序代码
  if (encryption_lena.empty())
  {
    AfxMessageBox("未检测到加密图像,请先进行加密");
    return;
  }
  CString picPath;  // 定义图片路径变量  
  CString FileName;   // 定义图片路径变量  
  CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
    _T("image files (*.tiff;*.bmp ;*.jpg;)|*.tiff;*.bmp; *.jpg |ALL Files (*.*) |*.*||"), AfxGetMainWnd());
  // 打开文件对话框的标题名
  dlg.m_ofn.lpstrTitle = _T("保存加密图片");
  if (dlg.DoModal() == IDOK)
  {
    picPath = dlg.GetPathName();  // 获取图片路径
    FileName = dlg.GetFileName(); // 获取文件名
    picPath += _T(".bmp");
    USES_CONVERSION;
    // 保存操作
    if(!picPath.IsEmpty())
    {
      //CString to string  使用这个方法记得字符集选用“使用多字节字符”,不然会报错  
      std::string picpath = picPath.GetBuffer(0);
      cv::imwrite(picpath, encryption_lena);
      AfxMessageBox("加密图像保存成功");
    }
  }
}
// 保存解密控件响应函数
void CEncryptionMFCDlg::OnBnClickedSaveDecrypting()
{
  if (decryption_lena.empty())
  {
    AfxMessageBox("未检测到加密图像,请先进行加密");
    return;
  }
  CString picPath;  // 定义图片路径变量  
  CString FileName;   // 定义图片路径变量 
  //CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY |
  //OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, NULL, this);   //选择文件对话框  
  CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
    _T("image files (*.tiff;*.bmp ;*.jpg;)|*.tiff;*.bmp; *.jpg |ALL Files (*.*) |*.*||"), AfxGetMainWnd());
  //打开文件对话框的标题名
  dlg.m_ofn.lpstrTitle = _T("保存解密图片");
  if (dlg.DoModal() == IDOK)
  {
    picPath = dlg.GetPathName();  // 获取图片路径
    FileName = dlg.GetFileName(); // 获取文件名
    picPath += _T(".bmp");
    USES_CONVERSION;
    // 保存操作
    if (!picPath.IsEmpty())
    {
      // CString to string  使用这个方法记得字符集选用“使用多字节字符”,不然会报错  
      std::string picpath = picPath.GetBuffer(0);
      cv::imwrite(picpath, decryption_lena);
      AfxMessageBox("解密图像保存成功");
    }
  }
  // TODO: 在此添加控件通知处理程序代码
}
// 载入密图至加密窗口控件响应函数
void CEncryptionMFCDlg::OnBnClickedLoadencryption2enWindow()
{
  // TODO: 在此添加控件通知处理程序代码
  CString picPath;   // 定义图片路径变量  
  //CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY |
  //OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT, NULL, this);   //选择文件对话框  
  CFileDialog dlg(true, _T("*.tiff;*.bmp; *.tif;*.jpg"), NULL, OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
    _T("image files (*.tiff;*.bmp ;*.jpg;)|*.tiff;*.bmp; *.jpg |ALL Files (*.*) |*.*||"), NULL);
  // 打开文件对话框的标题名
  dlg.m_ofn.lpstrTitle = _T("选择图片");
  if (dlg.DoModal() == IDOK)
  {
    picPath = dlg.GetPathName();  //获取图片路径  
  }
  //CString to string  使用这个方法记得字符集选用“使用多字节字符”,不然会报错  
  std::string picpath = picPath.GetBuffer(0);
  encryption_lena = cv::imread(picpath, cv::IMREAD_COLOR);
  if (encryption_lena.empty())
  {
    MessageBox(_T("读取文件为空,请选择一张图像文件"));
    return;
  }
  SetDlgItemText(IDC_ImagePath, picPath);
  DrawMat(encryption_lena, IDC_ENCRYPTION1);
  if (!encryption_lena.empty())
  {
    AfxMessageBox("密文图像读取成功");
  }
}
// 绘图函数
void CEncryptionMFCDlg::DrawMat(cv::Mat & img, UINT nID)
{
  cv::Mat imgTmp;
  CRect rect;
  GetDlgItem(nID)->GetClientRect(&rect);  // 获取控件大小
  cv::resize(img, imgTmp, cv::Size(rect.Width(), rect.Height()));// 缩小或放大Mat并备份
  // 转一下格式 ,这段可以放外面,
  switch (imgTmp.channels())
  {
  case 1:
    cv::cvtColor(imgTmp, imgTmp, CV_GRAY2BGRA); // GRAY单通道
    break;
  case 3:
    cv::cvtColor(imgTmp, imgTmp, CV_BGR2BGRA);  // BGR三通道
    break;
  default:
    break;
  }
  int pixelBytes = imgTmp.channels()*(imgTmp.depth() + 1); // 计算一个像素多少个字节 
  // 制作bitmapinfo(数据头)
  BITMAPINFO bitInfo;
  bitInfo.bmiHeader.biBitCount = 8 * pixelBytes;
  bitInfo.bmiHeader.biWidth = imgTmp.cols;
  bitInfo.bmiHeader.biHeight = -imgTmp.rows;
  bitInfo.bmiHeader.biPlanes = 1;
  bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bitInfo.bmiHeader.biCompression = BI_RGB;
  bitInfo.bmiHeader.biClrImportant = 0;
  bitInfo.bmiHeader.biClrUsed = 0;
  bitInfo.bmiHeader.biSizeImage = 0;
  bitInfo.bmiHeader.biXPelsPerMeter = 0;
  bitInfo.bmiHeader.biYPelsPerMeter = 0;
  // Mat.data + bitmap数据头 -> MFC
  CDC *pDC = GetDlgItem(nID)->GetDC();
  ::StretchDIBits(
    pDC->GetSafeHdc(),
    0, 0, rect.Width(), rect.Height(),
    0, 0, rect.Width(), rect.Height(),
    imgTmp.data,
    &bitInfo,
    DIB_RGB_COLORS,
    SRCCOPY
  );
  ReleaseDC(pDC);
}
// 定义图像加密函数
void CEncryptionMFCDlg::EncrytingMat(cv::Mat & Leimg, const double Enx_chaos[], const double Eny_chaos[])
{
  std::vector<int> lenarow(Leimg.cols);
  encryption_lena = Leimg.clone();
  // 申明变换位数变量
  int num_shf;
  int tempCount_n = 0;
  int tempCount_m = 0;
  // 进行行移位与扩散
  // 注意的是行变换使用的是x混沌序列
  for (int k = 0; k < Leimg.channels(); ++k)
  {
    for (int i = 0; i < Leimg.rows; ++i)
    {
      // 读取图像矩阵的行数据到lenarow数组
      for (int j = 0; j < Leimg.cols; ++j)
      {
        lenarow[j] = Leimg.at<cv::Vec3b>(i, j)[k];
      }
      // 强制类型转换,根据x混沌序列中确定行移位的位数
      num_shf = static_cast<int>(*(Enx_chaos + tempCount_n));
      // 调用自定义的数组循环右移函数,对图像矩阵的行进行循环移位
      array_rightshift(lenarow, num_shf);
      // 判断若为第一行,则直接与x混沌序列进行异或;不为第一行,则先与图像矩阵前一行异或再与x混沌序列异或
      if (i == 0)
      {
        for (int j = 0; j < Leimg.cols; ++j)
        {
          // 给加密像素矩阵赋值
          int temp = lenarow[j] ^ static_cast<int>(*(Enx_chaos + tempCount_n));
          encryption_lena.at<cv::Vec3b>(i, j)[k] = temp;
          ++tempCount_n;
        }
      }
      else
      {
        for (int j = 0; j < Leimg.cols; j++)
        {
          // 给加密像素矩阵赋值
          int temp = lenarow[j] ^ static_cast<int>(encryption_lena.at<cv::Vec3b>(i - 1, j)[k]);
          temp = temp ^ static_cast<int>(*(Enx_chaos + tempCount_n));
          encryption_lena.at<cv::Vec3b>(i, j)[k] = temp;
          ++tempCount_n;
        }
      }
    }
  }
  std::vector<int> lenacols(Leimg.rows);
  // 进行列移位与扩散
  // 注意的是列变换使用的是y混沌序列
  for (int k = 0; k < Leimg.channels(); ++k)
  {
    for (int j = 0; j < Leimg.cols; ++j)
    {
      // 读取图像矩阵的行数据到lenacols数组
      for (int i = 0; i < Leimg.rows; ++i)
      {
        lenacols[i] = encryption_lena.at<cv::Vec3b>(i, j)[k];
      }
      // 强制类型转换,根据y混沌序列中确定列移位的位数
      num_shf = static_cast<int>(*(Eny_chaos + tempCount_m));
      // 调用自定义的数组循环右移函数,对图像矩阵的列进行循环移位
      array_rightshift(lenacols, num_shf);
      // 判断若为第一列,则直接与y混沌序列进行异或;不为第一列,则先与图像矩阵前一列异或再与y混沌序列异或
      if (j == 0)
      {
        for (int i = 0; i < Leimg.rows; ++i)
        {
          // 给加密像素矩阵赋值
          int temp = lenacols[i] ^ static_cast<int>(*(Eny_chaos + tempCount_m));
          encryption_lena.at<cv::Vec3b>(i, j)[k] = temp;
          ++tempCount_m;
        }
      }
      else
      {
        for (int i = 0; i < Leimg.rows; ++i)
        {
          // 给加密像素矩阵赋值
          int temp = lenacols[i] ^ encryption_lena.at<cv::Vec3b>(i, j - 1)[k];
          temp = temp ^ static_cast<int>(*(Eny_chaos + tempCount_m));
          encryption_lena.at<cv::Vec3b>(i, j)[k] = temp;
          ++tempCount_m;
        }
      }
      EnProgress.SetPos((tempCount_m-1 )* 1); // 设置一个位置
    }
  }
  count_n = tempCount_n;
  count_m = tempCount_m;
}
// 定义图像解密函数
void CEncryptionMFCDlg::DecrytingMat(cv::Mat & Enimg, const double Enx_chaos[], const double Eny_chaos[])
{
  //int tempCount_n = count_n - 1;
  //int tempCount_m = count_m - 1;
  int tempCount_n = Enimg.rows * Enimg.cols * Enimg.channels() - 1;
  int tempCount_m = Enimg.rows * Enimg.cols * Enimg.channels() - 1;
  decryption_lena = Enimg.clone();
  std::vector<int> lenacols(Enimg.rows);
  // 反向逐列遍历加密图像矩阵
  for (int k = Enimg.channels() - 1; k >= 0; k--)
  {
    for (int j = Enimg.cols - 1; j >= 0; j--)
    {
      // 判断是否为第一列,执行与加密相反的操作
      if (j == 0)
      {
        for (int i = Enimg.rows - 1; i >= 0; i--)
        {
          lenacols[i] = static_cast<int>(Enimg.at<cv::Vec3b>(i, j)[k]) ^ static_cast<int>(*(Eny_chaos + tempCount_m));
          tempCount_m--;
        }
      }
      else
      {
        for (int i = Enimg.rows - 1; i >= 0; i--)
        {
          lenacols[i] = static_cast<int>(Enimg.at<cv::Vec3b>(i, j)[k]) ^ static_cast<int>(*(Eny_chaos + tempCount_m));
          lenacols[i] = lenacols[i] ^ static_cast<int>(Enimg.at<cv::Vec3b>(i, j - 1)[k]);
          tempCount_m--;
        }
      }
      int num_shf = Enimg.rows - static_cast<int>(*(Eny_chaos + tempCount_m + 1));
      array_rightshift(lenacols, num_shf);
      for (int i = 0; i < Enimg.rows; i++)
      {
        decryption_lena.at<cv::Vec3b>(i, j)[k] = lenacols[i];
      }
    }
  }
  std::vector<int> lenarow(Enimg.cols);
  // 进行行解密
  // 反向逐行遍历加密图像矩阵
  for (int k = Enimg.channels() - 1; k >= 0; k--)
  {
    for (int i = Enimg.rows - 1; i >= 0; i--)
    {
      // 判断是否为第一列,执行与加密相反的操作
      if (i == 0)
      {
        for (int j = Enimg.cols - 1; j >= 0; j--)
        {
          lenarow[j] = static_cast<int>(decryption_lena.at<cv::Vec3b>(i, j)[k]) ^ static_cast<int>(*(Enx_chaos + tempCount_n));
          tempCount_n--;
        }
      }
      else
      {
        for (int j = Enimg.cols - 1; j >= 0; j--)
        {
          lenarow[j] = static_cast<int>(decryption_lena.at<cv::Vec3b>(i, j)[k]) ^ static_cast<int>(*(Enx_chaos + tempCount_n));
          lenarow[j] = lenarow[j] ^ static_cast<int>(decryption_lena.at<cv::Vec3b>(i - 1, j)[k]);
          tempCount_n--;
        }
      }
      int num_shf = Enimg.cols - static_cast<int>(*(Enx_chaos + tempCount_n + 1));
      array_rightshift(lenarow, num_shf);
      for (int j = 0; j < Enimg.cols; j++)
      {
        decryption_lena.at<cv::Vec3b>(i, j)[k] = lenarow[j];
      }
      DeProgress.SetPos(Enimg.rows * Enimg.cols * Enimg.channels() - tempCount_n);//设置一个位置
    }
  }
}
void CEncryptionMFCDlg::OnSize(UINT nType, int cx, int cy)
{
  // TODO: 在此处添加消息处理程序代码
  CDialogEx::OnSize(nType, cx, cy);
  if (m_listRect.GetCount() > 0)
  {
    CRect dlgNow;
    GetWindowRect(&dlgNow);
    POSITION pos = m_listRect.GetHeadPosition();    // 第一个保存的是对话框的Rect  
    CRect dlgSaved;
    dlgSaved = m_listRect.GetNext(pos);
    ScreenToClient(dlgNow);
    float x = dlgNow.Width() * 1.0 / dlgSaved.Width();  // 根据当前和之前保存的对话框的宽高求比例  
    float y = dlgNow.Height()  *1.0 / dlgSaved.Height();
    ClientToScreen(dlgNow);
    CRect childSaved;
    CWnd* pWnd = GetWindow(GW_CHILD);
    while (pWnd)
    {
      childSaved = m_listRect.GetNext(pos);                 // 依次获取子窗体的Rect  
      childSaved.left = dlgNow.left + (childSaved.left - dlgSaved.left)*x;  // 根据比例调整控件上下左右距离对话框的距离  
      childSaved.right = dlgNow.right + (childSaved.right - dlgSaved.right)*x;
      childSaved.top = dlgNow.top + (childSaved.top - dlgSaved.top)*y;
      childSaved.bottom = dlgNow.bottom + (childSaved.bottom - dlgSaved.bottom)*y;
      ScreenToClient(childSaved);
      pWnd->MoveWindow(childSaved);
      pWnd = pWnd->GetNextWindow();
    }
  }
}
相关文章
|
1月前
|
计算机视觉
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
360 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
|
2月前
|
算法 计算机视觉
opencv图像形态学
图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
51 4
|
2月前
|
存储 计算机视觉
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
本文介绍了使用OpenCV进行图像读取、显示和存储的基本操作,以及如何绘制直线、圆形、矩形和文本等几何图形的方法。
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
|
3月前
|
算法 计算机视觉 Python
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
WK
|
3月前
|
编解码 计算机视觉 Python
如何在OpenCV中进行图像转换
在OpenCV中,图像转换涉及颜色空间变换、大小调整及类型转换等操作。常用函数如`cvtColor`可实现BGR到RGB、灰度图或HSV的转换;`resize`则用于调整图像分辨率。此外,通过`astype`或`convertScaleAbs`可改变图像数据类型。对于复杂的几何变换,如仿射或透视变换,则可利用`warpAffine`和`warpPerspective`函数实现。这些技术为图像处理提供了强大的工具。
WK
113 1
|
5月前
|
算法 计算机视觉
【Qt&OpenCV 图像的感兴趣区域ROI】
【Qt&OpenCV 图像的感兴趣区域ROI】
178 1
|
5月前
|
运维 算法 计算机视觉
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
82 1
|
5月前
|
存储 编解码 算法
【Qt&OpenCV 检测图像中的线/圆/轮廓 HoughLinesP/HoughCircles/findContours&drawContours】
【Qt&OpenCV 检测图像中的线/圆/轮廓 HoughLinesP/HoughCircles/findContours&drawContours】
96 0
|
4月前
|
机器学习/深度学习 XML 计算机视觉
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,它提供了大量的函数和工具,用于处理图像和视频数据。
|
5月前
|
算法 计算机视觉
【Qt&OpenCV 图像边缘检测 Sobel/Laplace/Canny】
【Qt&OpenCV 图像边缘检测 Sobel/Laplace/Canny】
70 0
下一篇
无影云桌面