之前学长带我做一个数字图像权限控制的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)<<" "; } } }
水印图:
最终结果: