之前學長帶我做一個數字圖像權限控制的Demo程序,其大體過程是這樣的:先將一幅圖像進行8X8分塊的DCT變換,這時候每個分塊的左上角像素的能量是最高的(最亮),這時取出每個分塊的左上角的像素值組成一個新的矩陣,然後爲其加水印(水印圖像的尺寸與矩陣尺寸一致),再對其進行Sobel邊緣檢測,進行二值化,最後將二值化後的信息與用戶信息進行哈希處理生成一個認證碼作爲該用戶對圖像的權限標識。
以下是我的代碼(哈希那一部分太弱智了,見笑了):
// OpenCV_Helloworld.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <fstream>
#include <iostream>
#include <bitset>
#define pi 3.14159
using namespace std;
/*
src--變換源矩陣 dst--變換目的矩陣
xbegin--需要變換的8*8矩陣的在原始矩陣中的起始行座標 ybegin--起始列座標
imgwidth--圖像的寬度 imgheight--圖像的高度
*/
void DCT_8X8(double *src,double *dst,int imgwidth,int imgheight);
//矩陣相乘
void matXmat(double * a,double *b,double *res,int len);
//計算變換矩陣
void A(double *src,int x);
//計算逆矩陣
void AT(double *src,double *dst,int x);
//索貝爾變換
void sobel(double *src,double *dst,int len);
//將用戶ID經散列後得到長度爲64x64的01串
void userIdHash(string userId,unsigned int* res,unsigned int length);
int _tmain(int argc, _TCHAR* argv[])
{
//原始圖像512x512 24位
IplImage *imgS = cvLoadImage("lena.jpg");
//水印圖像64x64 24位
IplImage *imgWM = cvLoadImage("hnu.jpg");
//cvNamedWindow("Image:",1);
//cvShowImage("Image:",img);
//printf("step:%d,origin:%d,bitDepth:%d,Channel:%d,width:%d,height:%d\n",img->widthStep,img->origin,img->depth,img->nChannels,img->width,img->height);
//對源圖像進行的操作
int step = imgS->widthStep;
int x = imgS->width;
int y = imgS->height;
//將原圖像由RGB彩色系統轉換爲YUV系統,只獲取YUV中的Y
double *YS = new double[y*x];
//ofstream out;
//out.open("Y.txt",ios::out|ios::trunc);
for(int i = 0;i < y;i++)
{
for(int j = 0;j < x;j++)
{
YS[i*y+j] = ((int)((uchar*)(imgS->imageData + step * i))[j*3])*0.114 + ((int)((uchar*)(imgS->imageData + step * i))[j*3+1])*0.587 + ((int)((uchar*)(imgS->imageData + step * i))[j*3+2])*0.299;
//out<<Y[i*x+j]<<" ";
}
//out<<endl<<endl<<endl<<endl;
}
//out.close();
//對原圖像的每個8x8分塊進行DCT 變換
double *afterDCT = new double[y*x];
DCT_8X8(YS,afterDCT,x,y);
//保存每個DCT變換後的8X8矩陣的左上角的值
int xi = x/8,yj=y/8;
int len = xi>yj?yj:xi;
double *left_top = new double[len*len];
for(int m=0;m<len;m++)
{
for(int n=0;n<len;n++)
{
*(left_top + m*len + n) = *(afterDCT + 8*m*x + 8*n);
}
}
//對每個8X8的塊的左上角值組成的新矩陣進行sobel邊緣檢測 經測試,閾值取1650比較好
double *dstS = new double[len*len];
unsigned int * SRC = new unsigned int[len*len];
IplImage *sobelimgS = cvCreateImage(cvSize(len,len),IPL_DEPTH_8U,1);
sobel(left_top,dstS,len);
for(int k=0;k<len;k++)
for(int o=0;o<len;o++)
{
if(*(dstS + k*len + o) > 1650)
{
*(sobelimgS->imageData + k*len + o) = 255;
*(SRC + k*len + o) =1;
}
else
{
*(sobelimgS->imageData + k*len + o) = 0;
*(SRC + k*len + o) = 0;
}
}
char c[40];
sprintf_s(c,"lena_%d.bmp",1650);
cvSaveImage( c,sobelimgS);
//對水印圖像進行的操作
int h = imgWM->height;
int w = imgWM->width;
int sw = imgWM->widthStep;
//將水印圖像由RGB彩色系統轉換爲YUV系統,只獲取YUV中的Y
double *YWM = new double[h*w];
//ofstream out;
//out.open("Y.txt",ios::out|ios::trunc);
for(int i = 0;i < h;i++)
{
for(int j = 0;j < w;j++)
{
YWM[i*h+j] = ((int)((uchar*)(imgWM->imageData + sw * i))[j*3])*0.114 + ((int)((uchar*)(imgWM->imageData + sw * i))[j*3+1])*0.587 + ((int)((uchar*)(imgWM->imageData + sw * i))[j*3+2])*0.299;
//out<<Y[i*x+j]<<" ";
}
//out<<endl<<endl<<endl<<endl;
}
//out.close();
//直接對圖像進行sobel邊緣檢測
IplImage *sobelimgWM = cvCreateImage(cvSize(imgWM->width,imgWM->width),IPL_DEPTH_8U,1);
double * dstWM = new double[sobelimgWM->width * sobelimgWM->height];
unsigned int *DST = new unsigned int[h*w];
sobel(YWM,dstWM,sobelimgWM->width);
for(int k=0;k<sobelimgWM->width;k++)
for(int o=0;o<sobelimgWM->width;o++)
{
if(*(dstWM + k*(sobelimgWM->width) + o) > 550)
{
*(sobelimgWM->imageData + k*(sobelimgWM->width) + o) = 255;
*(DST + k*(sobelimgWM->width) + o) = 1;
}
else
{
*(sobelimgWM->imageData + k*(sobelimgWM->width) + o) = 0;
*(DST + k*(sobelimgWM->width) + o) = 0;
}
}
sprintf_s(c,"hnu_%d.bmp",550);
cvSaveImage( c,sobelimgWM);
ofstream out;
out.open("data.txt",ios::out|ios::trunc);
out<<"SRC:\n";
for(int ii = 0;ii<len;ii++)
{
for(int jj = 0;jj<len;jj++)
out<<(*(SRC + ii*len + jj))<<" ";
out<<endl;
}
out<<endl<<endl<<endl<<"DST:\n";
for(int ii = 0;ii<len;ii++)
{
for(int jj = 0;jj<len;jj++)
out<<(*(DST + ii*len + jj))<<" ";
out<<endl;
}
//認證碼
unsigned int *code = new unsigned int[len*len];
out<<endl<<endl<<endl<<"XOR:\n";
//加水印(異或操作)
unsigned int temp1,temp2;
for(int ii = 0;ii<len;ii++)
{
for(int jj = 0;jj<len;jj++)
{
temp1 = *(DST + ii*len + jj);
temp2 = *(SRC + ii*len + jj);
*(code + ii*len +jj) = (temp1^temp2);
out<<(*(code + ii*len +jj))<<" ";
}
out<<endl;
}
//加了水印後的圖像
IplImage *imgww = cvCreateImage(cvSize(len,len),IPL_DEPTH_8U,1);
out<<endl<<endl<<endl<<endl<<endl<<"RES:\n";
for(int ii = 0;ii<len;ii++)
{
for(int jj = 0;jj<len;jj++)
{
out<<(*(SRC + ii*len +jj))<<" ";
}
out<<endl;
for(int jj = 0;jj<len;jj++)
{
out<<(*(DST + ii*len +jj))<<" ";
}
out<<endl;
for(int jj = 0;jj<len;jj++)
{
if((*(code + ii*len +jj)) == 1)
*(imgww->imageData + len * ii + jj) = 255;
else
*(imgww->imageData + len * ii + jj) = 0;
out<<(*(code + ii*len +jj))<<" ";
}
out<<endl<<endl<<endl;
}
out.close();
sprintf_s(c,"imgWithwatermark.bmp");
cvSaveImage( c,imgww);
out.open("userHash.txt",ios::out|ios::trunc);
//out<<0<<" "<<1<<endl;
out<<endl;
unsigned int * id = new unsigned int[64*64];
for(int tt = 0;tt<64*64;tt++)
id[tt] = 0;
userIdHash("zxc_20081610125",id,64*64);
for(int rr=0;rr<64*64;rr++)
{
if((*(id+rr)) == 1)
out<<"1"<<" ";
else
out<<"0"<<" ";
}
out.close();
//int i;cin>>i;
delete [] id;
//cvShowImage("sebol:",pic);
//cvShowImage("sobel:",sobelimg);
//cvWaitKey();
//cvDestroyWindow("sobel:");
cvReleaseImage(&imgS);
cvReleaseImage(&imgWM);
cvReleaseImage(&sobelimgS);
cvReleaseImage(&sobelimgWM);
//cvReleaseImage(&pic);
delete [] YS;
delete [] YWM;
delete [] afterDCT;
delete [] left_top;
delete [] dstS;
delete [] dstWM;
delete [] SRC;
delete [] DST;
delete [] code;
return 0;
}
void DCT_8X8(double *src,double *dst,int imgwidth,int imgheight)
{
double a[8*8],at[8*8],temp1[8*8],temp2[8*8];
A(a,8);
AT(a,at,8);
int i = imgwidth/8,j=imgheight/8;
int len = i>j?j:i;
for(int m=0;m<len;m++)
{
for(int n=0;n<len;n++)
{
for(int q=0;q<8;q++)
for(int w=0;w<8;w++)
{
*(temp1 + q*8 + w) = *(src +(8*m+q)*imgwidth + 8*n + w);
}
matXmat(a,temp1,temp2,8);
matXmat(temp2,at,temp1,8);
for(int r=0;r<8;r++)
for(int t=0;t<8;t++)
{
*(dst +(8*m+r)*imgwidth + 8*n + t) = *(temp1 + r*8 + t);
}
}
}
}
void A(double *src,int x)
{
for(int i=0;i<x;i++)
for(int j =0;j<x;j++)
{
*(src+i*x+j) = sqrt((i==0?1:2)/(x*1.0))*cos(pi*(2.0*j+1)*i/(x*2));
}
}
void AT(double *src,double *dst,int x)
{
for(int i=0;i<x;i++)
for(int j =0;j<x;j++)
{
*(dst+j*x+i) = *(src+i*x+j);
}
}
void matXmat(double * a,double *b,double *res,int len)
{
double temp;
for(int i=0;i<len;i++)
{
for(int j = 0 ;j<len ; j++)
{
temp = 0.0;
for(int k=0 ; k<len;k++)
temp+=(*(a + i*len + k)) * (*(b + k*len + j));
*(res + i*len + j) = temp;
}
}
}
void sobel(double *src,double *dst,int len)
{
int i,j;
double tempx,tempy;
for(j = 0;j<len;j++)
{
for(i=0;i<len;i++)
*(dst + j*len + i) = 0;
}
for(j = 1;j<len-1;j++)
{
for(i=1;i<len-1;i++)
{
//x方向
tempx = (*(src + (j-1)*len + i+1)) - (*(src + (j-1)*len + i-1)) + 2*((*(src + j*len + i+1))-(*(src + j*len + i-1))) + ((*(src + (j+1)*len + i+1))-(*(src + (j+1)*len + i-1)));
//y方向
tempy = (*(src + (j-1)*len + i-1)) - *(src + (j+1)*len + i-1) + 2*((*(src + (j-1)*len + i))-(*(src + (j+1)*len + i))) + (*(src + (j-1)*len + i+1)) - (*(src + (j+1)*len + i+1));
//將梯度存入dst
*(dst + j*len + i ) = sqrt(tempx*tempx + tempy*tempy);
//cout<<*(dst + j*len + i )<<" ";
}
//cout<<endl;
}
}
void userIdHash(string userId,unsigned int* res,unsigned int length)
{
char ch;
for(unsigned int i=0;i<userId.length();i++)
{
ch=userId[i];
bitset<8> bits((int)ch);
for(int j=0;j<8;j++)
{
if((unsigned int)(8*i+7) < length)
{
bool a = bits.at(7-j);
if(a)
*(res + 8*i +j) = 1;
else
*(res + 8*i +j) = 0;
//res[8*i+j] = 1;
}
//cout<<*(res + 8*i +j)<<" ";
}
}
}
原圖:
水印圖:
最終結果: