[toc]
Lab1: LSB Embedding for Image
1.Assignment Requirements
1). Find a grayscale image that is 512x512 pixels in size. Watermark can be abinary image or a logo with small size. Preprocess the watermark data andchoose the suitable region for embedding data.
2). Assignment BasicRequirement:
Design the algorithm with twofunctions: one is for LSB embedding to embed the watermark into a grayscaleimage, and the other is for LSB extraction to extract the correct watermarkfrom the watermarked image.
2.Assignment Content andSteps
1). Watermark Embedding Process
Implement LSB Methodfor watermark embedding with 30%,60%,100% capacity, respectively.
2). Watermark Extraction Process
Implement LSB Method for watermark (logo image) extraction.
3.Experimental ResultsAnalysis
1) Imperceptibility
Compare the originalimage with the watermarked image by PSNR.
Analyze the resultswith different images and different payload/capacity.
2) False Rate
Compare the original watermarkwith the extracted watermark to calculate the error false.
3) Robustness
Apply some attacks (image noise,image compression, content modification et al.) to the watermarked image, thenextract the watermark and compare with the original one to calculate the errorfalse.
4.Conclusion
Highlight your own contribution in the group.
Summarize your own understanding andinterpretation of the results.
5.Experiment process and code
Gray image LSB encryption script:
from PIL import Image
p = Image.open('goldhill.bmp').convert('L')
flag_p = Image.open('cipher.bmp').convert('L')
a,b = p.size
np = Image.new('L',(a,b),255) #加密后图片
for y in range(b):
for x in range(a):
if flag_p.getpixel((x,y)) == 255:
#如果加密数据块是白色,则将原图的最后一位改为0
if p.getpixel((x,y))%2 == 1:
np.putpixel((x,y),p.getpixel((x,y))-1)
else:
np.putpixel((x,y),p.getpixel((x,y)))
else:
#如果加密数据块是黑色,则将原图的最后一位改为1
if p.getpixel((x,y))%2 == 1:
np.putpixel((x,y),p.getpixel((x,y)))
else:
np.putpixel((x,y),p.getpixel((x,y))+1)
#np.convert('RGB')
np.save('encode.bmp')
Original image — goldhill.bmp:
Watermark image — cipher.bmp:
Encrypted image — encode.bmp:
Gray image LSB decryption script:
from PIL import Image
import numpy as np
import math
import cv2
p = Image.open('encode.bmp').convert('L')
a,b = p.size
flag = Image.new('L',(a,b),255)
for y in range(b):
for x in range(a):
if p.getpixel((x,y))%2==0:
flag.putpixel((x,y),255)
else:
flag.putpixel((x,y),0)
#flag.show()
flag.save("decode.bmp")
#计算错误率
pic = Image.open('cipher.bmp').convert('L')
length = a*b
num = 0
for y in range(b):
for x in range(a):
if flag.getpixel((x,y)) != pic.getpixel((x,y)):
num += 1
print("错误率为:%.2f%%" % (num/length*100))
#PSNA 错误率0%时,PSNR为100
gt = cv2.imread('cipher.bmp')
img= cv2.imread('decode.bmp')
def psnr(img1, img2):
mse = np.mean( (img1/255. - img2/255.) ** 2 )
if mse < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
print(psnr(gt, img))
#错误率为:0.00%
#100
Because of lossless compression and no noise attack, the error rate is 0.00% and PSNR is 100
Decrypted image — decode.bmp:
Noise attack script:
import numpy as np
import random
import cv2
from matplotlib import pyplot as plt
def sp_noise(image,prob):
'''
添加椒盐噪声
prob:噪声比例
'''
output = np.zeros(image.shape,np.uint8)
thres = 1 - prob
for i in range(image.shape[0]):
for j in range(image.shape[1]):
rdn = random.random()
if rdn < prob:
output[i][j] = 0
elif rdn > thres:
output[i][j] = 255
else:
output[i][j] = image[i][j]
return output
def gasuss_noise(image, mean=0, var=0.001):
'''
添加高斯噪声
mean : 均值
var : 方差
'''
image = np.array(image/255, dtype=float)
noise = np.random.normal(mean, var ** 0.5, image.shape)
out = image + noise
if out.min() < 0:
low_clip = -1.
else:
low_clip = 0.
out = np.clip(out, low_clip, 1.0)
out = np.uint8(out*255)
#cv.imshow("gasuss", out)
return out
# Read image
img = cv2.imread("cipher.bmp")
# 添加椒盐噪声,噪声比例为 0.02
out1 = sp_noise(img, prob=0.02) #修改噪声比例
# 添加高斯噪声,均值为0,方差为0.001
out2 = gasuss_noise(img, mean=0, var=0.001) #修改噪声比例
cv2.imwrite("sp_cipher.bmp",out1) #椒盐噪声
cv2.imwrite('gasuss_cipher.bmp',out2) #高斯噪声
def psnr(img1, img2):
mse = np.mean( (img1/255. - img2/255.) ** 2 )
if mse < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
#噪声攻击后进行psnr计算
import math
pic_sp = cv2.imread("sp_cipher.bmp")
pic_gasuss = cv2.imread("gasuss_cipher.bmp")
pic_cipher = cv2.imread("cipher.bmp")
print("椒盐噪声攻击后psnr值: " + str(psnr(pic_sp, pic_cipher))) #椒盐噪声攻击后psnr
print("高斯噪声攻击后psnr值: " + str(psnr(pic_gasuss, pic_cipher))) #高斯噪声攻击后psnr
#椒盐噪声攻击后psnr值: 16.94018294833099
#高斯噪声攻击后psnr值: 24.678779189491333
Image after Salt and Pepper noise attack — sp_cipher.bmp:
decrypted:
Image after Gaussian noise attack — gasuss_cipher.bmp:
decrypted:
Image compression:
Because JPG image is compressed, BMP image can be saved as JPG image to achieve compression effect.
from PIL import Image
p = Image.open('goldhill.bmp').convert('L')
flag_p = Image.open('cipher.bmp').convert('L')
a,b = p.size
np = Image.new('L',(a,b),255) #加密后图片
for y in range(b):
for x in range(a):
if flag_p.getpixel((x,y)) == 255:
#如果加密数据块是白色,则将原图的最后一位改为0
if p.getpixel((x,y))%2 == 1:
np.putpixel((x,y),p.getpixel((x,y))-1)
else:
np.putpixel((x,y),p.getpixel((x,y)))
else:
#如果加密数据块是黑色,则将原图的最后一位改为1
if p.getpixel((x,y))%2 == 1:
np.putpixel((x,y),p.getpixel((x,y)))
else:
np.putpixel((x,y),p.getpixel((x,y))+1)
#np.convert('RGB')
np.save('encode.jpg')
The result image shows that the image has been damaged:
from PIL import Image
import numpy as np
import math
import cv2
p = Image.open('encode.jpg').convert('L')
a,b = p.size
flag = Image.new('L',(a,b),255)
for y in range(b):
for x in range(a):
if p.getpixel((x,y))%2==0:
flag.putpixel((x,y),255)
else:
flag.putpixel((x,y),0)
#flag.show()
flag.save("decode.jpg")
#计算错误率
pic = Image.open('cipher.bmp').convert('L')
length = a*b
num = 0
for y in range(b):
for x in range(a):
if flag.getpixel((x,y)) != pic.getpixel((x,y)):
num += 1
print("错误率为:%.2f%%" % (num/length*100))
#PSNA 错误率0%时,PSNR为100
gt = cv2.imread('cipher.bmp')
img= cv2.imread('decode.jpg')
def psnr(img1, img2):
mse = np.mean( (img1/255. - img2/255.) ** 2 )
if mse < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
print(psnr(gt, img))
#错误率为:49.85%
#3.144016884376673
Lab2: DCT based Watermarking method
1.Assignment Requirements
1). Find a grayscale image that is 512x512 pixels in size. Watermark canbe a binary image or a logo with small size. Preprocess the watermark data andchoose the suitable region for embedding data.
2). Assignment BasicRequirement:
Design the algorithm with twofunctions: one is for DCT embedding to embed the watermark into a grayscaleimage, and the other is for DCT extraction to extract the correct watermarkfrom the watermarked image.
2.Assignment Content andSteps
1). WatermarkEmbedding Process
Implement DCT Method for watermark embedding with differentembedding locations, respectively.
The embedding algorithm might take the following form (however, you areencouraged to design your own method):
IF watermark = 1
IF coefficient >= τ THEN Coefficient=Coefficient
ELSE Coefficient = α
ELSE IF watermark = 0
IF *coefficient >= --*τ* THEN** Coefficient=Coefficient
ELSE *Coefficient=-α
where τ > 0 is the threshold that controls the perceptual quality of the watermarkedimage, and α is a constant between τ/2 to τ.
2). Watermark Extraction Process
Implement LSB Method for watermark (logo image) extraction.
A simple extraction algorithm mightbe:
IF coefficient >= 0, THEN watermark bit = 1
ELSE watermark bit = 0
However, you are again encouraged to design yourown method.
3.Experimental ResultsAnalysis
1) Imperceptibility
Compare the originalimage with the watermarked image by PSNR.
Analyze the resultswith different images and different payload/capacity.
2) False Rate
Compare the original watermarkwith the extracted watermark to calculate the error false.
3) Robustness
Apply some attacks (image noise,image compression, content modification et al.) to the watermarked image, thenextract the watermark and compare with the original one to calculate the errorfalse.
4.Conclusion
Highlight your own contribution in the group.
Summarize your own understanding andinterpretation of the results.
5.Experiment process and code
DCTEncrypt:
import cv2
import math
import numpy as np
#嵌入深度对水印正确率有绝对性关系,增加嵌入深度可大幅度提高正确率。
img = cv2.imread('goldhill.bmp', 0)
img_water = cv2.imread('cipher.bmp', 0)
a, b = img.shape #512, 512
part_a = int(a/8) #以8x8格单位划分
part_b = int(b/8)
#fingernum为指纹像素总点数
fingernum = img_water.shape[0] * img_water.shape[1] #4096
r = math.ceil(fingernum/(part_a*part_b)) #每个区块要存1个指纹像素
#print(r)
img = np.float32(img) # 将数值精度调整为32位浮点型
#img_water = np.float32(img_water)
finish_pic = img
for i in range(part_a):
for j in range(part_b):
part8x8 = cv2.dct(img[8*i:8*i+8, 8*j:8*j+8])
#print(part8x8)
for t in range(r):
rx, ry = 4, 4
r1 = part8x8[rx, ry]
r2 = part8x8[7-rx, 7-ry]
detat=abs(r1-r2)
p = float(detat + 3) #嵌入深度,影响隐写读取
if img_water[i][j] == 0:
if r1 <= r2:
part8x8[rx, ry] += p
if img_water[i][j] == 255:
if r1 >= r2:
part8x8[7-rx, 7-ry] += p
finish_pic[8*i:8*i+8,8*j:8*j+8] = cv2.idct(part8x8)
cv2.imwrite("dct.bmp", finish_pic)
Original image — goldhill.bmp:
Watermark image — cipher.bmp:
Encrypted image — dct.bmp:
DCTDecrypt:
import cv2
import math
import numpy as np
img = cv2.imread('dct.bmp', 0)
img = img.astype('float32')
part_a = int(img.shape[0]/8)
part_b = int(img.shape[1]/8)
#每个8x8块内隐写一个数据
r = 1
# 待还原水印图,最大载空体64x64
img_water = np.zeros([64,64], np.uint8)
#print(img_water)
for i in range(part_a):
for j in range(part_b):
part8x8 = cv2.dct(img[8*i:8*i+8,8*j:8*j+8])
for t in range(r):
rx, ry = 4, 4
r1 = part8x8[rx, ry]
r2 = part8x8[7-rx, 7-ry]
if r1 > r2:
img_water[i, j] = 0
if r1 < r2:
img_water[i, j] = 255
cv2.imwrite("decode.bmp", img_water)
#PSNA 错误率0%时,PSNR为100
gt = cv2.imread('cipher.bmp')
img= cv2.imread('decode.bmp')
def psnr(img1, img2):
mse = np.mean( (img1/255. - img2/255.) ** 2 )
if mse < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
print(psnr(gt, img))
#23.336063470149455
Decrypted image — decode.bmp:
Noise attack script:
import numpy as np
import random
import cv2
from matplotlib import pyplot as plt
def sp_noise(image,prob):
'''
添加椒盐噪声
prob:噪声比例
'''
output = np.zeros(image.shape,np.uint8)
thres = 1 - prob
for i in range(image.shape[0]):
for j in range(image.shape[1]):
rdn = random.random()
if rdn < prob:
output[i][j] = 0
elif rdn > thres:
output[i][j] = 255
else:
output[i][j] = image[i][j]
return output
def gasuss_noise(image, mean=0, var=0.001):
'''
添加高斯噪声
mean : 均值
var : 方差
'''
image = np.array(image/255, dtype=float)
noise = np.random.normal(mean, var ** 0.5, image.shape)
out = image + noise
if out.min() < 0:
low_clip = -1.
else:
low_clip = 0.
out = np.clip(out, low_clip, 1.0)
out = np.uint8(out*255)
#cv.imshow("gasuss", out)
return out
# Read image
img = cv2.imread("decode.bmp")
# 添加椒盐噪声,噪声比例为 0.02
out1 = sp_noise(img, prob=0.02) #修改噪声比例
# 添加高斯噪声,均值为0,方差为0.001
out2 = gasuss_noise(img, mean=0, var=0.001) #修改噪声比例
cv2.imwrite("sp_cipher.bmp",out1) #椒盐噪声
cv2.imwrite('gasuss_cipher.bmp',out2) #高斯噪声
def psnr(img1, img2):
mse = np.mean( (img1/255. - img2/255.) ** 2 )
if mse < 1.0e-10:
return 100
PIXEL_MAX = 1
return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
#噪声攻击后进行psnr计算
import math
pic_sp = cv2.imread("sp_cipher.bmp")
pic_gasuss = cv2.imread("gasuss_cipher.bmp")
pic_cipher = cv2.imread("cipher.bmp")
print("椒盐噪声攻击后psnr值: " + str(psnr(pic_sp, pic_cipher))) #椒盐噪声攻击后psnr
print("高斯噪声攻击后psnr值: " + str(psnr(pic_gasuss, pic_cipher))) #高斯噪声攻击后psnr
#椒盐噪声攻击后psnr值: 15.829761702825646
#高斯噪声攻击后psnr值: 14.615217407675145
When embedded depth + 3:
Image after Salt and Pepper noise attack — sp_cipher.bmp:
decrypted:
Image after Gaussian noise attack — gasuss_cipher.bmp:
decrypted:
When embedded depth + 100:
Image after Salt and Pepper noise attack — sp_cipher.bmp:
decrypted:
Image after Gaussian noise attack — gasuss_cipher.bmp:
decrypted:
Image compression:
Because JPG image is compressed, BMP image can be saved as JPG image to achieve compression effect.
import cv2
import math
import numpy as np
'''
嵌入深度对水印正确率有绝对性关系
增加嵌入深度可大幅度提高正确率。
'''
img = cv2.imread('goldhill.bmp', 0)
img_water = cv2.imread('cipher.bmp', 0)
a, b = img.shape #512, 512
part_a = int(a/8) #以8x8格单位划分
part_b = int(b/8)
#fingernum为指纹像素总点数
fingernum = img_water.shape[0] * img_water.shape[1] #4096
r = math.ceil(fingernum/(part_a*part_b)) #每个区块要存1个指纹像素
#print(r)
img = np.float32(img) # 将数值精度调整为32位浮点型
#img_water = np.float32(img_water)
finish_pic = img
for i in range(part_a):
for j in range(part_b):
part8x8 = cv2.dct(img[8*i:8*i+8, 8*j:8*j+8])
#print(part8x8)
for t in range(r):
rx, ry = 4, 4
r1 = part8x8[rx, ry]
r2 = part8x8[7-rx, 7-ry]
detat=abs(r1-r2)
p = float(detat + 3) #嵌入深度,影响隐写读取
if img_water[i][j] == 0:
if r1 <= r2:
part8x8[rx, ry] += p
if img_water[i][j] == 255:
if r1 >= r2:
part8x8[7-rx, 7-ry] += p
finish_pic[8*i:8*i+8,8*j:8*j+8] = cv2.idct(part8x8)
cv2.imwrite("dct.jpg", finish_pic)
The result image shows that the image has been damaged:
Lab3: Steganalysis Algorithms
1.Assignment Requirements
1). Make your own image database with different images which are watermarkedby your own method or others watermarking methods. Make another image databasewith original images without embedding watermark.
2). Assignment BasicRequirement:
Design the algorithm with twofunctions: one is for visual attack to extract the LSB of the test images, andtell the difference visually; and the other is for c2 analysis by calculating the p-value for verifying the watermarked andunwatermarked images.
2.Assignment Content andSteps
1). Visual Attack
Implement LSB Methodfor watermark embedding with 30%,60%,100% capacity, respectively. Test the images whether theyare watermarked and how much is watermarked, visually.
2). c2 Analysis
LSB utilizes thelowest bit plane for embedding, and substitutes every suitable bit with amessage bit.
The concept of PoV is defined as pairs of values which combines two pixel values 2i and 2i + 1together as a pair. It can be easily noticed that if a pixel value is in a pair, then afterembedding the value is still in the same pair.
Letthe frequencies of pixel value 2i, 2i+1 be h(2i), h(2i+1).
Showthe histogram of pixel values before and after embedding a watermark with LSB.
To get the statisticsfor the difference between distributions of PoV’s used the below mentionedequation:
The processing stepscan be designed as follows:
3.Experimental ResultsAnalysis
1) False Positive Rate
Calculate the percentageof falsely detected as watermarked images which are unwatermarkedactually.
Analyze the resultswith different images and different payload/capacity.
2) False Negative Rate
Calculate the percentageof falsely detected as unwatermarked images which are watermarkedactually.
Analyze the resultswith different images and different payload/capacity.
4.Conclusion
Highlight your own contribution in the group.
Summarize your own understanding andinterpretation of the results.
5.Experiment process and code
1.Visual Attack
The script:
from PIL import Image
import os
dir_list = os.listdir('..\\图片库')
print(dir_list)
for i in dir_list:
pic = Image.open('..\\图片库\\' + i).convert('L')
a,b = pic.size
flag = Image.new('L',(a,b),255)
for y in range(b):
for x in range(a):
if (pic.getpixel((x, y)) >> 0 ) % 2 == 1: #>> 0代表最低位,>>1代表倒数第二位,0 1 2均有水印图,可自行修改
flag.putpixel((x, y), 0)
else:
flag.putpixel((x, y), 255)
flag.save('..\\解码\\' + i)
Original picture library:
Decoded picture library:
2.Chi square analysis:
The script:
%im1 = imread('avion.bmp');
%im1 = imread('avion1.bmp');
%im1 = imread('lena1.bmp');
%im1 = imread('boats.bmp');
%im1 = imread('peppers.bmp');
%im1 = imread('baboon.bmp');
N = 4; %4*4块,共16块
K = 128; %每块128*128像素
BLOCK = zeros(K, K); %存放当前块
r = 0;
a = 1;
hx = zeros(1, 128);
pr = zeros(1, 16);
pc = zeros(1, 16);
for p = 1:N
for q = 1:N
x = (p-1)*K + 1;
y = (q-1)*K + 1;
BLOCK = im1(x:x+K-1, y:y+K-1);
[h, x] = imhist(BLOCK);
for i = 1:128
hx(i) = (h(2*i-1)+h(2*i))/2;
if hx(i) ~= 0
r = r+(h(2*i-1)-hx(i))^2/hx(i);
end
end
pr(a) = r;
pc(a) = 1 - chi2pdf(r, 127);
a = a + 1;
r = 0;
end
end
subplot(2, 1, 1);
plot(pr);
title('r=sum(h2i-h2o*)^2/h2i*')
subplot(2, 1, 2)
plot(pc)
title('p=1-chi2pdf(r, 127)')
The avion.bmp:
The avion1.bmp:
The lena1.bmp:
The boats.bmp:
The peppers.bmp:
The baboon.bmp:
Obviously, when p is almost equal to 1, it indicates that there is a watermark in the image.