【问题标题】:Issue Related To DCT Based Steganography与基于 DCT 的隐写术相关的问题
【发布时间】:2021-12-08 23:16:08
【问题描述】:

我正在尝试通过将图像转换为 HSV 并应用 DCT 并对其进行量化并隐藏文本消息并拼接图像来执行 DCT 隐写术。在解码过程中,应用 DCT 并对其进行量化并从中提取文本消息。但是,在这里我得到了不正确的答案。我正在使用 HSV 来获得与原始图像相似的相同图像颜色。我使用饱和通道来隐藏其中的文本。现在,我陷入其中,没有得到正确的答案。请帮我解决这个问题。 代码如下:

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 19 11:13:50 2021 
@author: SM
"""
  
from PIL import Image
import numpy as np
import itertools
import types
import cv2
from Crypto.Cipher import AES
#creation of quantization matrix of quality factor as 50
quant = np.array([[16,11,10,16,24,40,51,61],
                [12,12,14,19,26,58,60,55],
                [14,13,16,24,40,57,69,56],
                [14,17,22,29,51,87,80,62],
                [18,22,37,56,68,109,103,77],
                [24,35,55,64,81,104,113,92],
                [49,64,78,87,103,121,120,101],
                [72,92,95,98,112,100,103,99]])
class DiscreteCosineTransform:
    #created the constructor
    def __init__(self):
        self.message = None
        self.bitMessage = None
        self.oriCol = 0
        self.oriRow = 0
        self.numBits = 0
    #utility and helper function for DCT Based Steganography
    #helper function to stich the image back together
    def chunks(self,l,n):
        m = int(n)
        for i in range(0,len(l),m):
            yield l[i:i+m]
    #function to add padding to make the function dividable by 8x8 blocks
    def addPadd(self,img,row,col):
         img = cv2.resize(img,(col+(8-col%8),row+(8-row%8)))
         return img
    #function to transform the message that is wanted to be hidden from plaintext to a list of bits
    def toBits(self):
         bits = []
         for char in self.message:
            binval = bin(char)[2:].rjust(8,'0')
            #print('bin '+binval)
            bits.append(binval)
         self.numBits = bin(len(bits))[2:].rjust(8,'0')
         return bits
    #main part 
    #encoding function 
    #applying dct for encoding 
    def DCTEncoder(self,img,secret):
        self.message = str(len(secret)).encode()+b'*'+secret
        self.bitMessage = self.toBits()
        #get the size of the image in pixels
        row, col = img.shape[:2]
        self.oriRow = row
        self.oriCol = col
        if((col/8)*(row/8)<len(secret)):
            print("Error: Message too large to encode in image")
            return False
        if(row%8!=0 or col%8!=0):
            img = self.addPadd(img,row,col)
        row,col = img.shape[:2]
        #split image into RGB channels
        hImg,sImg,vImg = cv2.split(img)
        #message to be hid in blue channel so converted to type float32 for dct function
        #print(bImg.shape)
        sImg = np.float32(sImg)
        #breaking the image into 8x8 blocks
        imgBlocks = [np.round(sImg[j:j+8,i:i+8]-128) for (j,i) in itertools.product(range(0,row,8),range(0,col,8))]
        #print(imgBlocks[0])
        #blocks are run through dct / apply dct to it
        dctBlocks = [np.round(cv2.dct(ib)) for ib in imgBlocks]
        #print('DCT Blocks')
        #print(dctBlocks[0])
        #blocks are run through quantization table / obtaining quantized dct coefficients
        quantDCT = [np.round(dbk/quant) for dbk in dctBlocks]
        #print('Quant Blocks')
        #print(quantDCT[0])
        #set LSB in DC value corresponding bit of message
        messIndex=0
        letterIndex=0
        print(self.bitMessage)
        for qb in quantDCT:
            #find LSB in DCT cofficient and replace it with message bit
            #print(len(qb))
            DC = qb[0][0]
            #print(DC.shape)
            DC = np.uint8(DC)
            #print(DC)
            DC = np.unpackbits(DC)
            #print(DC[0])
            #print(self.bitMessage[messIndex][letterIndex])
            #print(DC[7])
            #print(type(DC[7]))
            #print(DC[7].shape)
            #print(type(self.bitMessage))
            #a=self.bitMessage[messIndex][letterIndex]
            #print(a)
            DC[7] = self.bitMessage[messIndex][letterIndex]
            DC = np.packbits(DC)
            DC = np.float32(DC)
            DC = DC - 255
            qb[0][0] = DC
            letterIndex = letterIndex + 1
            if (letterIndex == 8):
                letterIndex = 0
                messIndex = messIndex + 1
                if (messIndex == len(self.message)):
                    break
        #writing the stereo image
        #blocks run inversely through quantization table
        sImgBlocks = [quantizedBlock *quant+128 for quantizedBlock in quantDCT]
        #blocks run through inverse DCT
        #sImgBlocks = [cv2.idct(B)+128 for B in quantizedDCT]
        #puts the new image back together
        aImg=[]
        for chunkRowBlocks in self.chunks(sImgBlocks, col/8):
            for rowBlockNum in range(8):
                for block in chunkRowBlocks:
                    aImg.extend(block[rowBlockNum])
        print(len(aImg))
        aImg = np.array(aImg).reshape(row, col)
        #converted from type float32
        aImg = np.uint8(aImg)
        #show(sImg)
        aImg = cv2.merge((hImg,aImg,vImg))
        return aImg
    #decoding
    #apply dct for decoding 
    def DCTDecoder(self,img):
        row, col = img.shape[:2]
        messSize = None
        messageBits = []
        buff = 0
        #split the image into RGB channels
        hImg,sImg,vImg = cv2.split(img)
        #message hid in blue channel so converted to type float32 for dct function
        sImg = np.float32(sImg)
        #break into 8x8 blocks
        imgBlocks = [sImg[j:j+8,i:i+8]-128 for (j,i) in itertools.product(range(0,row,8),range(0,col,8))]
        #dctBlocks = [np.round(cv2.dct(ib)) for ib in imgBlocks]
        # the blocks are run through quantization table
        quantDCT = [ib/quant for ib in imgBlocks]
        i=0
        flag = 0
        nb = ''
        #message is extracted from LSB of DCT coefficients
        for qb in quantDCT:
            DC = qb[0][0]
            DC = np.uint8(DC)
            #unpacking of bits of DCT
            DC = np.unpackbits(DC)
            #print('DC',DC,end=' ')
            if (flag == 0):
                if (DC[7] == 1):
                    buff+=(0 & 1) << (7-i)
                elif (DC[7] == 0):
                    buff+=(1&1) << (7-i)
            else:
                if (DC[7] == 1):
                    nb+='0'
                elif (DC[7] == 0):
                    nb+='1'
            i=1+i
            #print(i)
            if (i == 8):
                #print(buff,end=' ')
                if (flag == 0):
                    messageBits.append(buff)
                    #print(buff,end=' ')
                    buff = 0
                else:
                    messageBits.append(nb)
                    #print(nb,end=' ')
                    nb = ''
                i =0
                if (messageBits[-1] == 42 and messSize is None):
                    try:
                        flag = 1
                        messSize = int(str(chr(messageBits[0]))+str(chr(messageBits[1])))#int(''.join(messageBits[:-1]))
                        print(messSize,'a')
                    except:
                        print('b')
                        pass
            if (len(messageBits) - len(str(messSize)) - 1 == messSize):
                #print(''.join(messageBits)[len(str(messSize))+1:])
                return messageBits
                pass
        print(messageBits)
        return ''
def msg_encrypt(msg,cipher):
    if (len(msg)%16 != 0):
        #a = len(msg)%16 != 0 
        #print(a)
        msg = msg + ' '*(16 - len(msg)%16)
        #nonce = cipher.nonce
    t1 = msg.encode()
    enc_msg = cipher.encrypt(t1)
    return enc_msg
def msg_decrypt(ctext,cipher):
    dec_msg = cipher.decrypt(ctext)
    msg1 = dec_msg.decode()
    return msg1
image = cv2.imread('C://Users//hp//Desktop//Lenna.jpg',cv2.IMREAD_UNCHANGED)
image = cv2.cvtColor(image,cv2.COLOR_BGR2HSV_FULL)
#image = cv2.cvtColor(image,cv2.COLOR_RGB2HSV)
secret_msg = 'Shaina'
print(secret_msg)
key = b'Sixteen byte key'
#encryption of message
cipher = AES.new(key,AES.MODE_ECB)
enc_msg = msg_encrypt(secret_msg,cipher)
print(enc_msg)
d = DiscreteCosineTransform() 
dct_img_encoded = d.DCTEncoder(image, enc_msg) 
dct_img_encoded = cv2.cvtColor(dct_img_encoded,cv2.COLOR_HSV2BGR_FULL)
#dct_img_encoded = cv2.cvtColor(dct_img_encoded,cv2.COLOR_BGR2RGB)
cv2.imwrite('C://Users//hp//Desktop//DCT1.png',dct_img_encoded)
eimg = cv2.imread('C://Users//hp//Desktop//DCT1.png',cv2.IMREAD_UNCHANGED)
eimg = cv2.cvtColor(eimg,cv2.COLOR_BGR2HSV_FULL)
#eimg = cv2.cvtColor(eimg,cv2.COLOR_RGB2HSV)
text = d.DCTDecoder(eimg)
ntext = []
print(text)
for i in range(len(text)):
    if(type(text[i]) == str):
        ntext.append(text[i])
print(ntext)
#print(type(text))
#print(next)
#binary_data = ''.join([ format(ord(i), "08b") for i in next ])
#all_bytes = [ binary_data[i: i+8] for i in range(0,len(binary_data),8)]
decoded_data = b''
for byte in next:
    try:
        decoded_data += int (byte,2).to_bytes (len(byte) // 8, byteorder='big')
    except Exception as e:
        print(byte)
        break
print(decoded_data)
#decryption of message
dtext = msg_decrypt(decoded_data,cipher)
print(dtext)

我得到的结果是:

请帮帮我。

【问题讨论】:

  • 首先,您应该消除加密/解密并只存储一个简单的字符串。我不知道你想用量化做什么;除了第一个系数,您的除法/回合将所有值发送到 0 并破坏饱和度。您是否有参考表明这种 DCT 操作应该有效?
  • 好的,谢谢。我正在向您发送参考。
  • 好的,但他们正在修改颜色通道(如下所示),而不是饱和度。 RGB/HSV 转换导致您丢失了隐写术。
  • 好的,现在我明白了。非常感谢。

标签: python image steganography dct


【解决方案1】:

好的,我已经简化了很多事情并进行了一些更改,这似乎适用于我的示例图像。

您似乎面临的最大的总体问题是 RGB/HSV 转换搞砸了您的最低有效位,从而丢失了嵌入的消息。我不相信操纵饱和度是正确的方法。我在这里所做的是把它留在 RGB 中,我正在操纵绿色波段。我没有进行量化,因为我认为这不是正确的方法,但我将消息嵌入到第 0 个 DCT 元素的底部 5 位中。这样,我可以在解码过程中进行一些舍入,以留出一些废话。

也许这可以帮助您前进。

from PIL import Image
import numpy as np
import itertools
import cv2

class DiscreteCosineTransform:
    #created the constructor
    def __init__(self):
        self.message = None
        self.numBits = 0

    #utility and helper function for DCT Based Steganography
    #helper function to stich the image back together
    def chunks(self,l,n):
        m = int(n)
        for i in range(0,len(l),m):
            yield l[i:i+m]
    #function to add padding to make the function dividable by 8x8 blocks
    def addPadd(self,img,row,col):
         img = cv2.resize(img,(col+(8-col%8),row+(8-row%8)))
         return img

    #main part 
    #encoding function 
    #applying dct for encoding 
    def DCTEncoder(self,img,secret):
        self.message = str(len(secret)).encode()+b'*'+secret
        #get the size of the image in pixels
        row, col = img.shape[:2]
        if((col/8)*(row/8)<len(secret)):
            print("Error: Message too large to encode in image")
            return False
        if row%8 or col%8:
            img = self.addPadd(img,row,col)
        row,col = img.shape[:2]
        #split image into RGB channels
        hImg,sImg,vImg = cv2.split(img)
        #message to be hid in saturation channel so converted to type float32 for dct function
        #print(bImg.shape)
        sImg = np.float32(sImg)
        #breaking the image into 8x8 blocks
        imgBlocks = [np.round(sImg[j:j+8,i:i+8]-128) for (j,i) in itertools.product(range(0,row,8),range(0,col,8))]
        #print('imgBlocks',imgBlocks[0])
        #blocks are run through dct / apply dct to it
        dctBlocks = [np.round(cv2.dct(ib)) for ib in imgBlocks]
        print('imgBlocks', imgBlocks[0])
        print('dctBlocks', dctBlocks[0])
        #blocks are run through quantization table / obtaining quantized dct coefficients
        quantDCT = dctBlocks
        print('quantDCT', quantDCT[0])
        #set LSB in DC value corresponding bit of message
        messIndex=0
        letterIndex=0
        print(self.message)
        for qb in quantDCT:
            #find LSB in DCT cofficient and replace it with message bit
            bit = (self.message[messIndex] >> (7-letterIndex)) & 1
            DC = qb[0][0]
            DC = (int(DC) & ~31) | (bit * 15)
            qb[0][0] = np.float32(DC)
            letterIndex += 1
            if letterIndex == 8:
                letterIndex = 0
                messIndex += 1
                if messIndex == len(self.message):
                    break
        #writing the stereo image
        #blocks run inversely through quantization table
        #blocks run through inverse DCT
        sImgBlocks = [cv2.idct(B)+128 for B in quantDCT]
        #puts the new image back together
        aImg=[]
        for chunkRowBlocks in self.chunks(sImgBlocks, col/8):
            for rowBlockNum in range(8):
                for block in chunkRowBlocks:
                    aImg.extend(block[rowBlockNum])
        aImg = np.array(aImg).reshape(row, col)
        #converted from type float32
        aImg = np.uint8(aImg)
        #show(sImg)
        return cv2.merge((hImg,aImg,vImg))

    #decoding
    #apply dct for decoding 
    def DCTDecoder(self,img):
        row, col = img.shape[:2]
        messSize = None
        messageBits = []
        buff = 0
        #split the image into RGB channels
        hImg,sImg,vImg = cv2.split(img)
        #message hid in saturation channel so converted to type float32 for dct function
        sImg = np.float32(sImg)
        #break into 8x8 blocks
        imgBlocks = [sImg[j:j+8,i:i+8]-128 for (j,i) in itertools.product(range(0,row,8),range(0,col,8))]
        dctBlocks = [np.round(cv2.dct(ib)) for ib in imgBlocks]
        # the blocks are run through quantization table
        print('imgBlocks',imgBlocks[0])
        print('dctBlocks',dctBlocks[0])
        quantDCT = dctBlocks
        i=0
        flag = 0
        #message is extracted from LSB of DCT coefficients
        for qb in quantDCT:
            if qb[0][0] > 0:
                DC = int((qb[0][0]+7)/16) & 1
            else:
                DC = int((qb[0][0]-7)/16) & 1
            #unpacking of bits of DCT
            buff += DC << (7-i)
            i += 1
            #print(i)
            if i == 8:
                messageBits.append(buff)
                #print(buff,end=' ')
                buff = 0
                i =0
                if messageBits[-1] == 42 and not messSize:
                    try:
                        messSize = int(chr(messageBits[0])+chr(messageBits[1]))
                        print(messSize,'a')
                    except:
                        print('b')
            if len(messageBits) - len(str(messSize)) - 1 == messSize:
                return messageBits
        print("msgbits", messageBits)
        return None

image = cv2.imread('20210827_092821.jpg',cv2.IMREAD_UNCHANGED)

enc_msg = b'Shaina Sixteen byte key'
#print(enc_msg)

d = DiscreteCosineTransform() 
dct_img_encoded = d.DCTEncoder(image, enc_msg) 

cv2.imwrite('2021_encoded.png',dct_img_encoded)
eimg = cv2.imread('2021_encoded.png',cv2.IMREAD_UNCHANGED)

text = d.DCTDecoder(eimg)
print(text)

decoded = bytes(text[3:])
print(decoded)

【讨论】:

    猜你喜欢
    • 2016-05-25
    • 2020-03-12
    • 2014-04-18
    • 2012-06-08
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2013-10-13
    • 2015-07-25
    相关资源
    最近更新 更多