Python 3.4
- Bonus 1: Kendi kendine ters: yinelenen orijinal görüntüyü geri yükler.
- İsteğe bağlı anahtar görüntü: orijinal görüntü yalnızca aynı anahtar görüntü kullanılarak yeniden yüklenebilir.
- Bonus 2: Çıktıda model üretmek: şifrelenmiş piksellerde ana görüntü yaklaşıkdır.
Bonus 2'ye ulaşıldığında, ilave bir anahtar görüntü kullanarak, bonus 1 kaybedilmez. Yine aynı tuş görüntüsü ile çalıştırılması şartıyla program hala kendi kendine ters.
Standart kullanım
Test görüntüsü 1:
Test görüntüsü 2:
Programı argüman olarak tek bir görüntü dosyasıyla çalıştırmak, görüntü dosyasını tüm görüntünün üzerine eşit şekilde karıştırılmış olarak kaydeder. Tekrar karıştırılmış çıktıyla çalıştırmak, tekrar uygulanan karıştırmayla bir görüntü dosyasını kaydeder; bu, yeniden karıştırma işlemi kendi tersi olduğundan orijinali geri yükler.
Çırpma işlemi kendi kendine terstir, çünkü tüm piksellerin listesi 2 çevrime ayrılır, böylece her piksel bir ve yalnızca bir pikselle değiştirilir. İkinci kez çalıştırma, her pikseli ilk olarak değiştirildiği pikselle değiştirerek her şeyi nasıl başladığına geri döndürür. Tek sayıda piksel varsa, hareket etmeyen bir piksel olacaktır.
Sayesinde mfvonh cevabı ilk olarak 2-döngüleri önermek.
Anahtar görüntü ile kullanım
Scrambling Test görüntüsü 1 ile Test görüntüsü 2 ile anahtar görüntü olarak
Scrambling Test görüntüsü 2 Test görüntüsü 1 ile anahtar görüntü olarak
Programı ikinci bir görüntü dosyası argümanı (anahtar görüntü) ile çalıştırmak, orijinal görüntüyü anahtar görüntüye göre bölgelere ayırır. Bu bölgelerin her biri ayrı ayrı 2-çevrime bölünmüştür, böylece çırpma işleminin tamamı bölgeler içinde gerçekleşir ve pikseller bir bölgeden diğerine taşınmaz. Bu, pikselleri her bölgeye yayar ve böylelikle bölgeler düzgün bir benekli renk olur, ancak her bölge için biraz farklı bir ortalama renge sahiptir. Bu, yanlış görüntünün yanlış renklerde çok kaba bir şekilde tahmin edilmesini sağlar.
Tekrar çalıştırmak, her bölgedeki aynı piksel çiftlerini değiştirir, böylece her bölge orijinal durumuna geri yüklenir ve görüntü bir bütün olarak yeniden belirir.
Görüntüyü bölgelere ayırmayı öneren ilk olarak edc65'in cevabı sayesinde . Keyfi bölgeleri kullanmak için bunu genişletmek istedim, ancak bölge 1'deki her şeyi bölge 2'deki her şeyle değiştirme yaklaşımı, bölgelerin aynı büyüklükte olması gerektiği anlamına geliyordu. Benim çözümüm bölgeleri birbirinden yalıtılmış tutmak ve her bölgeyi kendi içine karıştırmak. Bölgelerin artık benzer boyutta olmaları gerekmediğinden, isteğe bağlı şekilli bölgelerin uygulanması daha kolay hale gelir.
kod
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')
JPEG görüntü yazma
.jpg dosyaları çok hızlı bir şekilde işleniyor, ancak çok sıcak çalıştırma pahasına. Bu, orijinal geri yüklendiğinde görüntüden sonra yanık bırakıyor:
Ancak cidden, kayıplı bir format bazı piksel renklerinin hafifçe değişmesine neden olur ve bu da kendi başına çıktıyı geçersiz kılar. Bir anahtar görüntü kullanıldığında ve piksellerin karıştırılması bölgelere sınırlandırıldığında, tüm bozulma gerçekleştiği bölgede tutulur ve ardından görüntü geri yüklendiğinde bu bölgeye eşit şekilde yayılır. Bölgeler arasındaki ortalama bozulma farkı, aralarında gözle görülür bir fark bırakır, bu nedenle karıştırma işleminde kullanılan bölgeler geri yüklenen görüntüde görünmeye devam eder.
Çırpmadan önce .png'ye (veya kayıpsız herhangi bir biçime) dönüştürmek, şifrelenmemiş görüntünün, yanma veya bozulma olmadan orijinaliyle aynı olmasını sağlar:
Küçük detaylar
- Bölgelere asgari boyutta 256 piksel uygulanır. Görüntünün çok küçük bölgelere bölünmesine izin verilirse, orijinal görüntü karıştırıldıktan sonra hala kısmen görünebilir.
- Tek sayıda piksel içeren birden fazla bölge varsa, ikinci bölgeden bir piksel birinciye atanır vb. Bunun anlamı, tek sayıda piksel içeren yalnızca bir bölgenin olabileceği ve bu nedenle yalnızca bir pikselin şifrelenmemiş kalacağı anlamına gelir.
- Bölge sayısını kısıtlayan üçüncü bir isteğe bağlı argüman vardır. Bunu 2'ye ayarlamak örneğin, iki tonlu karıştırılmış görüntü verecektir. İlgili görüntülere bağlı olarak bu daha iyi veya daha kötü görünebilir. Burada bir numara belirtilirse, görüntü yalnızca aynı numara kullanılarak tekrar geri yüklenebilir.
- Orijinal görüntüdeki farklı renklerin sayısı, bölge sayısını da sınırlar. Orijinal resim iki ton ise, o zaman ana resim veya üçüncü argüman ne olursa olsun, yalnızca en fazla 2 bölge olabilir.