Я работаю над проектом по созданию программы стеганографии на основе DCT в Python, и я нашел рабочую модель в Github. Однако программа может кодировать только один из каналов RGB. В результате получается обесцвеченное изображение. Изображение разбивается на полосы RGB с использованием OpenCV и DCT, и квантование выполняется только по синему каналу, а затем оно объединяется с остальными каналами. Есть ли способ заставить его работать на всех каналах или избежать обесцвечивания.
Я упомянул сжатие dct для изображений RGB, чтобы найти решение, и обнаружил, что dct и квантование должны выполняться для всех 3 полос отдельно и затем выполняется сжатие. Должен ли я сделать то же самое и здесь? Как кодировать одно и то же сообщение три раза во всех диапазонах, чтобы избежать обесцвечивания?
Алгоритм кодирования
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