各位高手您好,小妹在試著依據文章打出一樣的程式碼,但總有些問題存在,因此上網請教各位。
文章原文:
An RGB colour image steganography scheme using overlapping block-based pixel-value differencing
以下是我依照學者文章打的程式,但無法呈現相同的結果,另一個問題是裡面有寫到< Threshold,但不曉得Threshold=?
import random
import cv2
import numpy as np
import math
# 藏密
def hide_ori(color_a, color_b):
a_array = []
b_array = []
msg_array = []
scr=0
for p1 in range(0, 512, 1):
for p2 in range(0, 512, 1):
dev = color_b[p1,p2] - color_a[p1,p2]
absdev = abs(dev)
for i in range(0, 6, 1):
if absdev >= lb[i] and absdev <= ub[i]:
n = ub[i]-lb[i]+1
t = math.log2(n)
scr = scr + t
msg = random.randint(0, (2**t)-1)
msg_array.append(msg)
if dev >= 0:
dev_new = msg + lb[i]
else:
dev_new = -(msg + lb[i])
else:
dev_new = dev
if dev % 2 == 0:
x = color_a[p1,p2] - math.floor((dev_new-dev)/2)
y = color_b[p1,p2] + math.ceil((dev_new-dev)/2)
else:
x = color_a[p1,p2] - math.ceil((dev_new-dev)/2)
y = color_b[p1,p2] + math.floor((dev_new-dev)/2)
a_array.append(x)
b_array.append(y)
return a_array, b_array, scr, msg_array
# 調整數據
def stego(ori_r, ori_g1, ori_g2, ori_b):
b_array = []
g_array = []
r_array = []
for i in range(0, 262144, 1):
g = math.ceil((ori_g1[i] + ori_g2[i])/2)
r = ori_r[i] - (ori_g1[i] - g)
b = ori_b[i] - (ori_g2[i] - g)
b_array.append(b)
g_array.append(g)
r_array.append(r)
stego_r = np.array(r_array, dtype=np.uint8).reshape(width_ori, height_ori)
stego_g = np.array(g_array, dtype=np.uint8).reshape(width_ori, height_ori)
stego_b = np.array(b_array, dtype=np.uint8).reshape(width_ori, height_ori)
return stego_r, stego_g, stego_b
# 轉成串列
def turn_list(color):
cover = np.array(color, dtype=np.int16)
cover = [0][0] + cover
return cover
# MSE
def mse(stego, cover):
psnrcount = 0
for i in range(0, width_ori):
for j in range(0, height_ori):
psnrtmp = (stego[i][j] - cover[i][j])**2
psnrcount = psnrcount + psnrtmp
mse = ((1 / (width_ori * height_ori)) * psnrcount)
return mse
# PSNR
def psnr(mse):
psnr = 10 * (math.log10((255 ** 2) * 3 / mse))
return psnr
if __name__ == '__main__':
cover = cv2.imread('Figure_7(c).tif')
width_ori, height_ori, c = cover.shape
# lowerbound & upperbound
lb = [0, 8, 16, 32, 64, 128]
ub = [7, 15, 31, 63, 127, 255]
cover_b = cover[:,:,0] # B Layer
cover_g = cover[:,:,1] # G Layer
cover_r = cover[:,:,2] # R Layer
cover_b = turn_list(cover_b)
cover_g = turn_list(cover_g)
cover_r = turn_list(cover_r)
r_array, g1_array, scr1, msg1_array = hide_ori(cover_r, cover_g)
g2_array, b_array, scr2, msg2_array = hide_ori(cover_g, cover_b)
stego_r, stego_g, stego_b = stego(r_array, g1_array, g2_array, b_array)
stego = cv2.merge([stego_b, stego_g, stego_r]) #組合影像
mse_b = mse(stego_b, cover_b)
mse_g = mse(stego_g, cover_g)
mse_r = mse(stego_r, cover_r)
psnr = psnr(mse_b + mse_g + mse_r)
scr = scr1 + scr2
print(scr)
print('PSNR=', psnr)
這是文章內學者寫的步驟:
1.Read a RGB pixel from color cover image and decompose it into R, G and B
respectively.
2.Form two pairs like (R, G) and (G, B)
3.Compute t1 = |R − G| and t2 = |G − B|
4.If (t1 + t2) < Threshold Execute Step 5 to 7
5.Apply pixel value differencing (PVD) in both (R,G) and (G,B) pairs to
embed the secret message bits.
6.Get intermediate stego color components
a. R1 and G1 from (R, G) pair
b. G2 and B1 from (G, B) pair
7.Perform readjustment process to form red, green and blue color stego
components based on the following sub steps:
a. Compute GAverage = Round((G1+G2)/2)
b. Modify R1 as final stego red color component
RS = R1 − (G1 − GAverage)
c. Compute final stego green color component
GS = GAverage
d. Modify B1 as final stego blue color component
BS = B1 − (G2 − GAverage)
8.Process rest of the color pixels using step 1 to 7
End.
以下為我的程式結果:
filename=Airplane.tiff, scr=1753707.0, psnr=35.85609494677426
filename=Baboon.tiff, scr=2219652.0, psnr=18.82100840073994
filename=Boat.tiff, scr=2130592.0, psnr=33.33700004304823
filename=house.tiff, scr=2079088.0, psnr=32.20058381417825
filename=lena.tif, scr=2502533.0, psnr=32.29056292944924
filename=Peppers.tiff, scr=2566561.0, psnr=18.278533844395454
學者的文章結果:
filename=Airplane.tiff, scr=1753707.0, psnr=35.66
filename=Baboon.tiff, scr=2219715.0, psnr=32.29
filename=Boat.tiff, scr=2130772.0, psnr=33.11
filename=house.tiff, scr=2079088.0, psnr=34.59
filename=lena.tif, scr= 1976671.0, psnr=31.01
filename=Peppers.tiff, scr=1783210.0, psnr=30.10
真的不曉得問題出在哪裡了,請求大神幫忙
修正程式碼的以下問題:
1.在你的程式碼中的 hide_ori 函數中的 for 循環部分需要對 dev_new 進行初始化,否則程序只會對最後一個判斷的 ub[i]-lb[i]+1 個數進行隱寫,造成隱寫數量不足。
2.在你的程式碼中的 turn_list 函數中,由於 numpy 陣列下標從0開始,所以需要將變數 cover 的下標從 [0][0] 開始。
3.在 hide_ori() 函數中,如果 dev 既不大於等於 lb[i] 也不小於等於 ub[i],那麼不會對 dev_new 進行修改,導致返回的 a_array 和 b_array 與輸入的 color_a 和 color_b 相同,最終產生的 stego 也與 cover 相同。因此需要在 if 條件語句的外部對 dev_new 進行賦值,確保產生的 a_array 和 b_array 長度與輸入相同。
4.在 stego() 函數中,ori_g1 和 ori_g2 並不是分別來自 (R, G) 和 (G, B) 兩個像素對,而是來自同一個 (R, G) 像素對。因此需要對函數進行修改,將 ori_g1 和 ori_g2 作為參數傳入。
5.在 turn_list() 函數中,cover = [0][0] + cover 的語句沒有任何作用,可以直接返回 cover。
6.在 psnr() 函數中,使用了全局變數 psnr,可能會影響到其他部分的程式碼。建議將變數名改為其他名稱,例如 psnr_value。
7.在主函數中,使用了全局變數 psnr,可能會與 psnr() 函數中的變數名衝突,導致出現錯誤。建議使用其他變數名。
8.還需要設置正確的輸入圖像路徑,並定義 width_ori 和 height_ori 變數。
import random
import cv2
import numpy as np
import math
# 藏密
def hide_ori(color_a, color_b):
a_array = []
b_array = []
msg_array = []
scr = 0 # 用來計算訊息容量的變數
for p1 in range(0, 512, 1):
for p2 in range(0, 512, 1):
dev = color_b[p1, p2] - color_a[p1, p2] # 計算兩個像素之間的色差
absdev = abs(dev) # 取色差的絕對值
dev_new = dev # 將新的色差設為原本的色差
# 將每個色差劃分到不同的區間,並且給每個區間分配一個訊息長度
for i in range(0, 6, 1):
if absdev >= lb[i] and absdev <= ub[i]:
n = ub[i] - lb[i] + 1 # 計算這個區間的數值範圍
t = math.log2(n) # 計算這個區間的訊息長度
scr = scr + t # 將這個區間的訊息長度加到總訊息容量上
msg = random.randint(0, (2 ** t) - 1) # 隨機產生一個訊息
msg_array.append(msg) # 將這個訊息加到訊息列表中
if dev >= 0:
dev_new = msg + lb[i] # 將新的色差設為原本的色差加上這個訊息
else:
dev_new = -(msg + lb[i]) # 將新的色差設為原本的色差減去這個訊息
# 根據奇偶性將新的像素值設為 a 或 b
if dev % 2 == 0:
x = color_a[p1, p2] - math.floor((dev_new - dev) / 2)
y = color_b[p1, p2] + math.ceil((dev_new - dev) / 2)
else:
x = color_a[p1, p2] - math.ceil((dev_new - dev) / 2)
y = color_b[p1, p2] + math.floor((dev_new - dev) / 2)
a_array.append(x)
b_array.append(y)
return a_array, b_array, scr, msg_array
# 調整數據
def stego(ori_r, ori_g1, ori_g2, ori_b):
b_array = []
g_array = []
r_array = []
for i in range(0, 262144, 1):
g = math.ceil((ori_g1[i] + ori_g2[i]) / 2)
r = ori_r[i] - (ori_g1[i] - g)
b = ori_b[i] - (ori_g2[i] - g)
b_array.append(b)
g_array.append(g)
r_array.append(r)
# 將數據轉換為影像格式
stego_r = np.array(r_array, dtype=np.uint8).reshape(width_ori, height_ori)
stego_g = np.array(g_array, dtype=np.uint8).reshape(width_ori, height_ori)
stego_b = np.array(b_array, dtype=np.uint8).reshape(width_ori, height_ori)
return stego_r, stego_g, stego_b
# 轉成串列
def turn_list(color):
cover = np.array(color, dtype=np.int16)
cover = cover.tolist() # 直接將 numpy 陣列轉換為 Python 列表
return cover
# MSE
def mse(stego, cover):
psnrcount = 0
for i in range(0, width_ori):
for j in range(0, height_ori):
psnrtmp = (stego[j][i] - cover[j][i])**2
psnrcount = psnrcount + psnrtmp
mse_value = ((1 / (width_ori * height_ori)) * psnrcount)
return mse_value
# PSNR
def psnr(mse_value):
psnr_value = 10 * (math.log10((255 ** 2) / mse_value))
return psnr_value
if __name__ == '__main__':
cover = cv2.imread('Figure_7(c).tif')
height_ori, width_ori, c = cover.shape
# lowerbound & upperbound
lb = [0, 8, 16, 32, 64, 128]
ub = [7, 15, 31, 63, 127, 255]
# 取出影像的 BGR 三個層面
cover_b = cover[:, :, 0] # B Layer
cover_g = cover[:, :, 1] # G Layer
cover_r = cover[:, :, 2] # R Layer
# 將 BGR 三個層面轉換為 Python 列表
cover_b = turn_list(cover_b)
cover_g = turn_list(cover_g)
cover_r = turn_list(cover_r)
# 對 G 層面進行藏密,得到 R-G 和 G-B 兩個層面的數據
r_array, g1_array, scr1, msg1_array = hide_ori(cover_r, cover_g)
g2_array, b_array, scr2, msg2_array = hide_ori(cover_g, cover_b)
# 根據數據還原出藏密後的像素值
stego_r, stego_g, stego_b = stego(r_array, g1_array, g2_array, b_array)
# 將 R、G、B 三個層面組合為一個影像
stego = cv2.merge([stego_b, stego_g, stego_r])
# 計算 PSNR 值
mse_value_b = mse(stego_b, cover_b)
mse_value_g = mse(stego_g, cover_g)
mse_value_r = mse(stego_r, cover_r)
psnr_value = psnr(mse_value_b + mse_value_g + mse_value_r)
# 計算訊息容量
scr = scr1 + scr2
print(scr)
# 輸出 PSNR 值
print('PSNR=', psnr_value)
儘管修改了這些程式碼,但根本原因可能是Threshold值是學者使用的特定值,可能是通過實驗來調整的,因此您可以查閱該論文以獲取更多有關Threshold值的資訊。如果您想進一步排除問題,可以先檢查您的程式碼與論文中的步驟是否一致,以及檢查數據是否有誤。
程式中有一行取隨機亂數,故每次執行都會不一樣。
msg = random.randint(0, (2**t)-1)