Nén hình ảnh vào bản xem trước 4 KiB


30

Trong thử thách này, bạn sẽ tạo ra một thuật toán nén xem trước hình ảnh. Mục tiêu của nó là giảm một tệp hình ảnh tùy ý thành hình ảnh xem trước 4 KiB, có thể được sử dụng để nhanh chóng xác định hình ảnh với rất ít băng thông.

Bạn phải viết hai chương trình (hoặc một chương trình kết hợp): máy nén và bộ giải nén. Cả hai phải lấy một tệp hoặc stdin làm đầu vào và xuất ra tệp hoặc thiết bị xuất chuẩn. Máy nén phải chấp nhận một hình ảnh ở định dạng hình ảnh không mất dữ liệu chính (ví dụ PNG, BMP, PPM) và xuất ra một tệp có tối đa 4096 byte . Bộ giải nén phải chấp nhận bất kỳ tệp nào do máy nén tạo ra và xuất ra một hình ảnh càng gần với đầu vào. Lưu ý rằng không có giới hạn kích thước mã nguồn cho bộ mã hóa / giải mã, vì vậy bạn có thể sáng tạo trong thuật toán của mình.

Hạn chế:

  • Không gian lận'. Các chương trình của bạn không được sử dụng các đầu vào ẩn, lưu trữ dữ liệu trên internet, v.v. Bạn cũng bị cấm chỉ bao gồm các tính năng / dữ liệu liên quan đến bộ ảnh ghi điểm.

  • Đối với thư viện / công cụ / tích hợp, bạn được phép sử dụng các hoạt động xử lý ảnh chung (chia tỷ lệ, làm mờ, chuyển đổi không gian màu, v.v.), nhưng không phải là hoạt động giải mã / mã hóa / nén hình ảnh (ngoại trừ đầu vào máy nén và đầu ra bộ giải nén). Nén / giải nén chung cũng không được phép . Dự định là bạn sẽ tự thực hiện nén cho thử thách này.

  • Kích thước của đầu ra hình ảnh của bộ giải nén phải khớp chính xác với kích thước của tệp gốc được cung cấp cho máy nén. Bạn có thể cho rằng kích thước hình ảnh không vượt quá 2 16 theo một trong hai hướng.

  • Máy nén của bạn phải chạy trên PC tiêu dùng trung bình dưới 5 phút và bộ giải nén phải chạy dưới 10 giây cho bất kỳ hình ảnh nào trong bộ bên dưới.

Chấm điểm

Để giúp xác minh nhanh chóng và so sánh trực quan, vui lòng bao gồm một album hình ảnh không mất dữ liệu của kho kiểm tra sau khi nén bằng câu trả lời của bạn.

Máy nén của bạn sẽ được kiểm tra bằng cách sử dụng sau đây corpus của hình ảnh :

đầy sao nguồn phòng cầu vồng
lề llama đứa trẻ julia

Bạn có thể tải xuống tất cả các hình ảnh trong một tệp zip ở đây .

Điểm của bạn sẽ là chỉ số tương tự cấu trúc trung bình cho máy nén của bạn trên tất cả các hình ảnh. Chúng tôi sẽ sử dụng nguồn mở dssimcho thử thách này. Nó dễ dàng được xây dựng từ nguồn hoặc nếu bạn đang sử dụng Ubuntu thì nó cũng có PPA. Được ưu tiên nếu bạn chấm điểm câu trả lời của riêng bạn, nhưng nếu bạn không biết cách xây dựng các ứng dụng C và bạn không chạy Debian / Ubuntu, bạn có thể để người khác chấm điểm cho mình. dssimmong đợi đầu vào / đầu ra ở PNG, vì vậy hãy chuyển đổi đầu ra của bạn thành PNG trước nếu bạn xuất ở định dạng khác.

Để làm cho việc ghi điểm không gây đau đớn, đây là tập lệnh trợ giúp nhanh của Python, cách sử dụng 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)))

Điểm số thấp nhất chiến thắng.


hình ảnh nén có phải xem được không?
Eumel

2
@Eumel Bạn có thể coi bộ giải nén là người xem. Vì vậy, không, định dạng nén của bạn có thể tùy ý và hoàn toàn phụ thuộc vào bạn. Chỉ sau khi giải nén, một hình ảnh có thể xem được mới xuất hiện.
orlp

7
You may assume that the image dimensions do not exceed 2^32 in either direction.Đây có phải là một chút quá mức? Điều này có nghĩa là tôi phải sử dụng tối đa 16 byte để lưu trữ một cặp tọa độ (x, y). Rất ít tệp hình ảnh có kích thước hơn 2 ^ 16 (65536) pixel theo cả hai hướng và 2 ^ 11 là đủ cho tất cả các hình ảnh trong kho văn bản.
Peter Olson

@PeterOlson Tôi sẽ thay đổi nó thành 2^16.
orlp

@orlp Các quy tắc nêu rõ rằng bộ giải nén phải mất ít hơn mười giây để giải mã một hình ảnh. Ý tưởng tôi có khả năng sẽ mất vài phút để tạo các tệp tham chiếu sẽ được sử dụng trong các cuộc gọi tiếp theo tới bộ giải nén. tức là hoạt động một lần tắt tương tự như "cài đặt" một ứng dụng. Giải pháp này sẽ bị loại?
Moogie 10/2/2016

Câu trả lời:


8

Python với PIL, điểm 0,094218

Máy nén:

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

Giải nén:

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

Cả hai tập lệnh nhận đầu vào thông qua các đối số dòng lệnh, như hai thư mục (đầu vào và đầu ra) và chuyển đổi tất cả các hình ảnh trong thư mục đầu vào.

Ý tưởng là tìm kích thước vừa với 4 KiB và có cùng tỷ lệ khung hình như ban đầu, và sử dụng bộ lọc Lanczos để có được chất lượng cao nhất từ ​​hình ảnh được ghép xuống càng tốt.

Imgur album ảnh nén, sau khi thay đổi kích thước về kích thước ban đầu

Chấm điểm đầu ra tập lệnh:

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

Tôi mới nhận ra rằng giải pháp của bạn sử dụng WebP, không được phép. Giải pháp của bạn không hợp lệ.
orlp

@orlp Bây giờ đã cố định để sử dụng PPM, đây là định dạng không nén.
Mego

Ổn thỏa. Mặc dù vậy, thách thức này đã bộc lộ khá nhiều điểm yếu của DSSIM. Tôi sẽ tranh luận rằng hầu hết các hình ảnh của Moogie trông thực sự tốt hơn.
orlp

@orlp Chúng trông đẹp như hình thu nhỏ. Khi được thổi lên kích thước ban đầu của chúng (sử dụng Lanczos), chúng trông có cùng chất lượng hoặc tệ hơn. Tôi đang làm việc để có được hình thu nhỏ của đầu ra của tôi được tải lên.
Mego

7

Java (vanilla, nên hoạt động với java 1.5+), điểm 0,672

Nó không tạo ra điểm số dssim đặc biệt tốt, nhưng trong mắt tôi, nó tạo ra hình ảnh thân thiện với con người hơn ...

đầy sao nguồn phòng cầu vồng
lề llama đứa trẻ julia

Album: http://imgur.com/a/yL31U

Chấm điểm đầu ra tập lệnh:

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

Chuỗi nén:

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.

Để giải nén, thổi phồng và sau đó đọc các chỉ mục khối và xuất bản vá tương ứng vào tệp đầu ra, sau đó thay đổi kích thước về kích thước ban đầu.

Thật không may, mã quá lớn cho stackoverflow nên có thể được tìm thấy tại https://gist.github.com/anonymous/989ab8a1bb6ec14f6ea9

Chạy:

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.

Lần đầu tiên ứng dụng này được chạy, các tệp yêu cầu sẽ được tạo và lưu trong một thư mục liên quan đến thực thi thư mục làm việc. Có thể sẽ mất vài phút. Đối với các lần thực hiện tiếp theo, bước này sẽ không cần phải được thực hiện.


Điều này có vẻ tuyệt vời. Chỉ cần xác nhận, các bước 1-6 không dựa vào tử thi chút nào? Ngoài ra, bạn có phiền nếu tôi chỉnh lại mã của bạn trên gist.github.com không?
orlp

Chính xác, không sử dụng bất kỳ tập tin văn bản nào làm đầu vào. bạn có thể thấy những hình ảnh mà nó tạo ra để tạo ra các bản vá mua thay đổi hằng số "OUTPUT_SAMPLE_IMAGES" thành đúng. Nó sẽ xuất những hình ảnh này vào thư mục làm việc: data / hình ảnh / làm việc /
Moogie 13/2/2016

@orlp hiện đang sử dụng gist.github
Moogie 13/2/2016

Các kết quả thật đáng kinh ngạc, nhưng việc không sử dụng deflate / Inflate có phá vỡ quy tắc về việc không cho phép nén / giải nén chung không?
algmyr

@ achmyr Đã được một thời gian, nhưng tôi nghĩ rằng tôi đã giải thích quy tắc nén không chung chung có nghĩa là không nén "hình ảnh" chung chung ... tức là jpeg, v.v. Nhưng tôi có thể đã giải thích rằng không chính xác, trong trường hợp này, vâng, điều này trình nên được diqualified.
Moogie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.