배고픈 이미지 뱀-구멍 # 3


25

홀 # 1

뱀이 배고프다.

그는 한 번에 한 픽셀 씩 그림을 먹는다.

그는 정말 밝은 픽셀을 좋아합니다.

도전

Joe가 위, 아래, 왼쪽 또는 오른쪽으로 만 움직일 수 있다는 점에서 가장 밝은 픽셀을 먹도록 프로그램하십시오.

명세서

  • Joe는 이미지의 왼쪽 상단 픽셀에서 시작해야합니다.
  • Joe는 한 번만 가로 또는 세로로만 움직일 수 있습니다
  • Joe는 그림에서 픽셀 양의 1/3을 이동할 수있는 시간이 충분합니다 (1/3는 픽셀 수만큼 이동). 픽셀 수가 3의 배수가 아닌 경우 가장 가까운 정수로 내림합니다.
  • Joe는 경로를 건너 갈 수 있지만 밝기는 0입니다.
  • 밝기는 r, g 및 b의 합을 기준으로하므로 rgb (0,0,0)의 밝기는 0이고 rgb (255,255,255)의 밝기는 최대입니다.

입력

원하는대로 이미지를 입력 할 수 있습니다.

산출

  • 사진의 최종 결과를 보여주는 이미지 (검은 색 픽셀).
  • 섭취 한 밝기의 양 (답의 범위를 지정하십시오)

채점

귀하의 프로그램은 다음에 평가됩니다 :

  • Joe가 먹는 픽셀의 평균 밝기 / 사진에서 픽셀의 평균 밝기 *

* 프로그램에서 이것을 하드 코딩 할 수 있습니다

총점은 다음 이미지의 평균 점수가됩니다.

테스트 이미지 :

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

http://upload.wikimedia.org/wikipedia/en/thumb/f/f4/The_Scream.jpg/800px-The_Scream.jpg

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오


3
재미있는 마크 다운 사실-이미지를 원본에 대한 링크로 전환 할 수 있습니다 [![image description](SE URL for downsized image)](URL for original image).
Calvin 's Hobbies

1
사람들에게 답변에 "먹은"이미지의 예를 포함 시키라고 요청하는 것이 좋습니다.
Nathaniel

답변:


16

C ++, 점수 : 1.42042 1.46766

이것은 본질적으로 기존의 두 가지 솔루션 중 약간 더 정교한 버전입니다. 네 가지 가능한 동작 중 밝기를 최대화하는 것을 선택합니다. 그러나 대상 픽셀의 밝기 만 보는 대신 대상 픽셀 근처에서 가중 된 픽셀 밝기의 합을보고, 대상에 더 가까운 픽셀의 가중치가 더 큽니다.

편집 : 이웃 계산에 비선형 밝기를 사용하면 점수가 약간 향상됩니다.

로 컴파일하십시오 g++ joe.cpp -ojoe -std=c++11 -O3 -lcairo. 카이로가 필요합니다.

로 실행하십시오 joe <image-file> [<radius>]. <image-file>입력 PNG 이미지입니다. <radius>(선택적 인수)는 합산 된 이웃의 반경을 픽셀 단위로 나타냅니다 (작을수록 빠를수록 클수록 (거의) 좋습니다). 점수와 이미지를 출력합니다 out.<image-file>.

#include <cairo/cairo.h>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>

using namespace std;

int main(int argc, const char* argv[]) {
    auto* img = cairo_image_surface_create_from_png(argv[1]);
    int width = cairo_image_surface_get_width(img),
        height = cairo_image_surface_get_height(img),
        stride = cairo_image_surface_get_stride(img);
    unsigned char* data = cairo_image_surface_get_data(img);

    double* brightness = new double[width * height];
    double total_brightness = 0;
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            const unsigned char* p = data + stride * y + 4 * x;
            total_brightness += brightness[y * width + x] = p[0] + p[1] + p[2];
        }
    }

    const int r = argc > 2 ? stoi(argv[2]) : 64, R = 2 * r + 1;
    double* weight = new double[R * R];
    for (int y = -r; y <= r; ++y) {
        for (int x = -r; x <= r; ++x)
            weight[R * (y + r) + (x + r)] = 1.0 / (x*x + y*y + 1);
    }

    auto neighborhood = [&] (int x, int y) {
        double b = 0;
        int x1 = max(x - r, 0), x2 = min(x + r, width - 1);
        int y1 = max(y - r, 0), y2 = min(y + r, height - 1);
        for (int v = y1; v <= y2; ++v) {
            const double *B = brightness + width * v + x1;
            const double *W = weight + R * (v - (y - r)) + (x1 - (x - r));
            for (int u = x1; u <= x2; ++u, ++B, ++W)
                b += (*W) * (*B) * (*B);
        }
        return b;
    };

    int n = (2 * width * height + 3) / 6;
    int x = 0, y = 0;
    double path_brightness = 0;
    int O[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    for (int i = 0; i < n; ++i) {
        if (i % 1000 == 0) cerr << (200 * i + n) / (2 * n) << "%\r";

        path_brightness += brightness[width * y + x]; brightness[width * y + x] = 0;
        unsigned char* p = data + stride * y + 4 * x;
        p[0] = p[1] = 16 * i % 255; p[2] = 0;

        auto O_end = partition(begin(O), end(O), [&] (const int* o) {
            return x + o[0] >= 0 && x + o[0] < width &&
                   y + o[1] >= 0 && y + o[1] < height;
        });
        const int* o_max; double o_max_neighborhood = -1;
        for (auto o = O; o != O_end; ++o) {
            double o_neighborhood = neighborhood(x + (*o)[0], y + (*o)[1]);
            if (o_neighborhood > o_max_neighborhood)
                o_max = *o, o_max_neighborhood = o_neighborhood;
        }
        x += o_max[0]; y += o_max[1];
    }

    cout << (path_brightness * width * height) / (n * total_brightness) << endl;

    cairo_surface_write_to_png(img, (string("out.") + argv[1]).c_str());

    delete []brightness;
    delete []weight;
    cairo_surface_destroy(img);
}

결과

Bridge    1.39945
Balls     1.77714
Scream    1.38349
Fractal   1.31727
Vortex    1.66493
Tornado   1.26366
-----------------
Average   1.46766

다리 불알 비명 프랙탈 와동 폭풍

더 눈 사탕

소용돌이 애니메이션 토네이도 애니메이션


방금 내 샘플 이미지 중 일부에서 프로그램을 시도했지만 시작 지점 주위에서만 검은 색이 많이 생겼으며 NaN을 반환하는 이웃 람다로 인해 프로그램이 충돌합니다.
PlasmaHH

@PlasmaHH 마음에 드는 이미지를 공유 하시겠습니까?
Ell

나는 휴가 이미지를 공급하고 있었다.
PlasmaHH

@PlasmaHH 글쎄, 순전히 검은 이미지는 정의되지 않은 점수를 가지고 있으며, 0보다 0이며 NaN입니다. 그러나 주변 계산에 영향을 주거나 프로그램을 중단해서는 안됩니다 (물론 부동 소수점 환경에 따라 달라질 수 있음)
Ell

if (o_neighborhood > o_max_neighborhood) o_max = *o, o_max_neighborhood = o_neighborhood;이 코드 만 설정 하는 o_max 포인터를 살펴보십시오 . 그러나 nan이 관련되어 있기 때문에 비교는 항상 거짓이므로 o_max는 설정되지 않고 초기화되지 않은 상태로 사용됩니다.
PlasmaHH

7

파이썬 3, 점수 = 1.57

먼저 뱀이 이미지를 이동하여 서로 같은 거리에있는 세로선을 만듭니다.

에이

세로줄에서 서로 옆에 두 개의 점을 찍고 끝 점이 그들 인 루프를 만들어이 뱀을 확장 할 수 있습니다.

|      |
|  =>  +----+
|      +----+
|      |

점을 쌍으로 구성하고 모든 쌍에 대해 루프의 크기와 평균 밝기 값을 저장하여 평균 밝기가 가장 높습니다.

모든 단계에서 우리는 가장 높은 값을 가진 쌍을 선택하여 루프에서 확장하여 최대 평균 밝기를 얻도록하고 새로운 최적의 루프 크기와 밝기 값을 계산합니다.

(value, size, point_pair) 삼중 항을 값으로 정렬 된 힙 구조에 저장하므로 가장 큰 요소 (O (1))를 제거하고 새로운 수정 된 요소 (O (log n))를 효율적으로 추가 할 수 있습니다.

픽셀 수 제한에 도달하면 그 뱀이 마지막 뱀이됩니다.

수직선 사이의 거리는 결과에 거의 영향을 미치지 않으므로 일정한 40 픽셀이 선택되었습니다.

결과

swirl    1.33084397946
chaos    1.76585674741
fractal  1.49085737611
bridge   1.42603926741
balls    1.92235115238
scream   1.48603818637
----------------------
average  1.57033111819

에이 에이 에이 에이 에이 에이

참고 : 원본 "Scream"그림을 사용할 수 없었으므로 비슷한 해상도의 다른 "Scream"그림을 사용했습니다.

"소용돌이"이미지에서 뱀 확장 과정을 보여주는 GIF :

에이

이 코드는 stdin에서 하나 이상의 공백으로 구분 된 파일 이름을 가져 와서 결과 뱀 이미지를 png 파일에 기록하고 점수를 stdout에 인쇄합니다.

from PIL import Image
import numpy as np
import heapq as hq

def upd_sp(p,st):
    vs,c=0,0
    mv,mp=-1,0
    for i in range(st,gap):
        if p[1]+i<h:
            vs+=v[p[0],p[1]+i]+v[p[0]+1,p[1]+i]
            c+=2
            if vs/c>mv:
                mv=vs/c
                mp=i
    return (-mv,mp)

mrl=[]
bf=input().split()

for bfe in bf:
    mr,mg=0,0    
    for gap in range(40,90,1500):

        im=Image.open(bfe)
        im_d=np.asarray(im).astype(int)

        v=im_d[:,:,0]+im_d[:,:,1]+im_d[:,:,2]

        w,h=v.shape

        fp=[]
        sp=[]
        x,y=0,0
        d=1

        go=True
        while go:
            if 0<=x+2*d<w:
                fp+=[(x,y)]
                fp+=[(x+d,y)]
                sp+=[(x-(d<0),y)]
                x+=2*d
                continue
            if y+gap<h:
                for k in range(gap):
                    fp+=[(x,y+k)]
                y+=gap
                d=-d
                continue
            go=False

        sh=[]
        px=im.load()

        pl=[]

        for p in fp:
            pl+=[v[p[0],p[1]]]
            px[p[1],p[0]]=(0,127,0)   

        for p in sp:
            mv,mp=upd_sp(p,1)
            if mv<=0:
                hq.heappush(sh,(mv,1,mp+1,p))

        empty=False
        pleft=h*w//3
        pleft-=len(fp)
        while pleft>gap*2 and not empty:

            if len(sh)>0:
                es,eb,ee,p=hq.heappop(sh)
            else:
                empty=True
            pleft-=(ee-eb)*2

            mv,mp=upd_sp(p,ee)
            if mv<=0:
                hq.heappush(sh,(mv,ee,mp+1,p))    

            for o in range(eb,ee):
                pl+=[v[p[0],p[1]+o]]
                pl+=[v[p[0]+1,p[1]+o]]
                px[p[1]+o,p[0]]=(0,127,0)   
                px[p[1]+o,p[0]+1]=(0,127,0)

        pl+=[0]*pleft

        sb=sum(pl)/len(pl)
        ob=np.sum(v)/(h*w)

        im.save(bfe[:-4]+'snaked.png')

        if sb/ob>mr:
            mr=sb/ob
            mg=gap

    print(bfe,mr)
    mrl+=[mr]

print(sum(mrl)/len(mrl))

5

파이썬 2 (점수 : 0.0797116)

볼 롤링을 얻기 위해 매우 간단하고 순진한 욕심 많은 알고리즘.

#!/usr/bin/python

from PIL import Image

OFFSETS = [(-1, 0), (0, -1), (1, 0), (0, 1)]
def test_img(filename):
    img = Image.open(filename)

    joe, eaten = (0, 0), []
    img_w, img_h = img.size
    all_pixels = [
        sum(img.getpixel((x, y)))
        for x in xrange(img_w)
        for y in xrange(img_h)
    ]
    total_brightness = float(sum(all_pixels)) / len(all_pixels)

    for _ in xrange(0, (img_w*img_h)/3):
        max_offset, max_brightness = (0, 0), 0
        for o in OFFSETS:
            try:
                brightness = sum(img.getpixel((joe[0] + o[0], joe[1] + o[1])))
            except IndexError:
                brightness = -1
            if brightness >= max_brightness:
                max_offset = o
                max_brightness = brightness

        joe = (joe[0] + max_offset[0], joe[1] + max_offset[1])
        eaten.append(max_brightness)
        img.putpixel(joe, (0, 0, 0))

    eaten_brightness = float(sum(eaten)) / len(eaten)
    print('%d of %d (score %f)' % (eaten_brightness, total_brightness, eaten_brightness / total_brightness))
    img.show()

test_img('img0.jpg')
test_img('img1.png')
test_img('img2.jpg')
test_img('img3.jpg')
test_img('img4.jpg')

산출:

llama@llama:~/Code/python/ppcg40069hungrysnake$ ./hungrysnake.py 
15 of 260 (score 0.060699)
9 of 132 (score 0.074200)
16 of 300 (score 0.055557)
4 of 369 (score 0.010836)
79 of 400 (score 0.197266)

1
나는 당신의 점수가 꺼져 있다고 생각합니다. 그것은 전체 그림의 평균 밝기보다 먹은 Joe의 밝기의 평균입니다. 임의의 Joe는 대략 1의 점수를 얻어야합니다.
Stretch Maniac

@StretchManiac 흠, 나는 잘못된 것을 보지 못한다. sum of brightnesses of eaten pixels / amount of eaten pixels올바른 공식입니까? 어쩌면 그것은 정말 끔찍한 알고리즘 일 것입니다.)
Doorknob

@Doorknob 그것은The average brightness of pixels Joe eats / The average brightness of the pixels in the picture*
hmatt1

오렌지색과 검은 색 소용돌이 모양 (파란색이 아닌)의 경우 평균 밝기가 68.0846입니다 ... 어떤 것과도 일치하지 않는 것 같습니다. 아마도 sum (getPixel (...))이 원하는 것을 반환하지 않습니까? (저는 파이썬 초보자입니다). BTW에는 6 개의 사진이 있지만 5 개의 출력 만 있습니다. 어떻게 든 사진에 라벨을 붙일 수 있습니까?
스트레칭 미치 광

@StretchManiac 밝기를 어떻게 계산합니까? 광산은 단지 R, G 및 B 값의 합계입니다. 죄송합니다. 두 번째로 마지막으로 나오는 소용돌이 모양을 놓쳤습니다 (귀하의 의견에서 언급 한 것 같습니다). 나는 아침에 그것을 추가 할 것입니다 (지금 자야합니다).
Doorknob

5

자바 (점수 : 0.6949)

현재 픽셀을 둘러싸고있는 4 개의 픽셀 중 가장 밝은 픽셀을 먹는 간단한 알고리즘입니다. 동점의 경우, 먹은 픽셀은 임의적이며, 점수가 다르고 매 실행마다 이미지가 달라집니다. 따라서 아래 점수는 각 이미지에서 평균 50 회 이상 실행 된 것입니다.

그것을 세 가지 인수는 소스 (클래스 상수로 기존) 중 편집을 실행하거나 형태로 명령 줄을 통해이를 전달하려면 먹을 이미지의 소스 파일, 이미지를 먹는 횟수 (복용입니다 평균 점수 및 모든 반복에서 최고 점수 저장) 및 각 반복의 점수를 인쇄하려면 true 이고, 그렇지 않으면 false입니다.java HungryImageSnake <source> <iterations> <printScores><source><iterations><printScores>

import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

public class HungryImageSnake {

    private static final String SOURCE = "tornado.jpg";
    private static final int ITERATIONS = 50;
    private static final boolean PRINT_SCORES = true;

    public static void main(String[] args) {
        try {
            String source = args.length > 0 ? args[0] : SOURCE;
            int iterations = args.length > 1 ? Integer.parseInt(args[1]) : ITERATIONS;
            boolean printScores = args.length > 2 ? Boolean.parseBoolean(args[2]) : PRINT_SCORES;

            System.out.printf("Reading '%s'...%n", source);
            System.out.printf("Performing %d meals...%n", iterations);
            BufferedImage image = ImageIO.read(new File(source));
            double totalScore = 0;
            double bestScore = 0;
            BufferedImage bestImage = null;
            for (int i = 0; i < iterations; i++) {
                HungryImageSnake snake = new HungryImageSnake(image);
                while (snake.isHungry()) {
                    snake.eat();
                }
                double score = snake.getScore();
                if (printScores) {
                    System.out.printf("    %d: score of %.4f%n", i + 1, score);
                }
                totalScore += score;
                if (bestImage == null || score > bestScore) {
                    bestScore = score;
                    bestImage = snake.getImage();
                }
            }
            System.out.printf("Average score: %.4f%n", totalScore / iterations);
            String formattedScore = String.format("%.4f", bestScore);
            String output = source.replaceFirst("^(.*?)(\\.[^.]+)?$", "$1-b" + formattedScore + "$2");
            ImageIO.write(bestImage, source.substring(source.lastIndexOf('.') + 1), new File(output));
            System.out.printf("Wrote best image (score: %s) to '%s'.%n", bestScore, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int x;
    private int y;
    private int movesLeft;
    private int maximumMoves;
    private double eatenAverageBrightness;
    private double originalAverageBrightness;
    private BufferedImage image;

    public HungryImageSnake(BufferedImage image) {
        this.image = copyImage(image);
        int size = image.getWidth() * image.getHeight();
        this.maximumMoves = size / 3;
        this.movesLeft = this.maximumMoves;
        int totalBrightness = 0;
        for (int x = 0; x < image.getWidth(); x++) {
            for (int y = 0; y < image.getHeight(); y++) {
                totalBrightness += getBrightnessAt(x, y);
            }
        }
        this.originalAverageBrightness = totalBrightness / (double) size;
    }

    public BufferedImage getImage() {
        return image;
    }

    public double getEatenAverageBrightness() {
        return eatenAverageBrightness;
    }

    public double getOriginalAverageBrightness() {
        return originalAverageBrightness;
    }

    public double getScore() {
        return eatenAverageBrightness / originalAverageBrightness;
    }

    public boolean isHungry() {
        return movesLeft > 0;
    }

    public void eat() {
        if (!isHungry()) {
            return;
        }
        int[][] options = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        shuffleArray(options); // prevent snake from getting stuck in corners
        int[] bestOption = null;
        int bestBrightness = 0;
        for (int[] option : options) {
            int optionX = this.x + option[0];
            int optionY = this.y + option[1];
            if (exists(optionX, optionY)) {
                int brightness = getBrightnessAt(optionX, optionY);
                if (bestOption == null || brightness > bestBrightness) {
                    bestOption = new int[]{ optionX, optionY };
                    bestBrightness = brightness;
                }
            }
        }

        image.setRGB(bestOption[0], bestOption[1], 0);
        this.movesLeft--;
        this.x = bestOption[0];
        this.y = bestOption[1];
        this.eatenAverageBrightness += bestBrightness / (double) maximumMoves;
    }

    private boolean exists(int x, int y) {
        return x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight();
    }

    private int getBrightnessAt(int x, int y) {
        int rgb = image.getRGB(x, y);
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = rgb & 0xFF;
        return r + g + b;
    }

    private static <T> void shuffleArray(T[] array) {
        Random random = new Random();
        for (int i = array.length - 1; i > 0; i--) {
            int index = random.nextInt(i + 1);
            T temp = array[index];
            array[index] = array[i];
            array[i] = temp;
        }
    }

    private static BufferedImage copyImage(BufferedImage source){
        BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
        Graphics g = b.getGraphics();
        g.drawImage(source, 0, 0, null);
        g.dispose();
        return b;
    }
}

이미지를 기준으로 50 회 이상의 평균 점수 :

Bridge - 0.7739
Spheres - 0.5580
Scream - 0.8197
Fractal - 0.3850
Vortex - 0.9158
Tornado - 0.7172

동일한 50 회 반복에서 이미지 별 최고 점수 :

Bridge - 0.8996
Spheres - 0.8741
Scream - 0.9183
Fractal - 0.5720
Vortex - 1.1520
Tornado - 0.9281

가장 높은 점수를받은 런의 이미지 :

다리-0.8996 구체-0.8741 비명-0.9183 프랙탈-0.5720 소용돌이-1.1520 토네이도-0.9281

이미지에서 알 수 있듯이, 뱀은 이미 먹은 픽셀 사이에 때때로 붙어 있기 때문에 픽셀의 3 분의 1보다 훨씬 적게 실제로 먹습니다.이 지점에서 움직임의 임의성이 나타날 때까지 죽은 영역 내에 붙어 있습니다. 이미지의 식용 부분.

뱀이 다시 먹는 픽셀의 결과로, 데드 픽셀의 제로 밝기가 다시 평균으로 반영되기 때문에 점수가 아래로 바이어스됩니다. 스코어링 알고리즘을 수정하여 모든 움직임이 아닌 새로운 픽셀을 먹는 움직임의 수로 만 나누도록 수정하면 뱀이 이전에 먹은 죽은 픽셀을 먹는 동작을 포함하여 훨씬 더 높은 점수를 기대합니다. ).

물론 더 나은 방법은 각 픽셀에 대해 일종의 밝기 휴리스틱을 생성하고 width * height / 3평균 평균 밝기가 가장 높은 픽셀 의 경로를 찾는 것입니다 . 그러나이 방법은 런타임에서 특히 숫자가 큰 이미지에서 최적 일 것입니다. 가능한 순열의 수가 매우 클 것입니다. 나중에이 접근법의 어떤 형태로 촬영하여 별도의 답변에 게시 할 수 있습니다.


내 답변의 크기로 인해 누군가가 신경 쓰이는 경우 (내 이미지로 인해) 알려 주시면 링크 나 다른 덜 대안적인 대안을 위해 이미지를 제거하겠습니다. 또는 누군가가 "먹은"이미지의 전체 해상도 원본을 원한다면 의견으로도 알려주십시오.
FThompson

4

파이썬 2, 점수 : 1.205

얼마 전에 빠른 Python 솔루션을 만들었지 만 게시하지 않았습니다. 여기있어. 이미지에서 가장 풍부한 블록을 찾은 다음 각 블록으로 이동하여 가장 좋은 블록을 모두 섭취합니다.

결과

bridge.jpg: 591.97866/515.41501 =                               1.14855 
BallsRender.png: 493.24711/387.80635 =                          1.27189 
Mandel_zoom_04_seehorse_tail.jpg: 792.23990/624.60579 =         1.26838 
Red_Vortex_Apophysis_Fractal_Flame.jpg: 368.26121/323.08463 =   1.13983 
The_Scream.jpg: 687.18565/555.05221 =                           1.23806
swirl.jpg: 762.89469/655.73767 =                                1.16341

AVERAGE                                                         1.205

예시 사진

가공 된 다리 사진

파이썬 2.7 코드

from pygame.locals import *
import pygame, sys, random

fn = sys.argv[1]

screen = pygame.display.set_mode((1900,1000))
pic = pygame.image.load(fn)
pic.convert()
W,H = pic.get_size()
enough = W*H/3
screen.blit(pic, (0,0))

ORTH = [(-1,0), (1,0), (0,-1), (0,1)]
def orth(p):
    return [(p[0]+dx, p[1]+dy) for dx,dy in ORTH]

def look(p):
    x,y = p
    if 0 <= x < W and 0 <= y < H:
        return sum(pic.get_at(p))
    else:
        return -1

# index picture
locs = [(x,y) for x in range(W) for y in range(H)]
grid = dict( (p,sum(pic.get_at(p))) for p in locs )
rank = sorted( grid.values() )
median = rank[ len(rank)/2 ]
dark = dict( (k,v) for k,v in grid if v < median )
good = dict( (k,v) for k,v in grid if v > median )
pictotal = sum(rank)
picavg = 1.0 * pictotal/(W*H)
print('Indexed')

# compute zone values:
block = 16
xblocks, yblocks = (W-1)/block, (H-1)/block
zones = dict( ((zx,zy),0) for zx in range(xblocks) for zy in range(yblocks) )
for x,y in locs:
    div = (x/block, y/block)
    if div in zones:
        colsum = sum( pic.get_at((x,y)) )
        zones[div] += colsum

# choose best zones:
zonelist = sorted( (v,k) for k,v in zones.items() )
cut = int(xblocks * yblocks * 0.33)
bestzones = dict( (k,v) for v,k in zonelist[-cut:] )

# make segment paths:
segdrop = [(0,1)] * (block-1)
segpass = [(1,0)] * block
segloop = [(0,-1)] * (block-1) + [(1,0)] + [(0,1)] * (block-1)
segeat = ( segloop+[(1,0)] ) * (block/2)
segshort = [(1,0)] * 2 + ( segloop+[(1,0)] ) * (block/2 - 1)

def segtopath(path, seg, xdir):
    for dx,dy in seg:
        x,y = path[-1]
        newloc = (x+dx*xdir, y+dy)
        path.append(newloc)

# design good path:
xdir = 1
path = [(0,0)]
segtopath(path, segdrop, xdir)
shortzone = True
while True:
    x,y = path[-1]
    zone = (x/block, y/block)
    if zone in bestzones:
        if shortzone:
            seg = segshort
        else:
            seg = segeat
    else:
        seg = segpass
    segtopath(path, seg, xdir)
    shortzone = False
    # check end of x block run:
    x,y = path[-1]
    zone = (x/block, y/block)
    if not ( 0 <= x < xblocks*block ):
        del path[-1]
        segtopath(path, segdrop, xdir)
        shortzone = True
        xdir = xdir * -1
    if len(path) > enough:
        break
print('Path Found')

# show path on picture:
loc = path.pop(0)
eaten = 1
joetotal = grid[loc]
i = 0
while eaten <= enough:
    loc = path[i]
    i += 1
    pic.set_at(loc, (0,0,0))
    joetotal += grid[loc]
    eaten += 1
    if i % 1000 == 0:
        screen.blit(pic, (0,0))
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == QUIT: sys.exit(0)

# save picture and wait:
screen.blit(pic, (0,0))
pygame.display.flip()
pygame.image.save(pic, 'output/'+fn)
joeavg = 1.0 * joetotal/eaten
print '%s: %7.5f/%7.5f = %7.5f' % (fn, joeavg, picavg, joeavg/picavg)
while True:
    for event in pygame.event.get():
        if event.type == QUIT: sys.exit(0)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.