ไปและทำให้มันเป็นดาว


14

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

การเปลี่ยนแปลงที่อนุญาตคือการเปลี่ยนพิกเซลสีขาวเป็นสีดำและเปลี่ยนพิกเซลสีดำเป็นสีขาว

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

คำนิยาม

ติดดาวโดเมน

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

เส้นตรงระหว่างสองพิกเซล

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

พิกเซล

ตัวอย่าง

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

ตัวอย่างผลงาน วิธีแก้ปัญหาตัวอย่างแรก ตัวอย่างการแก้ปัญหาที่สอง

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

กรณีทดสอบ

กรณีทดสอบ follwoing คือ png โดยแต่ละขนาดมีขนาด 256 x 256 พิกเซล

กรณีทดสอบ 1 กรณีทดสอบ 2 กรณีทดสอบ 3 กรณีทดสอบ 4 กรณีทดสอบ 5 กรณีทดสอบ 6

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

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

ลีดเดอร์บอร์ด

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
มันจะช่วยถ้าคุณต้องอธิบายรูปที่ 1. ทำไมคุณถึงเชื่อมต่อพิกเซลสีแดงเช่น?
DavidC

4
ฉันไม่แน่ใจจริงๆว่าคุณหมายถึงอะไร คุณสามารถให้แบบทดสอบก่อนและหลังของกรณีทดสอบได้หรือไม่?

เส้นจะต้องอยู่ใกล้กับมุมพิกเซลมากแค่ไหนเพื่อให้ถือว่าผ่านได้?
TheNumberOne

ฉันเพิ่มตัวอย่างบางส่วนและพยายามอธิบายข้อความฉันหวังว่ามันชัดเจนแล้ว!
ข้อบกพร่อง

มีใครอีกที่ตั้งใจจะลองทำสิ่งนี้หรือไม่? ฉันค่อนข้างสับสนเนื่องจากมีคนเพียงไม่กี่คนที่เอาชนะความท้าทายนี้ แต่เราได้รับคำตอบเพียงคำเดียวเท่านั้น (ไม่จริงจังมาก) คำวิจารณ์ใด ๆ
ข้อบกพร่อง

คำตอบ:


4

Java 8, 47,867 การเปลี่ยนแปลงทั้งหมด

ใช้ค่าเฉลี่ยของภาพเป็นจุดศูนย์กลาง จากนั้นจะดึงรังสีที่เป็นไปได้ทั้งหมดไปยังจุดศูนย์กลาง จากนั้นให้แต้มสีไม่ถูกต้องทั้งหมดเป็นสีดำ

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

ผล

รูปภาพ 1 - 0 การเปลี่ยนแปลงรูปภาพ 2 - 13,698 การเปลี่ยนแปลง

12

รูปที่ 3 - 24,269 การเปลี่ยนแปลงรูปที่ 4 - 103 การเปลี่ยนแปลง

34

รูปภาพ 5 - 5,344 การเปลี่ยนแปลงรูปภาพ 6 - 4,456 การเปลี่ยนแปลง

56

หากไม่มีการลบพิกเซลที่ไม่ถูกต้องจะมีการเปลี่ยนแปลงทั้งหมด 42,782 รายการ

พิกเซลสีเขียวเป็นเลเยอร์แรกของพิกเซลที่ไม่ถูกต้อง

รูปภาพ 1 - 0 การเปลี่ยนแปลงรูปภาพ 2- 9,889 การเปลี่ยนแปลง

12

รูปที่ 3 - 24,268 การเปลี่ยนแปลงรูปที่ 4 - 103 การเปลี่ยนแปลง

34

รูปภาพ 5 - 4,471 การเปลี่ยนแปลงรูปภาพ 6- การเปลี่ยนแปลง 4,050 รายการ

56

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

args[0] มีชื่อไฟล์อินพุต

args[1] มีชื่อไฟล์ที่ส่งออก

พิมพ์ตามstdoutจำนวนการเปลี่ยนแปลง


ดูดี! คุณสามารถอธิบายสิ่งที่คุณหมายถึงโดย 'พิกเซลที่ไม่ถูกต้อง'? ฉันไม่เข้าใจอย่างนั้น นอกจากนี้ในภาพที่ 2 ที่ด้านล่างขวาฉันไม่สามารถทำตามสาเหตุที่โปรแกรม 'diggs' ของคุณเข้าไปในกำแพงสีดำ แต่แล้วก็ยังคงมีจุดสีขาวดำอีกครั้ง แต่ฉันคิดว่าสิ่งนี้เกี่ยวข้องกับ 'invalid pixels' หรือไม่
ข้อผิดพลาด

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

3

Python - PIL - 216,228 108,363 การเปลี่ยนแปลงทั้งหมด

Whoo! ลดครึ่งนี้ด้วย @AJMansfield! อัลกอริทึมนี้ข้ามความกังวลทั้งหมดเกี่ยวกับการคำนวณเส้นและการเพิ่มประสิทธิภาพและสิ่งที่ไม่ มันเปลี่ยนเป็นคนผิวขาวทั้งหมดเป็นสีดำยกเว้นเพียงคนเดียว หากไม่มีผ้าขาวก็จะทำให้ขาวดำหนึ่ง มันตรวจสอบว่ามีคนผิวขาวหรือดำมากขึ้นและเปลี่ยนหนึ่งคนอื่น ๆ เพื่อมันยกเว้นหนึ่ง ถ้าไม่มีสีดำมันทำให้ (0, 0) ตรงกลาง

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")

ผล

Image 1 - 28688 การเปลี่ยนแปลง Image 2 - 24208 เปลี่ยนแปลง

รูปที่ 3 - 24248 การเปลี่ยนแปลงรูปที่ 4 - 7103 เปลี่ยนแปลง

ภาพ 5 - 11097 การเปลี่ยนแปลงรูปภาพ 6 - 13019 การเปลี่ยนแปลง

ใช้ชื่อไฟล์จาก raw_input และเขียนไปยัง out.png และพิมพ์จำนวนการเปลี่ยนแปลง


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

มันเป็นไปไม่ได้หากไม่มีพิกเซลสีขาวหรือสีดำ (เช่นสีเต็ม) ไม่ว่าในกรณีใดฉันจะทำการเปลี่ยนแปลงอื่น ๆ
Maltysen

โอ้ ภาพขาวดำ ความผิดฉันเอง.
Maltysen

ฉันคิดว่ามันอาจมีประสิทธิภาพมากกว่าในการทำกลยุทธ์ตรงกันข้ามและเปลี่ยนพิกเซลสีดำทั้งหมดเป็นสีขาว คุณลองที่
AJMansfield

@JMansfield ฉันคิดว่านี่จะมีประสิทธิภาพมากขึ้นสำหรับกรณีทดสอบที่กำหนดดังนั้นบางทีนี่อาจถือได้ว่าเป็นการปรับอัลกอริทึมสำหรับการทดสอบที่ให้มา
ข้อบกพร่อง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.