python - 如何在 RGB 图像上应用 DCT 隐写术?
问题描述
我正在做一个项目,用 Python 制作一个基于 DCT 的隐写术程序,我在 Github 中找到了一个工作模型。但是,该程序只能在其中一个 RGB 通道上进行编码。导致图像变色。使用 OpenCV 和 DCT 将图像拆分为 RGB 波段,并且仅在蓝色通道上进行量化,然后将其与其余通道组合。有没有办法让它在所有渠道上工作或避免变色。
我已经参考了 RGB 图像上的 dct 压缩以找到解决方案,并发现必须分别对所有 3 个波段进行 dct 和量化,然后进行压缩。我也应该在这里做同样的事情吗?就像在所有频段中对相同的消息进行三次编码以避免变色一样?
编码算法
def encode_image(self,img,secret_msg):
secret=secret_msg
self.message = str(len(secret))+'*'+secret
print(self.message)
self.bitMess = self.toBits()
print(self.bitMess)
row,col = img.shape[:2]
self.oriRow, self.oriCol = row, col
if((col/8)*(row/8)<len(secret)):
print("Error: Message too large to encode in image")
return False
#make divisible by 8x8
if row%8 != 0 or col%8 != 0:
img = self.addPadd(img, row, col)
row,col = img.shape[:2]
##col, row = img.size
#split image into RGB channels
bImg,gImg,rImg = cv2.split(img)
def enc(bImg):
#message to be hid in blue channel so converted to type float32 for dct function
bImg = np.float32(bImg)
#break into 8x8 blocks
imgBlocks = [np.round(bImg[j:j+8, i:i+8]-128) for (j,i) in itertools.product(range(0,row,8),
range(0,col,8))]
#Blocks are run through DCT function
dctBlocks = [np.round(cv2.dct(img_Block)) for img_Block in imgBlocks]
#blocks then run through quantization table
quantizedDCT = [np.round(dct_Block/quant) for dct_Block in dctBlocks]
#set LSB in DC value corresponding bit of message
messIndex = 0
letterIndex = 0
for quantizedBlock in quantizedDCT:
#find LSB in DC coeff and replace with message bit
DC = quantizedBlock[0][0]
DC = np.uint8(DC)
DC = np.unpackbits(DC)
DC[7] = self.bitMess[messIndex][letterIndex]
DC = np.packbits(DC)
DC = np.float32(DC)
DC= DC-255
quantizedBlock[0][0] = DC
letterIndex = letterIndex+1
if letterIndex == 8:
letterIndex = 0
messIndex = messIndex + 1
if messIndex == len(self.message):
break
#blocks run inversely through quantization table
sImgBlocks = [quantizedBlock *quant+128 for quantizedBlock in quantizedDCT]
#blocks run through inverse DCT
sImgDCT = [cv2.idct(B)+128 for B in sImgBlocks]
#puts the new image back together
sImg=[]
for chunkRowBlocks in self.chunks(sImgDCT, col/8):
for rowBlockNum in range(8):
for block in chunkRowBlocks:
sImg.extend(block[rowBlockNum])
sImg = np.array(sImg).reshape(row, col)
#converted from type float32
sImg = np.uint8(sImg)
return sImg
bImg=enc(bImg)
#show(sImg)
sImg = cv2.merge((bImg,gImg,rImg))
return sImg
解码算法
def decode_image(self,img):
row,col = img.shape[:2]
messSize = None
messageBits = []
buff = 0
#split image into RGB channels
bImg,gImg,rImg = cv2.split(img)
#message hid in blue channel so converted to type float32 for dct function
bImg = np.float32(bImg)
#break into 8x8 blocks
imgBlocks = [bImg[j:j+8, i:i+8]-128 for (j,i) in itertools.product(range(0,row,8),
range(0,col,8))]
#blocks run through quantization table
dctBlocks = [cv2.dct(img_Block) for img_Block in imgBlocks]
#quantizedDCT = [dct_Block/ (quant) for dct_Block in dctBlocks]
quantizedDCT = [dct_Block/quant for dct_Block in dctBlocks]
i=0
#message extracted from LSB of DC coeff
for quantizedBlock in quantizedDCT:
DC = quantizedBlock[0][0]
DC = np.uint8(DC)
DC = np.unpackbits(DC)
if DC[7] == 1:
buff+=(0 & 1) << (7-i)
elif DC[7] == 0:
buff+=(1&1) << (7-i)
i=1+i
if i == 8:
messageBits.append(chr(buff))
buff = 0
i =0
if messageBits[-1] == '*' and messSize is None:
try:
messSize = int(''.join(messageBits[:-1]))
except:
pass
if len(messageBits) - len(str(messSize)) - 1 == messSize:
return ''.join(messageBits)[len(str(messSize))+1:]
#blocks run inversely through quantization table
sImgBlocks = [quantizedBlock *quant+128 for quantizedBlock in quantizedDCT]
#blocks run through inverse DCT
#sImgBlocks = [cv2.idct(B)+128 for B in quantizedDCT]
#puts the new image back together
sImg=[]
for chunkRowBlocks in self.chunks(sImgBlocks, col/8):
for rowBlockNum in range(8):
for block in chunkRowBlocks:
sImg.extend(block[rowBlockNum])
sImg = np.array(sImg).reshape(row, col)
#converted from type float32
sImg = np.uint8(sImg)
sImg = cv2.merge((sImg,gImg,rImg))
##sImg.save(img)
#dct_decoded_image_file = "dct_" + original_image_file
#cv2.imwrite(dct_decoded_image_file,sImg)
return ''
"""Helper function to 'stitch' new image back together"""
def chunks(self, l, n):
m = int(n)
for i in range(0, len(l), m):
yield l[i:i + m]
def addPadd(self,img, row, col):
img = cv2.resize(img,(col+(8-col%8),row+(8-row%8)))
return img
def toBits(self):
bits = []
for char in self.message:
binval = bin(ord(char))[2:].rjust(8,'0')
bits.append(binval)
self.numBits = bin(len(bits))[2:].rjust(8,'0')
return bits
解决方案
推荐阅读
- android - 从 Web 到 Android 的 HTTP 请求
- mysql - SQL - 获取具有一个结果和选定选项的行 - 关系表
- python - 从 SQL 输出表为 csv 格式并在列周围添加引号
- sql - Oracle 到 SQL Server 迁移中的外键错误
- reactjs - 向用户显示“For”循环的状态
- powerbi - Power BI if condition if true then column with date value else NULL
- c++ - 从一系列字符构造 string_view
- python-3.x - 根据另一列的对应行重命名一列的行
- jasper-reports - Jasper Json 嵌套列表
- google-cloud-platform - 如何将持久存储挂载到 Google Cloud Run?