Görüntüyü 4 KiB önizlemesine sıkıştır


30

Bu meydan okumada, bir görüntü önizleme sıkıştırma algoritması oluşturacaksınız. Amacı, çok az bant genişliğine sahip görüntüleri hızlı bir şekilde tanımlamak için kullanılabilen rastgele bir görüntü dosyasını 4 KiB önizleme görüntüsüne indirmektir.

İki program yazmalısınız (veya bir birleşik program): bir kompresör ve bir dekompresör. Her ikisi de bir dosyayı almak veya girdi olarak stdin almak ve bir dosyaya veya stdout'a çıktı almak zorundadır. Kompresör, bir ana kayıpsız görüntü seçim biçiminde (örneğin PNG, BMP, PPM) bir görüntüyü kabul etmeli ve en fazla 4096 baytlık bir dosya çıkarmalıdır . Dekompresör, kompresör tarafından oluşturulan herhangi bir dosyayı kabul etmeli ve girdiye mümkün olduğu kadar yakın bir görüntü çıkarmalıdır. Kodlayıcı / kod çözücü için kaynak kod boyutu sınırı olmadığını unutmayın, böylece algoritmada yaratıcı olabilirsiniz.

Kısıtlamalar:

  • Hile yok'. Programlarınız gizli girişleri kullanmayabilir, internette veri depolamaya vb. İzin vermeyebilir. Yalnızca puanlama görüntüleri grubuyla ilgili özellikleri / verileri eklemeniz de yasaktır.

  • Kütüphaneler / araç / Ankastre için, olan kullanmasına izin jenerik (ölçekleme, bulanık, renk uzayı dönüşümü, vs) görüntü işleme operasyonları, ama değil görüntü çözme / kodlama / sıkıştırma (kompresör giriş ve çıkış açıcı hariç) işlemleri. Genel sıkıştırma / açma işlemine de izin verilmez . Bu zorluk için kendi sıkıştırmanızı uygulamanız amaçlanmıştır.

  • Dekompresör tarafından çıkarılan görüntünün boyutları tam olarak kompresöre verilen orijinal dosyanınkilerle aynı olmalıdır. Görüntü boyutlarının her iki yönde 2 16'yı geçmediğini varsayabilirsiniz .

  • Kompresörünüz ortalama bir tüketici PC'sinde 5 dakikadan daha az bir sürede çalışmalı ve dekompresör aşağıdaki setteki herhangi bir görüntü için 10 saniyenin altında çalışmalıdır.

puanlama

Hızlı doğrulama ve görsel karşılaştırmaya yardımcı olmak için lütfen cevabınızı kullanarak sıkıştırma sonrasında test corpus'un kayıpsız bir resim albümünü ekleyin.

Kompresörünüz aşağıdaki görüntü koruyucusu kullanılarak test edilecektir :

yıldızlı kaynak oda gökkuşağı
kenar lama çocuk julia

Sen bir zip dosyası tüm görüntüleri indirebilirsiniz burada .

Puanınız tüm görüntülerde kompresörünüzün ortalama yapısal benzerlik endeksi olacaktır. dssimBu sorunu çözmek için açık kaynağı kullanacağız . Kolayca kaynaktan inşa edilir veya Ubuntu'daysanız PPA'sı da vardır. Kendi cevabınızı puanlarsanız tercih edilir, ancak C uygulamalarını nasıl oluşturacağınızı bilmiyorsanız ve Debian / Ubuntu'yu çalıştırmazsanız, başkalarının sizin için puan vermesine izin verebilirsiniz. dssimPNG'de girdi / çıktı beklediğinden, farklı bir biçimde çıktı alırsanız önce çıktınızı PNG'ye dönüştürün.

Puanlamayı acısız hale getirmek için işte size hızlı bir yardımcı Python komut dosyası kullanın python score.py corpus_dir compressed_dir:

import glob, sys, os, subprocess

scores = []
for img in sorted(os.listdir(sys.argv[1])):
    ref, preview = (os.path.join(sys.argv[i], img) for i in (1, 2))
    sys.stdout.write("Comparing {} to {}... ".format(ref, preview))
    out = subprocess.check_output(["dssim", ref, preview]).decode("utf-8").split()[0]
    print(out)
    scores.append(float(out))

print("Average score: {:.6f}".format(sum(scores) / len(scores)))

En düşük puan kazanır.


sıkıştırılmış resmin görüntülenebilir olması gerekiyor mu?
Eumel

2
@Eumel Dekompresörü bir izleyici olarak düşünebilirsiniz. Yani hayır, sıkıştırılmış formatınız keyfi olabilir ve tamamen size bağlıdır. Sadece dekompresyondan sonra görüntülenebilir bir görüntünün çıkması gerekir.
orlp

7
You may assume that the image dimensions do not exceed 2^32 in either direction.Bu biraz aşırı değil mi? Bu, bir çift (x, y) koordinatını depolamak için 16 bayt kullanmam gerektiği anlamına gelir. Çok az resim dosyası, her iki yönde 2 ^ 16 (65536) pikselden daha büyük boyutlara sahip ve 2 ^ 11, korpustaki tüm resimler için yeterli.
Peter Olson

@PeterOlson olarak değiştireceğim 2^16.
orlp

@ orlp Kurallar, bir görüntüyü çözmek için açma işleminin on saniyeden daha kısa sürmesi gerektiğini belirtir. Sahip olduğum fikir, daha sonra dekompresöre yapılan aramalarda kullanılacak referans dosyalarını oluşturmak için birkaç dakika sürecektir. yani bir uygulamanın "kurulmasına" benzer bir seferlik bir faaliyettir. Bu çözüm diskalifiye olur mu?
Moogie,

Yanıtlar:


8

PIL ile Python, puan 0.094218

Kompresör:

#!/usr/bin/env python
from __future__ import division
import sys, traceback, os
from PIL import Image
from fractions import Fraction
import time, io

def image_bytes(img, scale):
    w,h = [int(dim*scale) for dim in img.size]
    bio = io.BytesIO()
    img.resize((w,h), Image.LANCZOS).save(bio, format='PPM')
    return len(bio.getvalue())

def compress(img):
    w,h = img.size
    w1,w2 = w // 256, w % 256
    h1,h2 = h // 256, h % 256
    n = w*h
    total_size = 4*1024 - 8 #4 KiB minus 8 bytes for
                            # original and new sizes
    #beginning guess for the optimal scaling
    scale = Fraction(total_size, image_bytes(img, 1))
    #now we do a binary search for the optimal dimensions,
    # with the restriction that we maintain the scale factor
    low,high = Fraction(0),Fraction(1)
    best = None
    start_time = time.time()
    iter_count = 0
    while iter_count < 100: #scientifically chosen, not arbitrary at all
        #make sure we don't take longer than 5 minutes for the whole program
        #10 seconds is more than reasonable for the loading/saving
        if time.time() - start_time >= 5*60-10:
            break
        size = image_bytes(img, scale)
        if size > total_size:
            high = scale
        elif size < total_size:
            low = scale
            if best is None or total_size-size < best[1]:
                best = (scale, total_size-size)
        else:
            break
        scale = (low+high)/2
        iter_count += 1
    w_new, h_new = [int(dim*best[0]) for dim in (w,h)]
    wn1,wn2 = w_new // 256, w_new % 256
    hn1, hn2 = h_new // 256, h_new % 256
    i_new = img.resize((w_new, h_new), Image.LANCZOS)
    bio = io.BytesIO()
    i_new.save(bio, format='PPM')
    return ''.join(map(chr, (w1,w2,h1,h2,wn1,wn2,hn1,hn2))) + bio.getvalue()

if __name__ == '__main__':
    for f in sorted(os.listdir(sys.argv[1])):
        try:
            print("Compressing {}".format(f))
            with Image.open(os.path.join(sys.argv[1],f)) as img:
                with open(os.path.join(sys.argv[2], f), 'wb') as out:
                    out.write(compress(img.convert(mode='RGB')))
        except:
            print("Exception with {}".format(f))
            traceback.print_exc()
            continue

Açıcı:

#!/usr/bin/env python
from __future__ import division
import sys, traceback, os
from PIL import Image
from fractions import Fraction
import io

def process_rect(rect):
    return rect

def decompress(compressed):
    w1,w2,h1,h2,wn1,wn2,hn1,hn2 = map(ord, compressed[:8])
    w,h = (w1*256+w2, h1*256+h2)
    wc, hc = (wn1*256+wn2, hn1*256+hn2)
    img_bytes = compressed[8:]
    bio = io.BytesIO(img_bytes)
    img = Image.open(bio)
    return img.resize((w,h), Image.LANCZOS)


if __name__ == '__main__':
    for f in sorted(os.listdir(sys.argv[1])):
        try:
            print("Decompressing {}".format(f))
            with open(os.path.join(sys.argv[1],f), 'rb') as img:
                decompress(img.read()).save(os.path.join(sys.argv[2],f))
        except:
            print("Exception with {}".format(f))
            traceback.print_exc()
            continue

Her iki komut dosyası da iki dizin (giriş ve çıkış) olarak komut satırı argümanları üzerinden girdi alır ve girdi dizinindeki tüm görüntüleri dönüştürür.

Buradaki fikir, 4 KiB'in altına uyan ve orijinal ile aynı en boy oranına sahip bir boyut bulmak ve aşağı örneklenen görüntüden mümkün olduğunca yüksek kalitede elde etmek için bir Lanczos filtresi kullanmaktır.

Orijinal boyutlarına göre yeniden boyutlandırıldıktan sonra sıkıştırılmış resimlerin imgur albümü

Puanlama komut dosyası çıktısı:

Comparing corpus/1 - starry.png to test/1 - starry.png... 0.159444
Comparing corpus/2 - source.png to test/2 - source.png... 0.103666
Comparing corpus/3 - room.png to test/3 - room.png... 0.065547
Comparing corpus/4 - rainbow.png to test/4 - rainbow.png... 0.001020
Comparing corpus/5 - margin.png to test/5 - margin.png... 0.282746
Comparing corpus/6 - llama.png to test/6 - llama.png... 0.057997
Comparing corpus/7 - kid.png to test/7 - kid.png... 0.061476
Comparing corpus/8 - julia.png to test/8 - julia.png... 0.021848
Average score: 0.094218

Çözümünüzün izin verilmeyen WebP kullandığını fark ettim. Çözümün geçersiz.
orlp

@orlp Sıkıştırılmamış bir format olan PPM'yi kullanmak için şimdi düzeltildi.
Mego

Peki. Bu zorluk olsa da, DSSIM'in biraz zayıflığını ortaya koyuyor. Moogie'nin resimlerinin çoğunun daha iyi göründüğünü savunuyorum.
orlp

@orlp Küçük resimler olarak iyi görünüyorlar. Orijinal boyutlarına kadar şişirildiğinde (Lanczos kullanarak), aynı kalitede veya daha kötü görünüyorlar. Çıktımın küçük resimlerinin yüklenmesini sağlamak için çalışıyorum.
Mego

7

Java (vanilya, java 1.5+ ile çalışması gerekir), puan 0.672

Özellikle iyi dssim skorları üretmiyor ama gözüme daha insan dostu görüntüler üretiyor ...

yıldızlı kaynak oda gökkuşağı
kenar lama çocuk julia

Albüm: http://imgur.com/a/yL31U

Puanlama komut dosyası çıktısı:

Comparing corpus/1 - starry.png to test/1 - starry.png... 2.3521
Comparing corpus/2 - source.png to test/2 - source.png... 1.738
Comparing corpus/3 - room.png to test/3 - room.png... 0.1829
Comparing corpus/4 - rainbow.png to test/4 - rainbow.png... 0.0633
Comparing corpus/5 - margin.png to test/5 - margin.png... 0.4224
Comparing corpus/6 - llama.png to test/6 - llama.png... 0.204
Comparing corpus/7 - kid.png to test/7 - kid.png... 0.36335
Comparing corpus/8 - julia.png to test/8 - julia.png... 0.05
Average score: 0.672

Sıkıştırma zinciri:

1. if filter data has already been generated goto step 6
2. create sample images from random shapes and colours
3. take sample patches from these sample images
4. perform k-clustering of patches based on similarity of luminosity and chomanosity.
5. generate similarity ordered lists for each patch as compared to the other patches.
6. read in image
7. reduce image size to current multiplier * blocksize
8. iterate over image comparing each blocksize block against the list of clustered luminosity patches and chromanosity patches, selecting the closest match
9. output the index of the closet match from the similarity ordered list (of the previous block) (repeat 8 for chromanosity)
10. perform entropy encoding using deflate.
11. if output size is < 4096 bytes then increment current multiplier and repeat step 7
12. write previous output to disk.

Sıkıştırmak için, şişirmek ve blok indekslerini okumak ve ilgili yamayı çıkış dosyasına çıkarmak, ardından orijinal boyutlara yeniden boyutlandırmak.

Maalesef kod yığın akışı için çok büyük olduğundan https://gist.github.com/anonymous/989ab8a1bb6ec14f6ea9 adresinde bulunabilir.

Koşmak:

Usage: 
       For single image compression: java CompressAnImageToA4kibPreview -c <INPUT IMAGE> [<COMPRESSED IMAGE>]
       For multiple image compression: java CompressAnImageToA4kibPreview -c <INPUT IMAGES DIR> [<COMPRESSED IMAGE DIR>]
       For single image decompression: java CompressAnImageToA4kibPreview -d <COMPRESSED IMAGE> [<DECOMPRESSED IMAGE>
       For multiple image decompression: java CompressAnImageToA4kibPreview -d <COMPRESSED IMAGE DIR> [<DECOMPRESSED IMAGES DIR>]

If optional parameters are not set then defaults will be used:
       For single image compression, compressed image will be created in same directory are input image and have '.compressed' file extension.
       For multiple image compression, compressed images will be created in a new 'out' sub directory of <INPUT IMAGES DIR> and have '.compressed' file extensions.
       For single image decompression, decompressed image will be created in same directory are input image and have '.out.png' file extension.
       For multiple image decompression, decompressed images will be created a new 'out' sub directory of <COMPRESSED IMAGE DIR> and have '.png' file extensions.

Bu uygulama ilk çalıştırıldığında, gerekli dosyalar çalıştırma çalışma dizinine göre bir dizinde oluşturulur ve kaydedilir. Bu bir kaç dakika alabilir. Daha sonraki işlemler için bu adımın gerçekleştirilmesi gerekmez.


Bu harika görünüyor. Sadece onaylamak için, 1-6 arası adımlar corpus'a hiç güvenmiyor mu? Ayrıca, bunun yerine kodunuzu gist.github.com adresinde yeniden barındırmamın sakıncası var mı?
orlp

Doğru, hiçbir korpus dosyasını giriş olarak kullanmaz. "OUTPUT_SAMPLE_IMAGES" sabitini true olarak değiştirerek satın aldığınız yamaları üretmek için oluşturduğu görüntüleri görebilirsiniz. Bu görüntüleri çalışma klasörüne çıkaracak: data / images / working /
Moogie

@orlp şimdi gist.github kullanıyor
Moogie 11

Sonuçlar çarpıcı, ancak deflate / şişirmek kullanmak, genel sıkıştırma / dekompresyona izin vermeme kuralını bozmaz mı?
algmyr

@algmyr Uzun zaman oldu, ama genel sıkıştırma kuralını genel 'görüntü' sıkıştırması yok ... yani jpeg, vb. olarak yorumladığımı düşünüyorum. Ama bu yanlış, belki de evet, bu başvuru diskalifiye edilmelidir.
Moogie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.