이미지를 4 KiB 미리보기로 압축


30

이 과제에서는 이미지 미리보기 압축 알고리즘을 작성하게됩니다. 목표는 임의의 이미지 파일을 4KiB 미리보기 이미지로 줄여 대역폭이 거의없는 이미지를 빠르게 식별하는 데 사용할 수 있습니다.

압축기와 압축 해제 기의 두 가지 프로그램 (또는 하나의 결합 된 프로그램)을 작성해야합니다. 둘 다 파일 또는 stdin을 입력으로 가져 와서 파일 또는 stdout으로 출력해야합니다. 컴프레서는 주류 무손실 이미지 형식 (예 : PNG, BMP, PPM)으로 하나의 이미지를 수용 하고 최대 4096 바이트 의 파일 출력해야합니다 . 압축 해제 기는 압축기에서 생성 된 모든 파일을 수용하고 입력에 최대한 근접한 이미지를 출력해야합니다. 인코더 / 디코더에는 소스 코드 크기 제한이 없으므로 알고리즘을 창의적으로 사용할 수 있습니다.

제한 사항 :

  • 컨닝 하지마'. 프로그램은 숨겨진 입력을 사용하지 않고 인터넷에 데이터를 저장하는 등의 작업을 수행 할 수 없습니다. 또한 일련의 스코어링 이미지에만 관련된 기능 / 데이터를 포함 할 수 없습니다.

  • 라이브러리 / 툴 / 빌트인 들어, 당신이 되어 사용할 수 일반 (스케일링, 번짐, 색 공간 변환 등)의 화상 처리 동작을하지만, 하지 이미지 디코딩 / 인코딩 / 압축 (압축기 입력 및 압축 해 출력 제외) 동작. 일반 압축 / 압축 해제도 허용되지 않습니다 . 이 문제에 대한 자체 압축을 구현하기위한 것입니다.

  • 압축 해제기에 의해 출력되는 이미지의 크기는 압축기에 제공된 원본 파일의 크기와 정확히 일치해야합니다. 이미지 크기가 양방향으로 2 16 을 초과하지 않는다고 가정 할 수 있습니다 .

  • 컴프레서는 평균 소비자 PC에서 5 분 이내에 가동해야하며, 압축 해제 기는 아래 세트의 모든 이미지에 대해 10 초 이내에 가동해야합니다.

채점

빠른 검증 및 시각적 비교 를 위해 답변을 사용하여 압축 후 테스트 코퍼스의 무손실 이미지 앨범을 포함하십시오.

압축기는 다음 이미지 모음을 사용하여 테스트됩니다 .

별이 빛나는 출처 방 무지개
여유 야마 아이 줄리아

여기 에서 zip 파일로 모든 이미지를 다운로드 할 수 있습니다 .

점수는 모든 이미지에서 압축기 의 평균 구조 유사성 지수 가됩니다. 우리는 dssim이 도전에 오픈 소스를 사용할 것입니다. 소스에서 쉽게 만들거나 Ubuntu를 사용하는 경우 PPA도 있습니다. 자신의 답변에 점수를 매기는 것이 바람직하지만 C 응용 프로그램을 작성하는 방법을 모르고 데비안 / 우분투를 실행하지 않으면 다른 사람이 점수를 매길 수 있습니다. dssimPNG 로의 입 / 출력을 예상하므로 다른 형식으로 출력하는 경우 먼저 출력을 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 압축 해제기를 뷰어로 생각할 수 있습니다. 따라서 압축 형식은 임의적 일 수 있으며 전적으로 귀하에게 달려 있습니다. 압축 해제 후에 만 ​​볼 수있는 이미지가 나오게됩니다.
orlp

7
You may assume that the image dimensions do not exceed 2^32 in either direction.조금 과도하지 않습니까? 이것은 (x, y) 좌표 쌍을 저장하기 위해 최대 16 바이트를 사용해야 함을 의미합니다. 어느 방향 으로든 2 ^ 16 (65536) 픽셀 이상의 치수를 가진 이미지 파일은 거의 없으며, 2 ^ 11이면 말뭉치의 모든 이미지에 충분합니다.
피터 올슨

@PeterOlson로 변경하겠습니다 2^16.
orlp

@orlp 규칙에 따라 압축 해제 기는 이미지를 디코딩하는 데 10 초 미만이 소요되어야합니다. 압축 해제기에 대한 후속 호출에 사용될 참조 파일을 생성하는 데 몇 분이 소요될 수 있습니다. 즉, 응용 프로그램 "설치"와 비슷한 일회성 활동입니다. 이 솔루션이 실격 처리됩니까?
Moogie

답변:


8

PIL이 포함 된 Python, 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

압축 해제 기 :

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

좋구나. 그러나이 도전은 DSSIM의 약점을 드러냅니다. 나는 Moogie의 이미지 대부분이 훨씬 더 좋아 보인다고 주장합니다.
orlp

@orlp 축소판 그림으로보기 좋습니다. Lanczos를 사용하여 원래 크기로 날려 보면 동일한 품질 또는 그 이상으로 보입니다. 출력물의 미리보기 이미지를 업로드하려고합니다.
Mego

7

자바 (바닐라, 자바 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.

압축을 풀고 블록 인덱스를 확장 한 다음 해당 패치를 출력 파일로 출력 한 다음 원래 크기로 크기를 조정하십시오.

불행히도 코드는 스택 오버 플로우에 비해 너무 커서 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.

이 응용 프로그램을 처음 실행하면 필요한 파일이 생성되어 실행 작업 디렉토리와 관련된 디렉토리에 저장됩니다. 이 작업은 몇 분 정도 걸릴 수 있습니다. 후속 실행의 경우이 단계를 수행 할 필요가 없습니다.


대단해. 확인하기 위해 1-6 단계는 코퍼스에 전혀 의존하지 않습니까? 또한 gist.github.com에서 코드를 다시 호스팅해도 괜찮습니까?
orlp

올바른 말뭉치 파일을 입력으로 사용하지 마십시오. 패치 구매를 생성하기 위해 생성하는 이미지에서 상수 "OUTPUT_SAMPLE_IMAGES"를 true로 변경하는 것을 볼 수 있습니다. 이 이미지들은 작업 폴더로 출력됩니다 : data / images / working /
Moogie

@orlp는 gist.github를 사용합니다
Moogie

결과는 놀랍지 만 수축 / 팽창을 사용하여 일반 압축 / 압축 해제를 허용하지 않는 규칙을 위반하지 않습니까?
algmyr

@algmyr 오랜 시간이 지났지 만 일반적인 압축 규칙이 일반 '이미지'압축을 의미하지 않는 것으로 해석했다고 생각합니다. 즉, jpeg 등입니다. 제출물은 자격을 상실해야합니다.
Moogie
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.