优化算法无法正常工作

问题描述 投票:0回答:1

我需要将像素艺术.png 转换为json。我有这个结构。我已经在 .spwn 上编写了工作脚本并且它工作正常。但在 C# 上,我遇到了编程世界的技能问题之一。

722 像素/对象 - 开始时。 380 个对象必须经过优化。

Program.cs文件:

using Structures;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.Json;

class MainClass
{
    public static int NULL_cnt, COLOR_cnt = 0;
    public static List<Structures.Color>? pallete;

    public static bool Color_exist(Structures.Color Color)
    {
        if (pallete == null)
        {
            pallete = new List<Structures.Color>();
            pallete.Add(Color);
        }

        foreach (Structures.Color clr in pallete)
        {
            if (clr.Equals(Color)) return true;
        }

        pallete.Add(Color);
        return false;
    }

    public static int Serch_clr_id(Structures.Color color)
    {
        Color_exist(color);
        for (int id = 0; id < pallete.Count; id++)
        {
            if (pallete[id].Equals(color)) return id;
        }
        return -1;
    }

    public static int Get_block_index_by_pos(float x, float y, Block[] blocks)
    {
        Block to_check = null;
        foreach(Block block in blocks)
        {
            if (block.x == x && block.y == y) {
                to_check = block;
                break;
            }
        }
        return blocks.ToList().IndexOf(to_check);


    }

    public static Block Get_block_by_pos(float x, float y, Block[] blocks)
    {
        foreach (Block block in blocks)
        {
            if (block.x == x && block.y == y) return block;
        }
        return null;
    }

    public static int Get_index_by_block(Block block, Block[] blocks)
    {
        return blocks.ToList().IndexOf(block);
    }

    public static bool Is_optimizeble(Block block, Block[] blocks_array, int size, Size img_size)
    {
        int x = (int)block.x;
        int y = (int)block.y;

        if (x + size > img_size.Width || y + size > img_size.Height) return false;
        for (int X = x; X < x + size; X++)
        {
            for (int Y = y; Y < y + size; Y++)
            {
                Block to_check = Get_block_by_pos(X, Y, blocks_array);
                if (to_check == null)
                {
                    return false;
                }
                if (to_check.color_id != block.color_id)
                {
                    return false;
                }
            }
        }
        return true;
    }

    public static Block[] Optimize(Block[] blocks, Size size)
    {
        // Optimization algorithm
        List<Block> new_blocks = blocks.ToList();
        List<Block> to_fill = new List<Block>();
        bool flag = false;
        


        for (int pixel_size = 4; pixel_size > 1; pixel_size -= 2)
        {
            List<Block> blocks_to_check = new_blocks;

            while (true)
            {
                flag = true;

                //List<Block> local_BTC = blocks_to_check;
                foreach (Block block in blocks_to_check.ToList())
                {
                    blocks_to_check.Remove(block);

                    if (Is_optimizeble(block, new_blocks.ToArray(), pixel_size, size))
                    {
                        flag = false;
                        float X = block.x;
                        float Y = block.y;

                        for (int x = (int)X; x < X + pixel_size; x++)
                        {
                            for (int y = (int)Y; y < Y + pixel_size; y++)
                            {
                                int to_remove = Get_block_index_by_pos(x, y, new_blocks.ToArray<Block>());
                                if (to_remove != -1) new_blocks.RemoveAt(to_remove);
                            }
                        }
                        bool condition = pixel_size == 4;
                        float offset_multipling = condition ? 1.5f : 0.5f;

                        to_fill.Add(new Block(
                                condition ? (int)Block_ID.Full_Pixel : (int)Block_ID.Quadro_Pixel,
                                block.x + offset_multipling,
                                block.y + offset_multipling,
                                block.color_id
                        ));

                        break;
                    }

                    
                }
                if (flag)
                {
                    flag = false;
                    break;
                }
            }
        }
        return to_fill.ToArray<Block>();
    }

    public static JSON_Image Convert(Bitmap image)
    {
        image.RotateFlip(RotateFlipType.RotateNoneFlipY);
        Size size = image.Size;
        Block[] blocks = new Block[size.Width * size.Height];
        
        for (int index = 0; index < size.Width * size.Height; index++)
        {
            int xPos = index % size.Width;
            int yPos = (int)(index / size.Width);
            Structures.Color curr_color = new Structures.Color(image.GetPixel(xPos, yPos));
            blocks[index] = new Block(((int)Block_ID.Pixel), xPos, yPos, Serch_clr_id(curr_color));
        }

        List<Block> blocks_to_check = new List<Block>();
        foreach (Block block in blocks)
        {
            if (pallete[block.color_id].a == 0) continue;
            blocks_to_check.Add(block);
        }

        int[] arr_size = new int[2] { size.Width, size.Height };

        Console.WriteLine($"{blocks_to_check.Count} LIST\n{blocks.Length} ARRAY");

        blocks = Optimize(blocks_to_check.ToArray<Block>(), size);

        Console.WriteLine($"Optimization result: {blocks.Length} blocks");

        return new JSON_Image(arr_size, pallete.ToArray(), blocks);

    }
    
    static void Main(string[] args)
    {
        Bitmap img = new Bitmap("C:\\Users\\DENIS\\Desktop\\kris.png", false);

        string fileName = "C:\\Users\\DENIS\\Desktop\\kris.json";
        string jsonString = JsonSerializer.Serialize(Convert(img));
        File.WriteAllText(fileName, jsonString);

        Console.WriteLine($"{NULL_cnt} {COLOR_cnt}");


    }
}

结构.cs

namespace Structures
{
    internal enum Block_ID
    {
        Pixel = 917,
        Quadro_Pixel = 916,
        Full_Pixel = 955
    }

    internal class Block
    {
        public int obj_id { get; set; }
        public float x { get; set; }
        public float y { get; set; }
        public int color_id { get; set; }
        public Block(int OBJ_ID, float X, float Y, int COLOR_ID)
        {
            obj_id = OBJ_ID;
            x = X;
            y = Y;
            color_id = COLOR_ID;
        }

        public bool Equals(Block other) => this.obj_id == other.obj_id && this.x == other.x && this.y == other.y && this.color_id == other.color_id;
    }

    internal class Color
    {
        public int r { get; set; }
        public int g { get; set; }
        public int b { get; set; }
        public int a { get; set; }
        public Color(int R, int G, int B, int A)
        {
            r = R; g = G; b = B; a = A;
        }

        public Color(System.Drawing.Color color)
        {
            r = color.R; g = color.G; b = color.B; a = color.A;
        }

        public int[] ToArray() => new int[4] { this.r, this.g, this.b, this.a };

        public bool Equals(Color other) => this.r == other.r && this.g == other.g && this.b == other.b && this.a == other.a;

    }

    internal class JSON_Image
    {
        public int[] size { get; set; } = new int[2];
        public Array[] Blocks { get; set; }
        public Array[] Colors_set { get; set; }
        public JSON_Image(int[] size, Color[] colors_set, Block[] blocks)
        {
            this.size = size;
            Blocks = new Array[blocks.Length];
            Colors_set = new Array[colors_set.Length];

            for (int i = 0; i < blocks.Length; i++) this.Blocks[i] = new float[4] { blocks[i].obj_id, blocks[i].x, blocks[i].y, blocks[i].color_id };
            for (int i = 0; i < colors_set.Length; i++) this.Colors_set[i] = new float[4] { colors_set[i].r, colors_set[i].g, colors_set[i].b, colors_set[i].a };
        }
    }
}

Image_json_into_gd_art.spwn

extract obj_props
// block size 30, 1/4 block size 7.5 | id 917

path = "C:\\Users\\DENIS\\Desktop\\gd gameplay deltarune-undertale\\Undertale-Deltarune-gameplay-in-GD-with-SPWN\\spwn files\\"

let channels_colors_set = []
let colors = []
let imgSize = []
let blocks = []
let gridSize = 7.5
let offset = 0

check_match = (match_c) {
    for color in colors {
        if (color.r8() == match_c.r8() && color.b8() == match_c.b8() && color.g8() == match_c.g8() && color.a8() == match_c.a8()) {
            return true
        }
    }
    return false
}

get_block_by_pos = (x, y, blocks_array) {
    for block in blocks_array {
        if block[X] == x * gridSize && block[Y] == y * gridSize {
            return block
        }
    }
    return null
}

is_optimizeble = (block, blocks_array, size) {
    $.print("Next...")
    let block_cc = block[COLOR]
    let X = block[X] / gridSize
    let Y = block[Y] / gridSize
    let succes_cnt = 0

    if X + size > imgSize[0] || Y + size > imgSize[1] { return false }

    for x in X..X+size { for y in Y..Y+size {
        let to_check = get_block_by_pos(x, y, blocks_array)
        if to_check == null { return false }
        if to_check[COLOR] != block_cc { return false }
        succes_cnt += 1
        $.print(succes_cnt / (size ** 2))
    }}
    return true
}

optimize = (objects){
    let new_blocks = objects
    let new_fill_blocks = []
    let flag = false

    let optimized = {}

    $.print("Objects count optimization...")

    for optim_block_size in 5..2..2 {
        let blocks_to_check = new_blocks
        let optimized[@string(optim_block_size)] = 0
        while true {
            flag = true

            for block in blocks_to_check {
                $.print("Remains to check: ", blocks_to_check.length)
                blocks_to_check.pop(blocks_to_check.index(block))


                if is_optimizeble(block, new_blocks, optim_block_size) {
                    flag = false
                    let Xpos = block[X] / gridSize
                    let Ypos = block[Y] / gridSize
                    for x in Xpos..Xpos+optim_block_size { for y in Ypos..Ypos+optim_block_size {
                        let a = new_blocks.index(get_block_by_pos(x, y, new_blocks))
                        if a != null {
                            $.print("Removing block...")
                            new_blocks.pop(a)
                    }}}

                    let filling_offset = 11.25 if optim_block_size == 4 else 3.75



                    let filling = obj {
                        X: Xpos * gridSize + filling_offset,
                        Y: Ypos * gridSize + filling_offset,
                        OBJ_ID: 955 if optim_block_size == 4 else 916,
                        SCALING: 1,
                        ROTATION: 0,
                        COLOR: block[COLOR]
                    }

                    optimized[@string(optim_block_size)] += 1

                    new_fill_blocks.push(filling)

                    $.print("Done: ", @string(optimized[@string(optim_block_size)]))
                    $.print("Blocks: ", @string(new_blocks.length + new_fill_blocks.length))

                    $.print("Filling block at X: ", @string(filling[X]), " | Y: ", @string(filling[Y]), "\n")

                    break
                } 
            }

            if flag == true {
                flag = false
                break
            }
        }
    }
    

    for block in new_fill_blocks {
        new_blocks.push(block)
    }

    $.print("Optimization results:")

    for [optSize, optCnt] in optimized {
        $.print(optSize, "x", optSize, ": ", (@number(optSize) ** 2) * optCnt, " -> ", optCnt)
    }

    $.print("In short: ", blocks.length, " -> ", new_blocks.length)
    $.print("Optimized: ", blocks.length - new_blocks.length, "\n")

    return new_blocks
}




$.print("Reading JSON...")

let data = $.readfile(path + "kris.json", "json")
let raw_colors_set = data['Colors_set']
imgSize = data['size']
let pixels = data['Blocks']

$.print("Done\n")



$.print("Color optimization...")

for color in raw_colors_set {
    if !check_match(rgb8(color[0], color[1], color[2], color[3])) {
        let cc = ?c
        cc.set(rgb8(color[0], color[1], color[2], color[3]))
        channels_colors_set.push(cc)
        colors.push(rgb8(color[0], color[1], color[2], color[3]))
    }
}

$.print("Done\n")



$.print("Adding blocks...")
    
for pixel in pixels {
    if raw_colors_set[pixel[3] - 1][3] != 0 {
        blocks.push( obj {
            X: pixel[1] * gridSize + offset,
            Y: pixel[2] * gridSize,
            OBJ_ID: pixel[0],
            COLOR: channels_colors_set[pixel[3]]
        })
    }
}
//offset += 30

$.print("Done\n")



//blocks = optimize(blocks)



$.print("Adding blocks into level...")

for block in blocks {
    $.add(block)
}

$.print("Done\n")

要转换的图像:kris.png

拜托,我在调试中花费了 6 小时以上,但什么也没得到。

我尝试修复 List.Index(block) 的 -1,但什么也没有 我尝试将平铺队列从 4x4 -> 2x2 更改为 2x2 -> 4x4 还有其他东西,比如缓冲区。

c# optimization
1个回答
0
投票

错误出现在 C# 奇怪的数据存储中。我需要改变

List<Block> blocks_to_check = new_blocks;

List<Block> blocks_to_check = new_blocks.ToList();

C# 同步

blocks_to_check
new_blocks
并且将列表转换为“其他”列表后问题得到解决。

© www.soinside.com 2019 - 2024. All rights reserved.