Vẽ một cuộc sống tĩnh lặng (hoặc một chuyển động) - vẽ một hình ảnh trong Trò chơi cuộc sống


36

Bạn được cung cấp như là một hình ảnh thang độ xám. Nhiệm vụ của bạn là tìm một mô hình tĩnh hoặc vòng lặp trong Trò chơi cuộc sống của Conway giống với hình ảnh đầu vào càng gần càng tốt.

Đầu ra của bạn có thể hình ảnh tĩnh hoặc hình động lặp ở một số định dạng có thể được chuyển đổi thành gif. Kích thước hình ảnh đầu ra phải giống với kích thước đầu vào và nó chỉ phải chứa các pixel đen và trắng.

Nếu đầu ra là một hình ảnh động, mỗi khung hình phải được tạo từ khung hình trước theo quy tắc Trò chơi Cuộc sống, với một ô cho mỗi pixel. Hoạt hình phải lặp, với khung đầu tiên được tạo từ khung cuối cùng theo cùng một quy tắc.

Nếu đầu ra là một hình ảnh tĩnh, áp dụng quy tắc trò chơi cuộc sống cho nó phải tạo ra cùng một hình ảnh. Điều này có nghĩa là không có tế bào 'còn sống' nào có thể có nhiều hơn ba hoặc ít hơn hai người hàng xóm 'còn sống' và không có tế bào 'chết' nào có thể có chính xác ba người hàng xóm 'còn sống'. (Lưu ý rằng về cơ bản nó giống như một hình ảnh động như được mô tả ở trên, nhưng chỉ có một khung hình.)

Thêm quy tắc và làm rõ:

  • Bạn (hoặc chương trình của bạn) có thể chọn các ô 'còn sống' được biểu thị là màu trắng và 'chết' là màu đen hay ngược lại. Đó là, bạn có thể mã cứng này hoặc chương trình của bạn có thể chọn nó dựa trên hình ảnh đầu vào. (Nhưng nó phải giống nhau cho mọi khung hình của hình ảnh động.)

  • Các điều kiện biên phải là định kỳ, nghĩa là các ô trên cột ngoài cùng bên phải có hàng xóm trên cột ngoài cùng bên trái, v.v.

  • Đối với hình ảnh động, tốc độ khung hình tùy thuộc vào bạn (hoặc chương trình của bạn); Tôi tưởng tượng tốc độ khung hình nhanh sẽ hoạt động tốt để xấp xỉ các pixel màu xám.

  • Vui lòng gửi ít nhất hai kết quả được nhúng trong câu trả lời của bạn. Nếu bạn có thể đăng kết quả từ tất cả các hình ảnh đầu vào bên dưới, thì tốt hơn là.

  • Có thể chấp nhận thu nhỏ hình ảnh thử nghiệm nếu điều này là cần thiết để đạt được gifs với kích thước tệp đủ nhỏ. Nếu bạn muốn liên kết đến các tệp lớn hơn, điều đó tốt. Nếu bạn muốn thể hiện, hãy thoải mái tìm một số tệp nguồn có độ phân giải cao hơn.

  • Vui lòng cố gắng tránh có quá nhiều tham số có thể kiểm soát trong mã của bạn - tốt nhất nếu đầu vào duy nhất của chương trình là hình ảnh. Ngoại lệ là nếu bạn muốn có một tham số để kiểm soát số lượng khung hình động, vì điều đó sẽ ảnh hưởng đến kích thước tệp.

  • Bạn có thể sử dụng các chương trình bên ngoài để thay đổi định dạng của các tệp đầu vào và đầu ra, và / hoặc biên dịch các khung đầu ra thành một hình động nếu bạn muốn. (Đây không phải là một thách thức xử lý định dạng tệp.)

  • Đây là , vì vậy câu trả lời có nhiều phiếu nhất sẽ thắng.

Dưới đây là một lựa chọn các hình ảnh thử nghiệm, chủ yếu được lấy từ các câu hỏi khác trên trang web này. (Có thể tôi sẽ thêm hình ảnh đầu vào "phần thưởng" bổ sung sau.)

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Để bắt đầu, đây là một nỗ lực tham khảo rất ngớ ngẩn trong Python 2, lợi dụng thực tế là một khối bốn hình vuông là một cấu trúc ổn định trong Trò chơi cuộc sống. Nó chỉ thay đổi hình ảnh đầu vào theo hệ số 4, sau đó vẽ một khối nếu pixel tương ứng tối hơn 0,5.

from skimage import io
from skimage import transform
import sys

img = io.imread(sys.argv[1],as_grey=True)

source = transform.resize(img, [i/4 for i in img.shape])

img[:]=1
for x in xrange(source.shape[0]):
    for y in xrange(source.shape[1]):
        if source[x,y]<0.5:
            img[x*4, y*4] = 0
            img[x*4+1, y*4] = 0
            img[x*4, y*4+1] = 0
            img[x*4+1, y*4+1] = 0

io.imsave(sys.argv[2], img)

Dưới đây là một số kết quả đầu ra từ mã ví dụ. Tôi chắc chắn rằng kết quả tốt hơn nhiều là có thể.

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


2
Đây là một số phân đoạn tĩnh vật có mật độ cao: en.wikipedia.org/wiki/ . Bạn không thể nhận được nhiều hơn mật độ 1/2 trong giới hạn.
xnor

Trong ví dụ của bạn, không phải các tế bào mới được sinh ra ở ngã ba của ba hình vuông?
xnor

@xnor ồ, đúng rồi. Bây giờ tôi nên xóa ví dụ trong trường hợp đó. (Tôi cũng nên bắt đầu viết một số mã xác minh!)
Nathaniel

3
Không chắc điều đó sẽ giúp ích như thế nào, vì không có khu vườn nào có hoa văn eden vẫn còn sống. (điều này sẽ khiến chúng trở thành tiền thân của chính chúng) Lý do tương tự cho lý do tại sao chúng không phải là dao động.
Kiểm đếm

1
Một số nguồn cảm hứng khác cho các thí sinh: tlrobinson.net/blog/2009/02/game-of-life-generator
Abulafia

Câu trả lời:


13

Con trăn

import sys, random, itertools
from PIL import Image

filename, cutoff = sys.argv[1], int(sys.argv[2]) if len(sys.argv) > 2 else 128

# load command-line arg as image
src = Image.open(sys.argv[1]).convert("L") # grayscale
(w, h), src = src.size, src.load()
# flatten
src = bytearray(src[x, y] for y in range(h) for x in range(w))
size = len(src)
neighbour_offsets = (-w-1,-w,-w+1,-1,1,w-1,w,w+1)    

shapes = set()
max_shape_x, max_shape_y = 0, 0
for shape in (((1, 1), (1, 1), "b"), # block
    ((0,1,1,0),(1,0,0,1),(0,1,1,0), "h"), # hive
    ((0,0,1,0),(0,1,0,1),(1,0,0,1),(0,1,1,0), "l"), # loaf
    ((0,1,0),(1,0,1),(0,1,0), "t"), # tub
    ((1,1,0),(1,0,1),(0,1,0), "B"), # boat
    ((1,1,0),(1,0,1),(0,1,1), "s"), # ship
    ((1,1,0,1,1),(0,1,0,1,0),(0,1,0,1,0),(1,1,0,1,1), "I"), # II
    ((0,0,0,1,1),(0,0,0,0,1),(0,0,0,1,0),(1,0,1,0,0),(1,1,0,0,0), "c"), # canoe sinking
    ((1,1,0,0),(1,0,0,1),(0,0,1,1), "a"), # aircraft carrier
    ((0,1,1,0,0),(1,0,0,1,0),(0,1,0,0,1),(0,0,1,1,0), "m"), # mango
    ((0,1,1,0),(1,0,0,1),(1,0,0,1),(0,1,1,0), "p"), # pond
    ((0,0,0,1,1),(0,0,1,0,1),(0,0,1,0,0),(1,0,1,0,0),(1,1,0,0,0), "i"), # integral
    ((1,1,0,1),(1,0,1,1), "S"), # snake
    ((1,1,0,0),(1,0,1,0),(0,0,1,0),(0,0,1,1), "f"), # fish hook
    ):
    X, Y = len(shape[0]), len(shape)-1
    max_shape_x, max_shape_y = max(X, max_shape_x), max(Y, max_shape_y)
    shapes.add(((X, Y), tuple(y*w+x for y in range(Y) for x in range(X) if shape[y][x]), shape[:-1], shape[-1]))
    shapes.add(((X, Y), tuple(y*w+x for y in range(Y) for x in range(X-1,-1,-1) if shape[y][x]), shape[:-1], shape[-1]))
    shapes.add(((X, Y), tuple(y*w+x for y in range(Y-1,-1,-1) for x in range(X) if shape[y][x]), shape[:-1], shape[-1]))
    shapes.add(((X, Y), tuple(y*w+x for y in range(Y-1,-1,-1) for x in range(X-1,-1,-1) if shape[y][x]), shape[:-1], shape[-1]))

def torus(i, *indices):
    if len(indices) == 1:
        return (i + indices[0]) % size
    return [(i + n) % size for n in indices]

def iter_neighbours(i):
    return torus(i, *neighbour_offsets)

def conway(src, dest):
    for i in range(size):
        alive = count_alive(src, i)
        dest[i] = (alive == 2 or alive == 3) if src[i] else (alive == 3)

def calc_score(i, set):
    return 255-src[i] if not set else src[i]

def count_alive(board, i, *also):
    alive = 0
    for j in iter_neighbours(i):
        if board[j] or (j in also):
            alive += 1
    return alive

def count_dead(board, i, *also):
    dead = 0
    for j in iter_neighbours(i):
        if (not board[j]) and (j not in also):
            dead += 1
    return dead

def iter_alive(board, i, *also):
    for j in iter_neighbours(i):
        if board[j] or (j in also):
            yield j

def iter_dead(board, i, *also):
    for j in iter_neighbours(i):
        if (not board[j]) and (j not in also):
            yield j

def check(board):
    for i in range(size):
        alive = count_alive(board, i)
        if board[i]:
            assert alive == 2 or alive == 3, "alive %d has %d neighbours %s" % (i, alive, list(iter_alive(board, i)))
        else:
            assert alive != 3, "dead %d has 3 neighbours %s" % (i, list(iter_alive(board, i)))

dest = bytearray(size)

if False:
    # turn into contrast
    for i in range(size):
        mx = max(src[i], max(src[j] for j in iter_neighbours(i)))
        mn = min(src[i], min(src[j] for j in iter_neighbours(i)))
        dest[i] = int((0.5 * src[i]) + (128 * (1 - float(src[i] - mn) / max(1, mx - mn))))
    src, dest = dest, bytearray(size)

try:
    checked, bad, score_cache = set(), set(), {}
    next = sorted((calc_score(i, True), i) for i in range(size))
    while next:
        best, best_score = None, sys.maxint
        current, next = next, []
        for at, (score, i) in enumerate(current):
            if score > cutoff:
                break
            if best and best_score < score:
                break
            if not dest[i] and not count_alive(dest, i):
                do_nothing_score = calc_score(i, False)
                clean = True
                for y in range(-max_shape_y-1, max_shape_y+2):
                    for x in range(-max_shape_x-1, max_shape_x+2):
                        if dest[torus(i, y*w+x)]:
                            clean = False
                            break
                    if not clean:
                        break
                any_ok = False
                for (X, Y), shape, mask, label in shapes:
                    for y in range(Y):
                        for x in range(X):
                            if mask[y][x]:
                                pos, ok = torus(i, -y*w-x), True
                                if (pos, label) in bad:
                                    continue
                                if clean and (pos, label) in score_cache:
                                    score = score_cache[pos, label]
                                else:
                                    paint = torus(pos, *shape)
                                    for j in paint:
                                        for k in iter_alive(dest, j, *paint):
                                            if count_alive(dest, k, *paint) not in (2, 3):
                                                ok = False
                                                break
                                        if not ok:
                                            break
                                        for k in iter_dead(dest, j, *paint):
                                            if count_alive(dest, k, *paint) == 3:
                                                ok = False
                                                break
                                        if not ok:
                                            break
                                    if ok:
                                        score = 0
                                        any_ok = True
                                        for x in range(X):
                                            for y in range(Y):
                                                score += calc_score(torus(pos, y*w+x), mask[y][x])
                                            score /= Y*X
                                        if clean:
                                            score_cache[pos, label] = score
                                    else:
                                        bad.add((pos, label))
                                if ok and best_score > score and do_nothing_score > score:
                                    best, best_score = (pos, shape, label), score
                if any_ok:
                    next.append((score, i))
        if best:
            pos, shape, label = best
            shape = torus(pos, *shape)
            sys.stdout.write(label)
            sys.stdout.flush()
            for j in shape:
                dest[j] = True
            check(dest)
            next += current[at+1:]
        else:
            break
except KeyboardInterrupt:
    pass
print

if True:
    check(dest)
    anim = False
    while dest != src:
        if anim:
            raise Exception("animation!")
        else:
            anim = True
        sys.stdout.write("x"); sys.stdout.flush()
        conway(dest, src)
        dest, src = src, dest
        check(dest)

# canvas
out = Image.new("1", (w, h))
out.putdata([not i for i in dest])

# tk UI
Tkinter = None
try:
    import Tkinter
    from PIL import ImageTk
    root = Tkinter.Tk()
    root.bind("<Button>", lambda event: event.widget.quit())
    root.geometry("%dx%d" % (w, h))
    show = ImageTk.PhotoImage(out)
    label = Tkinter.Label(root, image=show)
    label.pack()
    root.loop()
except Exception as e:
    print "(no Tkinter)", e
    Tkinter = False

if len(sys.argv) > 3:
    out.save(sys.argv[3])

if not Tkinter:
    out.show()

Xin hãy nheo mắt:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Các tem mã trên các pixel trắng nhất với tiêu chuẩn phù hợp nhất vẫn còn sống . Có một đối số giới hạn để bạn có thể quyết định là làm tròn ngưỡng trắng đen đi. Tôi đã thử nghiệm sống trắng và kết quả cũng giống như vậy.


9
Tốt nhất là bao gồm mã của bạn trong bài đăng của bạn và đặt tiêu đề cho bài đăng của bạn bằng tên ngôn ngữ. ví dụ#Python
Calvin Sở thích

Kịch bản trình xác nhận của tôi nói rằng bạn có một số pixel xấu ở cạnh trái và phải. Có vẻ như khi các pixel bao quanh từ phải sang trái, chúng cũng di chuyển một pixel xuống dưới.
Nathaniel

+1 mặc dù - cảm ơn vì câu trả lời rất nhanh!
Nathaniel

@Nathaniel thx đã giới thiệu cho tôi thực hiện GoL. Một sự hiểu lầm khá đơn giản. Đầu ra sẽ giống nhau và tôi không muốn chờ đợi chúng xuất hiện trở lại :( Thử thách này có lỗi tương tự như hoạt hình của riêng tôi - mọi người thực sự tưởng tượng họ muốn xem kết quả, nhưng phải mất nhiều thời gian Đầu tư nhiều vào không gian phức tạp của vấn đề đặc biệt này làm cho các cuộc thi của azspcs.net bị chế ngự. Thật đáng tiếc khi GoL là đơn sắc và, thành thật mà nói, phù hợp với hình ảnh tĩnh. SmoothLife có vẻ vui, nhưng không phải để vẽ bức ảnh với.
Will

@ Sẽ không cần phải lo lắng về việc sửa lỗi, tôi chỉ cảm thấy buộc phải đề cập đến nó vì tôi đã gặp rắc rối khi viết một chương trình để kiểm tra nó!
Nathaniel

8

Java

Một cách tiếp cận dựa trên phát hiện cạnh. Yêu cầu tệp văn bản này trong thư mục đang chạy.

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.*;

import javax.imageio.ImageIO;


public class StillLifer{
    private static List<boolean[][]>patterns=new ArrayList<>();
    private static boolean[][] copy(boolean[][]b,int x,int y){
        boolean[][]r=new boolean[6][6];
        for(int i=0;i<6;i++){
            for(int j=0;j<6;j++){
                r[i][j]=b[y+i][x+j];
            }
        }
        return r;
    }
    private static void paste(boolean[][]from,boolean[][]to,int x,int y){
        for(int i=0;i<from.length;i++)for(int j=0;j<from[0].length;j++){
            to[y+i][x+j]=from[i][j];
        }
    }
    private static boolean[][]findClosest(boolean[][]b){
        boolean[][]c=null;
        int d=999999;
        for(boolean[][]k:patterns){
            int d2=editDistance(b,k);
            if(d2<d){
                c=k;
                d=d2;
            }
        }
        return c;
    }
    private static boolean[][]decode(String s){
        char[]a=s.toCharArray();
        boolean[][]r=new boolean[6][6];
        int k=0;
        for(int i=0;i<6;i++){
            for(int j=0;j<6;j++){
                r[i][j]=a[k++]=='1';
            }
        }
        return r;
    }
    private static class EdgeDetectEntry{
        int l;
        int x;
        int y;
        public EdgeDetectEntry(int m,int x,int y){
            this.l=m;
            this.x=x;
            this.y=y;
        }
    }
    private static Random rand;
    private static int w,h;
    private static BufferedImage img;
    private static boolean[][]grid;
    private static File file;
    private static int editDistance(boolean[][]from,boolean[][]to){
        int w=from.length;
        int h=from[0].length;
        int k=0;
        for(int x=0;x<w;x++){
            for(int y=0;y<h;y++){
                k+=from[y][x]^to[y][x]?1:0;
            }
        }
        return k;
    }
    private static int colorDistance(Color from,Color to){
        return from.getRed()-to.getRed();
    }
    private static int edgeDetectWeight(int x,int y){
        int k=0;
        Color c=new Color(img.getRGB(x, y));
        for(int x2=Math.max(0,x-1);x2<Math.min(w,x+2);x2++){
            for(int y2=Math.max(0,y-1);y2<Math.min(h,y+2);y2++){
                int l=colorDistance(c,new Color(img.getRGB(x2, y2)));
                k+=l*l;
            }
        }
        return k;
    }
    private static void save() throws Exception{
        int bk=Color.BLACK.getRGB();
        int wt=Color.WHITE.getRGB();
        for(int x=0;x<w;x++){
            for(int y=0;y<h;y++){
                img.setRGB(x,y,grid[y][x]?wt:bk);
            }
        }
        String k=file.getName().split("\\.")[0];
        ImageIO.write(img,"png",new File(k="out_"+k+".png"));
    }
    private static String rle(boolean[][]grid){
        StringBuilder st=new StringBuilder();
        for(boolean[]row:grid){
            for(int j=0;j<row.length;j++){
                int k=1;
                for(;j<row.length-1&&row[j]==row[j+1];j++)k++;
                if(k!=1)st.append(Integer.toString(k,36));
                st.append(row[j]?'@':'-');
            }
        }
        return st.toString();
    }
    private static int getVal(boolean[][]grid,int x,int y){
        if(x<0)x+=w;
        if(y<0)y+=h;
        if(x==w)x=0;
        if(y==h)y=0;
        return grid[y][x]?1:0;
    }
    private static boolean newState(boolean[][]grid,int x,int y,String rule){
        String[]r=rule.split("/");
        int k=0;
        for(int a=-1;a<=1;a++)for(int b=-1;a<=1;a++)k+=(a|b)==0?0:getVal(grid,x+a,y+b);
        String s=Integer.toString(k);
        return grid[y][x]?r[1].contains(s):r[0].contains(s);
    }
    private static boolean[][] next(boolean[][]grid,String rule){
        boolean[][]r=new boolean[h][w];
        for(int x=0;x<w;x++){
            for(int y=0;y<h;y++){
                r[y][x]=newState(grid,x,y,rule);
            }
        }
        return r;
    }
    private static void loadPatterns() throws Exception{
        Scanner reader=new Scanner(new File("lib.txt"));
        while(reader.hasNext()){
            String line=reader.nextLine();
            if(line.startsWith("--"))continue;
            patterns.add(decode(line));
        }
        reader.close();
    }
    public static void main(String[]a) throws Exception{
        loadPatterns();
        Scanner in=new Scanner(System.in);
        img=ImageIO.read(file=new File(in.nextLine()));
        in.close();
        w=img.getWidth();
        h=img.getHeight();
        grid=new boolean[h][w];
        final int npix=w*h;
        rand=new Random(npix*(long)img.hashCode());
        List<EdgeDetectEntry> list=new ArrayList<>();
        for(int x=0;x<w;x++){
            for(int y=0;y<h;y++){
                list.add(new EdgeDetectEntry(edgeDetectWeight(x,y),x,y));
            }
        }
        list.sort((one,two)->{int k=two.l-one.l;if(k>0)return 1;if(k<0)return -1;return 0;});
        for(int i=Math.max(Math.min(3,npix),npix/5);i>0;i--){
            EdgeDetectEntry e=list.get(i);
            grid[e.y][e.x]=rand.nextDouble()<0.9;
        }
        grid=next(grid,"/2345678");
        boolean[][]d=new boolean[h][w];
        for(int i=0;i<w/6;i++){
            for(int j=0;j<h/6;j++){
                paste(findClosest(copy(grid,i*6,j*6)),d,i*6,j*6);
            }
        }
        grid=d;
        assert(rle(next(grid,"3/23")).equals(rle(grid)));
        save();
    }
}

Một số kết quả:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


5

C ++

Phương pháp tiếp cận pixel đơn giản bằng cách sử dụng mức trung bình của mỗi lưới 8x8 để chọn lưới đầu ra 8x8 ("kết cấu màu"). Mỗi lưới đầu ra 8x8 có một ngăn cách 2 ô ở trên cùng và bên phải. Các lưới được thiết kế từ 4 ô vẫn còn sống đến 18 ô vẫn sống trong 6x6 pixel còn lại.

Chương trình hoạt động như một bộ lọc từ PGM nhị phân sang PBM nhị phân. Theo mặc định, hình ảnh là "tối"; màu đen là cái chết và màu trắng là sự sống; -iđảo ngược điều này. -g [value]thêm một gamma, được sử dụng để tính trung bình trước khi cân trước khi chọn họa tiết màu.

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <cmath>

// colors 4 through 18 have 4 through 18 live cells
// colors 1-3 are repetitions of 0 or 4 used
// as artificially weighted bins
unsigned char gol_colors[]={
      0,  0,  0,  0,  0,  0,  0,  0 // Color  0
   ,  0,  0,  0,  0,  0,  0,  0,  0 // Color  1
   ,  0,  0,  0, 16, 40, 16,  0,  0 // Color  2
   ,  0,  0,  0, 16, 40, 16,  0,  0 // Color  3
   ,  0,  0,  0, 16, 40, 16,  0,  0 // Color  4
   ,  0,  0,  0, 24, 40, 16,  0,  0 // Color  5
   ,  0,  0,  0, 16, 40, 80, 32,  0 // Color  6
   ,  0,  0,  0, 48, 72, 40, 16,  0 // Color  7
   ,  0,  0,  8, 20,  8, 64,160, 64 // Color  8
   ,  0,  0,  8, 20,  8, 64,160, 96 // Color  9
   ,  0,  0, 12, 20,  8, 64,160, 96 // Color 10
   ,  0,  0, 12, 20,  8,192,160, 96 // Color 11
   ,  0,  0,204,204,  0,  0, 48, 48 // Color 12
   ,  0,  0,204,204,  0,192,160, 64 // Color 13
   ,  0,  0,  0,108,168,168,108,  0 // Color 14
   ,  0,  0, 96,144,104, 40,172,192 // Color 15
   ,  0,  0,204,204,  0,  0,204,204 // Color 16
   ,  0,  0,216,216,  0,216,212,  8 // Color 17
   ,  0,  0,204,164, 40, 80,148,204 // Color 18
};

enum { gol_bins = sizeof(gol_colors)/(sizeof(*gol_colors))/8 };

bool inverted=false;

bool applygamma=false;
double gammasetting=0.0;

unsigned int corrected(unsigned int i, unsigned int r) {
   return static_cast<unsigned int>(r*std::pow(i/static_cast<double>(r), gammasetting));
}

int main(int argc, char** argv) {
   std::vector<unsigned short> pgm_data;
   unsigned pgm_width;
   unsigned pgm_height;
   unsigned pgm_vpp;

   std::vector<unsigned char> pbm_data;
   unsigned pbm_width;
   unsigned pbm_height;

   unsigned int doublings=0;

   std::vector<std::string> args(argv+1, argv+argc);
   for (unsigned int i=0, e=args.size(); i<e; ++i) {
      if (args[i]=="-i") { inverted=true; continue; }
      if (args[i]=="-g") {
         if (i+1==e) continue;
         std::stringstream ss;
         ss << args[++i];
         if (ss >> gammasetting) applygamma = true;
         continue;
      }
   }

   std::string line;
   std::getline(std::cin, line);
   if (line!="P5") return 1;
   enum { nothing, have_w, have_h, have_bpp } readstate = nothing;
   while (std::cin) {
      std::getline(std::cin, line);
      if (line.empty()) continue;
      if (line[0]=='#') continue;
      std::stringstream ss; ss << line;
      for(;;) {
         switch (readstate) {
         case nothing: if (ss >> pgm_width) readstate = have_w; break;
         case have_w:  if (ss >> pgm_height) readstate = have_h; break;
         case have_h:  if (ss >> pgm_vpp) readstate = have_bpp; break;
         }
         if (readstate==have_bpp) break;
         if (ss) continue;
         break;
      }
      if (readstate==have_bpp) break;
   }
   if (readstate!=have_bpp) return 1;
   // Fill pgm data
   pgm_data.resize(pgm_width*pgm_height);
   for (unsigned i=0, e=pgm_width*pgm_height; i<e; ++i) {
      int v = std::cin.get();
      if (v==std::char_traits<char>::eof()) return 1;
      pgm_data[i] = static_cast<unsigned int>(std::char_traits<char>::to_char_type(v))&0xFFU;
   }
   pbm_width  = pgm_width/8*8;
   pbm_height = pgm_height/8*8;
   pbm_data.resize(pbm_width*pbm_height/8);
   for (unsigned x=0, xe=pbm_width/8; x<xe; ++x) {
      for (unsigned y=0, ye=pbm_height/8; y<ye; ++y) {
         // Calculate the average of this 8x8 area
         unsigned int total=0;
         for (unsigned int xd=0; xd<8; ++xd) {
            for (unsigned int yd=0; yd<8; ++yd) {
               unsigned int c = x+xd+(y+yd)*pgm_width;
               unsigned int pv = pgm_data[x*8+xd+(y*8+yd)*pgm_width];
               // Apply gamma prior to averaging
               if (applygamma) pv=corrected(pv, pgm_vpp);
               total += pv;
            }
         }
         total /= 64;
         // Invert average if inverting colors (white on black)
         if (inverted) total=pgm_vpp-total;
         total *= gol_bins;
         total /= (pgm_vpp+1);
         // Fill 8x8 areas with gol color texture
         for (unsigned int yd=0; yd<8; ++yd) {
            pbm_data[x+(y*8+yd)*pbm_width/8] = gol_colors[total*8+yd];
         }
      }
   }
   // Now, write a pbm
   std::cout
      << "P4\n"
      << "# generated by pgm2gol\n"
      << pbm_width << " " << pbm_height << "\n";
   for (unsigned i=0, e=pbm_data.size(); i<e; ++i) {
      unsigned char data=pbm_data[i];
      if (!inverted) { data=pbm_data[i]^0xFF; }
      std::cout.put(data);
   }
}

Kết quả được chọn (lưu ý: tất cả pbm đã được chuyển đổi sang png bằng chương trình bên thứ ba để tải lên):

Escher, gamma 2.2
Escher

Mona Lisa, gamma 2.2
Mona

Đại dương, gamma 2.2 đảo ngược
đại dương

Cún con, gamma 2.2
Cún yêu

Phản bội hình ảnh, gamma 2.2 đảo ngược
Phản bội

Mona Lisa gamma 2.2, đảo ngược, để so sánh
Mona

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.