Hungrige Bild-Schlange - Loch # 3


25

Loch Nr. 1

Joe die Schlange hat Hunger.

Er isst Pixel für Pixel Bilder.

Er mag wirklich helle Pixel.

Die Herausforderung

Programmiere Joe, um die hellsten Pixel zu essen, die er finden kann, vorausgesetzt, er kann sich nur nach oben, unten, links oder rechts bewegen.

Spezifikationen

  • Joe muss am oberen linken Pixel des Bildes beginnen.
  • Joe kann sich bei jeder Bewegung nur um 1 horizontal oder vertikal bewegen
  • Joe hat nur genug Zeit, um 1/3 der Pixelanzahl im Bild zu verschieben (1/3 so viele Bewegungen wie Pixel). Wenn die Anzahl der Pixel kein Vielfaches von 3 ist, runden Sie auf die nächste Ganzzahl ab.
  • Joe kann seinen Weg kreuzen, obwohl das als 0 Helligkeit zählt
  • Die Helligkeit basiert auf der Summe von r, g und b, sodass rgb (0,0,0) eine Helligkeit von 0 hat, während rgb (255,255,255) die maximale Helligkeit hat.

Eingang

Sie können das Bild eingeben, wie Sie möchten.

Ausgabe

  • ein Bild, das das Endergebnis Ihres Bildes zeigt (wobei Schwarz Pixel sind).
  • Die Menge der verbrauchten Helligkeit (bitte geben Sie den Bereich in Ihrer Antwort an)

Wertung

Ihr Programm wird benotet mit:

  • Die durchschnittliche Helligkeit der Pixel, die Joe isst / Die durchschnittliche Helligkeit der Pixel im Bild *

* Sie können dies in Ihrem Programm fest codieren

Ihre Gesamtpunktzahl ist der Durchschnitt der Punkte für die folgenden Bilder:

Testbilder:

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

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

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben


3
Fun Markdown Tatsache - Sie können Bilder in Links drehen , um ihre Originale: [![image description](SE URL for downsized image)](URL for original image).
Calvins Hobbys

1
Es könnte eine Idee sein, die Leute zu bitten, ein Beispiel für ein "gegessenes" Bild in ihre Antworten aufzunehmen.
Nathaniel

Antworten:


16

C ++, Partitur: 1,42042 1,46766

Dies ist im Wesentlichen eine etwas ausgefeiltere Version der beiden vorhandenen Lösungen: Von den vier möglichen Zügen wählt sie diejenige aus, die die Helligkeit maximiert. Anstatt nur die Helligkeit des Zielpixels zu betrachten, wird die gewichtete Summe der Pixelhelligkeit in der Nachbarschaft des Zielpixels betrachtet, wobei Pixel, die näher am Ziel liegen, ein größeres Gewicht haben.

BEARBEITEN: Die Verwendung von nichtlinearer Helligkeit bei der Nachbarschaftsberechnung verbessert die Punktzahl geringfügig.

Kompilieren mit g++ joe.cpp -ojoe -std=c++11 -O3 -lcairo. Benötigt Kairo.

Laufen Sie mit joe <image-file> [<radius>]. <image-file>ist das Eingangs-PNG-Bild. <radius>(optionales Argument) ist der Radius der aufsummierten Nachbarschaft in Pixel (kleiner ist schneller, größer ist (ungefähr) besser). Gibt die Partitur und ein benanntes Bild aus 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);
}

Ergebnisse

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

Brücke Bälle Schrei Fraktale Wirbel Tornado

Noch mehr Augenschmaus

Vortex-Animation Tornado-Animation


Ich habe gerade Ihr Programm an einigen meiner eigenen Beispielbilder ausprobiert, und eines hat nur um den Startpunkt sehr viel Schwarz, und dort stürzt Ihr Programm ab, weil das Lambda der Nachbarschaft NaN zurückgibt.
PlasmaHH

@PlasmaHH Stört es Sie, das beleidigende Bild zu teilen?
Ell

Ich habe es mit Urlaubsbildern gefüttert ... 400x400 reines Schwarz macht aber auch den "Trick".
PlasmaHH

@PlasmaHH Nun, ein rein schwarzes Bild hat eine undefinierte Punktzahl, es ist null über null, was ein NaN wäre. Es sollte sich jedoch nicht auf die Nachbarschaftsberechnung auswirken oder das Programm zum Absturz bringen (obwohl dies von der Gleitkommaumgebung abhängen kann.)
Ell

Schauen Sie sich den o_max-Zeiger an, if (o_neighborhood > o_max_neighborhood) o_max = *o, o_max_neighborhood = o_neighborhood;nur dieser Code setzt ihn. Aufgrund von Nan ist der Vergleich jedoch immer falsch, daher wird o_max nie gesetzt und nicht initialisiert verwendet.
PlasmaHH

7

Python 3, Score = 1,57

Zuerst bewegt sich unsere Schlange durch das Bild und erzeugt vertikale Linien mit gleichem Abstand voneinander.

ein

Wir können diese Schlange erweitern, indem wir zwei Punkte in einer vertikalen Linie nebeneinander nehmen und eine Schleife erstellen, deren Endpunkte sie sind.

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

Wir ordnen die Punkte paarweise an und speichern für jedes Paar die Größe und den durchschnittlichen Helligkeitswert der Schleife, die die größte durchschnittliche Helligkeit ergibt.

Bei jedem Schritt wählen wir das Paar mit dem höchsten Wert aus, erweitern seine Schleife, um die maximale durchschnittliche Helligkeit der Erweiterung zu erreichen, und berechnen die neue optimale Schleifengröße und den Helligkeitswert für das Paar.

Wir speichern die (value, size, point_pair) -Triplets in einer nach Wert sortierten Heap-Struktur, damit wir das größte Element (in O (1)) entfernen und das neue modifizierte Element (in O (log n)) effizient hinzufügen können.

Wir hören auf, wenn wir die Pixelzahlgrenze erreicht haben und diese Schlange wird die letzte Schlange sein.

Der Abstand zwischen den vertikalen Linien hat nur einen sehr geringen Einfluss auf das Ergebnis. Daher wurde eine konstante Anzahl von 40 Pixeln gewählt.

Ergebnisse

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

ein ein ein ein ein ein

Hinweis: Das Originalbild "The Scream" war nicht verfügbar, daher habe ich ein anderes Bild "The Scream" mit ähnlicher Auflösung verwendet.

Gif zeigt den Vorgang der Schlangenerweiterung auf dem "Wirbel" -Bild:

ein

Der Code nimmt einen (oder mehrere durch Leerzeichen getrennte) Dateinamen von stdin und schreibt die resultierenden Schlangenbilder in PNG-Dateien und druckt die Partituren nach 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

Python 2 (Ergebnis: 0.0797116)

Nur ein sehr einfacher und naiver, gieriger Algorithmus, um den Ball ins Rollen zu bringen.

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

Ausgabe:

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
Ich denke, Ihre Wertung ist aus. Es ist der Durchschnitt von Joes Helligkeit, der über der durchschnittlichen Helligkeit des gesamten Bildes liegt ... Ein zufälliger Joe sollte eine Punktzahl von ungefähr 1 erhalten.
Stretch Maniac

@StretchManiac Hmm, ich sehe nichts falsches. sum of brightnesses of eaten pixels / amount of eaten pixelsist die richtige Formel, richtig? Vielleicht ist es nur ein wirklich schrecklicher Algorithmus;)
Türknauf

@Doorknob ist es The average brightness of pixels Joe eats / The average brightness of the pixels in the picture*
hmatt1

Für das Orange und Schwarz (nicht Blau) habe ich eine durchschnittliche Helligkeit von 68,0846 ... Die scheint keiner von Ihnen zu entsprechen. Vielleicht liefert sum (getPixel (...)) nicht das, was Sie wollen? (Ich bin ein bisschen ein Python-Neuling). Übrigens gibt es 6 Bilder, aber Sie haben nur 5 Ausgänge. Könntest du die Bilder auch irgendwie beschriften?
Stretch Maniac

@StretchManiac Wie berechnen Sie Ihre Helligkeit? Meins summiert nur die R-, G- und B-Werte. Entschuldigung, ich habe den vorletzten Wirbel verpasst (den, den Sie in Ihrem Kommentar erwähnt haben, glaube ich). Ich werde das morgen hinzufügen (ich muss jetzt schlafen).
Türklinke

5

Java (Ergebnis: 0.6949)

Ein einfacher Algorithmus, der das hellste Pixel der vier das aktuelle Pixel umgebenden Pixel auffrisst. Im Falle eines Unentschieden ist das Pixel zufällig, was bei jeder Ausführung zu unterschiedlichen Ergebnissen und resultierenden Bildern führt. Daher sind die unten stehenden Bewertungen die Durchschnittswerte von über 50 Ausführungen für jedes Bild.

Um es auszuführen, bearbeiten Sie entweder die drei Argumente (die als Klassenkonstanten existieren) in der Quelle oder übergeben Sie sie über die Befehlszeile in der Form, java HungryImageSnake <source> <iterations> <printScores>in der <source>sich die Quelldatei des Bildes befindet, und geben Sie an, <iterations>wie oft das Bild aufgenommen werden soll die durchschnittliche Punktzahl und das Speichern der besten Punktzahl über alle Iterationen) und <printScores>ist wahr, um die Punktzahl jeder Iteration zu drucken, oder falsch, um nicht zu drucken.

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;
    }
}

Durchschnittliche Punktzahl pro Bild über fünfzig Iterationen:

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

Die besten Ergebnisse nach Bild in den gleichen fünfzig Iterationen:

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

Die Bilder der Läufe mit der höchsten Punktzahl:

Brücke - 0,8996 Kugeln - 0,8741 Schrei - 0,9183 Fraktale - 0,5720 Vortex - 1,1520 Tornado - 0,9281

Wie aus den Bildern hervorgeht, wird weit weniger als ein Drittel der Pixel tatsächlich gefressen, da die Schlange gelegentlich zwischen den Pixeln stecken bleibt, die sie bereits gefressen hat. Dabei bleibt sie im toten Bereich stecken, bis die Zufälligkeit ihrer Bewegungen sie dazu bringt ein essbarer Teil des Bildes.

Auch als Folge des erneuten Verzehrs der Pixel durch die Schlange werden die Punktzahlen nach unten verschoben, da die Helligkeit der toten Pixel von Null erneut in den Durchschnitt einbezogen wird. Ich würde weitaus höhere Punktzahlen erwarten, wenn der Bewertungsalgorithmus dahingehend modifiziert würde, dass er nur durch die Anzahl der Züge dividiert wird, die zum Essen neuer Pixel geführt haben, anstatt durch alle Züge (einschließlich der Züge, bei denen die Schlange ein jetzt totes Pixel isst, das sie zuvor gegessen hat) ).

Ein besserer Ansatz wäre natürlich, für jedes Pixel eine Art Helligkeitsheuristik zu erstellen und den Pfad der width * height / 3Pixel mit der höchsten durchschnittlichen Helligkeit zu ermitteln, aber ich bezweifle, dass dieser Ansatz in der Laufzeit optimal ist, insbesondere bei größeren Bildern als Anzahl von möglichen Permutationen wäre sehr groß. Ich werde vielleicht später einen Versuch unternehmen und ihn in einer separaten Antwort veröffentlichen, wenn dies der Fall ist.


Wenn es jemanden stört, wie groß meine Antwort ist (aufgrund der darin enthaltenen Bilder), lassen Sie es mich wissen, und ich werde die Bilder zugunsten von Links oder einer anderen weniger geräumigen Alternative entfernen. Oder wenn jemand die Originalbilder in voller Auflösung von "gegessenen" Bildern haben möchte, lass es mich auch in einem Kommentar wissen.
FThompson

4

Python 2, Score: 1,205

Ich habe vor einiger Zeit eine schnelle Python-Lösung zusammengestellt, aber vergessen, sie zu posten. Hier ist es. Es findet die reichsten Blöcke im Bild, fährt dann zu jedem Block und frisst die besten Blöcke auf, zu denen es kommt.

Ergebnisse

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

Beispiel Bild

Verarbeitetes Brückenbild

Python 2.7-Code

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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.