ADD file via upload

This commit is contained in:
p65192740 2023-11-29 19:49:50 +08:00
parent 2e948c42c1
commit 554565f358
1 changed files with 302 additions and 0 deletions

302
main.py Normal file
View File

@ -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_())