Hungry Image Snake - Hole # 3


25

หลุม # 1

โจงูหิว

เขากินรูปภาพครั้งละหนึ่งพิกเซล

เขาชอบพิกเซลที่สดใส

ความท้าทาย

โปรแกรมโจเพื่อกินพิกเซลที่สว่างที่สุดที่เขาสามารถหาได้เนื่องจากเขาสามารถเลื่อนขึ้นลงซ้ายหรือขวา

ข้อมูลจำเพาะ

  • โจต้องเริ่มต้นที่พิกเซลซ้ายบนของภาพ
  • Joe สามารถเคลื่อนที่ในแนวนอนหรือแนวตั้งได้เพียง 1 ครั้งเท่านั้น
  • Joe มีเวลาเพียงพอที่จะย้าย 1/3 ของจำนวนพิกเซลในรูปภาพ (1/3 เคลื่อนที่เป็นพิกเซล) หากจำนวนพิกเซลไม่เท่ากับ 3 ให้ปัดเศษเป็นจำนวนเต็มที่ใกล้เคียงที่สุด
  • Joe อาจข้ามเส้นทางของเขาแม้ว่านั่นจะนับว่าเป็นความสว่าง 0
  • ความสว่างขึ้นอยู่กับผลรวมของ r, g และ b ดังนั้น rgb (0,0,0) จึงมีความสว่างเป็น 0 ในขณะที่ rgb (255,255,255) มีความสว่างสูงสุด

อินพุต

คุณสามารถใส่ภาพได้ตามต้องการ

เอาท์พุต

  • รูปภาพที่แสดงผลลัพธ์สุดท้ายของรูปภาพของคุณ (สีดำกำลังถูกกินพิกเซล)
  • จำนวนความสว่างที่รับประทาน (โปรดระบุช่วงที่คุณตอบ)

เกณฑ์การให้คะแนน

โปรแกรมของคุณจะได้รับเกรดเมื่อ:

  • ความสว่างโดยเฉลี่ยของพิกเซลโจกิน / ความสว่างเฉลี่ยของพิกเซลในภาพ *

* คุณอาจ hardcode นี้ในโปรแกรมของคุณ

คะแนนรวมของคุณจะเป็นคะแนนเฉลี่ยสำหรับภาพต่อไปนี้:

ภาพทดสอบ:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

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

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


3
สนุก Markdown ความเป็นจริง - [![image description](SE URL for downsized image)](URL for original image)คุณสามารถเปิดภาพลงในการเชื่อมโยงกับต้นฉบับของพวกเขา
งานอดิเรกของ Calvin

1
อาจเป็นความคิดที่จะขอให้ผู้คนใส่ตัวอย่าง "ภาพ" ที่กินเข้าไปในคำตอบของพวกเขา
นาธาเนียล

คำตอบ:


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

สะพาน ลูก กรีดร้อง เศษส่วน กระแสน้ำวน พายุทอร์นาโด

ขนมตาเพิ่มเติม

ภาพเคลื่อนไหว Vortex ภาพเคลื่อนไหวทอร์นาโด


ฉันลองโปรแกรมของคุณในภาพตัวอย่างบางภาพของฉันเองและภาพหนึ่งมีจุดสีดำมากรอบ ๆ จุดเริ่มต้นเท่านั้นและโปรแกรมของคุณก็ขัดข้อง
PlasmaHH

@PlasmaHH คุณต้องการแบ่งปันภาพที่ละเมิดหรือไม่
Ell

ผมก็ให้อาหารมันภาพวันหยุด ... 400x400 บริสุทธิ์สีดำไม่ "เคล็ดลับ" เกินไป แต่
PlasmaHH

@PlasmaHH อืมภาพสีดำล้วน ๆ มีคะแนนที่ไม่ได้กำหนดมันมีค่ามากกว่าศูนย์ซึ่งจะเป็น NaN ไม่ควรส่งผลกระทบต่อการคำนวณพื้นที่ใกล้เคียงหรือทำให้โปรแกรมขัดข้อง (ซึ่งอาจขึ้นอยู่กับสภาพแวดล้อมของจุดลอยตัว)
Ell

มีลักษณะที่ชี้ o_max if (o_neighborhood > o_max_neighborhood) o_max = *o, o_max_neighborhood = o_neighborhood;เพียงรหัสนี้ชุดมัน อย่างไรก็ตามเนื่องจากมีส่วนเกี่ยวข้องกับน่านการเปรียบเทียบจึงเป็นเท็จเสมอดังนั้น o_max จึงไม่เคยถูกตั้งค่าและใช้งานโดยไม่กำหนดค่าเริ่มต้น
PlasmaHH

7

Python 3 คะแนน = 1.57

ครั้งแรกของเราเดินทางงูภาพการสร้างเส้นแนวตั้งที่มีระยะทางเท่ากันจากแต่ละอื่น ๆ

a

เราสามารถขยายงูนี้โดยการจับสองจุดติดกันเป็นแนวตั้งและสร้างลูปที่มีจุดปลายอยู่

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

เราจัดระเบียบคะแนนให้เป็นคู่และสำหรับทุกคู่ที่เราจัดเก็บขนาดและค่าความสว่างเฉลี่ยของลูปที่ให้มีความสว่างเฉลี่ยมากที่สุด

ในทุกขั้นตอนเราเลือกคู่ที่มีค่าสูงสุดขยายลูปเพื่อให้ได้ความสว่างเฉลี่ยสูงสุดในส่วนขยายและคำนวณขนาดลูปและความสว่างที่เหมาะสมที่สุดสำหรับคู่

เราเก็บ Triplets (ค่า, ขนาด, 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

a a a a a a

หมายเหตุ: รูปภาพต้นฉบับ "The Scream" ไม่พร้อมใช้งานดังนั้นฉันจึงใช้รูปภาพ "The Scream" อื่นที่มีความละเอียดใกล้เคียงกัน

Gif แสดงกระบวนการขยายงูบนภาพ "หมุนวน":

a

รหัสใช้ชื่อไฟล์หนึ่งชื่อ (หรือมากกว่าคั่นด้วยช่องว่าง) จาก 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

Python 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
ฉันคิดว่าคะแนนของคุณไม่ดี มันเป็นค่าเฉลี่ยของความสว่างของโจกินมากกว่าความสว่างเฉลี่ยสำหรับภาพรวม ... สุ่มโจควรจะได้รับคะแนนประมาณ 1.
ยืด 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

สำหรับสีส้มและสีดำ swirly (ไม่ใช่สีน้ำเงิน) ฉันได้ความสว่างเฉลี่ยที่ 68.0846 ... ซึ่งดูเหมือนจะไม่ตรงกับของคุณเลย บางทีผลรวม (getPixel (... )) จะไม่ส่งคืนสิ่งที่คุณต้องการใช่ไหม (ฉันเป็นมือใหม่หลาม) BTW มี 6 ภาพ แต่คุณมีเพียง 5 ผลลัพธ์ คุณสามารถติดป้ายรูปภาพได้ไหม?
ยืด Maniac

@StretchManiac คุณคำนวณความสว่างของคุณอย่างไร? ฉันจะสรุปค่า R, G และ B ขออภัยฉันพลาดหนึ่ง swirly ที่มาเป็นครั้งที่สองถึงครั้งสุดท้าย (คนที่คุณกล่าวถึงในความคิดเห็นของคุณฉันคิดว่า) ฉันจะเพิ่มมันในตอนเช้า (ฉันต้องนอนตอนนี้)
Doorknob

5

Java (คะแนน: 0.6949)

อัลกอริทึมง่าย ๆ ที่กินพิกเซลที่สว่างที่สุดออกมาจากสี่พิกเซลรอบ ๆ พิกเซลปัจจุบัน ในกรณีที่มีการเสมอกันพิกเซลที่กินจะถูกสุ่มนำไปสู่คะแนนที่แตกต่างกันและทำให้เกิดภาพแต่ละภาพ ด้วยเหตุนี้คะแนนด้านล่างจึงเป็นค่าเฉลี่ยมากกว่าการประหารชีวิต 50 ครั้งในแต่ละภาพ

หากต้องการเรียกใช้ให้แก้ไขอาร์กิวเมนต์สามตัว (ที่มีอยู่เป็นค่าคงที่คลาส) ในแหล่งข้อมูลหรือส่งผ่านทางบรรทัดคำสั่งในรูปแบบ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;
    }
}

คะแนนเฉลี่ยโดยภาพมากกว่าห้าซ้ำซ้ำ:

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

คะแนนที่ดีที่สุดโดยภาพในช่วงห้าซ้ำซ้ำ:

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

ภาพวิ่งให้คะแนนสูงสุด:

สะพาน - 0.8996 ทรงกลม - 0.8741 Scream - 0.9183 เศษส่วน - 0.5720 Vortex - 1.1520 พายุทอร์นาโด - 0.9281

ดังที่เห็นได้ชัดจากภาพนั้นกินน้อยกว่าหนึ่งในสามของจำนวนพิกเซลจริง ๆ ขณะที่งูติดอยู่ในหมู่พิกเซลที่มันกินเข้าไปแล้วซึ่งมันยังคงติดอยู่ในบริเวณที่ตายจนกว่าการเคลื่อนไหวแบบสุ่มจะนำไปสู่ ส่วนที่กินได้ของภาพ

เช่นเดียวกับผลจากการกินพิกเซลงูอีกครั้งคะแนนจะลดลงเนื่องจากความสว่างของศูนย์พิกเซลที่ตายแล้วจะถูกนำมาพิจารณาอีกครั้งโดยเฉลี่ย ฉันคาดหวังว่าจะเห็นคะแนนที่สูงกว่านี้หากอัลกอริทึมการให้คะแนนได้รับการแก้ไขเพื่อหารด้วยจำนวนการเคลื่อนไหวที่นำไปสู่การกินพิกเซลใหม่มากกว่าการเคลื่อนไหวทั้งหมด (รวมถึงการที่งูกินพิกเซลที่ตายแล้ว )

แน่นอนว่าวิธีที่ดีกว่าคือการสร้าง heuristic ความสว่างสำหรับแต่ละพิกเซลและค้นหาเส้นทางของwidth * height / 3พิกเซลที่มีความสว่างเฉลี่ยสูงสุด แต่ฉันสงสัยว่าวิธีการนี้จะเหมาะสมที่สุดในเวลาทำงานโดยเฉพาะกับรูปภาพที่มีขนาดใหญ่ขึ้นตามจำนวน ของการเรียงสับเปลี่ยนที่เป็นไปได้จะมีขนาดใหญ่มาก ฉันอาจใช้วิธีนี้ในบางรูปแบบในภายหลังและโพสต์ไว้ในคำตอบแยกต่างหากถ้าเป็นเช่นนั้น


หากมีใครสนใจว่าคำตอบของฉันมีขนาดใหญ่เพียงใด (เนื่องจากภาพในภาพ) ให้ฉันรู้และฉันจะลบภาพออกไปในรูปของลิงก์หรือทางเลือกอื่นที่ไม่ค่อยมีชีวิตชีวา หรือหากใครต้องการต้นฉบับที่มีความละเอียดเต็มรูปแบบของภาพ "eaten" ใด ๆ โปรดแจ้งให้เราทราบในความคิดเห็นด้วย
FThompson

4

Python 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

รูปภาพตัวอย่าง

รูปภาพบริดจ์ที่ประมวลผล

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.