บีบอัดภาพเพื่อแสดงตัวอย่าง 4 KiB


30

ในการท้าทายนี้คุณจะต้องสร้างอัลกอริทึมการบีบอัดภาพตัวอย่าง เป้าหมายคือเพื่อลดไฟล์ภาพที่กำหนดเองไปเป็นภาพตัวอย่างขนาด 4 KiB ซึ่งสามารถใช้เพื่อระบุรูปภาพที่มีแบนด์วิดท์น้อยมากได้อย่างรวดเร็ว

คุณต้องเขียนโปรแกรมสองโปรแกรม (หรือโปรแกรมที่รวมกันหนึ่งโปรแกรม): คอมเพรสเซอร์และตัวขยายการบีบอัด ทั้งสองต้องใช้ไฟล์หรือ stdin เป็นอินพุตและเอาต์พุตไปยังไฟล์หรือ stdout คอมเพรสเซอร์ต้องยอมรับภาพหนึ่งภาพในรูปแบบภาพหลัก lossless ของทางเลือก (เช่น PNG, BMP, PPM) และเอาท์พุทไฟล์ของที่มากที่สุด 4096 ไบต์ ตัวขยายการบีบอัดจะต้องยอมรับไฟล์ใด ๆ ที่สร้างโดยคอมเพรสเซอร์และส่งภาพออกให้ใกล้เคียงที่สุดกับอินพุต โปรดทราบว่าไม่มีการ จำกัด ขนาดซอร์สโค้ดสำหรับตัวเข้ารหัส / ตัวถอดรหัสดังนั้นคุณสามารถสร้างสรรค์ในอัลกอริทึมของคุณ

ข้อ จำกัด :

  • ไม่มีการโกง'. โปรแกรมของคุณอาจไม่ใช้อินพุตที่ซ่อนอยู่การจัดเก็บข้อมูลบนอินเทอร์เน็ต ฯลฯ นอกจากนี้คุณยังถูกห้ามไม่ให้รวมคุณลักษณะ / ข้อมูลที่เกี่ยวข้องกับชุดภาพการให้คะแนนเท่านั้น

  • สำหรับห้องสมุด / เครื่องมือ / built-ins ที่คุณจะได้รับอนุญาตให้ใช้ทั่วไปการดำเนินงานการประมวลผลภาพ (ปรับเบลอสีเปลี่ยนแปลงพื้นที่ ฯลฯ ) แต่ไม่ได้ภาพถอดรหัส / เข้ารหัส / การบีบอัดการดำเนินงาน (ยกเว้นสำหรับการป้อนข้อมูลคอมเพรสเซอร์และการส่งออกขยายการบีบอัด) ทั่วไปการบีบอัด decompression / ยังไม่ได้รับอนุญาต มีวัตถุประสงค์เพื่อให้คุณใช้การบีบอัดของคุณเองสำหรับความท้าทายนี้

  • ขนาดของเอาต์พุตภาพโดยตัวขยายการบีบอัดจะต้องตรงกับขนาดของไฟล์ต้นฉบับที่กำหนดให้กับคอมเพรสเซอร์ คุณอาจคิดว่าขนาดภาพไม่เกิน 2 16ในทิศทางใดทิศทางหนึ่ง

  • คอมเพรสเซอร์ของคุณต้องทำงานบนพีซีสำหรับผู้บริโภคโดยเฉลี่ยในเวลาไม่เกิน 5 นาทีและตัวบีบอัดจะต้องทำงานภายใน 10 วินาทีสำหรับภาพใด ๆ ในชุดด้านล่าง

เกณฑ์การให้คะแนน

เพื่อช่วยในการตรวจสอบและเปรียบเทียบอย่างรวดเร็วโปรดใส่อัลบั้มภาพที่ไม่มีการสูญเสียของคลังข้อมูลการทดสอบหลังจากการบีบอัดโดยใช้คำตอบของคุณ

คอมเพรสเซอร์ของคุณจะถูกทดสอบโดยใช้คลังภาพต่อไปนี้:

แจ่มจรัส แหล่ง ห้อง รุ้ง
ขอบ สัตว์สี่เท้าชนิดหนึ่ง เด็ก จูเลีย

คุณสามารถดาวน์โหลดภาพทั้งหมดใน zip ไฟล์ที่นี่

คะแนนของคุณจะเป็นดัชนีความคล้ายคลึงโครงสร้างโดยเฉลี่ยสำหรับคอมเพรสเซอร์ของคุณในภาพทั้งหมด เราจะใช้โอเพ่นซอร์สdssimสำหรับความท้าทายนี้ มันถูกสร้างขึ้นจากแหล่งที่มาได้อย่างง่ายดายหรือถ้าคุณอยู่บน Ubuntu ก็มี PPA เป็นที่ต้องการถ้าคุณให้คะแนนคำตอบของคุณเอง แต่ถ้าคุณไม่รู้วิธีสร้างแอปพลิเคชั่น C และคุณไม่ได้ใช้ Debian / Ubuntu คุณสามารถให้คนอื่นทำคะแนนให้คุณได้ dssimคาดว่าอินพุต / เอาต์พุตใน PNG ดังนั้นแปลงผลลัพธ์ของคุณเป็น PNG ก่อนหากคุณส่งออกในรูปแบบอื่น

เพื่อให้คะแนนที่ไม่เจ็บปวดนี่เป็นสคริปต์ Python ช่วยเหลือด่วนการใช้งาน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)))

คะแนนต่ำสุดชนะ


รูปภาพที่บีบอัดต้องดูได้ไหม
Eumel

2
@Eumel คุณสามารถพิจารณา decompressor เป็นตัวแสดง ดังนั้นรูปแบบการบีบอัดของคุณอาจไม่แน่นอนและขึ้นอยู่กับคุณทั้งหมด หลังจากคลายการบีบอัดภาพที่สามารถดูได้จะต้องออกมา
orlp

7
You may assume that the image dimensions do not exceed 2^32 in either direction.นี่มันน้อยไปหน่อยเหรอ? ซึ่งหมายความว่าฉันต้องใช้ถึง 16 ไบต์เพื่อจัดเก็บพิกัด (x, y) คู่ ไฟล์รูปภาพบางไฟล์มีขนาดมากกว่า 2 ^ 16 (65536) พิกเซลในทิศทางใดทิศทางหนึ่งและ 2 ^ 11 เพียงพอสำหรับรูปภาพทั้งหมดในคลังข้อมูล
Peter Olson

@PeterOlson 2^16ฉันจะเปลี่ยนไป
orlp

@orlp กฎระบุว่าตัวขยายการบีบอัดต้องใช้เวลาน้อยกว่าสิบวินาทีในการถอดรหัสภาพ ความคิดที่ฉันมีอาจใช้เวลาสองสามนาทีเพื่อสร้างไฟล์อ้างอิงที่จะใช้ในการเรียกไปยังตัวขยายการบีบอัดที่ตามมา นั่นคือเป็นกิจกรรมปิดครั้งเดียวคล้ายกับ "การติดตั้ง" แอปพลิเคชัน โซลูชันนี้จะถูกตัดสิทธิ์หรือไม่
Moogie

คำตอบ:


8

Python กับ PIL คะแนน 0.094218

คอมเพรสเซอร์:

#!/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

decompressor:

#!/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

สคริปต์ทั้งสองรับอินพุตผ่านอาร์กิวเมนต์บรรทัดคำสั่งเนื่องจากเป็นสองไดเร็กทอรี (อินพุตและเอาต์พุต) และแปลงรูปภาพทั้งหมดในไดเร็กทอรีอินพุต

แนวคิดคือการหาขนาดที่เหมาะสมต่ำกว่า 4 KiB และมีอัตราส่วนกว้างยาวเหมือนต้นฉบับและใช้ตัวกรอง Lanczos เพื่อให้ได้ภาพที่มีคุณภาพต่ำที่สุดเท่าที่เป็นไปได้

อัลบั้ม Imgur ของภาพที่บีบอัดหลังจากปรับขนาดเป็นขนาดดั้งเดิม

เกณฑ์การให้คะแนนเอาต์พุตสคริปต์:

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

ฉันเพิ่งรู้ว่าโซลูชันของคุณใช้ WebP ซึ่งไม่ได้รับอนุญาต โซลูชันของคุณไม่ถูกต้อง
orlp

@ orlp ตอนนี้ได้รับการแก้ไขแล้วให้ใช้ PPM ซึ่งเป็นรูปแบบที่ไม่มีการบีบอัด
Mego

Alright ความท้าทายนี้ทำให้ DSSIM มีจุดอ่อนเล็กน้อย ฉันจะยืนยันว่าภาพส่วนใหญ่ของ Moogie ดูดีขึ้นอย่างมาก
orlp

@orlp พวกเขาดูดีเป็นภาพขนาดย่อ เมื่อปลิวไปจนถึงขนาดดั้งเดิม (โดยใช้ Lanczos) พวกเขามองคุณภาพเดียวกันหรือแย่กว่านั้น ฉันกำลังทำงานเพื่อรับภาพขนาดย่อของผลลัพธ์ที่ฉันอัปโหลด
Mego

7

Java (วานิลลาควรทำงานกับ java 1.5+) คะแนน 0.672

มันไม่ได้สร้างคะแนน dssim ที่ดีเป็นพิเศษ แต่ในสายตาของฉันมันสร้างภาพที่เป็นมิตรกับมนุษย์มากขึ้น ...

แจ่มจรัส แหล่ง ห้อง รุ้ง
ขอบ สัตว์สี่เท้าชนิดหนึ่ง เด็ก จูเลีย

อัลบั้ม: http://imgur.com/a/yL31U

เกณฑ์การให้คะแนนเอาต์พุตสคริปต์:

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

ห่วงโซ่การบีบอัด:

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.

หากต้องการคลายบีบอัดให้ขยายแล้วอ่านดัชนีบล็อกและส่งออกแพทช์ที่สอดคล้องกับไฟล์เอาต์พุตจากนั้นปรับขนาดให้เป็นขนาดดั้งเดิม

น่าเสียดายที่รหัสมีขนาดใหญ่เกินไปสำหรับ stackoverflow ดังนั้นสามารถดูได้ที่https://gist.github.com/anonymous/989ab8a1bb6ec14f6ea9

วิ่ง:

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.

ครั้งแรกที่แอปพลิเคชันนี้ทำงานไฟล์ที่จำเป็นจะถูกสร้างและบันทึกในไดเรกทอรีที่สัมพันธ์กับการทำงานของ dir นี้อาจใช้เวลาไม่กี่นาที. สำหรับการประมวลผลที่ตามมาขั้นตอนนี้จะไม่จำเป็นต้องดำเนินการ


มันดูน่าทึ่งมาก เพียงเพื่อยืนยันขั้นตอนที่ 1-6 ไม่ต้องพึ่งพาคลังเลย นอกจากนี้คุณจะรังเกียจไหมถ้าฉันใส่รหัสใน gist.github.com แทน?
orlp

ถูกต้องไม่ใช้ไฟล์คลังข้อมูลใด ๆ เป็นอินพุต คุณสามารถเห็นภาพที่สร้างขึ้นเพื่อสร้างแพทช์ซื้อเปลี่ยนค่าคงที่ "OUTPUT_SAMPLE_IMAGES" เป็นจริง มันจะส่งออกภาพเหล่านี้ไปยังโฟลเดอร์การทำงาน: data / images / working /
Moogie

@orlp ตอนนี้ใช้ gist.github
Moogie

ผลลัพธ์เป็นสิ่งที่น่าทึ่ง แต่ไม่ได้ใช้การยุบ / ขยายแบบผิดกฎเกี่ยวกับการไม่อนุญาตให้ใช้การบีบอัด / การคลายการบีบอัดทั่วไปใช่ไหม
algmyr

@algmyr มันผ่านมาซักพักแล้ว แต่ฉันคิดว่าฉันตีความกติกาทั่วไปของการบีบอัดที่ไม่มีความหมายว่าไม่มีการบีบอัด 'image' ทั่วไป ... เช่น jpeg เป็นต้น แต่ฉันอาจตีความว่าไม่ถูกต้องซึ่งในกรณีนี้ใช่นี่ การส่งข้อมูลควรถูกทำให้เป็นของเหลว
Moogie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.