Experiment of Information Hiding

[toc]

Lab1: LSB Embedding for Image

1.Assignment Requirements

1.png

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:

goldhill

Watermark image — cipher.bmp:

cipher2345

Encrypted image — encode.bmp:

encode

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:

decode23456

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:

sp_cipher2345

decrypted:

decode11111111

Image after Gaussian noise attack — gasuss_cipher.bmp:

gasuss_cipher2345

decrypted:

decode222222

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:

decode2345

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.png

1). WatermarkEmbedding Process

1.png

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.

1.png

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:

goldhill

Watermark image — cipher.bmp:

cipher123

Encrypted image — dct.bmp:

dct

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:

decode1

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-20210607160847466

Image after Salt and Pepper noise attack — sp_cipher.bmp:

sp_cipher111111111

decrypted:

cipher1jiaoyan

Image after Gaussian noise attack — gasuss_cipher.bmp:

gasuss_cipher1111111111

decrypted:

cipher2gaosi

When embedded depth + 100:

image-20210607161416435

Image after Salt and Pepper noise attack — sp_cipher.bmp:

sp_cipxxxxxxxxxher

decrypted:

cipherxxxx1

Image after Gaussian noise attack — gasuss_cipher.bmp:

gasuxxxxss_cipher

decrypted:

cipherxxxx2

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:

decode4

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.

1.png

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.

1.png

To get the statisticsfor the difference between distributions of PoV’s used the below mentionedequation:

The processing stepscan be designed as follows:

1.png

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:

image-20210607162506191

Decoded picture library:

image-20210607162600828

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:

image-20210607162849307

The avion1.bmp:

image-20210607163033993

The lena1.bmp:

image-20210607163009421

The boats.bmp:

image-20210607163048705

The peppers.bmp:

image-20210607163104074

The baboon.bmp:

image-20210607163127416

Obviously, when p is almost equal to 1, it indicates that there is a watermark in the image.

发表评论