{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":19991,"databundleVersionId":1117522,"sourceType":"competition"},{"sourceId":7054711,"sourceType":"datasetVersion","datasetId":4060430}],"dockerImageVersionId":30587,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-26T07:16:24.231148Z","iopub.execute_input":"2023-11-26T07:16:24.231646Z","iopub.status.idle":"2023-11-26T07:16:24.775917Z","shell.execute_reply.started":"2023-11-26T07:16:24.231602Z","shell.execute_reply":"2023-11-26T07:16:24.774078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir /kaggle/working/lsb","metadata":{"execution":{"iopub.status.busy":"2023-11-26T07:16:24.779004Z","iopub.execute_input":"2023-11-26T07:16:24.779780Z","iopub.status.idle":"2023-11-26T07:16:25.953838Z","shell.execute_reply.started":"2023-11-26T07:16:24.779730Z","shell.execute_reply":"2023-11-26T07:16:25.952512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def hide_message(img, message, num_bits_per_channel=1, verbose=False):\n    \n    pixels = list(img.getdata())    \n    binary_data_string = ''.join(format(ord(char), '08b') for char in message)    \n    random_skip = random.randint(0, 10000)\n    num_pixels_to_use = math.ceil(len(binary_data_string) / num_bits_per_channel / 3) * random_skip # 3 channels\n    \n    while num_pixels_to_use >= len(pixels) - 2:\n        random_skip = random.randint(0, 8000)\n        num_pixels_to_use = math.ceil(len(binary_data_string) / num_bits_per_channel / 3) * random_skip # 3 channels\n    \n    if verbose:\n        print(f\"bin_data_len: {len(binary_data_string)} skip: {random_skip}, num_pixels_to_use: {num_pixels_to_use}\")\n    \n    data_index = 0\n    pixel_index = random.randint(0, len(pixels) - 1 - num_pixels_to_use)       \n    \n    if verbose:\n        print(f\"start pixel index: {pixel_index}\")\n        \n    skip = random_skip\n        \n    while data_index < len(binary_data_string):\n        pixel = pixels[pixel_index]\n        new_pixel = list(pixel)\n        if verbose:\n            print(f\"orig: {new_pixel} at index {pixel_index}\")\n        for channel in range (3):\n    #         if data_index >= len(binary_data_string):\n    #             break;\n            if verbose:\n                print(f'channel {channel}')\n                print(f\"orig: {format(new_pixel[channel], 'b')}\")\n            new_pixel[channel] = pixel[channel] & ~(2**num_bits_per_channel - 1)\n            if verbose:\n                print(f\"masked: {format(new_pixel[channel], 'b')}\")\n            for j in range(num_bits_per_channel):\n                if data_index >= len(binary_data_string):\n                    break;\n                new_pixel[channel] |= (int(binary_data_string[data_index]) << j)\n                if verbose:\n                    print(f'adding bit {int(binary_data_string[data_index])} to position {j}')\n                data_index += 1\n            if verbose:\n                print(f\"final: {format(new_pixel[channel], 'b')}\")\n        pixels[pixel_index] = tuple(new_pixel)\n        pixel_index += skip\n        if verbose:\n            print(\"new pixel: \", new_pixel);\n            print(\"-\" * 10)\n    \n    return pixels","metadata":{"execution":{"iopub.status.busy":"2023-11-26T07:16:25.957606Z","iopub.execute_input":"2023-11-26T07:16:25.958112Z","iopub.status.idle":"2023-11-26T07:16:25.977888Z","shell.execute_reply.started":"2023-11-26T07:16:25.958054Z","shell.execute_reply":"2023-11-26T07:16:25.976593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import numpy as np\n# import random\n\n# def hide_message(img, message, num_bits_per_channel=1, verbose=False):\n#     pixels = np.array(img, dtype=np.uint8)  # Ensure pixels are of type uint8\n#     binary_data_string = ''.join(format(ord(char), '08b') for char in message)\n    \n#     # Calculate the number of pixels to use outside the loop\n#     random_skip = random.randint(0, 10000)\n#     num_pixels_to_use = math.ceil(len(binary_data_string) / num_bits_per_channel / 3) * random_skip\n\n#     while num_pixels_to_use >= pixels.size - 2:\n#         random_skip = random.randint(0, 8000)\n#         num_pixels_to_use = math.ceil(len(binary_data_string) / num_bits_per_channel / 3) * random_skip\n\n#     if verbose:\n#         print(f\"bin_data_len: {len(binary_data_string)} skip: {random_skip}, num_pixels_to_use: {num_pixels_to_use}\")\n\n#     data_index = 0\n\n#     # Calculate indices outside the loop\n#     pixel_indices = np.arange(random.randint(0, pixels.size - 1 - num_pixels_to_use), step=random_skip)\n\n#     if verbose:\n#         print(f\"start pixel index: {pixel_indices[0]}\")\n\n#     for pixel_index in pixel_indices:\n#         if data_index >= len(binary_data_string):\n#             break\n\n#         # Perform bitwise operations using NumPy\n#         pixels_flat = pixels.flatten().astype(np.uint16)  # Convert to uint16 to avoid casting issues\n#         pixels_flat[pixel_index:pixel_index+3] &= ~(2**num_bits_per_channel - 1)\n\n#         for j in range(num_bits_per_channel):\n#             if data_index >= len(binary_data_string):\n#                 break\n#             pixels_flat[pixel_index:pixel_index+3] |= (int(binary_data_string[data_index]) << j)\n#             data_index += 1\n\n#     # Reshape back to the original shape and convert back to uint8\n#     pixels = pixels_flat.reshape(img.size[::-1] + (3,)).astype(np.uint8)\n\n#     return pixels\n","metadata":{"execution":{"iopub.status.busy":"2023-11-26T07:16:25.980751Z","iopub.execute_input":"2023-11-26T07:16:25.981285Z","iopub.status.idle":"2023-11-26T07:16:26.009642Z","shell.execute_reply.started":"2023-11-26T07:16:25.981244Z","shell.execute_reply":"2023-11-26T07:16:26.008058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## LSB","metadata":{}},{"cell_type":"code","source":"# s = \"A\"\n# b = bytearray()\n# b.extend(s.encode())\n# print(b)\n# print(b[0] & 1)\n\n# binary_data_string = ''.join(format(ord(char), '08b') for char in s)\n\n# print(format(ord(s[0]), '08b'))\n# print(binary_data_string)\n\nfrom PIL import Image\nimport random\nimport math\n\ndef print_binary(char):\n    print(format(ord(string), '08b'))\n\n\n# print(img.size)\n\n# w, h = img.size\n\n# print(pixels[:3])\n\nmsg = \"AAA\"\nwith open('/kaggle/input/dialogues-and-scripts/StarWars_EpisodeIV_script.txt', 'rb') as file:\n    try:\n        content = file.read().decode('utf-8', errors='ignore')\n        msg = content\n    except UnicodeDecodeError as e:\n        print(f\"UnicodeDecodeError: {e}\")\n\nimg = Image.open('/kaggle/input/alaska2-image-steganalysis/Cover/00001.jpg')\n\npixels = hide_message(img, msg, num_bits_per_channel=5, verbose=False)\n    \nencoded_image_path = '/kaggle/working/test.jpg'\nencoded_img = Image.new(img.mode, img.size)\nencoded_img.putdata(pixels)\nencoded_img.save(encoded_image_path, quality=100)\n    \narr1 = np.array(img)\narr2 = np.array(encoded_img)\ndiff = arr1 - arr2\n\n# print(np.where(arr1 != arr2))\n\nfeature_vector1 = arr1.flatten()\nfeature_vector2 = arr2.flatten()\nfeature_vector3 = diff.flatten()\n\n# print(np.where(feature_vector1 != feature_vector2))\n\n# Concatenate feature vectors\nfeature_matrix = np.vstack((feature_vector1, feature_vector2, feature_vector3))\n\nprint(feature_matrix.shape)\n    \nimport matplotlib.pyplot as plt\n\n# Reshape the feature matrix to (num_images, height, width, channels)\nfeature_matrix = feature_matrix.reshape((3, 512, 512, 3))\n\n# Row by column grid\nfig, axes = plt.subplots(1, 3)\n\naxes[0].imshow(feature_matrix[0])\naxes[0].axis('off')  # Turn off axis labels\naxes[1].imshow(feature_matrix[1])\naxes[1].axis('off')  # Turn off axis labels\naxes[2].imshow(feature_matrix[2])\naxes[2].axis('off')  # Turn off axis labels\n\nplt.show()\n\n\nroot = '/kaggle/input/dialogues-and-scripts'\n\ninput_file_paths = os.listdir(root)\nmessages = []     \n    \nfor path in input_file_paths:\n    full_path = os.path.join(root, path)\n    print(full_path)\n    with open(full_path, 'rb') as file:\n        try:\n            content = file.read().decode('utf-8', errors='ignore')\n            messages.append(content)\n        except UnicodeDecodeError as e:\n            print(f\"UnicodeDecodeError: {e}\")\n\nnum_bits_per_channel = 1\ni = 1\n\n# def hide_images(paths):\n\n# import threading\n\n# threads = []\n\n# for i in range(20):\n#     t = threading.Thread(target=print_hello, args=(f'Thread {i}',))\n#     threads.append(t)\n\n# for t in threads:\n#     t.start()\n\n# for t in threads:\n#     t.join()\n    \n\nfor cover_image_path in os.listdir('/kaggle/input/alaska2-image-steganalysis/Cover/'):\n    full_path = os.path.join('/kaggle/input/alaska2-image-steganalysis/Cover/', cover_image_path)\n\n    img = Image.open(full_path)\n    img.resize((28, 28))\n\n    message_index = i % len(messages)\n    message_to = random.randint(5000, len(messages[message_index]))    \n    message = messages[message_index][message_to - (100 * ((i % 4) + 1)):message_to]\n\n#     message = 'ABCERDKJDFKJ'\n\n    pixels = hide_message(img, message, num_bits_per_channel=num_bits_per_channel, verbose=False)\n\n    encoded_image_path = os.path.join('/kaggle/working/lsb', cover_image_path)\n    encoded_img = Image.new(img.mode, img.size)\n    encoded_img.putdata(pixels)\n    encoded_img.save(encoded_image_path, quality=100)\n    if i % 10 == 0:\n        print(f'saved at {encoded_image_path}')\n\n    num_bits_per_channel = ((num_bits_per_channel + 1) % 6) + 1\n\n    if i % 1000 == 0:\n        print(f\"length: {i}\")\n    i += 1\n\n\n# def decode_msg(img, message, num_bits_per_channel=1, verbose=False):\n# print('decoding')\n# print('-' * 10)\n# recovered = ''\n# pixel_index = 0\n# data_index = 0\n\n# while data_index < len(binary_data_string):\n#     pixel = pixels[pixel_index]\n#     for channel in range(3):  \n#         print(f'channel {channel}')\n#         print(f\"pixel: {format(new_pixel[channel], 'b')}\")\n#         for shift in range (num_bits_per_channel): # if num_bits_per_channel is 2 -> range is 1, 0\n#             if data_index >= len(binary_data_string):\n#                 break;\n#             bit = (pixel[channel] & (1 << shift)) >> shift\n#             print(f'extracted bit {bit} frim position {shift}')\n#             recovered += str(bit)\n#             data_index += 1\n#     pixel_index += 1\n# print(binary_data_string)\n# print(recovered)\n# print(binary_data_string == recovered)","metadata":{"execution":{"iopub.status.busy":"2023-11-26T07:19:15.836740Z","iopub.execute_input":"2023-11-26T07:19:15.837379Z","iopub.status.idle":"2023-11-26T07:19:26.068713Z","shell.execute_reply.started":"2023-11-26T07:19:15.837341Z","shell.execute_reply":"2023-11-26T07:19:26.067153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}