Con trăn 3,4
- Phần thưởng 1: Tự nghịch đảo: lặp lại khôi phục ảnh gốc.
- Hình ảnh khóa tùy chọn: hình ảnh gốc chỉ có thể được khôi phục bằng cách sử dụng lại cùng một hình ảnh chính.
- Phần thưởng 2: Tạo mẫu ở đầu ra: hình ảnh chính được xấp xỉ bằng các pixel được xáo trộn.
Khi đạt được phần thưởng 2, bằng cách sử dụng một hình ảnh quan trọng bổ sung, phần thưởng 1 sẽ không bị mất. Chương trình vẫn tự đảo ngược, miễn là nó được chạy với cùng một hình ảnh chính.
Tiêu chuẩn sử dụng
Hình ảnh thử nghiệm 1:
Hình ảnh thử nghiệm 2:
Chạy chương trình với một tệp hình ảnh duy nhất vì đối số của nó lưu một tệp hình ảnh với các pixel được xáo trộn đều trên toàn bộ hình ảnh. Chạy lại nó với đầu ra được xáo trộn sẽ lưu một tệp hình ảnh với sự xáo trộn được áp dụng lại, nó khôi phục lại bản gốc do quá trình xáo trộn là nghịch đảo của chính nó.
Quá trình xáo trộn là tự đảo ngược vì danh sách tất cả các pixel được chia thành 2 chu kỳ, do đó mọi pixel được hoán đổi với một và chỉ một pixel khác. Chạy nó lần thứ hai hoán đổi mọi pixel với pixel mà nó được hoán đổi lần đầu tiên, đưa mọi thứ trở lại cách nó bắt đầu. Nếu có một số pixel lẻ, sẽ có một pixel không di chuyển.
Nhờ câu trả lời của mfvonh là người đầu tiên đề xuất 2 chu kỳ.
Sử dụng với một hình ảnh quan trọng
Xáo trộn hình ảnh thử nghiệm 1 với hình ảnh thử nghiệm 2 làm hình ảnh chính
Xáo trộn hình ảnh thử nghiệm 2 với hình ảnh thử nghiệm 1 làm hình ảnh chính
Chạy chương trình với một đối số tệp hình ảnh thứ hai (hình ảnh chính) chia hình ảnh gốc thành các vùng dựa trên hình ảnh chính. Mỗi vùng trong số này được chia thành 2 chu kỳ riêng biệt, do đó tất cả các sự xáo trộn xảy ra trong các vùng và pixel không được di chuyển từ vùng này sang vùng khác. Điều này trải ra các pixel trên mỗi vùng và do đó các vùng trở thành một màu lốm đốm đồng nhất, nhưng với màu trung bình hơi khác nhau cho từng vùng. Điều này cung cấp một xấp xỉ rất thô của hình ảnh quan trọng, trong các màu sai.
Chạy lại hoán đổi các cặp pixel giống nhau ở mỗi vùng, do đó, mỗi vùng được khôi phục về trạng thái ban đầu và toàn bộ hình ảnh sẽ xuất hiện lại.
Nhờ câu trả lời của edc65 là người đầu tiên đề nghị chia hình ảnh thành các khu vực. Tôi muốn mở rộng về điều này để sử dụng các vùng tùy ý, nhưng cách tiếp cận hoán đổi mọi thứ trong khu vực 1 với mọi thứ trong khu vực 2 có nghĩa là các khu vực phải có kích thước giống hệt nhau. Giải pháp của tôi là giữ cho các vùng cách ly với nhau và chỉ cần xáo trộn từng vùng thành chính nó. Vì các vùng không còn cần phải có kích thước tương tự, nên việc áp dụng các vùng có hình dạng tùy ý trở nên đơn giản hơn.
Mã
import os.path
from PIL import Image # Uses Pillow, a fork of PIL for Python 3
from random import randrange, seed
def scramble(input_image_filename, key_image_filename=None,
number_of_regions=16777216):
input_image_path = os.path.abspath(input_image_filename)
input_image = Image.open(input_image_path)
if input_image.size == (1, 1):
raise ValueError("input image must contain more than 1 pixel")
number_of_regions = min(int(number_of_regions),
number_of_colours(input_image))
if key_image_filename:
key_image_path = os.path.abspath(key_image_filename)
key_image = Image.open(key_image_path)
else:
key_image = None
number_of_regions = 1
region_lists = create_region_lists(input_image, key_image,
number_of_regions)
seed(0)
shuffle(region_lists)
output_image = swap_pixels(input_image, region_lists)
save_output_image(output_image, input_image_path)
def number_of_colours(image):
return len(set(list(image.getdata())))
def create_region_lists(input_image, key_image, number_of_regions):
template = create_template(input_image, key_image, number_of_regions)
number_of_regions_created = len(set(template))
region_lists = [[] for i in range(number_of_regions_created)]
for i in range(len(template)):
region = template[i]
region_lists[region].append(i)
odd_region_lists = [region_list for region_list in region_lists
if len(region_list) % 2]
for i in range(len(odd_region_lists) - 1):
odd_region_lists[i].append(odd_region_lists[i + 1].pop())
return region_lists
def create_template(input_image, key_image, number_of_regions):
if number_of_regions == 1:
width, height = input_image.size
return [0] * (width * height)
else:
resized_key_image = key_image.resize(input_image.size, Image.NEAREST)
pixels = list(resized_key_image.getdata())
pixel_measures = [measure(pixel) for pixel in pixels]
distinct_values = list(set(pixel_measures))
number_of_distinct_values = len(distinct_values)
number_of_regions_created = min(number_of_regions,
number_of_distinct_values)
sorted_distinct_values = sorted(distinct_values)
while True:
values_per_region = (number_of_distinct_values /
number_of_regions_created)
value_to_region = {sorted_distinct_values[i]:
int(i // values_per_region)
for i in range(len(sorted_distinct_values))}
pixel_regions = [value_to_region[pixel_measure]
for pixel_measure in pixel_measures]
if no_small_pixel_regions(pixel_regions,
number_of_regions_created):
break
else:
number_of_regions_created //= 2
return pixel_regions
def no_small_pixel_regions(pixel_regions, number_of_regions_created):
counts = [0 for i in range(number_of_regions_created)]
for value in pixel_regions:
counts[value] += 1
if all(counts[i] >= 256 for i in range(number_of_regions_created)):
return True
def shuffle(region_lists):
for region_list in region_lists:
length = len(region_list)
for i in range(length):
j = randrange(length)
region_list[i], region_list[j] = region_list[j], region_list[i]
def measure(pixel):
'''Return a single value roughly measuring the brightness.
Not intended as an accurate measure, simply uses primes to prevent two
different colours from having the same measure, so that an image with
different colours of similar brightness will still be divided into
regions.
'''
if type(pixel) is int:
return pixel
else:
r, g, b = pixel[:3]
return r * 2999 + g * 5869 + b * 1151
def swap_pixels(input_image, region_lists):
pixels = list(input_image.getdata())
for region in region_lists:
for i in range(0, len(region) - 1, 2):
pixels[region[i]], pixels[region[i+1]] = (pixels[region[i+1]],
pixels[region[i]])
scrambled_image = Image.new(input_image.mode, input_image.size)
scrambled_image.putdata(pixels)
return scrambled_image
def save_output_image(output_image, full_path):
head, tail = os.path.split(full_path)
if tail[:10] == 'scrambled_':
augmented_tail = 'rescued_' + tail[10:]
else:
augmented_tail = 'scrambled_' + tail
save_filename = os.path.join(head, augmented_tail)
output_image.save(save_filename)
if __name__ == '__main__':
import sys
arguments = sys.argv[1:]
if arguments:
scramble(*arguments[:3])
else:
print('\n'
'Arguments:\n'
' input image (required)\n'
' key image (optional, default None)\n'
' number of regions '
'(optional maximum - will be as high as practical otherwise)\n')
Ghi hình ảnh JPEG
Các tập tin .jpg được xử lý rất nhanh, nhưng với chi phí chạy quá nóng. Điều này để lại một hình ảnh bị cháy sau khi bản gốc được khôi phục:
Nhưng nghiêm túc, một định dạng bị mất sẽ dẫn đến một số màu pixel bị thay đổi một chút, chính điều đó làm cho đầu ra không hợp lệ. Khi một hình ảnh quan trọng được sử dụng và việc xáo trộn các pixel bị giới hạn ở các vùng, tất cả các biến dạng được giữ trong vùng mà nó xảy ra, và sau đó trải đều trên vùng đó khi hình ảnh được khôi phục. Sự khác biệt về độ méo trung bình giữa các vùng để lại sự khác biệt có thể nhìn thấy giữa chúng, vì vậy các vùng được sử dụng trong quá trình xáo trộn vẫn có thể nhìn thấy trong hình ảnh được khôi phục.
Chuyển đổi sang .png (hoặc bất kỳ định dạng không mất dữ liệu nào) trước khi xáo trộn đảm bảo rằng hình ảnh không bị xáo trộn giống hệt với bản gốc mà không bị cháy hoặc biến dạng:
Chi tiết nhỏ
- Kích thước tối thiểu 256 pixel được áp đặt cho các vùng. Nếu hình ảnh được phép chia thành các vùng quá nhỏ, thì hình ảnh gốc vẫn có thể được nhìn thấy một phần sau khi xáo trộn.
- Nếu có nhiều hơn một vùng có số pixel lẻ thì một pixel từ vùng thứ hai sẽ được gán lại cho vùng thứ nhất, v.v. Điều này có nghĩa là chỉ có thể có một vùng có số pixel lẻ và do đó, chỉ một pixel sẽ vẫn bị xáo trộn.
- Có một đối số tùy chọn thứ ba giới hạn số lượng vùng. Đặt cài đặt này thành 2 chẳng hạn sẽ cho hai hình ảnh được xáo trộn. Điều này có thể trông tốt hơn hoặc xấu hơn tùy thuộc vào hình ảnh liên quan. Nếu một số được chỉ định ở đây, hình ảnh chỉ có thể được khôi phục bằng cách sử dụng lại cùng một số đó.
- Số lượng màu sắc riêng biệt trong ảnh gốc cũng giới hạn số lượng vùng. Nếu hình ảnh gốc là hai tông màu thì bất kể hình ảnh chính hay đối số thứ ba, chỉ có thể có tối đa 2 vùng.