--- tags: Data Hiding, Python disqus: HackMD --- 資料隱藏 Homework #3 === ```python= import os import cv2 import numpy as np import copy import pywt from PIL import Image from scipy.fftpack import dct from scipy.fftpack import idct ``` ```python= base_path = '/content/drive/MyDrive/H.成大上課講義/資料隱藏技術/作業/作業三/' file_path = base_path + 'images/' coverImage = file_path + 'Lenna256.png' watermarkimgA = file_path + 'watermarkA.jpg' watermarkimgB = file_path + 'watermarkB.jpg' ``` LsbWatermark --- ```python= class LSBSteg: def __init__(self, im): self.image = im self.height, self.width, self.nbchannels = im.shape self.size = self.width * self.height self.maskONEValues = [1, 2, 4, 8, 16, 32, 64, 128] # Mask used to put one ex:1->00000001, 2->00000010 .. associated with OR bitwise self.maskONE = self.maskONEValues.pop(0) # Will be used to do bitwise operations self.maskZEROValues = [254, 253, 251, 247, 239, 223, 191, 127] # Mak used to put zero ex:254->11111110, 253->11111101 .. associated with AND bitwise self.maskZERO = self.maskZEROValues.pop(0) self.curwidth = 0 # Current width position self.curheight = 0 # Current height position self.curchan = 0 # Current channel position def put_binary_value(self, bits): # Put the bits in the image for c in bits: val = list(self.image[self.curheight, self.curwidth]) # Get the pixel value as a list if int(c) == 1: val[self.curchan] = int(val[self.curchan]) | self.maskONE # OR with maskONE else: val[self.curchan] = int(val[self.curchan]) & self.maskZERO # AND with maskZERO self.image[self.curheight, self.curwidth] = tuple(val) self.next_slot() # Move "cursor" to the next space def next_slot(self): # Move to the next slot were information can be taken or put if self.curchan == self.nbchannels - 1: # Next Space is the following channel self.curchan = 0 if self.curwidth == self.width - 1: # Or the first channel of the next pixel of the same line self.curwidth = 0 if self.curheight == self.height - 1: # Or the first channel of the first pixel of the next line self.curheight = 0 if self.maskONE == 128: # Mask 1000000, so the last mask raise SteganographyException("No available slot remaining (image filled)") else: # Or instead of using the first bit start using the second and so on.. self.maskONE = self.maskONEValues.pop(0) self.maskZERO = self.maskZEROValues.pop(0) else: self.curheight += 1 else: self.curwidth += 1 else: self.curchan += 1 def read_bit(self): # Read a single bit int the image val = self.image[self.curheight, self.curwidth][self.curchan] val = int(val) & self.maskONE self.next_slot() if val > 0: return "1" else: return "0" def read_byte(self): return self.read_bits(8) def read_bits(self, nb): # Read the given number of bits bits = "" for i in range(nb): bits += self.read_bit() return bits def byteValue(self, val): return self.binary_value(val, 8) def binary_value(self, val, bitsize): # Return the binary value of an int as a byte binval = bin(val)[2:] if len(binval) > bitsize: raise SteganographyException("binary value larger than the expected size") while len(binval) < bitsize: binval = "0" + binval return binval def encode_text(self, txt): l = len(txt) binl = self.binary_value(l, 16) # Length coded on 2 bytes so the text size can be up to 65536 bytes long self.put_binary_value(binl) # Put text length coded on 4 bytes for char in txt: # And put all the chars c = ord(char) self.put_binary_value(self.byteValue(c)) return self.image def decode_text(self): ls = self.read_bits(16) # Read the text size in bytes l = int(ls, 2) i = 0 unhideTxt = "" while i < l: # Read all bytes of the text tmp = self.read_byte() # So one byte i += 1 unhideTxt += chr(int(tmp, 2)) # Every chars concatenated to str return unhideTxt def encode_image(self, imtohide): height = imtohide.shape[0] width = imtohide.shape[1] channels = imtohide.shape[2] if self.width * self.height * self.nbchannels < width * height * channels: raise SteganographyException("Carrier image not big enough to hold all the datas to steganography") binw = self.binary_value(width, 16) # Width coded on to byte so width up to 65536 binh = self.binary_value(height, 16) self.put_binary_value(binw) # Put width self.put_binary_value(binh) # Put height for h in range(height): # Iterate the hole image to put every pixel values for w in range(width): for chan in range(channels): val = imtohide[h, w][chan] self.put_binary_value(self.byteValue(int(val))) return self.image def decode_image(self): width = int(self.read_bits(16), 2) # Read 16bits and convert it in int height = int(self.read_bits(16), 2) channels = self.nbchannels unhideimg = np.zeros((width, height, 3), np.uint8) # Create an image in which we will put all the pixels read for h in range(height): for w in range(width): for chan in range(channels): val = list(unhideimg[w, h]) val[chan] = int(self.read_byte(), 2) # Read the value unhideimg[w, h] = tuple(val) return unhideimg def encode_binary(self, data): l = len(data) if self.width * self.height * self.nbchannels < l + 64: raise SteganographyException("Carrier image not big enough to hold all the datas to steganography") self.put_binary_value(self.binary_value(l, 64)) for byte in data: byte = byte if isinstance(byte, int) else ord(byte) # Compat py2/py3 self.put_binary_value(self.byteValue(byte)) return self.image def decode_binary(self): l = int(self.read_bits(64), 2) output = b"" for i in range(l): output += bytearray([int(self.read_byte(), 2)]) return output ``` DctWatermark --- ```python= class DCTSteg: def __init__(self): self.path = os.path.join("images") self.image = "" self.watermark = "" pass def resizeImage(self, filename, size): img = Image.open(os.path.join(self.path, filename)) img = img.resize((size, size), Image.ANTIALIAS) img.save(os.path.join(self.path, filename)) def resizeImage2(self, filename, width, height): img = Image.open(os.path.join(self.path, filename)) img = img.resize((width, height), Image.ANTIALIAS) img.save(os.path.join(self.path, filename)) def convertImage(self, imageName, size, imName): img = Image.open(imageName) img = img.resize((size, size), Image.ANTIALIAS) # Convert RGB image to gray scale img = img.convert('L') # Storing the gray scale image img.save(os.path.join(self.path, 'processedInputImage/' + imName)) imageArray = np.array(img.getdata(), dtype=np.float).reshape((size, size)) return imageArray def embedWatermark(self, watermarkArray, originalImage): watermarkFlat = watermarkArray.ravel() ind = 0 for x in range(0, len(originalImage), 8): for y in range(0, len(originalImage), 8): if ind < len(watermarkFlat): subdct = originalImage[x:x+8, y:y+8] subdct[5][5] = watermarkFlat[ind] originalImage[x:x+8, y:y+8] = subdct ind+= 1 return originalImage def applyDCT(self, imageArray): size = len(imageArray[0]) allSubdct = np.empty((size, size)) for i in range(0, size, 8): for j in range(0, size, 8): subpixels = imageArray[i:i+8, j:j+8] subdct = dct(dct(subpixels.T, norm="ortho").T, norm="ortho") allSubdct[i:i+8, j:j+8] = subdct return allSubdct def inverseDCT(self, allSubdct): size = len(allSubdct[0]) allSubidct = np.empty((size, size)) for i in range(0, size, 8): for j in range(0, size, 8): subidct = idct(idct(allSubdct[i:i+8, j:j+8].T, norm="ortho").T, norm="ortho") allSubidct[i:i+8, j:j+8] = subidct return allSubidct def getWatermark(self, dctWatermarkedCoeff, watermarkSize): subwatermarks = [] for x in range(0, len(dctWatermarkedCoeff), 8): for y in range(0, len(dctWatermarkedCoeff), 8): coeffSlice = dctWatermarkedCoeff[x:x+8, y:y+8] subwatermarks.append(coeffSlice[5][5]) watermark = np.array(subwatermarks).reshape(watermarkSize, watermarkSize) return watermark def recoverWatermark(self, imageArray, newpath, model='haar', level=1): coeffsWatermarkedImage=list(pywt.wavedec2(data=imageArray, wavelet=model, level=level)) dctWatermarkedCoeff = self.applyDCT(coeffsWatermarkedImage[0]) watermarkArray = self.getWatermark(dctWatermarkedCoeff, 128) watermarkArray = np.uint8(watermarkArray) # Save result img = Image.fromarray(watermarkArray) img.save(os.path.join(self.path, newpath)) def printImage(self, imageArray, name): imageArrayCopy = imageArray.clip(0, 255) imageArrayCopy = imageArrayCopy.astype("uint8") img = Image.fromarray(imageArrayCopy) img.save(os.path.join(self.path, 'result/' + name)) def watermarkImage(self, img1, img2): self.image = img1 self.watermark = img2 model = 'haar' level = 1 imageArray = self.convertImage(self.image, 2048, "1.jpg") watermarkArray = self.convertImage(self.watermark, 128, "2.png") coeffsImage = list(pywt.wavedec2(data=imageArray, wavelet=model, level=level)) # coeffs_image = process_coefficients(image_array, model, level=level) dctArray = self.applyDCT(coeffsImage[0]) dctArray = self.embedWatermark(watermarkArray, dctArray) coeffsImage[0] = self.inverseDCT(dctArray) # Watermark reconstruction imageArrayH = pywt.waverec2(coeffsImage, model) self.printImage(imageArrayH, 'watermarkedImage.jpg') # recover images # self.recoverWatermark(imageArray=imageArrayH, newpath='result/recoveredWatermark.jpg', model=model, level=level) def decodeWatermark(self, img, newpath): model = 'haar' level = 1 imageArray = self.convertImage(img, 2048, "3.jpg") self.recoverWatermark(imageArray=imageArray, newpath=newpath, model=model, level=level) ``` 圖片處理方法 --- ```python= class ImgUtility: def __init__(self): pass def greenCover(self, xmin, ymin, xmax, ymax): img = self cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (104, 255, 88), 16*8, 8*8) return img def colorCover(self, x, y): img = self height = img.shape[0] width = img.shape[1] for h in range(height): for w in range(width): if w >= x and h >= y: img[w, h] = 0 return img def colorCover2(self, xmin, ymin, xmax, ymax): img = self height = img.shape[0] width = img.shape[1] for h in range(height): for w in range(width): if (w >= xmin) and (h >= ymin) and (w <= xmin + xmax) and (h <= ymin + ymax): img[w, h] = 0 return img ``` 主程式開始 --- * 建立資料夾 ```python= if not os.path.isdir('images'): os.mkdir('images') if not os.path.isdir('images/result'): os.mkdir('images/result') if not os.path.isdir('images/processedInputImage'): os.mkdir('images/processedInputImage') ``` * coverImage空間域藏入watermark ```python= LsbWatermark = LSBSteg(cv2.imread(coverImage)) new_imgC = LsbWatermark.encode_image(cv2.imread(watermarkimgA)) # 嵌入空間域浮水印 cv2.imwrite('images/result/new_image_C.png', new_imgC) # 儲存C圖(已嵌入空間域浮水印) LsbWatermark = LSBSteg(cv2.imread('images/result/new_image_C.png')) # 取得空間域浮水印 decodeLsbWatermark = LsbWatermark.decode_image() # 第一張浮水印 img90 = np.rot90(cv2.flip(decodeLsbWatermark, 0), -1) # 轉正浮水印 cv2.imwrite('images/result/decodeLsbWatermark.png', img90) # 儲存空間域浮水印 ``` * coverImage頻率域藏入watermark ```python= """第一題嵌入浮水印得到D圖, image/result/watermarkedImage.jpg""" DctWatermark = DCTSteg() DctWatermark.watermarkImage('images/result/new_image_C.png', watermarkimgB) # 嵌入頻率域浮水印 ``` ```python= """第二題取出浮水印, image/result/Watermark_decode.jpg""" DctWatermark.decodeWatermark(os.path.join('images/result/watermarkedImage.jpg') , newpath='result/Watermark_decode.jpg') imgD = cv2.imread(os.path.join('images/result/watermarkedImage.jpg')) watermark_decode = cv2.imread(os.path.join('images/result/Watermark_decode.jpg')) watermark_decode97x195 = cv2.resize(watermark_decode, (97, 195), interpolation=cv2.INTER_CUBIC) cv2.imwrite(os.path.join('images/result/watermarkedImage97x195.jpg'), watermark_decode97x195) ``` ```python= """第三題將D圖之右下角的四分之一裁掉,然後取出剩下部分內部之 watermark""" tmp = copy.copy(imgD) cropimg = ImgUtility.colorCover(tmp, 128*8, 128*8) cv2.imwrite(os.path.join('images/result/cropImage.jpg'), cropimg) DctWatermark.decodeWatermark(os.path.join('images/result/cropImage.jpg') , newpath='result/cropImage_decode.jpg') DctWatermark.resizeImage2('result/cropImage_decode.jpg', 97, 195) ``` ```python= """第四題將中間32*32,64*64,128*128正方形分別裁掉,然後分別取出剩下部分內部之watermark。""" tmp = copy.copy(imgD) cropimg32x32 = ImgUtility.colorCover2(tmp, 112*8, 112*8, 32*8, 32*8) cv2.imwrite(os.path.join('images/result/cropImage32x32.jpg'), cropimg32x32) DctWatermark.decodeWatermark(os.path.join('images/result/cropImage32x32.jpg') , newpath='result/cropImage32x32_decode.jpg') DctWatermark.resizeImage2('result/cropImage32x32_decode.jpg', 97, 195) tmp = copy.copy(imgD) cropimg64x64 = ImgUtility.colorCover2(tmp, 96*8, 96*8, 64*8, 64*8) cv2.imwrite(os.path.join('images/result/cropImage64x64.jpg'), cropimg64x64) DctWatermark.decodeWatermark(os.path.join('images/result/cropImage64x64.jpg') , newpath='result/cropImage64x64_decode.jpg') DctWatermark.resizeImage2('result/cropImage64x64_decode.jpg', 97, 195) tmp = copy.copy(imgD) cropimg128x128 = ImgUtility.colorCover2(tmp, 64*8, 64*8, 128*8, 128*8) cv2.imwrite(os.path.join('images/result/cropImage128x128.jpg'), cropimg128x128) DctWatermark.decodeWatermark(os.path.join('images/result/cropImage128x128.jpg') , newpath='result/cropImage128x128_decode.jpg') DctWatermark.resizeImage2('result/cropImage128x128_decode.jpg', 97, 195) ``` ```python= """第五題將 D 圖截去如下圖中之兩圈綠色部分(兩圈實際位置請自行決定,但須說明 你做的選擇), 綠色部分的寬度均為 16 pixels,然後取出剩下部分內部之 watermark。""" tmp = copy.copy(imgD) img256x256 = cv2.resize(tmp, (256, 256)) cv2.imwrite('images/result/watermarkedImage256x256.jpg', img256x256) green1 = ImgUtility.greenCover(imgD, 10*8, 10*8, 220*8, 220*8) green2 = ImgUtility.greenCover(green1, 90*8, 90*8, 140*8, 140*8) tmp2 = copy.copy(green2) green256x256 = cv2.resize(green2, (256, 256)) cv2.imwrite(os.path.join('images/result/greenCoverImage256x256.jpg'), green256x256) cv2.imwrite(os.path.join('images/result/greenCoverImage.jpg'), tmp2) DctWatermark.decodeWatermark(os.path.join('images/result/greenCoverImage.jpg') , newpath='result/greenCoverImageWatermark_decode.jpg') DctWatermark.resizeImage2('result/greenCoverImageWatermark_decode.jpg', 97, 195) ```