Git ve yıldızlı yap


14

Bu yarışmada, siyah beyaz bir piksel görüntüsünü kabul eden ve değiştirmeye çalışan bir program yazmalısınız, böylece beyaz şekil mümkün olduğunca az değişiklikle yıldız alanı oluşturur .

İzin verilen değişiklikler beyaz pikselleri siyah olanlara ve siyah pikselleri beyaz olanlara dönüştürüyor.

Çıktı yine aynı görüntüden oluşmalıdır, ancak bu sefer tüm değişikliklerle ve / merkeziyle işaretlenmiş olmalıdır. Beyazdan siyaha değiştirilen piksellerin mavi, siyahtan beyaza değiştirilen piksellerin sarı ve en az bir merkez pikseli kırmızı olarak gösterilmelidir. (Tam renkler size kalmış.) Program, belirtilen görüntünün yanı sıra yapılan toplam değişiklik sayısını da çıkarmalıdır.

Tanımlar

Yıldız Alanı

Görüntünün beyaz pikseli kümesi (ve yalnızca) en az bir merkez piksel varsa bir yıldız alanını temsil eder . Merkezdeki piksel bir tarafından conneced edilebilir beyaz piksel biri düz çizgi çizgi sadece beyaz pikselleri erişir, böylece diğer beyaz tüm pikseller için. (Bu nedenle merkez piksel mutlaka benzersiz değildir.)

İki piksel arasında düz çizgi

İki piksel (başlangıç ​​ve bitiş, her ikisi de aşağıdaki çizimde kırmızıdır) verildiğinde , iki piksel arasındaki uzunluk çizgisi , ilkin merkezinden giden (aşağıdaki resimde matematiksel, sarı) çizgiye dokunan tüm piksellerden oluşur. Piksel son pikselin merkezine kadar. Bir piksel olduğu değil , sadece bir köşede bunu dokunursa bir piksel ait için, yani hattıyla temas piksel hattı (matematiksel, sarı) hattı, sıfır olmayan bir uzunluğa sahip, söz konusu pikselin geçmeye sahiptir. (Yalnızca köşe noktasına değerse, bu uzunluk sıfır olarak kabul edilir). Aşağıdaki örnekleri düşünün:

piksel

Misal

İlk resim örnek bir testcase 'girişini' temsil etmeli ve diğer iki resim verilen örnek için iki geçerli olası çıkışı temsil etmelidir:

örnek test çantası ilk örnek çözüm ikinci örnek çözüm

Sarı alanlar (eski adıyla siyah) 'beyaz' alan adına, mavi alanlar (eski adıyla beyaz) alan adının dışındaki 'siyah' kısma sayılır ve her seferinde kırmızı nokta olası bir merkez pikseli temsil eder.

Test Durumları

Follwoing test senaryoları her biri 256 x 256 piksel boyutunda olan png'lerdir.

test örneği 1 test örneği 2 test durumu 3 test çantası 4 test çantası 5 test çantası 6

puanlama

Lütfen programınızı aşağıdaki test senaryolarıyla çalıştırın ve çıktıyı (resim / değişiklik sayısı) cevabınıza ekleyin. Her test senaryosu için bir afiş yapacağım. Skorunuz skor tablosundaki her bir sıralamanın toplamı olacaktır - skor ne kadar düşükse o kadar iyidir. Standart boşluklar geçerlidir. Programın bu test senaryolarını tanımasına ve onlar için özel bir vaka çalıştırmasına izin verilmez. (Bu test senaryolarının her biri için en uygun merkez piksellerinin önceden hesaplanmasına ve kaydedilmesine izin verilmez.) Program herhangi bir görüntü için çalışmalıdır.

Liderler Sıralaması

Name        | Score | 1     - rk | 2     - rk | 3     - rk | 4     - rk | 5     - rk | 5     - rk | Total Changes
------------+-------+------------+------------+------------+------------+------------+------------+--------------
Maltysen    |    11 | 28688 -  2 | 24208 -  2 | 24248 -  1 |  7103 -  2 | 11097 -  2 | 13019 -  2 | 108363
TheBestOne  |     7 | 0     -  1 | 13698 -  1 | 24269 -  2 |   103 -  1 |  5344 -  1 |  4456 -  1 |  47867  

2
Şekil 1'i açıklamanız size yardımcı olacaktır. Örneğin, neden kırmızı pikseller bağlıyorsunuz?
DavidC

4
Ne demek istediğinden emin değilim. Test durumlarınızdan birinden önce ve sonra verebilir misiniz?

Bir çizginin geçmesi için piksel köşesine ne kadar yakın olması gerekir?
TheNumberOne

Bazı örnekler ekledim ve metni açıklığa kavuşturmaya çalıştım, umarım şimdi açıktır!
Kusur

Bu meydan okumayı denemek isteyen başka biri var mı? Biraz kafam karıştı, çünkü birkaç kişi bu zorluğu aştı ama şimdiye kadar sadece bir (çok ciddi değil) cevabımız var. Herhangi bir eleştiri var mı?
flawr

Yanıtlar:


4

Java 8, 47.867 toplam değişiklik.

Görüntünün ortalamasını merkez noktası olarak kullanır. Daha sonra olası tüm ışınları merkeze çeker ve renge en iyi yarıçapı verir. Ardından tüm geçersiz noktaları siyah renklendirir.

import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MakeItStarry {

    private static final int RGB_RED = Color.RED.getRGB();
    static int[][] originalImage;

    static final int WHITE = 0;
    static final int BLACK = 1;
    static final int RGB_WHITE = Color.WHITE.getRGB();
    static final int RGB_BLACK = Color.BLACK.getRGB();
    static final int RGB_BLUE = Color.BLUE.getRGB();
    static final int RGB_YELLOW = Color.YELLOW.getRGB();

    public static void main(String[] args) throws Exception{
        originalImage = convert(ImageIO.read(new File(args[0])));
        Point center = findCenter(originalImage);
        int[][] nextImage = starry(originalImage, center);
        BufferedImage result = difference(originalImage, nextImage);
        result.setRGB(center.x, center.y, RGB_RED);
        String fileType;
        String fileName;
        if (args[1].split("\\.").length > 1){
            fileType = args[1].split("\\.")[1];
            fileName = args[1];
        } else {
            fileType = "PNG";
            fileName = args[1] + ".PNG";
        }
        ImageIO.write(result, fileType, new File(fileName));
        System.out.println(cost);
    }

    static int cost;

    private static BufferedImage difference(int[][] image1, int[][] image2) {
        cost = 0;
        int height = image1[0].length;
        int width = image1.length;
        BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++){
            for (int y = 0; y < width; y++){
                if (image1[x][y] == image2[x][y]){
                    if (image1[x][y] == WHITE){
                        result.setRGB(x, y, RGB_WHITE);
                    } else {
                        result.setRGB(x, y, RGB_BLACK);
                    }
                } else {
                    cost++;
                    if (image1[x][y] == WHITE){
                        result.setRGB(x, y, RGB_BLUE);
                    } else {
                        result.setRGB(x, y, RGB_YELLOW);
                    }
                }
            }
        }
        return result;
    }

    private static int[][] starry(int[][] image, Point center) {
        int width = image.length;
        int height = image[0].length;
        int[][] result = new int[width][height];
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                result[x][y] = BLACK;
            }
        }
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++) {
                Point endPoint = new Point(x, y, image);
                List<Point> line = Point.lineTo(center, endPoint, image);
                List<Point> newLine = starRay(line);
                newLine.stream().filter(point -> result[point.x][point.y] == BLACK).forEach(point -> {
                    result[point.x][point.y] = point.color;
                });
            }
        }
        int distance = 0;
        while (distance < height || distance < width){//This removes pixels that can't see the center.
            for (int x = Math.max(center.x - distance,0); x < center.x + distance && x < width; x++){
                for (int y = Math.max(center.y - distance, 0); y < center.y + distance && y < height; y++){
                    Point point = new Point(x, y, result);
                    if (Point.distance(center, point) != distance){
                        continue;
                    }
                    if (point.color == WHITE){
                        List<Point> line = Point.lineTo(center, point, result);
                        for (Point p : line){
                            if (p.color == BLACK){
                                point.color = BLACK;
                                break;
                            }
                        }
                        result[point.x][point.y] = point.color;
                    }
                }
            }//All white pixels can technically see the center but only if looking from the edge.
            distance++;
        }
        return result;
    }

    private static List<Point> starRay(List<Point> line) {
        int numOfWhites = 0;
        int farthestGoodPoint = 0;
        int blackCost = 0;
        int whiteCost = 0;
        for (int i = 0; i < line.size(); i++){
            if (line.get(i).color == WHITE){
                numOfWhites++;
                whiteCost++;
                if (numOfWhites + whiteCost > blackCost){
                    blackCost = 0;
                    whiteCost = 0;
                    farthestGoodPoint = i;
                }
            } else {
                blackCost++;
                numOfWhites = 0;
            }
        }
        List<Point> result = new ArrayList<>();
        for (int i = 0; i < line.size(); i++){
            Point p = line.get(i);
            if (i <= farthestGoodPoint){
                result.add(new Point(p.x, p.y, WHITE));
            } else {
                result.add(new Point(p.x, p.y, BLACK));
            }
        }
        return result;
    }

    private static Point findCenter(int[][] image) {
        double totalx = 0;
        double totaly = 0;
        int counter = 0;
        int width = image.length;
        int height = image[0].length;
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                if (image[x][y] == WHITE){
                    totalx += x;
                    totaly += y;
                    counter++;
                }
            }
        }
        return new Point((int)(totalx/counter), (int)(totaly/counter), image);
    }

    private static int[][] convert(BufferedImage image) {
        int width = image.getWidth();
        int height  = image.getHeight();
        int[][] result = new int[width][height];
        for (int x = 0; x < width; x++){
            for (int y = 0; y < height; y++){
                if (image.getRGB(x, y) == RGB_WHITE){
                    result[x][y] = WHITE;
                } else {
                    result[x][y] = BLACK;
                }
            }
        }
        return result;
    }


    private static class Point {

        public int color;
        public int y;
        public int x;

        public Point(int x, int y, int[][] image) {
            this.x = x;
            this.y = y;
            this.color = image[x][y];
        }

        public Point(int x, int y, int color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public static List<Point> lineTo(Point point1, Point point2, int[][] image) {
            List<Point> result = new ArrayList<>();
            boolean reversed = false;
            if (point1.x > point2.x){
                Point buffer = point1;
                point1 = point2;
                point2 = buffer;
                reversed = !reversed;
            }
            int rise = point1.y - point2.y;
            int run = point1.x - point2.x;
            if (run == 0){
                if (point1.y > point2.y){
                    Point buffer = point1;
                    point1 = point2;
                    point2 = buffer;
                    reversed = !reversed;
                }
                int x = point1.x;
                for (int y = point1.y; y <= point2.y; y++){
                    result.add(new Point(x, y, image));
                }
                if (reversed){
                    return reversed(result);
                }
                return result;
            }
            if (rise == 0){
                if (point1.x > point2.x){
                    Point buffer = point1;
                    point1 = point2;
                    point2 = buffer;
                    reversed = !reversed;
                }
                int y = point1.y;
                for (int x = point1.x; x <= point2.x; x++){
                    result.add(new Point(x, y, image));
                }
                if (reversed){
                    return reversed(result);
                }
                return result;
            }
            int gcd = gcd(rise, run);
            rise /= gcd;
            run /= gcd;
            double slope = (rise + 0.0) / run;
            if (Math.abs(rise) >= Math.abs(run)){
                if (point1.y > point2.y){
                    Point buffer = point1;
                    point1 = point2;
                    point2 = buffer;
                    reversed = !reversed;
                }
                double x = point1.x;
                for (double y = point1.y + .5; y <= point2.y; y++){
                    int px = (int) Math.round(x);
                    if (Math.abs(Math.abs(px - x) - .5) < Math.abs(1.0 / (rise * 4))){
                        x += 1/slope;
                        continue;
                    }
                    result.add(new Point(px, (int) Math.round(y - .5), image));
                    result.add(new Point(px, (int) Math.round(y + .5), image));
                    x += 1/slope;
                }
                if (reversed){
                    return reversed(result);
                }
                return result;
            } else {
                if (point1.x > point2.x){
                    Point buffer = point1;
                    point1 = point2;
                    point2 = buffer;
                    reversed = !reversed;
                }
                double y = point1.y;
                for (double x = point1.x + .5; x <= point2.x; x++){
                    int py = (int) Math.round(y);
                    if (Math.abs(Math.abs(py - y) - .5) < Math.abs(1.0 / (run * 4))) {
                        y += slope;
                        continue;
                    }
                    result.add(new Point((int) Math.round(x - .5), py, image));
                    result.add(new Point((int) Math.round(x + .5), py, image));
                    y += slope;
                }
                if (reversed){
                    return reversed(result);
                }
                return result;
            }
        }

        private static List<Point> reversed(List<Point> points) {
            List<Point> result = new ArrayList<>();
            for (int i = points.size() - 1; i >= 0; i--){
                result.add(points.get(i));
            }
            return result;
        }

        private static int gcd(int num1, int num2) {
            if (num1 < 0 && num2 < 0){
                return -gcd(-num1, -num2);
            }
            if (num1 < 0){
                return gcd(-num1, num2);
            }
            if (num2 < 0){
                return gcd(num1, -num2);
            }
            if (num2 > num1){
                return gcd(num2, num1);
            }
            if (num2 == 0){
                return num1;
            }
            return gcd(num2, num1 % num2);
        }

        @Override
        public String toString(){
            return x + " " + y;
        }

        public static int distance(Point point1, Point point2) {
            return Math.abs(point1.x - point2.x) + Math.abs(point1.y - point2.y);
        }
    }
}

Sonuçlar

Resim 1-0 değişiklik, Resim 2 - 13.698 değişiklik

12

Resim 3 - 24.269 değişiklik, Resim 4 - 103 değişiklik

34

Resim 5 - 5.344 değişiklik, Resim 6 - 4.456 değişiklik

56

Geçersiz pikseller kaldırılmadan, toplam 42.782 değişiklik

Yeşil pikseller, geçersiz piksellerin ilk katmanıdır.

Resim 1-0 değişiklik, Resim 2- 9.989 değişiklik

12

Resim 3 - 24.268 değişiklik, Resim 4 - 103 değişiklik

34

Resim 5 - 4.471 değişiklik, Resim 6- 4.050 değişiklik

56

Tüm resimlerdeki tüm beyaz piksellerin, merkezden çıkması / bitmesi değil, pikselin herhangi bir yerinde olması gerekiyorsa, merkez pikselden kendilerine çizilen bir çizgiye sahip olabilir.

args[0] girdi dosya adını içerir.

args[1] çıktı dosya adını içerir.

stdoutDeğişiklik sayısına yazdırır .


Harika görünüyor! Ne demek istediğinizi 'geçersiz pikseller' ile açıklayabilir misiniz? Bunu tam olarak anlamadım. Ayrıca sağ alt taraftaki resim 2'de programınızın neden siyah duvara 'kazdığını' takip edemedim ama yine de beyaz noktaları tekrar siyah renklendirdim, ama bunun geçersiz piksellerle ilgisi olduğunu mu düşünüyorum?
Kusur

Birkaç geçersiz piksel, çok daha geçersiz hale getiren bir basamaklı etkiye neden olur. Geçersiz piksellerin ilk katmanını yeşil olarak göstermek için son birkaç görüntüyü değiştireceğim.
TheNumberOne

3

Python - PIL - 216.228 108.363 toplam değişiklik

Vaay @AJMansfield sayesinde yarıya indirin! Bu algoritma, hesaplama satırları ve optimizasyon ile ilgili tüm endişeleri atlıyor ve ne değil. Biri hariç tüm beyazları siyaha dönüştürür. Beyazlar yoksa, bir siyahı beyaz yapar. Daha fazla beyaz veya siyah olup olmadığını kontrol eder ve biri hariç diğer türlerin her birini değiştirir. Siyah yoksa (0, 0) merkez yapar.

import Image
from itertools import product

img = Image.open(raw_input())
img = img.convert("RGB")

pixdata = img.load()
changed=0

m=False
count=0
for x, y in product(xrange(img.size[1]), xrange(img.size[0])):
    if pixdata[x, y]==(0, 0, 0):
        count+=1

colors=[(0, 0, 0), (255, 255, 0)] if img.size[0]*img.size[1]-count>count else [(255, 255, 255), (0, 0, 255)]
m=False
for x, y in product(xrange(img.size[1]), xrange(img.size[0])):
    if pixdata[x, y] == colors[0]:
        if m:
            pixdata[x, y] = colors[1]
        else:
            pixdata[x, y] = (255, 0, 0)
            m=True
        changed+=1

if not m:
    pixdata[0, 0]==(255, 0, 0)
    changed+=1
if colors[0]==(255, 255, 255):
    changed-=1

print changed
img.save("out.png", "PNG")

Sonuçlar

Resim 1 - 28688 değişiklik, Resim 2 - 24208 değişiklik

Resim 3 - 24248 değişiklik, Resim 4 - 7103 değişiklik

Resim 5 - 11097 değişiklik, Resim 6 - 13019 değişiklik

Raw_input dosya adını alır ve out.png dosyasına yazar ve değişiklik sayısını yazdırır.


Çıktınızda siyahtan beyaza değişen piksellerin sarı olması gerektiğini unutmayın. Beyazdan siyaha değiştirilen Thos mavi olmalı ve merkez (sizin durumunuzda tek 'beyaz' pikseliniz kırmızı olmalıdır. Bunun dışında, katıldığınız için teşekkür ederiz =) PS: Her zaman mümkün olmalıdır giriş olarak tam bir siyah resminiz olsa bile bir yıldız alanı oluşturun, bir pikseli beyaza (kırmızı) dönüştürebilirsiniz.
flawr

Beyaz veya siyah piksel yoksa (yani tam renkli) mümkün olmayabilir . Her durumda diğer değişiklikleri yapıyorum.
Maltysen

Ah. Siyah beyaz görüntü. Benim hatam.
Maltysen

Bence karşıt stratejiyi yapmak ve tüm siyah pikselleri beyaz olanlara değiştirmek daha verimli olabilir. Bunu denedin mi?
AJMansfield

@AJMansfield Bence bu sadece verilen test durumu için daha verimli olacaktır, bu yüzden belki de bu zaten verilen testcasları için algoritma koşullandırma olarak düşünülebilir.
flawr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.