📄 wvlttrans.cpp
字号:
//图像的属性参数
int iWidth, iHeight, iWidth_H, iHeight_H;
float fr = fRadius;
//获得数据空间的指针
pData = spOriginData;
pTran0 = spTransData0;
pTran1 = spTransData1;
//图像属性参数赋值
iWidth = nWidth;
iWidth_H = nWidth_H;
iHeight = nHeight;
iHeight_H = nHeight_H;
//利用循环完成两次小波变换
for(i=1; i<=layer; i++)
{
DWT_Once(pData,pTran0,pTran1,iHeight,iHeight_H,iWidth,iWidth_H,i,fr);
iHeight = iHeight>>1;//高度的一半
iWidth = iWidth>>1;//宽度的一半
iHeight_H = iHeight/2;
iWidth_H = iWidth/2;
}
}
/********************************************************************************
*函数描述: DWTi_Once完成一次图像小波变换的逆变换 *
*函数参数: short **spData :二维指针,其数据空间存放小波逆变换后的图像数据*
* short **spTransData0:小波变换系数,存放一次水平变换后的小波系数 *
* short **spTransData1:小波变换系数,存放一次竖直变换后的小波系数 *
* int nHeight :图像属性参数,数值为原始图像的高度值 *
* int nHeight_H :图像属性参数,数值为原始图像高度值的一半 *
* int nWidth :图像属性参数,数值为原始图像的宽度值 *
* int nWidth_H :图像属性参数,数值为原始图像宽度值的一半 *
* int layer :小波变换的层数,数值为3层 *
* float fRadius :小波变换因子,在调用时候已指定数值为1.414 *
********************************************************************************/
void CWvltTrans::DWTi_Once(float **spData, float **spTransData0, float **spTransData1, int nHeight, int nHeight_H, int nWidth, int nWidth_H, int layer, float fRadius)
{
int Trans_W, //图像扫描线控制:横坐标
Trans_H, //图像扫描线控制:纵坐标
Trans_M, //图像矩阵的横坐标
Trans_N; //图像矩阵的纵坐标
int WvltCoeff0; //小波变换系数
signed int WvltCoeff1;
for(Trans_N=0; Trans_N<nWidth; Trans_N++)
{
for(Trans_M=0; Trans_M<nHeight_H; Trans_M++)
{
spTransData1[Trans_M][Trans_N]/=fRadius;
spTransData1[Trans_M+nHeight_H][Trans_N]*=fRadius;
}
}
//逆变换是一个逆过程,所以先从竖直方向开始
//竖直方向的逆变换(此时自然奇偶有序排列),Trans_N为图像矩阵的纵坐标
for(Trans_N=0; Trans_N<nWidth_H; Trans_N++)
{
//偶数坐标的小波系数逆变换时的边界处理
WvltCoeff0 = (int)((spTransData1[nHeight_H][Trans_N]+spTransData1[nHeight_H+1][Trans_N])/4);
spTransData1[0][Trans_N] = spTransData1[0][Trans_N]-WvltCoeff0;
WvltCoeff0 = (int)((spTransData1[nHeight_H][nWidth_H+Trans_N]+spTransData1[nHeight_H+1][nWidth_H+Trans_N])/4);
spTransData1[0][nWidth_H+Trans_N] = spTransData1[0][nWidth_H+Trans_N]-WvltCoeff0;
//竖直方向逆变换的第二次偶数坐标小波系数的逆变换
for(Trans_M=1; Trans_M<nHeight_H; Trans_M++)
{
WvltCoeff0 = (int)((spTransData1[nHeight_H+Trans_M][Trans_N]+spTransData1[nHeight_H+Trans_M-1][Trans_N])/4);
spTransData1[Trans_M][Trans_N] = spTransData1[Trans_M][Trans_N]-WvltCoeff0;
WvltCoeff0 = (int)((spTransData1[nHeight_H+Trans_M][nWidth_H+Trans_N]+spTransData1[nHeight_H+Trans_M-1][nWidth_H+Trans_N])/4);
spTransData1[Trans_M][nWidth_H+Trans_N] = spTransData1[Trans_M][nWidth_H+Trans_N]-WvltCoeff0;
}
//第二次奇数坐标小波系数的逆变换
for(Trans_M=0; Trans_M<nHeight_H-1; Trans_M++)
{
WvltCoeff1 = (int)((spTransData1[Trans_M][Trans_N]+spTransData1[Trans_M+1][Trans_N])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData1[nHeight_H+Trans_M][Trans_N] = spTransData1[nHeight_H+Trans_M][Trans_N]-WvltCoeff1;
WvltCoeff1 = (int)((spTransData1[Trans_M][nWidth_H+Trans_N]+spTransData1[Trans_M+1][nWidth_H+Trans_N])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData1[nHeight_H+Trans_M][nWidth_H+Trans_N] = spTransData1[nHeight_H+Trans_M][nWidth_H+Trans_N]-WvltCoeff1;
}
//奇数坐标小波系数逆变换时的边界处理
WvltCoeff1 = ((spTransData1[nHeight_H-1][Trans_N]+spTransData1[nHeight_H-2][Trans_N])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData1[nHeight-1][Trans_N] = spTransData1[nHeight-1][Trans_N]-WvltCoeff1;
WvltCoeff1 = (int)((spTransData1[nHeight_H-1][nWidth_H+Trans_N]+spTransData1[nHeight_H-2][nWidth_H+Trans_N])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData1[nHeight-1][nWidth_H+Trans_N] = spTransData1[nHeight-1][nWidth_H+Trans_N]-WvltCoeff1;
//本模块完成变换系数的赋值采样的逆操作
for(Trans_M=0; Trans_M<nHeight_H; Trans_M++)
{
Trans_H = Trans_M<<1;
spTransData0[Trans_H][Trans_N] = spTransData1[Trans_M][Trans_N];
spTransData0[Trans_H+1][Trans_N] = spTransData1[nHeight_H+Trans_M][Trans_N];
spTransData0[Trans_H][nWidth_H+Trans_N] = spTransData1[Trans_M][nWidth_H+Trans_N];
spTransData0[Trans_H+1][nWidth_H+Trans_N]= spTransData1[nHeight_H+Trans_M][nWidth_H+Trans_N];
}
}
//去除小波变换中频带系数的滤波影响
for(Trans_M=0; Trans_M<nHeight; Trans_M++)
{
for(Trans_N=0; Trans_N<nWidth_H; Trans_N++)
{
spTransData0[Trans_M][Trans_N]/=fRadius;
spTransData0[Trans_M][Trans_N+nWidth_H]*=fRadius;
}
}
//下面进行水平方向的逆变换
//水平方向的逆变换
for(Trans_H=0; Trans_H<nHeight; Trans_H++)
{
//偶数坐标小波系数逆变换时的边界处理
WvltCoeff0 = (int)((spTransData0[Trans_H][nWidth_H]+spTransData0[Trans_H][nWidth_H+1])/4);
spTransData0[Trans_H][0] = spTransData0[Trans_H][0]-WvltCoeff0;
//第二次偶数坐标小波系数的逆变换
for(Trans_N=1; Trans_N<nWidth_H; Trans_N++)
{
WvltCoeff0 = (int)((spTransData0[Trans_H][nWidth_H+Trans_N]+spTransData0[Trans_H][nWidth_H+Trans_N-1])/4);
spTransData0[Trans_H][Trans_N] = spTransData0[Trans_H][Trans_N]-WvltCoeff0;
}
//第二次奇数坐标小波系数的逆变换
for(Trans_N=0; Trans_N<nWidth_H-1; Trans_N++)
{
WvltCoeff1 = (int)((spTransData0[Trans_H][Trans_N]+spTransData0[Trans_H][Trans_N+1])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData0[Trans_H][nWidth_H+Trans_N] = spTransData0[Trans_H][nWidth_H+Trans_N]-WvltCoeff1;
}
//奇数坐标小波系数逆变换时的边界处理
WvltCoeff1 = (int)((spTransData0[Trans_H][nWidth_H-1]+spTransData0[Trans_H][nWidth_H-2])/2);
WvltCoeff1=~WvltCoeff1+1;
spTransData0[Trans_H][nWidth-1] = spTransData0[Trans_H][nWidth-1]-WvltCoeff1;
if(layer > 1)
{
for(Trans_N=0; Trans_N<nWidth_H; Trans_N++)
{
Trans_W =Trans_N<<1;
spTransData1[Trans_H][Trans_W] = spTransData0[Trans_H][Trans_N];
spTransData1[Trans_H][Trans_W+1] = spTransData0[Trans_H][nWidth_H+Trans_N];
}
}
if(layer == 1)
{
for(Trans_N=0; Trans_N<nWidth_H; Trans_N++)
{
Trans_W =Trans_N<<1;
if(fRadius!=2)
{
spTransData0[Trans_H][Trans_N]=spTransData0[Trans_H][Trans_N]+128;
spTransData0[Trans_H][nWidth_H+Trans_N]=spTransData0[Trans_H][nWidth_H+Trans_N]+128;
}
if(spTransData0[Trans_H][Trans_N]>255) spTransData0[Trans_H][Trans_N]=255;
if(spTransData0[Trans_H][Trans_N]<0) spTransData0[Trans_H][Trans_N]=0;
if(spTransData0[Trans_H][nWidth_H+Trans_N]>255) spTransData0[Trans_H][nWidth_H+Trans_N]=255;
if(spTransData0[Trans_H][nWidth_H+Trans_N]<0) spTransData0[Trans_H][nWidth_H+Trans_N]=0;
spData[Trans_H][Trans_W] = spTransData0[Trans_H][Trans_N];
spData[Trans_H][Trans_W+1] =spTransData0[Trans_H][nWidth_H+Trans_N];
}
}
}
}
//add by fengshaohui
/********************************************************************************
*函数描述: 基于Logistic映射的二值水印生成 *
*
*
********************************************************************************/
void CWvltTrans::LogisticWaterMark()
{
double* s = new double [MarkLength+1];//s用来存放混沌系统生成的实数
double temp ;
double T = 0.5;//(阈值)
int* p = new int [MarkLength+1];//存放由序列s转化成的二值序列
s[0] = 0.25;
int j = 0;
for(int i = 0; i<MarkLength; i++ )
{
temp = 3.93*s[i]*(1 - s[i]);
j = i + 1;
s[j] = temp;
//将生成的实数转化为二值整数
if(s[i] < T )
{
s[i] = 0;
p[i] = (int)s[i];
}
else
{
s[i] = 1;
p[i] = (int)s[i];
}
//将原始二值水印信息与上面得到的二值序列异或得到水印信息
WaterMarkOrigin[i] = p[i] ^ WaterMarkOrigin[i];
}
if( s!=NULL)
{
delete[] s;
s = NULL;
}
if( p!=NULL)
{
delete[] p;
p = NULL;
}
}
//改变水印序列的值域为{-1,1}
void CWvltTrans::changeMarkValue()
{
for(int i=0; i<MarkLength; i++)
{
if(WaterMarkOrigin[i] == 0)
{
WaterMarkOrigin[i] = -1;
}
}
}
/**********************************************************************************************
功能:加载二值水印,调用此函数后CoeffChoosed[][]中为被水印信息修改完的选定系数,m_WvltCoeff[][]为加载水印信息后的全部系数
CoeffChoosed[][]数组大小与原始图像像素数相同,WaterMarkOrigin[]中为-1与1序列
说明:用乘性规则嵌入,对单个图像加载水印
**********************************************************************************************/
void CWvltTrans::LoadWaterMark()
{
//changeMarkValue();//转换水印的值域([0,1]->[-1,1])
int i,j;
int k=0;
/*
//将嵌入前的选定系数写到文件中
char FilePathBuf[MAX_PATH];
GetCurrentDirectory(100,FilePathBuf);
CString strFilePath = FilePathBuf;
strFilePath = strFilePath + "\\CoeffChoosedBeforeLoad.txt";
WriteFile(strFilePath,CoeffChoosed,biHeight,biWidth);
*/
float** TempCoeff = new float* [biHeight];
for(i=0; i<biHeight; i++)//控制选定系数的行
{
TempCoeff[i] = new float[biWidth];
}
for(i=0; i<biHeight; i++)//控制选定系数的行
{
for(j=0; j<biWidth; j++)//控制选定系数的列
{
TempCoeff[i][j] = CoeffChoosed[i][j];
}
}
for(i=0; i<biHeight; i++)//控制选定系数的行
{
for(j=0; j<biWidth; j++)//控制选定系数的列
{
CoeffAfterLoad[i][j] = m_WvltCoeff[i][j];//加载水印后的系数数组初值为小波变换后系数
if(CoeffChoosed[i][j] != 0)//CoeffChoosed中不为0的个数刚好等于水印长度
{
//用水印信息修改选定系数
TempCoeff[i][j] = CoeffChoosed[i][j] * (1.0 + strength*WaterMarkOrigin[k]);
k++;//下一个水印信息
//用修改后的选定系数更新DWT变换后相应位置的系数
CoeffAfterLoad[i][j] = TempCoeff[i][j];
}
}
}
//删除临时空间
for(i=0; i<biHeight; i++)//控制选定系数的行
{
delete []TempCoeff[i];
TempCoeff[i] = NULL;
}
delete []TempCoeff;
TempCoeff = NULL;
/*
//将被水印信息修改后的选定系数写到文件中
strFilePath = FilePathBuf;
strFilePath = strFilePath + "\\CoeffChoosedAfterLoad.txt";
WriteFile(strFilePath,CoeffChoosed,biHeight,biWidth);
//将水印加载前后的系数写入文件中
strFilePath = FilePathBuf;
strFilePath = strFilePath + "\\CoeffAfterDWT.txt";
WriteFile(strFilePath,m_WvltCoeff,biHeight,biWidth);
strFilePath = FilePathBuf;
strFilePath = strFilePath + "\\CoeffAfterLoad.txt";
WriteFile(strFilePath,CoeffAfterLoad,biHeight,biWidth);
*/
}
//对单个图像加载水印
void CWvltTrans::LoadWaterMarkOne(CString CurrentFile)
{
CString CoeffChoosedSavePath = "";
int pos = CurrentFile.ReverseFind('\\');
picName = CurrentFile.Mid(pos+1);//取到当前文件名
CString Path = CurrentFile.Left(pos);//当前路径
SavePath = Path + "\\加水印后图像" + "\\" + picName;//保存加载水印后的图像路径
int pos2 = picName.ReverseFind('.');
CString picTitle = picName.Left(pos2);//不含扩展名的文件名
CoeffChoosedSavePath = Path + "\\加水印后图像" + "\\选择的系数\\" + picTitle + ".txt";//待保存的选定系数文件路径
if (!ReadBitmap(CurrentFile, m_pBitmap))
{
AfxMessageBox("读取原始文件" + CurrentFile + "错误!");
exit(1);
}
//分配缓冲区
pY = new float* [biHeight];
pU = new float* [biHeight];
pV = new float* [biHeight];
for(int i = 0; i < biHeight; i ++)
{
pY[i] = new float [biWidth];
pU[i] = new float [biWidth];
pV[i] = new float [biWidth];
}
RGBToYUV(m_pBitmap,pY,pU, pV);//将原始图像数据分解成Y、U、V
int x,y;
float **spTransData0, **spTransData1;
//分配图像小波变换的数据内存空间
spTransData0 = new float* [biHeight];
spTransData1 = new float* [biHeight];
m_WvltCoeff = new float * [biHeight];//存放小波变换后系数
for(i = 0; i < biHeight; i ++)
{
spTransData0[i] = new float [biWidth];
spTransData1[i] = new float [biWidth];
m_WvltCoeff[i] = new float [biWidth];
}
//完成图像的三次小波变换
DWT_nLayers(pY,spTransData0,spTransData1,biHeight,biHeight/2,biWidth,biWidth/2,3,(float)1.414);
//得到小波系数
for( y=0; y<biHeight; y++)
{
for( x=0; x<biWidth; x++)
{
m_WvltCoeff[y][x] = spTransData1[y][x];//得到三次小波变换后的系数
}
}
//为DWT各子带及选择的加载水印的系数、加载水印后的系数及小波逆变换后的系数分配缓冲区
allocBuffers();
ChooseCoeffByWholeThreshold();//选择要加载水印的系数,此函数中将小波变换后系数分成各子带
//将当前图像的选定系数写到文件中以备检测水印时用
WriteFile(CoeffChoosedSavePath,CoeffChoosed,biHeight,biWidth);//此函数为何有错(已解决,目录必须存在)
LoadWaterMark();//加载二值水印,加载过水印的小波系数保存在CoeffAfterLoad中
//对加载过水印的系数进行小波逆变换
DWT_Inverse(biHeight,biWidth,3,CoeffAfterLoad,CoeffIDWT);
unsigned char* RGBData = new BYTE [biHeight*biAlign];
if(RGBData == NULL)
{
AfxMessageBox("分配存放合成Y、U、V后的RGB空间失败!");
return;
}
YUVToRGB(CoeffIDWT,pU,pV,RGBData,biHeight,biWidth,biAlign);//恢复加载水印后图像为彩色图像
FileSaveAs(SavePath,BFH,BIH,RGBData,bmSize);//将加载水印后的数据另存为bmp图像
delete []RGBData;
RGBData = NULL;
freeBuffers();//此函数中将选择的系数释放
//释放空间
for(i = 0; i < biHeight; i++)
{
delete []m_WvltCoeff[i];
delete []spTransData0[i] ;
delete []spTransData1[i] ;
m_WvltCoeff[i] = NULL;
spTransData0[i] = NULL;
spTransData1[i] = NULL;
}
delete []m_WvltCoeff;
delete []spTransData0;
delete []spTransData1;
spTransData0 = NULL;
spTransData1 = NULL;
m_WvltCoeff = NULL;
if( m_pBitmap != NULL)
{
delete []m_pBitmap;
m_pBitmap = NULL;
}
for(i=0; i<biHeight; i++)
{
delete []pY[i];
delete []pU[i];
delete []pV[i];
pY[i] = NULL;
pU[i] = NULL;
pV[i] = NULL;
}
delete []pY;
delete []pU;
delete []pV;
pY = NULL;
pU = NULL;
pV = NULL;
AfxMessageBox("所选图像加载水印完毕!");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -