ADD file via upload
This commit is contained in:
parent
2e948c42c1
commit
554565f358
|
@ -0,0 +1,302 @@
|
|||
import sys, os
|
||||
from ui import Ui_Form
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui, QtSvg
|
||||
from PIL import Image, ImageQt
|
||||
|
||||
class UiMain(QtWidgets.QMainWindow, Ui_Form):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super(UiMain, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.initSlot()
|
||||
self.show()
|
||||
|
||||
def initSlot(self):
|
||||
self.pushButtonOpenCover.clicked.connect(self.EtOpenCover)
|
||||
self.pushButtonClearCover.clicked.connect(self.EtCleanCover)
|
||||
self.pushButtonSaveCover.clicked.connect(self.EtSaveCover)
|
||||
|
||||
self.pushButtonOpenSecret.clicked.connect(self.EtOpenSecret)
|
||||
self.pushButtonClearSecret.clicked.connect(self.EtCleanSecret)
|
||||
self.pushButtonSaveSecret.clicked.connect(self.EtSaveSecret)
|
||||
|
||||
self.pushButtonOpenContainer.clicked.connect(self.EtOpenContainer)
|
||||
self.pushButtonClearContainer.clicked.connect(self.EtCleanContainer)
|
||||
self.pushButtonSaveContainer.clicked.connect(self.EtSaveContainer)
|
||||
|
||||
self.pushButtonEncode.clicked.connect(self.EtEncode)
|
||||
self.pushButtonDecode.clicked.connect(self.EtDecode)
|
||||
|
||||
def EtCleanCover(self):
|
||||
self.labelCover.setPixmap(QtGui.QPixmap(""))
|
||||
|
||||
def EtCleanSecret(self):
|
||||
self.labelSecret.setPixmap(QtGui.QPixmap(""))
|
||||
|
||||
def EtCleanContainer(self):
|
||||
self.labelContainer.setPixmap(QtGui.QPixmap(""))
|
||||
|
||||
def EtOpenCover(self):
|
||||
path, fileType = QtWidgets.QFileDialog.getOpenFileName(self, "选取文件", os.getcwd(), "所有文件 (*)")
|
||||
if len(path) == 0: return
|
||||
self.PCover, self.QCover = self.loadImage(path, self.labelCover)
|
||||
|
||||
def EtOpenSecret(self):
|
||||
path, fileType = QtWidgets.QFileDialog.getOpenFileName(self, "选取文件", os.getcwd(), "所有文件 (*)")
|
||||
if len(path) == 0: return
|
||||
self.PSecret, self.QSecret = self.loadImage(path, self.labelSecret)
|
||||
|
||||
def EtOpenContainer(self):
|
||||
path, fileType = QtWidgets.QFileDialog.getOpenFileName(self, "选取文件", os.getcwd(), "所有文件 (*)")
|
||||
if len(path) == 0: return
|
||||
self.PContainer, self.QContainer = self.loadImage(path, self.labelContainer)
|
||||
|
||||
def EtSaveCover(self):
|
||||
dirpath = QtWidgets.QFileDialog.getSaveFileName(self, '选择保存路径', os.getcwd(), "所有文件 (*)")
|
||||
print(dirpath[0])
|
||||
self.PCover.save(dirpath[0])
|
||||
|
||||
def EtSaveSecret(self):
|
||||
dirpath = QtWidgets.QFileDialog.getSaveFileName(self, '选择保存路径', os.getcwd(), "所有文件 (*)")
|
||||
print(dirpath[0])
|
||||
self.PSecret.save(dirpath[0])
|
||||
|
||||
def EtSaveContainer(self):
|
||||
dirpath = QtWidgets.QFileDialog.getSaveFileName(self, '选择保存路径', os.getcwd(), "所有文件 (*)")
|
||||
print(dirpath[0])
|
||||
self.PContainer.save(dirpath[0])
|
||||
|
||||
def EtEncode(self):
|
||||
# self.PContainer = self.PCover
|
||||
self.PContainer = encode(self.PCover, self.PSecret)
|
||||
self.setLabelImage(ImageQt.toqimage(self.PCover), self.labelContainer)
|
||||
|
||||
def EtDecode(self):
|
||||
self.EtCleanCover()
|
||||
self.PSecret = decode(self.PContainer)
|
||||
# self.setLabelImage(ImageQt.toqimage(self.PCover), self.labelCover)
|
||||
self.setLabelImage(ImageQt.toqimage(self.PSecret), self.labelSecret)
|
||||
|
||||
def loadImage(self, path: str, label: QtWidgets.QLabel):
|
||||
p = Image.open(path)
|
||||
q = ImageQt.toqimage(p)
|
||||
self.setLabelImage(q, label)
|
||||
return p,q
|
||||
|
||||
def setLabelImage(self, qimage: QtGui.QImage, label: QtWidgets.QLabel):
|
||||
rect1 = label.rect()
|
||||
rect2 = qimage.rect()
|
||||
xscale = rect1.width() / rect2.width()
|
||||
yscale = rect1.height() / rect2.height()
|
||||
scale = min(xscale, yscale)
|
||||
trans = QtGui.QTransform()
|
||||
trans.scale(scale, scale)
|
||||
q = qimage.transformed(trans)
|
||||
label.setPixmap(QtGui.QPixmap.fromImage(q))
|
||||
|
||||
def add_leading_zeros(binary_number, expected_length):
|
||||
"""
|
||||
Adds leading zeros to a binary number so that the number of characters
|
||||
in the binary string matches the specified expected length and the value
|
||||
of the binary sring remains unchanged.
|
||||
|
||||
Args:
|
||||
binary_number: A string representation of a number in base 2
|
||||
expected_length: Expected length of the binary number string
|
||||
|
||||
Returns:
|
||||
A binary string of a length specified by the argument with the
|
||||
same numerical value as the binary number from the first argument.
|
||||
"""
|
||||
length = len(binary_number)
|
||||
return (expected_length - length) * '0' + binary_number
|
||||
|
||||
def rgb_to_binary(r, g, b):
|
||||
"""
|
||||
Converts decimal numbers representing RGB values of a pixel into
|
||||
binary numbers of the same values.
|
||||
|
||||
Args:
|
||||
r: Decimal representation of the red channel value
|
||||
g: Decimal representation of the green channel value
|
||||
b: Decimal representation of the blue channel value
|
||||
|
||||
Returns:
|
||||
Binary representations of the red, green, and blue channel values
|
||||
"""
|
||||
return add_leading_zeros(bin(r)[2:], 8), add_leading_zeros(bin(g)[2:], 8), add_leading_zeros(bin(b)[2:], 8)
|
||||
|
||||
def get_binary_pixel_values(img, width, height):
|
||||
"""
|
||||
Retrieves a string of concatenated binary representations of RGB channel values of all pixels in an image.
|
||||
|
||||
Args:
|
||||
img: An RGB image
|
||||
width: Width of the image
|
||||
height: Height of the image
|
||||
|
||||
Returns:
|
||||
A string with concatenated binary numbers representing the RGB channel values of all pixels in the image
|
||||
where each binary number representing one channel value is 8 bits long, padded with leading zeros
|
||||
when necessary. Therefore, each pixel in the image is represented by 24 bit long binary sequence.
|
||||
"""
|
||||
hidden_image_pixels = ''
|
||||
for col in range(width):
|
||||
for row in range(height):
|
||||
pixel = img[col, row]
|
||||
r = pixel[0]
|
||||
g = pixel[1]
|
||||
b = pixel[2]
|
||||
r_binary, g_binary, b_binary = rgb_to_binary(r, g, b)
|
||||
hidden_image_pixels += r_binary + g_binary + b_binary
|
||||
return hidden_image_pixels
|
||||
|
||||
def change_binary_values(img_visible, hidden_image_pixels, width_visible, height_visible, width_hidden, height_hidden):
|
||||
"""
|
||||
Replaces the 4 least significant bits of a subset of pixels in an image with bits representing a sequence of binary
|
||||
values of RGB channels of all pixels of the image to be concealed.
|
||||
|
||||
The first pixel in the top left corner is used to store the width and height of the image to be hidden, which is
|
||||
necessary for recovery of the hidden image.
|
||||
|
||||
Args:
|
||||
img_visible: An RGB image to be used for hiding another image
|
||||
hidden_image_pixels: Binary string representing all pixel values of the image to be hidden
|
||||
width_visible: Width of the image to be used for hiding another image
|
||||
height_visible: Height of the image to be used for hiding another image
|
||||
width_hidden: Width of the image to be hidden
|
||||
height_hidden: Height of the image to be hidden
|
||||
|
||||
Returns:
|
||||
An RGB image which is a copy of img_visible where the 4 least significant bits of a subset of pixels
|
||||
are replaced with bits representing the hidden image.
|
||||
"""
|
||||
idx = 0
|
||||
for col in range(width_visible):
|
||||
for row in range(height_visible):
|
||||
if row == 0 and col == 0:
|
||||
width_hidden_binary = add_leading_zeros(bin(width_hidden)[2:], 12)
|
||||
height_hidden_binary = add_leading_zeros(bin(height_hidden)[2:], 12)
|
||||
w_h_binary = width_hidden_binary + height_hidden_binary
|
||||
img_visible[col, row] = (int(w_h_binary[0:8], 2), int(w_h_binary[8:16], 2), int(w_h_binary[16:24], 2))
|
||||
continue
|
||||
r, g, b = img_visible[col, row]
|
||||
r_binary, g_binary, b_binary = rgb_to_binary(r, g, b)
|
||||
r_binary = r_binary[0:4] + hidden_image_pixels[idx:idx+4]
|
||||
g_binary = g_binary[0:4] + hidden_image_pixels[idx+4:idx+8]
|
||||
b_binary = b_binary[0:4] + hidden_image_pixels[idx+8:idx+12]
|
||||
idx += 12
|
||||
img_visible[col, row] = (int(r_binary, 2), int(g_binary, 2), int(b_binary, 2))
|
||||
if idx >= len(hidden_image_pixels):
|
||||
return img_visible
|
||||
# can never be reached, but let's return the image anyway
|
||||
return img_visible
|
||||
|
||||
def encode(img_visible, img_hidden):
|
||||
"""
|
||||
Loads the image to be hidden and the image used for hiding and conceals the pixel information from one image
|
||||
in the other one.
|
||||
|
||||
Args:
|
||||
img_visible: An RGB image used for hiding another image
|
||||
img_hidden: An RGB image to be concealed
|
||||
|
||||
Returns:
|
||||
An RGB image which is supposed to be not very different visually from img_visible, but contains all the information
|
||||
necessary to recover an identical copy of the image we want to hide.
|
||||
"""
|
||||
encoded_image = img_visible.load()
|
||||
img_hidden_copy = img_hidden.load()
|
||||
width_visible, height_visible = img_visible.size
|
||||
width_hidden, height_hidden = img_hidden.size
|
||||
hidden_image_pixels = get_binary_pixel_values(img_hidden_copy, width_hidden, height_hidden)
|
||||
encoded_image = change_binary_values(encoded_image, hidden_image_pixels, width_visible, height_visible, width_hidden, height_hidden)
|
||||
return img_visible
|
||||
|
||||
|
||||
def extract_hidden_pixels(image, width_visible, height_visible, pixel_count):
|
||||
"""
|
||||
Extracts a sequence of bits representing a sequence of binary values of
|
||||
all pixels of the hidden image.
|
||||
The information representing a hidden image is stored in the 4 least significant
|
||||
bits of a subset of pixels of the visible image.
|
||||
|
||||
Args:
|
||||
image: An RGB image to recover a hidden image from
|
||||
width_visible: Width of the visible image
|
||||
height_visible: Height of the visible image
|
||||
pixel_count: Number of pixels in the hidden image
|
||||
|
||||
Returns:
|
||||
A binary string representing pixel values of the hidden image
|
||||
"""
|
||||
hidden_image_pixels = ''
|
||||
idx = 0
|
||||
for col in range(width_visible):
|
||||
for row in range(height_visible):
|
||||
if row == 0 and col == 0:
|
||||
continue
|
||||
r, g, b = image[col, row]
|
||||
r_binary, g_binary, b_binary = rgb_to_binary(r, g, b)
|
||||
hidden_image_pixels += r_binary[4:8] + g_binary[4:8] + b_binary[4:8]
|
||||
if idx >= pixel_count * 2:
|
||||
return hidden_image_pixels
|
||||
return hidden_image_pixels
|
||||
|
||||
def reconstruct_image(image_pixels, width, height):
|
||||
"""
|
||||
Recontructs the hidden image using the extracted string of pixel binary values.
|
||||
|
||||
Args:
|
||||
image_pixels: A string of binary values of all pixels of the image to be recovered
|
||||
width: Width of the image to be recovered
|
||||
height: Height of the image to be recovered
|
||||
|
||||
Returns:
|
||||
The recovered image
|
||||
"""
|
||||
image = Image.new("RGB", (width, height))
|
||||
image_copy = image.load()
|
||||
idx = 0
|
||||
for col in range(width):
|
||||
for row in range(height):
|
||||
r_binary = image_pixels[idx:idx+8]
|
||||
g_binary = image_pixels[idx+8:idx+16]
|
||||
b_binary = image_pixels[idx+16:idx+24]
|
||||
if len(r_binary) == 0: r_binary = '0'
|
||||
if len(g_binary) == 0: g_binary = '0'
|
||||
if len(b_binary) == 0: b_binary = '0'
|
||||
# print(r_binary,g_binary,b_binary)
|
||||
image_copy[col, row] = (int(r_binary, 2), int(g_binary, 2), int(b_binary, 2))
|
||||
idx += 24
|
||||
return image
|
||||
|
||||
def decode(image):
|
||||
"""
|
||||
Loads the image to recover a hidden image from, retrieves the information about the
|
||||
size of the hidden image stored in the top left pixel of the visible image,
|
||||
extracts the hidden binary pixel values from the image and reconstructs the hidden
|
||||
image.
|
||||
|
||||
Args:
|
||||
image: An RGB image to recover a hidden image from
|
||||
|
||||
Returns:
|
||||
A recovered image, which was hidden in the binary representation of the visible image
|
||||
"""
|
||||
image_copy = image.load()
|
||||
width_visible, height_visible = image.size
|
||||
r, g, b = image_copy[0, 0]
|
||||
r_binary, g_binary, b_binary = rgb_to_binary(r, g, b)
|
||||
w_h_binary = r_binary + g_binary + b_binary
|
||||
width_hidden = int(w_h_binary[0:12], 2)
|
||||
height_hidden = int(w_h_binary[12:24], 2)
|
||||
pixel_count = width_hidden * height_hidden
|
||||
hidden_image_pixels = extract_hidden_pixels(image_copy, width_visible, height_visible, pixel_count)
|
||||
decoded_image = reconstruct_image(hidden_image_pixels, width_hidden, height_hidden)
|
||||
return decoded_image
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
ui = UiMain()
|
||||
sys.exit(app.exec_())
|
Loading…
Reference in New Issue