├── README.md ├── main.py ├── 理论+演示.pdf ├── 隐写用图 ├── DCT_origin.bmp ├── LSB_origin.png ├── image.png ├── mark.png ├── random_interval_origin.bmp └── regional_verification_origin.bmp └── 隐藏信息 ├── hideInfo_DCT.txt ├── hideInfo_LSB.txt ├── hideInfo_random_interval.txt └── hideInfo_regional_verification.txt /README.md: -------------------------------------------------------------------------------- 1 | # Visual-watermarking-system-based-on-digital-image 2 | 数字图像可视化水印系统的设计与实现 3 | 4 | (LSB算法、DCT算法、随机间隔算法、区域校验位算法、图像降级算法、图像降级算法改进等6种数字水印算法的实现) 5 | 6 | --- 7 | 8 | 9 | 10 | 11 | 12 | ### 程序介绍 13 | 14 | * 这是源自我的本科毕业设计的程序,使用Python实现了一个数字图形可视化水印系统。 15 | 16 | * 因为在毕设过程中,发现目前全网涉及到数字水印算法99%都是用matlab实现的,几乎没有合适的Python实现代码,于是只能参照matlab代码和算法原理,自己实现Python代码,在实现过程中也遇到了不少问题。所以我将实现成功的代码分享出来,有需要的人可以少走一些弯路,少费工夫 17 | 18 | * 并且截取部分毕业论文,上面有较为详细的操作演示 19 | 20 | * 论文获得2020本科优秀毕业论文 21 | 22 | 23 | 24 | ### 功能 25 | 26 | * LSB基本算法 27 | * 随机间隔算法 28 | * 区域校验位算法 29 | * 图像降级算法 30 | * 图像降级算法改进 31 | * DCT算法 32 | 33 | 34 | 35 | ### 环境 36 | 37 | * Python3.7 38 | 39 | 40 | 41 | ### 运行方式 42 | 43 | 直接运行即可 44 | 45 | ``` 46 | python main.py 47 | ``` 48 | 49 | * main.py是源代码 50 | * main.exe是用pyinstaller导出的exe可执行程序(因较大没有上传) 51 | * GUI使用的Tkinter,因为涉及多层窗口的嵌套,就没有对程序进行拆分,全部写到一个程序里面了 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | from tkinter import filedialog 3 | import tkinter.messagebox #弹窗库 4 | from PIL import Image, ImageDraw, ImageFont,ImageTk 5 | import code 6 | import matplotlib 7 | import matplotlib.pyplot as plt 8 | import cv2 9 | import shutil 10 | import numpy as np 11 | import itertools 12 | from skimage import color 13 | import math 14 | import random 15 | import os 16 | import tkinter.font as tkFont 17 | from tkinter.filedialog import askopenfilename 18 | from tkinter.ttk import * 19 | 20 | 21 | np.set_printoptions(suppress=True) 22 | 23 | plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签 24 | 25 | quant = np.array([[16,11,10,16,24,40,51,61], # QUANTIZATION TABLE 26 | [12,12,14,19,26,58,60,55], # required for DCT 27 | [14,13,16,24,40,57,69,56], 28 | [14,17,22,29,51,87,80,62], 29 | [18,22,37,56,68,109,103,77], 30 | [24,35,55,64,81,104,113,92], 31 | [49,64,78,87,103,121,120,101], 32 | [72,92,95,98,112,100,103,99]]) 33 | 34 | 35 | def plus(str): 36 | return str.zfill(8) 37 | #Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。 38 | 39 | def get_key(strr): 40 | #获取要隐藏的文件内容 41 | tmp = strr 42 | f = open(tmp,"rb") 43 | str = "" 44 | s = f.read() 45 | global text_len 46 | text_len = len(s) 47 | for i in range(len(s)): 48 | #code.interact(local=locals()) 49 | str = str+plus(bin(s[i]).replace('0b','')) 50 | #逐个字节将要隐藏的文件内容转换为二进制,并拼接起来 51 | #1.先用ord()函数将s的内容逐个转换为ascii码 52 | #2.使用bin()函数将十进制的ascii码转换为二进制 53 | #3.由于bin()函数转换二进制后,二进制字符串的前面会有"0b"来表示这个字符串是二进制形式,所以用replace()替换为空 54 | #4.又由于ascii码转换二进制后是七位,而正常情况下每个字符由8位二进制组成,所以使用自定义函数plus将其填充为8位 55 | #print str 56 | f.closed 57 | return str 58 | 59 | def mod(x,y): 60 | return x%y; 61 | 62 | def toasc(strr): 63 | return int(strr, 2) 64 | 65 | #q转换成第几行第几列 66 | #width行height列 67 | def q_converto_wh(q): 68 | w = q//600 69 | h = q%600 70 | return w,h 71 | 72 | 73 | def swap(a,b): 74 | return b,a 75 | 76 | def randinterval(m,n,count,key): 77 | #m,n = matrix.shape 78 | print(m,n) 79 | interval1 = int(m*n/count)+1 80 | interval2 = interval1-2 81 | if interval2 == 0: 82 | print('载体太小,不能将秘密信息隐藏进去!') 83 | # print('interval1:', interval1) 84 | # print('interval2:', interval2) 85 | 86 | #生成随机序列 87 | random.seed(key) 88 | a = [0]*count #a是list 89 | for i in range(0,count): 90 | a[i] = random.random() 91 | 92 | #初始化 93 | row = [0]*count 94 | col = [0]*count 95 | 96 | #计算row和col 97 | r = 0 98 | c = 0 99 | row[0] = r 100 | col[0] = c 101 | for i in range(1,count): 102 | if a[i]>= 0.5: 103 | c = c + interval1 104 | else: 105 | c = c + interval2 106 | if c > n: 107 | k = c%n 108 | r = r + int((c-k)/n) 109 | if r > m: 110 | print('载体太小不能将秘密信息隐藏进去!') 111 | c = k 112 | if c == 0: 113 | c=1 114 | row[i] = r 115 | col[i] = c 116 | 117 | return row,col 118 | 119 | 120 | 121 | 122 | 123 | #str1为载体图片路径,str2为隐写文件,str3为加密图片保存的路径 124 | def func_LSB_yinxie(str1,str2,str3): 125 | im = Image.open(str1) 126 | #获取图片的宽和高 127 | global width,height 128 | width = im.size[0] 129 | print("width:" + str(width)+"\n") 130 | height = im.size[1] 131 | print("height:"+str(height)+"\n") 132 | count = 0 133 | #获取需要隐藏的信息 134 | key = get_key(str2) 135 | print('key: ',key) 136 | keylen = len(key) 137 | print('keylen: ',keylen) 138 | 139 | 140 | for h in range(0,height): 141 | for w in range(0,width): 142 | pixel = im.getpixel((w,h)) 143 | #code.interact(local=locals()) 144 | a=pixel[0] 145 | b=pixel[1] 146 | c=pixel[2] 147 | if count == keylen: 148 | break 149 | #下面的操作是将信息隐藏进去 150 | #分别将每个像素点的RGB值余2,这样可以去掉最低位的值 151 | #再从需要隐藏的信息中取出一位,转换为整型 152 | #两值相加,就把信息隐藏起来了 153 | a= a-mod(a,2)+int(key[count]) 154 | count+=1 155 | if count == keylen: 156 | im.putpixel((w,h),(a,b,c)) 157 | break 158 | b =b-mod(b,2)+int(key[count]) 159 | count+=1 160 | if count == keylen: 161 | im.putpixel((w,h),(a,b,c)) 162 | break 163 | c= c-mod(c,2)+int(key[count]) 164 | count+=1 165 | if count == keylen: 166 | im.putpixel((w,h),(a,b,c)) 167 | break 168 | if count % 3 == 0: 169 | im.putpixel((w,h),(a,b,c)) 170 | im.save(str3) 171 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+str3) 172 | 173 | 174 | #le为所要提取的信息的长度,str1为加密载体图片的路径,str2为提取文件的保存路径 175 | def func_LSB_tiqu(le,str1,str2): 176 | a="" 177 | b="" 178 | im = Image.open(str1) 179 | #lenth = le*8 180 | lenth = le 181 | width = im.size[0] 182 | height = im.size[1] 183 | count = 0 184 | for h in range(0, height): 185 | for w in range(0, width): 186 | #获得(w,h)点像素的值 187 | pixel = im.getpixel((w, h)) 188 | #此处余3,依次从R、G、B三个颜色通道获得最低位的隐藏信息 189 | if count%3==0: 190 | count+=1 191 | b=b+str((mod(int(pixel[0]),2))) 192 | if count ==lenth: 193 | break 194 | if count%3==1: 195 | count+=1 196 | b=b+str((mod(int(pixel[1]),2))) 197 | if count ==lenth: 198 | break 199 | if count%3==2: 200 | count+=1 201 | b=b+str((mod(int(pixel[2]),2))) 202 | if count ==lenth: 203 | break 204 | if count == lenth: 205 | break 206 | 207 | print(b) 208 | 209 | with open(str2,"wb") as f: 210 | for i in range(0,len(b),8): 211 | #以每8位为一组二进制,转换为十进制 212 | stra = toasc(b[i:i+8]) 213 | #stra = b[i:i+8] 214 | #将转换后的十进制数视为ascii码,再转换为字符串写入到文件中 215 | stra = chr(stra) 216 | sb = bytes(stra, encoding = "utf8") 217 | #print(sb) 218 | #f.write(chr(stra)) 219 | f.write(sb) 220 | stra ="" 221 | f.closed 222 | 223 | global choosepic_LSB_basic 224 | def LSB_yinxie(): 225 | 226 | tkinter.messagebox.showinfo('提示','请选择要进行LSB隐写的图像') 227 | Fpath=filedialog.askopenfilename() 228 | shutil.copy(Fpath,'./') 229 | 230 | old = Fpath.split('/')[-1] 231 | 232 | global choosepic_LSB_basic 233 | choosepic_LSB_basic = old 234 | 235 | #处理后输出的图片路径 236 | new = old[:-4]+"_LSB-generated."+old[-3:] 237 | 238 | #需要隐藏的信息 239 | tkinter.messagebox.showinfo('提示','请选择要隐藏的信息(请选择txt文件)') 240 | txtpath = filedialog.askopenfilename() 241 | shutil.copy(txtpath,'./') 242 | enc=txtpath.split('/')[-1] 243 | # #print(enc) 244 | # plt.imshow(old) 245 | # plt.show() 246 | func_LSB_yinxie(old,enc,new) 247 | 248 | global LSB_new 249 | LSB_new = new 250 | 251 | old = cv2.imread(old) 252 | new = cv2.imread(new) 253 | 254 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 255 | #plt.suptitle('LSB信息隐藏') 256 | b,g,r = cv2.split(old) 257 | old = cv2.merge([r,g,b]) 258 | b,g,r = cv2.split(new) 259 | new = cv2.merge([r,g,b]) 260 | 261 | plt.subplot(2,2,1) 262 | plt.imshow(old) 263 | plt.title("原始图像") 264 | plt.subplot(2,2,2) 265 | plt.hist(old.ravel(), 256, [0,256]) 266 | plt.title("原始图像直方图") 267 | plt.subplot(2,2,3) 268 | plt.imshow(new) 269 | plt.title("隐藏信息的图像") 270 | plt.subplot(2,2,4) 271 | plt.hist(new.ravel(), 256, [0,256]) 272 | plt.title("隐藏信息图像直方图") 273 | plt.tight_layout() #设置默认的间距 274 | plt.show() 275 | 276 | 277 | global LSB_text_len 278 | def LSB_tiqu(): 279 | 280 | #le = text_len 281 | global LSB_text_len 282 | le = int(LSB_text_len) 283 | print('le: ',le) 284 | 285 | 286 | tkinter.messagebox.showinfo('提示','请选择要进行LSB提取的图像') 287 | Fpath=filedialog.askopenfilename() 288 | 289 | LSB_new = Fpath 290 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 291 | tiqu=filedialog.askdirectory() 292 | #print(tiqu) 293 | 294 | tiqu = tiqu+'/LSB_recover.txt' 295 | func_LSB_tiqu(le,LSB_new,tiqu) 296 | tkinter.messagebox.showinfo('提示','隐藏信息已提取,请查看LSB_recover.txt') 297 | 298 | 299 | def DCT_yinxie(): 300 | tkinter.messagebox.showinfo('提示','请选择要进行DCT隐写的图像') 301 | Fpath=filedialog.askopenfilename() 302 | shutil.copy(Fpath,'./') 303 | 304 | original_image_file = Fpath.split('/')[-1] 305 | #original_image_file是DCT_origin.bmp 306 | y = cv2.imread(original_image_file, 0) 307 | 308 | row,col = y.shape 309 | row = int(row/8) 310 | col = int(col/8) 311 | 312 | y1 = y.astype(np.float32) 313 | Y = cv2.dct(y1) 314 | 315 | tkinter.messagebox.showinfo('提示','请选择要隐藏的信息(请选择txt文件)') 316 | txtpath = filedialog.askopenfilename() 317 | shutil.copy(txtpath,'./') 318 | tmp=txtpath.split('/')[-1] 319 | #tmp是hideInfo_DCT.txt 320 | 321 | msg = get_key(tmp) 322 | 323 | count = len(msg) 324 | print('count: ',count) 325 | k1,k2 = randinterval(row,col,count,12) 326 | 327 | for i in range(0,count): 328 | k1[i] = (k1[i]-1)*8+1 329 | k2[i] = (k2[i]-1)*8+1 330 | 331 | 332 | #信息嵌入 333 | temp = 0 334 | H = 1 335 | for i in range(0,count): 336 | if msg[i] == '0': 337 | if Y[k1[i]+4,k2[i]+1] > Y[k1[i]+3,k2[i]+2]: 338 | Y[k1[i]+4,k2[i]+1] , Y[k1[i]+3,k2[i]+2] = swap(Y[k1[i]+4,k2[i]+1],Y[k1[i]+3,k2[i]+2]) 339 | else: 340 | if Y[k1[i]+4,k2[i]+1] < Y[k1[i]+3,k2[i]+2]: 341 | Y[k1[i]+4,k2[i]+1] , Y[k1[i]+3,k2[i]+2] = swap(Y[k1[i]+4,k2[i]+1],Y[k1[i]+3,k2[i]+2]) 342 | 343 | if Y[k1[i]+4,k2[i]+1] > Y[k1[i]+3,k2[i]+2]: 344 | Y[k1[i]+3,k2[i]+2] = Y[k1[i]+3,k2[i]+2]-H #将小系数调整更小 345 | else: 346 | Y[k1[i]+4,k2[i]+1] = Y[k1[i]+4,k2[i]+1]-H 347 | 348 | y2 = cv2.idct(Y) 349 | 350 | 351 | global dct_encoded_image_file 352 | dct_encoded_image_file = original_image_file[:-4]+"_DCT-generated."+original_image_file[-3:] 353 | 354 | cv2.imwrite(dct_encoded_image_file,y2) 355 | 356 | old = cv2.imread(original_image_file) 357 | new = cv2.imread(dct_encoded_image_file) 358 | 359 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+dct_encoded_image_file) 360 | 361 | 362 | b,g,r = cv2.split(old) 363 | old = cv2.merge([r,g,b]) 364 | b,g,r = cv2.split(new) 365 | new = cv2.merge([r,g,b]) 366 | 367 | 368 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 369 | 370 | plt.subplot(2,2,1) 371 | plt.imshow(old) 372 | plt.title("原始图像") 373 | plt.subplot(2,2,2) 374 | plt.hist(old.ravel(), 256, [0,256]) 375 | plt.title("原始图像直方图") 376 | plt.subplot(2,2,3) 377 | plt.imshow(new) 378 | plt.title("隐藏信息的图像") 379 | plt.subplot(2,2,4) 380 | plt.hist(new.ravel(), 256, [0,256]) 381 | plt.title("隐藏信息图像直方图") 382 | plt.tight_layout() #设置默认的间距 383 | plt.show() 384 | 385 | 386 | global DCT_text_len 387 | def DCT_tiqu(): 388 | 389 | 390 | # print('le: ',le) 391 | count = int(DCT_text_len) 392 | print('count: ',count) 393 | 394 | tkinter.messagebox.showinfo('提示','请选择要进行DCT提取的图像') 395 | Fpath=filedialog.askopenfilename() 396 | dct_encoded_image_file = Fpath.split('/')[-1] 397 | 398 | dct_img = cv2.imread(dct_encoded_image_file,0) 399 | print(dct_img) 400 | y=dct_img 401 | y1 = y.astype(np.float32) 402 | Y = cv2.dct(y1) 403 | row,col = y.shape 404 | row = int(row/8) 405 | col = int(col/8) 406 | # count = 448 407 | k1,k2 = randinterval(row,col,count,12) 408 | for i in range(0,count): 409 | k1[i] = (k1[i]-1)*8+1 410 | k2[i] = (k2[i]-1)*8+1 411 | 412 | 413 | #准备提取并回写信息 414 | str2 = 'DCT_recover.txt' 415 | b = "" 416 | 417 | for i in range(0,count): 418 | if Y[k1[i]+4,k2[i]+1] < Y[k1[i]+3,k2[i]+2]: 419 | b=b+str('0') 420 | # print('msg[i]: ',0) 421 | else: 422 | b=b+str('1') 423 | # print('msg[i]: ',1) 424 | 425 | print(b) 426 | 427 | 428 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 429 | tiqu=filedialog.askdirectory() 430 | tiqu = tiqu+'/DCT_hidden_text.txt' 431 | 432 | str2 = tiqu 433 | with open(str2,"wb") as f: 434 | for i in range(0,len(b),8): 435 | #以每8位为一组二进制,转换为十进制 436 | stra = toasc(b[i:i+8]) 437 | #stra = b[i:i+8] 438 | #将转换后的十进制数视为ascii码,再转换为字符串写入到文件中 439 | stra = chr(stra) 440 | sb = bytes(stra, encoding = "utf8") 441 | f.write(sb) 442 | stra ="" 443 | f.closed 444 | 445 | tkinter.messagebox.showinfo('提示','隐藏信息已提取,请查看DCT_hidden_text.txt') 446 | 447 | #图像降级改进 448 | def Image1_yinxie(): 449 | 450 | tkinter.messagebox.showinfo('提示','请选择载体图像') 451 | Fpath=filedialog.askopenfilename() 452 | 453 | shutil.copy(Fpath,'./') 454 | 455 | beiyinxie_image = Fpath.split('/')[-1] 456 | 457 | tkinter.messagebox.showinfo('提示','请选择要隐写的图像') 458 | Fpath=filedialog.askopenfilename() 459 | shutil.copy(Fpath,'./') 460 | mark_image = Fpath.split('/')[-1] 461 | 462 | img=np.array(Image.open(beiyinxie_image)) 463 | mark=np.array(Image.open(mark_image)) 464 | rows,cols,dims=mark.shape 465 | 466 | for i in range(0,dims): 467 | for j in range(0,rows*2): 468 | for k in range(0,cols*2): 469 | img[j,k,i]=img[j,k,i]&252 470 | 471 | for i in range(0,dims): 472 | for j in range(0,rows): 473 | for k in range(0,cols): 474 | img[2*j,2*k,i]=img[2*j,2*k,i]+(mark[j,k,i]&192)//64 475 | img[2*j,2*k+1,i]=img[2*j,2*k+1,i]+(mark[j,k,i]&48)//16 476 | img[2*j+1,2*k,i]=img[2*j+1,2*k,i]+(mark[j,k,i]&12)//4 477 | img[2*j+1,2*k+1,i]=img[2*j+1,2*k+1,i]+(mark[j,k,i]&3) 478 | #print(2*j+1,2*k+1) 479 | img=Image.fromarray(img) 480 | global new_image 481 | new_image = beiyinxie_image[:-4]+"_with_mark1."+beiyinxie_image[-3:] 482 | 483 | img.save(new_image) 484 | 485 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+new_image) 486 | 487 | old = cv2.imread(beiyinxie_image) 488 | new = cv2.imread(new_image) 489 | 490 | b,g,r = cv2.split(old) 491 | old = cv2.merge([r,g,b]) 492 | b,g,r = cv2.split(new) 493 | new = cv2.merge([r,g,b]) 494 | 495 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 496 | #plt.suptitle('LSB信息隐藏') 497 | plt.subplot(2,2,1) 498 | plt.imshow(old) 499 | plt.title("原始图像") 500 | plt.subplot(2,2,2) 501 | plt.hist(old.ravel(), 256, [0,256]) 502 | plt.title("原始图像直方图") 503 | plt.subplot(2,2,3) 504 | plt.imshow(new) 505 | plt.title("隐藏信息的图像") 506 | plt.subplot(2,2,4) 507 | plt.hist(new.ravel(), 256, [0,256]) 508 | plt.title("隐藏信息图像直方图") 509 | plt.tight_layout() #设置默认的间距 510 | plt.show() 511 | 512 | #图像降级改进 513 | def Image1_tiqu(): 514 | 515 | tkinter.messagebox.showinfo('提示','请选择要进行提取图片水印的图像') 516 | Fpath=filedialog.askopenfilename() 517 | new_image = Fpath 518 | 519 | 520 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 521 | tiqu=filedialog.askdirectory() 522 | 523 | print(tiqu) 524 | tiqu = tiqu+'/mark_get1.'+new_image[-3:] 525 | print(tiqu) 526 | 527 | imgwmark=np.array(Image.open(new_image)) 528 | result=imgwmark 529 | rows,cols,dims=imgwmark.shape 530 | rows=rows//2 531 | cols=cols//2 532 | for i in range(0,dims): 533 | for j in range(0,rows*2): 534 | for k in range(0,cols*2): 535 | imgwmark[j,k,i]=imgwmark[j,k,i]&3 536 | 537 | for i in range(0,dims): 538 | for j in range(0,rows): 539 | for k in range(0,cols): 540 | result[j,k,i]=imgwmark[2*j,2*k,i]*64+imgwmark[2*j,2*k+1,i]*16 541 | +imgwmark[2*j+1,2*k,i]*4+imgwmark[2*j+1,2*k+1,i] 542 | mark_get=Image.fromarray(result) 543 | mark_get.save(tiqu) 544 | 545 | tkinter.messagebox.showinfo('提示','水印图片已提取,请查看mark_get1.'+new_image[-3:]) 546 | 547 | 548 | #图像降级 549 | def Image_yinxie(): 550 | 551 | tkinter.messagebox.showinfo('提示','请选择载体图像') 552 | Fpath=filedialog.askopenfilename() 553 | 554 | shutil.copy(Fpath,'./') 555 | 556 | beiyinxie_image = Fpath.split('/')[-1] 557 | 558 | tkinter.messagebox.showinfo('提示','请选择要隐写的图像') 559 | Fpath=filedialog.askopenfilename() 560 | shutil.copy(Fpath,'./') 561 | mark_image = Fpath.split('/')[-1] 562 | 563 | img=np.array(Image.open(beiyinxie_image)) 564 | mark=np.array(Image.open(mark_image)) 565 | rows,cols,dims=mark.shape 566 | 567 | for i in range(0,dims): 568 | for j in range(0,rows*2): 569 | for k in range(0,cols*2): 570 | img[j,k,i]=img[j,k,i]&240 571 | 572 | for i in range(0,dims): 573 | for j in range(0,rows): 574 | for k in range(0,cols): 575 | img[j,k,i] = img[j,k,i] + ((mark[j,k,i]&240)//16) 576 | 577 | # img[2*j,2*k,i]=img[2*j,2*k,i]+(mark[j,k,i]&192)//64 578 | # img[2*j,2*k+1,i]=img[2*j,2*k+1,i]+(mark[j,k,i]&48)//16 579 | # img[2*j+1,2*k,i]=img[2*j+1,2*k,i]+(mark[j,k,i]&12)//4 580 | # img[2*j+1,2*k+1,i]=img[2*j+1,2*k+1,i]+(mark[j,k,i]&3) 581 | img=Image.fromarray(img) 582 | global new_image 583 | new_image = beiyinxie_image[:-4]+"_with_mark."+beiyinxie_image[-3:] 584 | 585 | img.save(new_image) 586 | 587 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+new_image) 588 | 589 | old = cv2.imread(beiyinxie_image) 590 | new = cv2.imread(new_image) 591 | 592 | b,g,r = cv2.split(old) 593 | old = cv2.merge([r,g,b]) 594 | b,g,r = cv2.split(new) 595 | new = cv2.merge([r,g,b]) 596 | 597 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 598 | #plt.suptitle('LSB信息隐藏') 599 | plt.subplot(2,2,1) 600 | plt.imshow(old) 601 | plt.title("原始图像") 602 | plt.subplot(2,2,2) 603 | plt.hist(old.ravel(), 256, [0,256]) 604 | plt.title("原始图像直方图") 605 | plt.subplot(2,2,3) 606 | plt.imshow(new) 607 | plt.title("隐藏信息的图像") 608 | plt.subplot(2,2,4) 609 | plt.hist(new.ravel(), 256, [0,256]) 610 | plt.title("隐藏信息图像直方图") 611 | plt.tight_layout() #设置默认的间距 612 | plt.show() 613 | 614 | #图像降级 615 | def Image_tiqu(): 616 | 617 | tkinter.messagebox.showinfo('提示','请选择要进行提取图片水印的图像') 618 | Fpath=filedialog.askopenfilename() 619 | new_image = Fpath 620 | 621 | 622 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 623 | tiqu=filedialog.askdirectory() 624 | #print(tiqu) 625 | 626 | tiqu = tiqu+'/mark_get.'+new_image[-3:] 627 | 628 | 629 | imgwmark=np.array(Image.open(new_image)) 630 | result=imgwmark 631 | rows,cols,dims=imgwmark.shape 632 | rows=rows//2 633 | cols=cols//2 634 | for i in range(0,dims): 635 | for j in range(0,rows*2): 636 | for k in range(0,cols*2): 637 | result[j,k,i]= (imgwmark[j,k,i]&15) 638 | result[j,k,i] = result[j,k,i]*16 639 | 640 | mark_get=Image.fromarray(result) 641 | mark_get.save(tiqu) 642 | 643 | tkinter.messagebox.showinfo('提示','水印图片已提取,请查看mark_get.'+new_image[-3:]) 644 | 645 | 646 | global LSB_suijijiange_step 647 | LSB_suijijiange_step = 2 648 | def func_LSB_suijijiange_yinxie(str1,str2,str3): 649 | im = Image.open(str1) 650 | global width,height 651 | width = im.size[0] 652 | print("width:" + str(width)+"\n") 653 | height = im.size[1] 654 | print("height:"+str(height)+"\n") 655 | count = 0 656 | #获取需要隐藏的信息 657 | global keylen 658 | key = get_key(str2) 659 | keylen = len(key) 660 | print(key) 661 | print(keylen) 662 | 663 | random.seed(2) 664 | global LSB_suijijiange_step 665 | step_max = int(width*height/keylen) 666 | print('step: ',LSB_suijijiange_step) 667 | print('step_max: ',step_max) 668 | LSB_suijijiange_step = int(LSB_suijijiange_step) 669 | if LSB_suijijiange_step > step_max: 670 | tkinter.messagebox.showinfo('提示','步长设置过大,请重新设置,步长最大值为: '+str(step_max)) 671 | global LSB_suijijiange_sf 672 | LSB_suijijiange_sf = False 673 | return 674 | 675 | step=LSB_suijijiange_step 676 | random_seq = [0]*keylen 677 | for i in range(0,keylen): 678 | random_seq[i] = int(random.random()*step+1) 679 | print(random_seq[i]) 680 | 681 | q=1 682 | 683 | for count in range(keylen): 684 | w,h = q_converto_wh(q) 685 | pixel = im.getpixel((w,h)) 686 | pixel = pixel-mod(pixel,2)+int(key[count]) 687 | q=q+random_seq[count] 688 | im.putpixel((w,h),pixel) 689 | 690 | im.save(str3) 691 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+str3) 692 | 693 | 694 | 695 | def LSB_suijijiange_yinxie(): 696 | 697 | tkinter.messagebox.showinfo('提示','请选择要进行LSB随机间隔隐写的图像') 698 | Fpath=filedialog.askopenfilename() 699 | shutil.copy(Fpath,'./') 700 | 701 | old = Fpath.split('/')[-1] 702 | 703 | if(os.path.exists('./'+old)==False): 704 | shutil.copy(Fpath,'./') 705 | #处理后输出的图片路径 706 | new = old[:-4]+"_LSB-random_interval-generated."+old[-3:] 707 | 708 | #需要隐藏的信息 709 | tkinter.messagebox.showinfo('提示','请选择要隐藏的信息(请选择txt文件)') 710 | txtpath = filedialog.askopenfilename() 711 | shutil.copy(txtpath,'./') 712 | enc=txtpath.split('/')[-1] 713 | 714 | if(os.path.exists('./'+enc)==False): 715 | shutil.copy(txtpath,'./') 716 | #print(enc) 717 | global LSB_suijijiange_sf 718 | LSB_suijijiange_sf = True 719 | func_LSB_suijijiange_yinxie(old,enc,new) 720 | print('LSB_suijijiange_sf: ',LSB_suijijiange_sf) 721 | 722 | global LSB_new 723 | LSB_new = new 724 | 725 | old = cv2.imread(old) 726 | new = cv2.imread(new) 727 | 728 | if LSB_suijijiange_sf == True: 729 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 730 | #plt.suptitle('LSB信息隐藏') 731 | plt.subplot(2,2,1) 732 | plt.imshow(old) 733 | plt.title("原始图像") 734 | plt.subplot(2,2,2) 735 | plt.hist(old.ravel(), 256, [0,256]) 736 | plt.title("原始图像直方图") 737 | plt.subplot(2,2,3) 738 | plt.imshow(new) 739 | plt.title("隐藏信息的图像") 740 | plt.subplot(2,2,4) 741 | plt.hist(new.ravel(), 256, [0,256]) 742 | plt.title("隐藏信息图像直方图") 743 | plt.tight_layout() #设置默认的间距 744 | plt.show() 745 | 746 | 747 | #le为所要提取的信息的长度,str1为加密载体图片的路径,str2为提取文件的保存路径 748 | def func_LSB_suijijiange_tiqu(le,str1,str2): 749 | a="" 750 | b="" 751 | im = Image.open(str1) 752 | 753 | 754 | global width 755 | global height 756 | width = im.size[0] 757 | height = im.size[1] 758 | print(width,',',height) 759 | len_total = le 760 | count = 0 761 | #print(len_total) 762 | random.seed(2) 763 | #step = int(width*height/len_total) 764 | step = int(LSB_suijijiange_step) 765 | random_seq = [0]*len_total 766 | for i in range(0,len_total): 767 | random_seq[i] = int(random.random()*step+1) 768 | 769 | 770 | q=1 771 | count = 0 772 | 773 | 774 | for count in range(len_total): 775 | 776 | w,h = q_converto_wh(q) 777 | pixel = im.getpixel((w, h)) 778 | #print(q,'-----',w,',',h) 779 | b=b+str(mod(pixel,2)) 780 | #print(count) 781 | q = q + random_seq[count] 782 | count+=1 783 | 784 | print(b) 785 | 786 | with open(str2,"wb") as f: 787 | for i in range(0,len(b),8): 788 | #以每8位为一组二进制,转换为十进制 789 | stra = toasc(b[i:i+8]) 790 | #stra = b[i:i+8] 791 | #将转换后的十进制数视为ascii码,再转换为字符串写入到文件中 792 | stra = chr(stra) 793 | sb = bytes(stra, encoding = "utf8") 794 | #print(sb) 795 | #f.write(chr(stra)) 796 | f.write(sb) 797 | stra ="" 798 | f.closed 799 | 800 | 801 | global LSB_suijijiange_text_len 802 | def LSB_suijijiange_tiqu(): 803 | global LSB_suijijiange_text_len 804 | le = int(LSB_suijijiange_text_len) 805 | print('le: ',le) 806 | 807 | 808 | tkinter.messagebox.showinfo('提示','请选择要进行LSB随机间隔算法提取的图像') 809 | Fpath=filedialog.askopenfilename() 810 | 811 | 812 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 813 | tiqu=filedialog.askdirectory() 814 | #print(tiqu) 815 | tiqu = tiqu+'/LSB-random_interval-recover.txt' 816 | LSB_new = Fpath 817 | print(LSB_new) 818 | func_LSB_suijijiange_tiqu(le,LSB_new,tiqu) 819 | tkinter.messagebox.showinfo('提示','隐藏信息已提取,请查看LSB-random_interval-recover.txt') 820 | 821 | 822 | global LSB_quyujiaoyan_size 823 | LSB_quyujiaoyan_size = 4 824 | def func_LSB_quyujiaoyan_yinxie(str1,str2,str3): 825 | im = Image.open(str1) 826 | #获取图片的宽和高 827 | global width,height 828 | width = im.size[0] 829 | print("width:" + str(width)+"\n") 830 | height = im.size[1] 831 | print("height:"+str(height)+"\n") 832 | count = 0 833 | #获取需要隐藏的信息 834 | global keylen 835 | key = get_key(str2) 836 | keylen = len(key) 837 | print(key) 838 | print(keylen) 839 | 840 | 841 | q=1 842 | 843 | global LSB_quyujiaoyan_size 844 | size = int(LSB_quyujiaoyan_size) 845 | print('size: ',size) 846 | print(int(width*height/keylen)) 847 | 848 | # LSB_suijijiange_step = int(LSB_suijijiange_step) 849 | # if LSB_suijijiange_step > step_max: 850 | size_max = int(width*height/keylen) 851 | print('size_max: ',size_max) 852 | if width * height < size* keylen : 853 | tkinter.messagebox.showinfo('提示','size设置过大,请重新设置,size最大值为: '+str(int(width*height/keylen))) 854 | 855 | pixel = [] 856 | for p in range(1,keylen+1): 857 | for i in range(1,size+1): 858 | w,h = q_converto_wh((p-1)*size+i) 859 | print(w,h) 860 | #e = im.getpixel(0,1) 861 | pixel.append(im.getpixel((w,h))) 862 | 863 | tem = 0 864 | for i,v in enumerate(pixel): 865 | tem = tem + mod(v,2) #+mod(pixel2,2)+mod(pixel3,2)+mod(pixel4,2) 866 | pixel = [] 867 | tem = mod(tem,2) 868 | 869 | if tem != int(key[p-1]): 870 | q = int(random.random()*size)+1 871 | w,h = q_converto_wh((p-1)*size+q) 872 | pix = im.getpixel((w,h)) 873 | im.putpixel((w,h),pix-1) 874 | 875 | 876 | im.save(str3) 877 | tkinter.messagebox.showinfo('提示','图像隐写已完成,隐写后的图像保存为'+str3) 878 | 879 | 880 | 881 | def LSB_quyujiaoyan_yinxie(): 882 | tkinter.messagebox.showinfo('提示','请选择要进行LSB区域校验位隐写的图像') 883 | Fpath=filedialog.askopenfilename() 884 | 885 | old = Fpath.split('/')[-1] 886 | 887 | if(os.path.exists('./'+old)==False): 888 | shutil.copy(Fpath,'./') 889 | #处理后输出的图片路径 890 | new = old[:-4]+"_LSB-regional_verification-generated."+old[-3:] 891 | 892 | #需要隐藏的信息 893 | tkinter.messagebox.showinfo('提示','请选择要隐藏的信息(请选择txt文件)') 894 | txtpath = filedialog.askopenfilename() 895 | enc=txtpath.split('/')[-1] 896 | 897 | if(os.path.exists('./'+enc)==False): 898 | shutil.copy(txtpath,'./') 899 | 900 | #print(enc) 901 | func_LSB_quyujiaoyan_yinxie(old,enc,new) 902 | 903 | global LSB_new 904 | LSB_new = new 905 | 906 | old = cv2.imread(old) 907 | new = cv2.imread(new) 908 | 909 | plt.figure(figsize=(6, 7)) #matplotlib设置画面大小 600*700 910 | #plt.suptitle('LSB信息隐藏') 911 | plt.subplot(2,2,1) 912 | plt.imshow(old) 913 | plt.title("原始图像") 914 | plt.subplot(2,2,2) 915 | plt.hist(old.ravel(), 256, [0,256]) 916 | plt.title("原始图像直方图") 917 | plt.subplot(2,2,3) 918 | plt.imshow(new) 919 | plt.title("隐藏信息的图像") 920 | plt.subplot(2,2,4) 921 | plt.hist(new.ravel(), 256, [0,256]) 922 | plt.title("隐藏信息图像直方图") 923 | plt.tight_layout() #设置默认的间距 924 | plt.show() 925 | 926 | 927 | #le为所要提取的信息的长度,str1为加密载体图片的路径,str2为提取文件的保存路径 928 | def func_LSB_quyujiaoyan_tiqu(le,str1,str2): 929 | a="" 930 | b="" 931 | im = Image.open(str1) 932 | 933 | 934 | global width 935 | global height 936 | width = im.size[0] 937 | height = im.size[1] 938 | print(width,',',height) 939 | len_total = le 940 | count = 0 941 | 942 | 943 | global LSB_quyujiaoyan_size 944 | size = int(LSB_quyujiaoyan_size) 945 | print('size: ',size) 946 | 947 | pixel = [] 948 | for p in range(1,len_total+1): 949 | for i in range(1,size+1): 950 | w,h = q_converto_wh((p-1)*size+i) 951 | pixel.append(im.getpixel((w,h))) 952 | 953 | re = 0 954 | for i,v in enumerate(pixel): 955 | re = re + mod(v,2) 956 | pixel = [] 957 | re = mod(re,2) 958 | b=b+str(re) 959 | 960 | 961 | print(b) 962 | 963 | with open(str2,"wb") as f: 964 | for i in range(0,len(b),8): 965 | #以每8位为一组二进制,转换为十进制 966 | stra = toasc(b[i:i+8]) 967 | #stra = b[i:i+8] 968 | #将转换后的十进制数视为ascii码,再转换为字符串写入到文件中 969 | stra = chr(stra) 970 | sb = bytes(stra, encoding = "utf8") 971 | 972 | f.write(sb) 973 | stra ="" 974 | f.closed 975 | 976 | 977 | global LSB_quyujiaoyan_text_len 978 | def LSB_quyujiaoyan_tiqu(): 979 | 980 | global LSB_quyujiaoyan_text_len 981 | le = int(LSB_quyujiaoyan_text_len) 982 | print('le: ',le) 983 | 984 | 985 | tkinter.messagebox.showinfo('提示','请选择要进行LSB区域校验位算法提取的图像') 986 | Fpath=filedialog.askopenfilename() 987 | 988 | tkinter.messagebox.showinfo('提示','请选择将提取信息保存的位置') 989 | tiqu=filedialog.askdirectory() 990 | 991 | tiqu = tiqu+'/LSB-regional_verification-recover.txt' 992 | 993 | LSB_new = Fpath 994 | func_LSB_quyujiaoyan_tiqu(le,LSB_new,tiqu) 995 | tkinter.messagebox.showinfo('提示','隐藏信息已提取,请查看LSB-regional_verification-recover.txt') 996 | 997 | 998 | def create_random_interval(): 999 | root = Toplevel() 1000 | root.title("随机间隔法") 1001 | root.geometry('800x400') 1002 | Label(root, text="随机间隔法",font=fontStyle1).pack() 1003 | 1004 | 1005 | button5 = Button(root,text="LSB随机间隔法水印嵌入",command=LSB_suijijiange_yinxie) # 控制label的颜色 1006 | button6 = Button(root, text="LSB随机间隔法水印提取",command=LSB_suijijiange_tiqu) # 控制label的颜色 1007 | button5.place(height =60,width =350,x = 30,y = 150) 1008 | button6.place(height =60,width =350,x = 430,y = 150) 1009 | myentry = Entry(root) 1010 | myentry.place(x=350,y=65) 1011 | def get_entry_text(): 1012 | global LSB_suijijiange_step 1013 | LSB_suijijiange_step = myentry.get() 1014 | tkinter.messagebox.showinfo('提示','随机间隔步长已被设置为'+LSB_suijijiange_step) 1015 | print('LSB_suijijiange_step: ',LSB_suijijiange_step) 1016 | Button(root,text="设置随机间隔的步长",command=get_entry_text,style='Test.TButton').place(x=357,y=87.5) 1017 | 1018 | 1019 | myentry1 = Entry(root) 1020 | myentry1.place(x=350,y=300) 1021 | def get_entry_text(): 1022 | global LSB_suijijiange_text_len 1023 | LSB_suijijiange_text_len = myentry1.get() 1024 | tkinter.messagebox.showinfo('提示','输入提取信息的长度已被设置为'+LSB_suijijiange_text_len) 1025 | print(LSB_suijijiange_text_len) 1026 | Button(root,text="输入提取信息的长度",command=get_entry_text,style='Test.TButton').place(x=350,y=320) 1027 | 1028 | Message(root,text='∎随机间隔法水印嵌入由用户选择图片和隐藏信息\n∎对图像进行随机间隔的LSB隐写后,将秘密信息写入\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像\n∎随机间隔的步长由用户输入').place(x=100,y=230) 1029 | Message(root,text='∎随机间隔法水印提取由用户选择要提取信息的图片和提取信息的保存路径\n∎程序将使用同样的随机种子,读取随机间隔法水印嵌入时保存的图像并提取出信息并保存到用户选择的路径').place(x=530,y=230) 1030 | 1031 | root.mainloop() 1032 | 1033 | 1034 | 1035 | def creatre_regional_verification(): 1036 | root = Toplevel() 1037 | root.title("区域校验位算法") 1038 | root.geometry('850x400') 1039 | Label(root, text="区域校验位算法",font=fontStyle1).pack() 1040 | 1041 | 1042 | button5 = Button(root, text="LSB区域校验位算法水印嵌入",command=LSB_quyujiaoyan_yinxie) 1043 | button6 = Button(root, text="LSB区域校验位算法水印提取",command=LSB_quyujiaoyan_tiqu) 1044 | button5.place(height =60,width =370,x = 30,y = 150) 1045 | button6.place(height =60,width =370,x = 430,y = 150) 1046 | 1047 | myentry = Entry(root) 1048 | myentry.place(x=350,y=55) 1049 | def get_entry_text(): 1050 | global LSB_quyujiaoyan_size 1051 | LSB_quyujiaoyan_size = myentry.get() 1052 | tkinter.messagebox.showinfo('提示','区域大小已被设置为'+LSB_quyujiaoyan_size) 1053 | print(LSB_quyujiaoyan_size) 1054 | Button(root,text="请输入区域校验位参数(区域大小)",command=get_entry_text,style='Test.TButton').place(x=330,y=78) 1055 | 1056 | 1057 | myentry1 = Entry(root) 1058 | myentry1.place(x=330,y=300) 1059 | def get_entry_text(): 1060 | global LSB_quyujiaoyan_text_len 1061 | LSB_quyujiaoyan_text_len = myentry1.get() 1062 | tkinter.messagebox.showinfo('提示','输入提取信息的长度已被设置为'+LSB_quyujiaoyan_text_len) 1063 | print(LSB_quyujiaoyan_text_len) 1064 | Button(root,text="输入提取信息的长度",command=get_entry_text,style='Test.TButton').place(x=335,y=323) 1065 | 1066 | Message(root,text='∎区域校验位算法水印嵌入由用户选择图片和隐藏信息\n∎对图像进行区域校验位的LSB隐写后,将秘密信息写入\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像\n∎区域校验位算法的区域大小由用户输入').place(x=100,y=230) 1067 | Message(root,text='∎区域校验位算法水印提取由用户选择要提取信息的图片和提取信息的保存路径\n∎读取区域校验位算法水印嵌入时保存的图像并提取出信息并保存到用户选择的路径').place(x=550,y=230) 1068 | 1069 | root.mainloop() 1070 | 1071 | 1072 | 1073 | #图像降级 1074 | def create_image(): 1075 | root = Toplevel() 1076 | 1077 | root.title("图片水印") 1078 | root.geometry('700x400') 1079 | 1080 | w = Canvas(root) 1081 | w.place(x=300,y=0, width=300,height=700) 1082 | w.create_line(180,50,180,330, 1083 | fill='#C0C0C0', 1084 | #fill='red', 1085 | width=2,) 1086 | 1087 | 1088 | Message(root,text='∎图像降级算法水印嵌入由用户选择载体图片和水印图片\n∎将载体图片的四个最低为比特位替换成水印图片的四个最高比特位\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像').place(x=500,y=60) 1089 | Message(root,text='∎图像降级算法水印提取由用户选择要提取信息的图片和提取信息的保存位置\n∎程序读取要提取信息的图片,提取出隐藏的图片并保存').place(x=500,y=230) 1090 | Label(root, text="图像降级算法",font=fontStyle).pack() 1091 | button5 = Button(root, text="图像降级算法水印嵌入",command=Image_yinxie) # 控制label的颜色 1092 | button6 = Button(root, text="图像降级算法水印提取",command=Image_tiqu) # 控制label的颜色 1093 | button5.place(height =60,width =300,x = 150,y = 80) 1094 | button6.place(height =60,width =300,x = 150,y = 230) 1095 | root.mainloop() 1096 | 1097 | 1098 | #图像降级改进 1099 | def create_image1(): 1100 | root = Toplevel() 1101 | root.title("图片水印") 1102 | root.geometry('700x400') 1103 | 1104 | 1105 | w = Canvas(root) 1106 | w.place(x=300,y=0, width=300,height=700) 1107 | w.create_line(205,50,205,330, 1108 | fill='#C0C0C0', 1109 | #fill='red', 1110 | width=2,) 1111 | 1112 | 1113 | Message(root,text='∎图像降级算法改进水印嵌入由用户选择载体图片和水印图片\n∎将水印图片的信息的八位的二进制数分成四块,每块分别加入到载体图片上去\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像',cursor='cross',width='150').place(x=520,y=60) 1114 | Message(root,text='∎图像降级算法改进水印提取由用户选择要提取信息的图片和提取信息的保存位置\n∎程序读取要提取信息的图片,提取出隐藏的图片并保存',cursor='cross',width='150').place(x=520,y=230) 1115 | 1116 | 1117 | Label(root, text="图像降级算法改进",font=fontStyle).pack() 1118 | button5 = Button(root, text="图像降级算法改进水印嵌入",command=Image1_yinxie) # 控制label的颜色 1119 | button6 = Button(root, text="图像降级算法改进水印提取",command=Image1_tiqu) # 控制label的颜色 1120 | button5.place(height =60,width =350,x = 130,y = 60) 1121 | button6.place(height =60,width =350,x = 130,y = 230) 1122 | root.mainloop() 1123 | 1124 | 1125 | 1126 | def create_LSB_improve(): 1127 | root = Toplevel() 1128 | root.title("LSB算法改进") 1129 | root.geometry('800x400') 1130 | 1131 | w = Canvas(root) 1132 | w.place(x=300,y=0, width=300,height=700) 1133 | w.create_line(290,100,290,300, 1134 | fill='#C0C0C0', 1135 | #fill='red', 1136 | width=2,) 1137 | 1138 | Label(root, text="LSB算法改进",font=fontStyle1).pack() 1139 | button7 = Button(root, text="LSB随机间隔法",command=create_random_interval) # 控制label的颜色 1140 | button9 = Button(root, text="LSB区域校验位算法",command=creatre_regional_verification) # 控制label的颜色 1141 | 1142 | button7.place(height =60,width =350,x = 200,y = 100) 1143 | button9.place(height =60,width =350,x = 200,y = 200) 1144 | Message(root,text='LSB随机间隔法包括随机间隔法水印嵌入和随机间隔水印提取',cursor='cross',width='150').place(x=600,y=100) 1145 | Message(root,text='LSB区域校验位算法包括区域校验位算法水印嵌入和区域校验位算法水印提取',cursor='cross',width='150').place(x=600,y=200) 1146 | root.mainloop() 1147 | 1148 | 1149 | 1150 | def create_image_downgrade(): 1151 | root = Toplevel() 1152 | root.title("图像降级算法及其改进") 1153 | root.geometry('800x400') 1154 | 1155 | w = Canvas(root) 1156 | w.place(x=300,y=0, width=300,height=700) 1157 | w.create_line(280,100,280,300, 1158 | fill='#C0C0C0', 1159 | #fill='red', 1160 | width=2,) 1161 | 1162 | 1163 | Label(root, text="图像降级算法及其改进",font=fontStyle1).pack() 1164 | button7 = Button(root, text="图像降级算法",command=create_image) # 控制label的颜色 1165 | button9 = Button(root, text="图像降级算法改进",command=create_image1) # 控制label的颜色 1166 | 1167 | button7.place(height =60,width =350,x = 200,y = 100) 1168 | button9.place(height =60,width =350,x = 200,y = 200) 1169 | Message(root,text='图像降级算法包括图像降级算法水印嵌入和图像降级算法水印提取').place(x=600,y=100) 1170 | Message(root,text='图像降级算法改进包括图像降级算法改进水印嵌入和图像降级算法改进水印提取').place(x=600,y=200) 1171 | 1172 | root.mainloop() 1173 | 1174 | 1175 | 1176 | def create_LSB_basic(): 1177 | root = Toplevel() 1178 | root.title("LSB基本算法") 1179 | root.geometry('800x400') 1180 | 1181 | w = Canvas(root) 1182 | w.place(x=300,y=0, width=300,height=700) 1183 | w.create_line(290,50,290,330, 1184 | fill='#C0C0C0', 1185 | #fill='red', 1186 | width=2,) 1187 | 1188 | button1 = Button(root, text="LSB基本算法水印嵌入",command=LSB_yinxie) 1189 | button2 = Button(root, text="LSB基本算法水印提取",command=LSB_tiqu) 1190 | 1191 | button1.place(height =60,width =300,x = 250,y = 50) 1192 | button2.place(height =60,width =300,x = 250,y = 200) 1193 | 1194 | Message(root,text='∎LSB基本算法水印嵌入由用户选择图片和隐藏信息\n∎对图像进行最低有效位隐写后将秘密信息写入\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像',cursor='cross',width='150').place(x=600,y=50) 1195 | Message(root,text='∎LSB基本算法水印提取由用户选择要提取信息的图片和提取信息的保存路径\n∎程序将读取LSB隐写时保存的图像并提取出信息,保存到用户选择的路径',cursor='cross',width='150').place(x=600,y=200) 1196 | 1197 | 1198 | myentry = Entry(root) 1199 | myentry.place(x=320,y=300) 1200 | def get_entry_text(): 1201 | global LSB_text_len 1202 | LSB_text_len = myentry.get() 1203 | tkinter.messagebox.showinfo('提示','提取信息长度已被设置为'+LSB_text_len) 1204 | print(LSB_text_len) 1205 | Button(root,text="输入提取信息的长度",command=get_entry_text,style='Test.TButton').place(x=320,y=320) 1206 | 1207 | Label(root, text="LSB基本算法",font=fontStyle1).pack() 1208 | 1209 | root.mainloop() 1210 | 1211 | 1212 | 1213 | def create_DCT(): 1214 | root = Toplevel() 1215 | 1216 | Label(root, text="变换域水印",font=fontStyle1).pack() 1217 | root.title("变换域水印") 1218 | root.geometry('700x400') 1219 | button3 = Button(root, text="DCT水印嵌入",command=DCT_yinxie) # 控制label的边界 1220 | button4 = Button(root, text="DCT水印提取",command=DCT_tiqu) # 控制label的颜色 1221 | button3.place(height =60,width =200,x = 100,y = 150) 1222 | button4.place(height =60,width =200,x = 400,y = 150) 1223 | 1224 | Message(root,text='∎DCT水印嵌入由用户选择图片和隐藏信息\n∎对图像进行DCT变换后将秘密信息写入\n∎绘制原始图像和隐写后的图像的直方图对比,并保存隐写后的图像',cursor='cross',width='150').place(x=100,y=250) 1225 | Message(root,text='∎DCT提取由用户选择要提取信息的图片和提取信息的保存路径\n∎程序将读取DCT隐写时保存的图像并提取出信息并保存到用户选择的路径',cursor='cross',width='150').place(x=430,y=250) 1226 | 1227 | myentry = Entry(root) 1228 | myentry.place(x=280,y=300) 1229 | def get_entry_text(): 1230 | global DCT_text_len 1231 | DCT_text_len = myentry.get() 1232 | tkinter.messagebox.showinfo('提示','提取信息长度已被设置为'+DCT_text_len) 1233 | print(DCT_text_len) 1234 | Button(root,text="输入提取信息的长度",command=get_entry_text,style='Test.TButton').place(x=280,y=330) 1235 | 1236 | root.mainloop() 1237 | 1238 | 1239 | def create_LSB(): 1240 | root1 = Toplevel() 1241 | root1.title("空间域水印") 1242 | root1.geometry('800x430') 1243 | 1244 | w = Canvas(root1) 1245 | w.place(x=300,y=0, width=300,height=700) 1246 | w.create_line(250,50,250,370, 1247 | fill='#C0C0C0', 1248 | #fill='red', 1249 | width=2,) 1250 | 1251 | Label(root1, text="空间域水印").pack() 1252 | button2 = Button(root1, text="LSB基本算法",command=create_LSB_basic) 1253 | button0 = Button(root1, text="LSB算法改进",command=create_LSB_improve ) 1254 | button7 = Button(root1, text='图像降级算法及其改进', command=create_image_downgrade ) 1255 | 1256 | Message(root1,text='∎LSB基本算法包括LSB基本算法水印嵌入和LSB基本算法水印提取.\n∎可以实现将信息隐藏在图片中和从隐藏信息的图片中提取信息的功能',cursor='cross',width='150').place(x=600,y=50) 1257 | Message(root1,text='∎LSB算法改进包括随机间隔法和区域校验位算法\n∎在LSB算法的基础上,减小了水印嵌入对载体图片统计特性的影响',cursor='cross',width='150').place(x=600,y=170) 1258 | Message(root1,text='∎图像降级算法及其改进包括图像降级算法和图像降级算法的改进\n∎可以实现将图片水印嵌入图片当中的功能',cursor='cross',width='150').place(x=600,y=300) 1259 | 1260 | button2.place(height =60,width =300,x = 200,y = 50) 1261 | button0.place(height = 60,width = 300,x = 200,y = 170) 1262 | button7.place(height =60,width =300,x = 200,y = 300) 1263 | 1264 | root.mainloop() 1265 | 1266 | 1267 | def center_window(root, width, height): 1268 | screenwidth = root.winfo_screenwidth() 1269 | screenheight = root.winfo_screenheight() 1270 | size = '%dx%d+%d+%d' % (width, height, (screenwidth - width)/2, (screenheight - height)/2) 1271 | #print(size) 1272 | root.geometry(size) 1273 | 1274 | 1275 | root = Tk() # 创建一个主窗体。相当于提供了一个搭积木的桌子 1276 | #center_window(root, 500, 200) 1277 | root.title("郝希烜") 1278 | # root.geometry('1100x500+200+20')#调整窗体大小,第一个数横大小,第二个数纵大小,第三个数离左屏幕边界距离,第四个数离上面屏幕边界距离 1279 | root.geometry('850x500')#调整窗体大小,第一个数横大小,第二个数纵大小,第三个数离左屏幕边界距离,第四个数离上面屏幕边界距离 1280 | 1281 | root.attributes('-toolwindow', False, 1282 | '-alpha', 0.9, 1283 | '-fullscreen', False, 1284 | '-topmost', False) 1285 | 1286 | global fontStyle 1287 | fontStyle = tkFont.Font(family="Lucida Grande", size=20) 1288 | fontStyle1 = tkFont.Font(family="Lucida Grande", size=15) 1289 | fontStyle2 = tkFont.Font(family="Lucida Grande", size=10) 1290 | 1291 | w = Canvas(root) 1292 | w.place(x=500,y=170, width=300,height=190) 1293 | 1294 | Label(root, text="基于数字图像的可视化水印系统",font=fontStyle).pack() 1295 | 1296 | style = Style(root) 1297 | style.configure("TButton",font=fontStyle) 1298 | style.configure("Test.TButton",font=fontStyle2) 1299 | Button(root, text='空间域水印',command=create_LSB).place(height =60,width =200,x = 170,y = 170) 1300 | Button(root, text='变换域水印',command=create_DCT).place(height = 60,width = 200,x = 450,y = 170) 1301 | 1302 | Message(root,text='空间域水印包含:\n LSB水印嵌入和提取\n LSB算法改进\n 图像降级算法及其改进',cursor='cross',width='200').place(x=200,y=270,width=200) 1303 | Message(root,text='变换域水印包含:\n DCT隐写\n DCT提取',cursor='cross',width='200').place(x=450,y=270,width=200) 1304 | 1305 | root.mainloop() # 开启一个消息循环队列,可以持续不断地接受操作系统发过来的键盘鼠标事件,并作出相应的响应 1306 | # mainloop应该放在所有代码的最后一行,执行他之后图形界面才会显示并响应系统的各种事件 -------------------------------------------------------------------------------- /理论+演示.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/理论+演示.pdf -------------------------------------------------------------------------------- /隐写用图/DCT_origin.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/DCT_origin.bmp -------------------------------------------------------------------------------- /隐写用图/LSB_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/LSB_origin.png -------------------------------------------------------------------------------- /隐写用图/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/image.png -------------------------------------------------------------------------------- /隐写用图/mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/mark.png -------------------------------------------------------------------------------- /隐写用图/random_interval_origin.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/random_interval_origin.bmp -------------------------------------------------------------------------------- /隐写用图/regional_verification_origin.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skyerhxx/Visual-watermarking-system-based-on-digital-image/0ca0d5b508c6af97d94ac66d0354e479d02fa2fc/隐写用图/regional_verification_origin.bmp -------------------------------------------------------------------------------- /隐藏信息/hideInfo_DCT.txt: -------------------------------------------------------------------------------- 1 | Visual watermarking system based on digital image by hxx -------------------------------------------------------------------------------- /隐藏信息/hideInfo_LSB.txt: -------------------------------------------------------------------------------- 1 | Visual watermarking system based on digital image by hxx -------------------------------------------------------------------------------- /隐藏信息/hideInfo_random_interval.txt: -------------------------------------------------------------------------------- 1 | Visual watermarking system based on digital image by hxx -------------------------------------------------------------------------------- /隐藏信息/hideInfo_regional_verification.txt: -------------------------------------------------------------------------------- 1 | Visual watermarking system based on digital image by hxx --------------------------------------------------------------------------------