線を使用して画像を再現する


31

トゥルーカラーRGBイメージI、描画する最大行数L、および各行の最小mおよび最大Mの長さを取り込むプログラムを作成します。出力画像Oのようなできるだけ見えるとIとを用いて描画さLの間のユークリッド長有する全てがまたはより少ない直線、MおよびMを

各ラインは単色で、Oの境界内に両方の端点があり、Bresenhamのラインアルゴリズムを使用して描画されている必要があります(ほとんどのグラフィックライブラリは既に対応しています)。個々の線の太さは1ピクセルのみです。

長さ0の行も含め、すべての行は少なくとも1ピクセルを占める必要があります。線は互いに重ねて描画できます。

線を描画する前に、Oの背景を任意の単色に初期化できます(Iに依存する場合があります)。

詳細

  • OIと同じ次元である必要があります。
  • Lは常に非負の整数です。Iの面積よりも大きい場合があります。
  • mおよびMは、M > = mの非負の浮動小数点数です。2つのピクセル間の距離は、それらの中心間のユークリッド距離です。この距離がm未満またはMより大きい場合、これらのピクセル間の線は許可されません。
  • ラインはアンチエイリアス処理されるべきではありません。
  • 不透明度とアルファは使用しないでください。
  • あなたのプログラムは、100万ピクセル未満でLが10,000未満の画像で、最新のコンピューターで実行するのに1時間以上かかることはありません。

テスト画像

もちろん、最も正確または興味深い出力画像を表示する必要があります(LIのピクセル数の5%から25%の間であり、mおよびMが対角サイズの約10分の1である場合に発生します)。

ここにいくつかのテスト画像があります(オリジナルをクリックしてください)。また、自分で投稿することもできます。

モナリザ 滝 ナイトホークス 星が輝く夜 ゴールデンゲートブリッジ

よりシンプルな画像:

ペンローズの階段メビウスの帯 ヒルベルト曲線

これは人気コンテストです。最も投票数の多い提出が勝ちです。

ノート

  • 絶対値と同様に、Iの合計ピクセルの割合からLを導出すると役立つ場合があります。例えば、同じことだろうかの8×8画素の画像でした。mMについても同様のことができます。これは必須ではありません。>>> imageliner I=img.png L=50% m=10 M=20>>> imageliner I=img.png L=32 m=10 M=20img.png
  • 行は境界を越えることができないため、可能な最長の行はIの対角線の長さです。持つMをこれ以上のことは何もかかわらを壊すべきではありません。
  • 当然、mが0で、LIのピクセル数以上の場合、各ピクセル位置に長さ0の「ライン」を持たせることで、OIと同じになります。この動作は必須ではありません。
  • 間違いなく、Iの形を再現することは、色を再現することよりも重要です。エッジ検出を検討することもできます。

明確にするため:SimpleCVのようなライブラリは許可されていますか?そして、答えには、m = 0とL = areaを含む、I、L、m、Mの選択がありますか?
有理数

@epicwisdomはい、すべてのライブラリ(このタスクを既に具体的に実行するものを除く)が許可されています。キーポイント、エッジ検出など、自由に使用できます。あなたのアルゴリズムは、のために働く必要があります任意の有効な選択肢ILMM、含まM = 0とL =エリアを。(もちろん、特定のパラメーターのチューニングではアルゴリズムがより良く見えるかもしれません。)
カルビンの趣味

次に、たとえば、この特定のライブラリアルゴリズムは無効な回答と見なされますか?
有理数

@epicwisdom実際、私はそれと他の同様のものを許可します。それはあなたが与える線から画像を作るためにまだいくつかの巧妙な微調整を必要とするように見えます。
カルビンの趣味

1
線には太さ1が必要ですか?
aditsu

回答:


21

C ++-ややランダムな行、そしていくつか

最初にいくつかのランダムな行

アルゴリズムの最初のステップでは、ラインをランダムに生成し、これに沿ってピクセルの平均をターゲットイメージに取得し、新しいラインをペイントする場合、すべてのピクセルのRGBスペース距離の合計平方が小さくなるかどうかを計算します(そしてそれがある場合のみ、ペイントしてください)。このための新しい線の色は、-15 / + 15のランダム加算で、rgb値のチャネルごとの平均として選択されます。

私が気づき、実装に影響を与えたもの:

  • 初期色は、完全な画像の平均です。これは、白にしたときのように面白い効果に対抗するためであり、領域は黒です。すでに明るい緑の線のようなものは、既に白の線よりも黒に近いので、より良く見えます。
  • 線の純粋な平均色をとるのは、後の線で上書きされてハイライトを生成できないことが判明するほど良くありません。少しランダムな偏差を行うことは少し役立ちますが、星空を見ると、多くの場所で局所的なコントラストが高いと失敗します。

私はいくつかの数字を使って実験し、選んだたL=0.3*pixel_count(I)し、左m=10M=50。行数0.25から約0の範囲で良い結果が得られます0.26が、0.3を選択して正確な詳細を表示する余地を増やしました。

フルサイズのゴールデンゲートイメージの場合、これにより235929行がペイントされました(ここでは、なんと13秒かかりました)。ここにあるすべての画像は縮小サイズで表示され、完全な解像度を表示するには新しいタブで開く/ダウンロードする必要があります。

価値のないものを消去する

次のステップはかなり高価です(235k行の場合、約1時間かかりましたが、「1メガピクセルで1万行の1時間」の時間要件内に収まるはずです)が、少し驚くべきことでもあります。以前に描いたすべての線を調べて、画像を良くしない線を削除します。これにより、この実行では、次の画像を生成する97347行のみが残ります。

ほとんどの違いを見つけるには、適切な画像ビューアでそれらをダウンロードして比較する必要があるでしょう。

そしてもう一度やり直す

今、私は再び235929の合計を持つために再びペイントできる多くのラインを持っています。言うまでもないので、ここに画像があります:

ここに画像の説明を入力してください

ショート分析

手順全体は、局所的なコントラストとオブジェクトサイズに敏感なぼかしフィルターのように機能するようです。しかし、線がどこでペイントされるかを見るのも興味深いので、プログラムもこれらを記録します(各線について、ピクセルの色が1ステップ白くなり、最後にコントラストが最大になります)。上記の3色に対応するものを次に示します。

アニメーション

そして、私たちは皆アニメーションが大好きなので、小さなゴールデンゲートイメージのプロセス全体のアニメーションGIFをいくつか紹介します。gif形式による大きなディザリングがあることに注意してください(また、トゥルーカラーアニメーションファイル形式の作成者とブラウザーのメーカーはエゴをめぐって争っているので、トゥルーカラーアニメーションの標準形式はありません。 )。

もう少し

リクエストに応じて、他の画像の結果をいくつか示します(これらを縮小するには、新しいタブで開く必要があります)

今後の考え

コードをいじってみると、興味深いバリエーションが得られます。

  • 平均に基づくのではなく、ランダムに線の色を選択します。3つ以上のサイクルが必要な場合があります。
  • pastebinのコードには遺伝的アルゴリズムのアイデアも含まれていますが、イメージはおそらく既に非常に優れているため、生成に時間がかかりすぎます。
  • 別のラウンドの消去/再描画、さらには2回...
  • 行を消去できる場所の制限を変更します(たとえば、「画像を少なくともN良くする必要がある」)

コード

これらは主に2つの便利な機能であり、コード全体はここに収まらず、http://ideone.com/Z2P6Lsで見つけることができます

bmpクラスrawraw_line関数が形式をBMPに書き込むことができ、オブジェクトのそれぞれにアクセスする画素や線を行う(それはちょうどいくつかのハック転がっていたと私はそれがどのライブラリーから、これはある程度独立しますと思いました)。

入力ファイル形式はPPMです

std::pair<bmp,std::vector<line>>  paint_useful( const bmp& orig, bmp& clone, std::vector<line>& retlines, bmp& layer, const std::string& outprefix, size_t x, size_t y )
{
        const size_t pixels = (x*y);
        const size_t lines = 0.3*pixels;
//      const size_t lines = 10000;

//      const size_t start_accurate_color = lines/4;

        std::random_device rnd;

        std::uniform_int_distribution<size_t> distx(0,x-1);
        std::uniform_int_distribution<size_t> disty(0,y-1);
        std::uniform_int_distribution<size_t> col(-15,15);
        std::uniform_int_distribution<size_t> acol(0,255);

        const ssize_t m = 1*1;
        const ssize_t M = 50*50;

        retlines.reserve( lines );

        for (size_t i = retlines.size(); i < lines; ++i)
        {
                size_t x0;
                size_t x1;

                size_t y0;
                size_t y1;

                size_t dist = 0;
                do
                {
                        x0 = distx(rnd);
                        x1 = distx(rnd);

                        y0 = disty(rnd);
                        y1 = disty(rnd);

                        dist = distance(x0,x1,y0,y1);
                }
                while( dist > M || dist < m );

                std::vector<std::pair<int32_t,int32_t>> points = clone.raw_line_pixels(x0,y0,x1,y1);

                ssize_t r = 0;
                ssize_t g = 0;
                ssize_t b = 0;

                for (size_t i = 0; i < points.size(); ++i)
                {
                        r += orig.raw(points[i].first,points[i].second).r;
                        g += orig.raw(points[i].first,points[i].second).g;
                        b += orig.raw(points[i].first,points[i].second).b;
                }

                r += col(rnd);
                g += col(rnd);
                b += col(rnd);

                r /= points.size();
                g /= points.size();
                b /= points.size();

                r %= 255;
                g %= 255;
                b %= 255;

                r = std::max(ssize_t(0),r);
                g = std::max(ssize_t(0),g);
                b = std::max(ssize_t(0),b);

//              r = acol(rnd);
//              g = acol(rnd);
//              b = acol(rnd);

//              if( i > start_accurate_color )
                {
                        ssize_t dp = 0; // accumulated distance of new color to original
                        ssize_t dn = 0; // accumulated distance of current reproduced to original
                        for (size_t i = 0; i < points.size(); ++i)
                        {
                                dp += rgb_distance(
                                                                                orig.raw(points[i].first,points[i].second).r,r,
                                                                                orig.raw(points[i].first,points[i].second).g,g,
                                                                                orig.raw(points[i].first,points[i].second).b,b
                                                                        );

                                dn += rgb_distance(
                                                                                clone.raw(points[i].first,points[i].second).r,orig.raw(points[i].first,points[i].second).r,
                                                                                clone.raw(points[i].first,points[i].second).g,orig.raw(points[i].first,points[i].second).g,
                                                                                clone.raw(points[i].first,points[i].second).b,orig.raw(points[i].first,points[i].second).b
                                                                        );

                        }

                        if( dp > dn ) // the distance to original is bigger, use the new one
                        {
                                --i;
                                continue;
                        }
                        // also abandon if already too bad
//                      if( dp > 100000 )
//                      {
//                              --i;
//                              continue;
//                      }
                }

                layer.raw_line_add(x0,y0,x1,y1,{1u,1u,1u});
                clone.raw_line(x0,y0,x1,y1,{(uint32_t)r,(uint32_t)g,(uint32_t)b});
                retlines.push_back({ (int)x0,(int)y0,(int)x1,(int)y1,(int)r,(int)g,(int)b});

                static time_t last = 0;
                time_t now = time(0);
                if( i % (lines/100) == 0 )
                {
                        std::ostringstream fn;
                        fn << outprefix + "perc_" << std::setw(3) << std::setfill('0') << (i/(lines/100)) << ".bmp"; 
                        clone.write(fn.str());
                        bmp lc(layer);
                        lc.max_contrast_all();
                        lc.write(outprefix + "layer_" + fn.str());
                }

                if( (now-last) > 10 )
                {
                        last = now;
                        static int st = 0;
                        std::ostringstream fn;
                        fn << outprefix + "inter_" << std::setw(8) << std::setfill('0') << i << ".bmp";
                        clone.write(fn.str());

                        ++st;
                }
        }
        clone.write(outprefix + "clone.bmp");
        return { clone, retlines };
}


void erase_bad( std::vector<line>& lines, const bmp& orig )
{
        ssize_t current_score = evaluate(lines,orig);

        std::vector<line> newlines(lines);

        uint32_t deactivated = 0;
        std::cout << "current_score = " << current_score << "\n";
        for (size_t i = 0; i < newlines.size(); ++i)
        {
                newlines[i].active = false;
                ssize_t score = evaluate(newlines,orig);
                if( score > current_score )
                {
                        newlines[i].active = true;
                }
                else
                {
                        current_score = score;
                        ++deactivated;
                }
                if( i % 1000 == 0 )
                {
                        std::ostringstream fn;
                        fn << "erase_" << std::setw(6) << std::setfill('0') << i << ".bmp";
                        bmp tmp(orig);
                        paint(newlines,tmp);
                        tmp.write(fn.str());
                        paint_layers(newlines,tmp);
                        tmp.max_contrast_all();
                        tmp.write("layers_" + fn.str());
                        std::cout << "\r i = " << i << std::flush;
                }
        }
        std::cout << "\n";
        std::cout << "current_score = " << current_score << "\n";
        std::cout << "deactivated = " << deactivated << "\n";


        bmp tmp(orig);

        paint(newlines,tmp);
        tmp.write("newlines.bmp");
        lines.clear();
        for (size_t i = 0; i < newlines.size(); ++i)
        {
                if( newlines[i].is_active() )
                {
                        lines.push_back(newlines[i]);
                }
        }
}

+1、実に素晴らしい。他のテスト画像の結果はありますか?
ナサニエル14年

1
@ナサニエル:いくつか追加しました。レクリエーションはほぼ完璧なピクセルであるため、「シンプルな」画像は魅力的ではありません。
PlasmaHH 14年

17

Java-ランダムな行

ランダムな線を描画し、ソース画像の平均色を計算する非常に基本的なソリューション。背景色は、ソースの平均色に設定されます。

L = 5000、m = 10、M = 50

ここに画像の説明を入力してください

L = 10000、m = 10、M = 50

ここに画像の説明を入力してください

編集

行の母集団を処理する遺伝的アルゴリズムを追加しました。各世代では、50%の最適なラインのみを保持し、他のラインをドロップして、ランダムに新しいラインを生成します。行を維持するための基準は次のとおりです。

  • ソース画像の色までの距離が小さい
  • 他の線との交点の数(小さいほど良い)
  • それらの長さ(長いほど良い)
  • 最近傍との角度(小さいほど良い)

残念なことに、このアルゴリズムは実際には画質を改善するようには見えません:-(行が平行になっているだけです。

第一世代(5000行)

ここに画像の説明を入力してください

第10世代(5000行)

ここに画像の説明を入力してください

パラメータで遊ぶ

ここに画像の説明を入力してくださいここに画像の説明を入力してくださいここに画像の説明を入力してください

package line;

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;

import snake.Image;

public class Lines {

    private final static int NB_LINES = 5000;
    private final static int MIN_LENGTH = 10;
    private final static int MAX_LENGTH = 50;

    public static void main(String[] args) throws IOException {     
        BufferedImage src = ImageIO.read(Image.class.getClassLoader().getResourceAsStream("joconde.png"));
        BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_RGB);


        int [] bgColor = {0, 0, 0};
        int avgRed = 0, avgGreen = 0, avgBlue = 0, count = 0;
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                int colsrc = src.getRGB(x, y);
                avgRed += colsrc & 255;
                avgGreen += (colsrc >> 8) & 255;
                avgBlue += (colsrc >> 16) & 255;
                count++;
            }
        }

        bgColor[0] = avgBlue/count; bgColor[1] = avgGreen/count; bgColor[2] = avgRed/count;
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                dest.getRaster().setPixel(x, y, bgColor);
            }
        }
        List<List<Point>> lines = new ArrayList<List<Point>>();
        Random rand = new Random();
        for (int i = 0; i < NB_LINES; i++) {
            int length = rand.nextInt(MAX_LENGTH - MIN_LENGTH) + MIN_LENGTH;
            double ang = rand.nextDouble() * Math.PI;
            int lx = (int)(Math.cos(ang) * length); // can be negative or positive
            int ly = (int)(Math.sin(ang) * length); // positive only
            int sx = rand.nextInt(dest.getWidth() -1 - Math.abs(lx));
            int sy = rand.nextInt(dest.getHeight() - 1- Math.abs(ly));
            List<Point> line;
            if (lx > 0) {
                line = line(sx, sy, sx+lx, sy+ly);
            } else {
                line = line(sx+Math.abs(lx), sy, sx, sy+ly);
            }
            lines.add(line);    
        }

        // render the picture
        int [] color = {0, 0, 0};
        for (List<Point> line : lines) {

            avgRed = 0; avgGreen = 0; avgBlue = 0;
            count = 0;
            for (Point p : line) {
                int colsrc = src.getRGB(p.x, p.y);
                avgRed += colsrc & 255;
                avgGreen += (colsrc >> 8) & 255;
                avgBlue += (colsrc >> 16) & 255;
                count++;
            }
            avgRed /= count; avgGreen /= count; avgBlue /= count;
            color[0] = avgBlue; color[1] = avgGreen; color[2] = avgRed;
            for (Point p : line) {
                dest.getRaster().setPixel(p.x, p.y, color);
            }

        }
        ImageIO.write(dest, "png", new File("a0.png"));

    }

    private static List<Point> line(int x0, int y0, int x1, int y1) {
        List<Point> points = new ArrayList<Point>();
        int deltax = x1 - x0;
        int deltay = y1 - y0;
        int tmp;
        double error = 0;       
        double deltaerr = 0;
        if (Math.abs(deltax) >= Math.abs(deltay)) {
            if (x0 > x1) { // swap the 2 points
                tmp = x0; x0 = x1; x1 = tmp;
                tmp = y0; y0 = y1; y1 = tmp;
                deltax = - deltax; deltay = -deltay;
            }
            deltaerr = Math.abs (((double)deltay) / deltax); 
            int y = y0;
            for (int x = x0; x <= x1; x++) {
                points.add(new Point(x, y));
                error += deltaerr;
                if (error >= 0.5) {
                    if (y0 < y1) y++; else y--;
                    error -= 1.0;
                }
            }
        } else {
            if (y0 > y1) { // swap the 2 points
                tmp = x0; x0 = x1; x1 = tmp;
                tmp = y0; y0 = y1; y1 = tmp;
                deltax = - deltax; deltay = -deltay;
            }
            deltaerr = Math.abs (((double)deltax) / deltay);   // Assume deltay != 0 (line is not horizontal),
            int x = x0;
            for (int y = y0; y <= y1; y++) {
                points.add(new Point(x, y));
                error += deltaerr;
                if (error >= 0.5) {
                    if (x0 < x1) x++; else x--;
                    error -= 1.0;
                }
            }
        }
        return points;
    }
}

最後に誰かが答えました:Dもっと例を見てみたいです。
カルビンの趣味14

@カルビン 今、私は(遺伝的アルゴリズムのいくつかの種類)が20%悪化し、再生成新しいもの例えばラインの人口を維持することによって、アルゴリズムの改善に取り組んで、そして排除しています
アルノー・

そのようなことを念頭に置いていましたが、書く時間はありませんでした。遺伝的藻類を楽しみにしています。結果:)
aditsu 14

おそらく、より小さな角度基準を削除したいですか?なぜそれを置いたのですか?元の画像はきれいに見えますが、線の交差角は小さくありません。
ちょうど半分14

@justhalf完了。ペインターブラシをシミュレートするために、角度基準を追加しました。
アルノー14

9

C-直線

ppmファイルを操作するCの基本的なアプローチ。アルゴリズムは、すべてのピクセルを埋めるために最適なライン長で垂直ラインを配置しようとします。背景色と線の色は、元の画像の平均値(各カラーチャンネルの中央値)として計算されます。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define SIGN(x) ((x > 0) ? 1 : (x < 0) ? -1 : 0)
#define MIN(x, y) ((x > y) ? y : x)
#define MAX(x, y) ((x > y) ? x : y)

typedef struct {
    size_t width;
    size_t height;

    unsigned char *r;
    unsigned char *g;
    unsigned char *b;
} image;

typedef struct {
    unsigned char r;
    unsigned char g;
    unsigned char b;
} color;

void init_image(image *data, size_t width, size_t height) {
    data->width = width;
    data->height = height;
    data->r = malloc(sizeof(data->r) * data->width * data->height);
    data->g = malloc(sizeof(data->g) * data->width * data->height);
    data->b = malloc(sizeof(data->b) * data->width * data->height);
}

#define BUFFER_LEN 1024
int load_image(const char *filename, image* data) {
    FILE *f = fopen(filename, "r");
    char buffer[BUFFER_LEN];          /* read buffer */
    size_t max_value;
    size_t i;
    fgets(buffer, BUFFER_LEN, f);
    if (strncmp(buffer, "P3", 2) != 0) {
        printf("File begins with %s instead of P3\n", buffer);
        return 0;
    }

    fscanf(f, "%u", &data->width);
    fscanf(f, "%u", &data->height);
    fscanf(f, "%u", &max_value);
    assert(max_value==255);

    init_image(data, data->width, data->height);

    for (i = 0; i < data->width * data->height; i++) {
        fscanf(f, "%hhu", &(data->r[i]));
        fscanf(f, "%hhu", &(data->g[i]));
        fscanf(f, "%hhu", &(data->b[i]));
    }
    fclose(f);

    printf("Read %zux%zu pixels from %s.\n", data->width, data->height, filename);
}

int write_image(const char *filename, image *data) {
    FILE *f = fopen(filename, "w");
    size_t i;
    fprintf(f, "P3\n%zu %zu\n255\n", data->width, data->height);
    for (i = 0; i < data->width * data->height; i++) {
        fprintf(f, "%hhu %hhu %hhu ", data->r[i], data->g[i], data->b[i]);
    }
    fclose(f);
}

unsigned char average(unsigned char *data, size_t data_len) {
    size_t i;
    size_t j;
    size_t hist[256];

    for (i = 0; i < 256; i++) hist[i] = 0;
    for (i = 0; i < data_len; i++) hist[data[i]]++;
    j = 0;
    for (i = 0; i < 256; i++) {
        j += hist[i];
        if (j >= data_len / 2) return i;
    }
    return 255;
}

void set_pixel(image *data, size_t x, size_t y, unsigned char r, unsigned char g, unsigned char b) {
    data->r[x + data->width * y] = r;
    data->g[x + data->width * y] = g;
    data->b[x + data->width * y] = b;
}

color get_pixel(image *data, size_t x, size_t y) {
    color ret;
    ret.r = data->r[x + data->width * y];
    ret.g = data->g[x + data->width * y];
    ret.b = data->b[x + data->width * y];
    return ret;
}

void fill(image *data, unsigned char r, unsigned char g, unsigned char b) {
    size_t i;
    for (i = 0; i < data->width * data->height; i++) {
        data->r[i] = r;
        data->g[i] = g;
        data->b[i] = b;
    }
}

void line(image *data, size_t x1, size_t y1, size_t x2, size_t y2, unsigned char r, unsigned char g, unsigned char b) {
    size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
    int dx, dy, incx, incy, err;

    dx=x2-x1;
    dy=y2-y1;
    incx=SIGN(dx);
    incy=SIGN(dy);
    if(dx<0) dx=-dx;
    if(dy<0) dy=-dy;
    if (dx>dy) {
        pdx=incx;
        pdy=0;
        ddx=incx;
        ddy=incy;
        es=dy;
        el=dx;
    } else {
        pdx=0;
        pdy=incy;
        ddx=incx;
        ddy=incy;
        es=dx;
        el=dy;
    }
    x=x1;
    y=y1;
    err=el/2;
    set_pixel(data, x, y, r, g, b);

    for(t=0; t<el; t++) {
        err -= es;
        if(err<0) {
            err+=el;
            x+=ddx;
            y+=ddy;
        } else {
            x+=pdx;
            y+=pdy;
        }
        set_pixel(data, x, y, r, g, b);
    }
}

color average_line(image *data, size_t x1, size_t y1, size_t x2, size_t y2) {
    size_t x, y, t, pdx, pdy, ddx, ddy, es, el;
    int dx, dy, incx, incy, err;
    color ret;
    color px;
    size_t i;
    size_t j;
    size_t hist_r[256];
    size_t hist_g[256];
    size_t hist_b[256];
    size_t data_len = 0;

    for (i = 0; i < 256; i++) {
        hist_r[i] = 0;
        hist_g[i] = 0;
        hist_b[i] = 0;
    }

    dx=x2-x1;
    dy=y2-y1;
    incx=SIGN(dx);
    incy=SIGN(dy);
    if(dx<0) dx=-dx;
    if(dy<0) dy=-dy;
    if (dx>dy) {
        pdx=incx;
        pdy=0;
        ddx=incx;
        ddy=incy;
        es=dy;
        el=dx;
    } else {
        pdx=0;
        pdy=incy;
        ddx=incx;
        ddy=incy;
        es=dx;
        el=dy;
    }
    x=x1;
    y=y1;
    err=el/2;
    px = get_pixel(data, x, y);
    hist_r[px.r]++;
    hist_g[px.g]++;
    hist_b[px.b]++;
    data_len++;

    for(t=0; t<el; t++) {
        err -= es;
        if(err<0) {
            err+=el;
            x+=ddx;
            y+=ddy;
        } else {
            x+=pdx;
            y+=pdy;
        }
        px = get_pixel(data, x, y);
        hist_r[px.r]++;
        hist_g[px.g]++;
        hist_b[px.b]++;
        data_len++;
    }

    j = 0;
    for (i = 0; i < 256; i++) {
        j += hist_r[i];
        if (j >= data_len / 2) {
            ret.r = i;
            break;
        }
    }
    j = 0;
    for (i = 0; i < 256; i++) {
        j += hist_g[i];
        if (j >= data_len / 2) {
            ret.g = i;
            break;
        }
    }
    j = 0;
    for (i = 0; i < 256; i++) {
        j += hist_b[i];
        if (j >= data_len / 2) {
            ret.b = i;
            break;
        }
    }
    return ret;
}


void lines(image *source, image *dest, size_t L, float m, float M) {
    size_t i, j;
    float dx;
    float mx, my;
    float mm = MAX(MIN(source->width * source->height / L, M), m);
    unsigned char av_r = average(source->r, source->width * source->height);
    unsigned char av_g = average(source->g, source->width * source->height);
    unsigned char av_b = average(source->b, source->width * source->height);
    fill(dest, av_r, av_g, av_b);
    dx = (float)source->width / L;
    mx = 0;
    my = mm / 2;
    for (i = 0; i < L; i++) {
        color avg;
        mx += dx;
        my += (source->height - mm) / 8;
        if (my + mm / 2 > source->height) {
            my = mm / 2 + ((size_t)(my + mm / 2) % (size_t)(source->height - mm));
        }
        avg = average_line(source, mx, my - mm / 2, mx, my + mm / 2);
        line(dest, mx, my - mm / 2, mx, my + mm / 2, avg.r, avg.g, avg.b);
    }
}

int main(int argc, char *argv[]) {
    image source;
    image dest;
    size_t L;
    float m;
    float M;

    load_image(argv[1], &source);
    L = atol(argv[2]);
    m = atof(argv[3]);
    M = atof(argv[4]);

    init_image(&dest, source.width, source.height);
    lines(&source, &dest, L, m, M);


    write_image(argv[5], &dest);
}

L = 5000、m = 10、M = 50

L = 5000、m = 10、M = 50

L = 5000、m = 10、M = 50

L = 5000、m = 10、M = 50

L = 100000、m = 10、M = 50

ここに画像の説明を入力してください


6

Python 3ベースの「ややランダムなラインに続いていくつかのライン」に加えて、sobelエッジ検出。

コードは理論的には永遠に実行できます(したがって、一晩実行して楽しむことができます)が、進行状況を記録するため、すべての画像は1〜10分で取得されます。

最初にイメージを読み取り、次に、ソーベルエッジ検出を使用してすべてのエッジの角度を検出し、線が別の色に違反しないようにします。(lengthmin、lengthmax)内のランダムな長さの線が設定されると、画像全体に寄与するかどうかをテストします。小さい線の方が良いですが、線の長さを10〜50に設定します。

from random import randint, uniform
import json
from PIL import Image, ImageDraw, ImageFilter
import math
k=(-1,0,1,-2,0,2,-1,0,1)
k1=(-1,-2,-1,0,0,0,1,2,1)
population=[]
lengthmin=10
lengthmax=50
number_lines=10**8
im=Image.open('0.png')
[x1,y1]=im.size
dx=0
class drawer():
    def __init__(self,genome,score,filename):
        self.genome=genome
        self.score=score
        self.filename=filename
    def initpoint(self,g1):
        g2=self.genome
        im=Image.open('0.png')
        im1=im.filter(ImageFilter.Kernel((3,3),k,1,128))
        im2=im.filter(ImageFilter.Kernel((3,3),k1,1,128))
        im1=im1.filter(ImageFilter.GaussianBlur(radius=4))
        im2=im2.filter(ImageFilter.GaussianBlur(radius=4))
        for x in range(0,number_lines):
            if(x%10**4==0):
                print(x*100/number_lines)
                self.save()
                g1.save('1.png')
            (x,y)=(randint(0,x1-1),randint(0,y1-1))
            w=im1.getpixel((x,y))[0]-128
            z=im2.getpixel((x,y))[0]-128
            w=int(w)
            z=int(z)
            W=(w**2+z**2)**0.5
            if(W!=0):
                w=(w/W)*randint(lengthmin,lengthmax)
                z=(z/W)*randint(lengthmin,lengthmax)
                (w,z)=(z,w)
                (a,b)=(x+w,y+z)
                a=int(a)
                b=int(b)
                x=int(x)
                y=int(y)
                if(a>=x1):
                    a=x1-1
                if(b>=y1):
                    b=y1-1
                if(a<0):
                    a=0
                if(b<0):
                    b=0
                if(x>=x1):
                    x=x1-1
                if(y>=y1):
                    y=y1-1
                if(x<0):
                    x=0
                if(y<0):
                    y=0
                C=[0,0,0]
                D=0
                E=0
                F=0
                G=0
                W=((x-a)**2+(y-b)**2)**0.5
                if(W!=0):
                    for Z in range(0,int(W)):
                        w=(Z/W)
                        (c,d)=((w*x+(1-w)*a),(w*y+(1-w)*b))
                        c=int(c)
                        d=int(d)
                        C[0]+=im.getpixel((c,d))[0]
                        C[1]+=im.getpixel((c,d))[1]
                        C[2]+=im.getpixel((c,d))[2]
                    C[0]/=W
                    C[1]/=W
                    C[2]/=W
                    C[0]=int(C[0])
                    C[1]=int(C[1])
                    C[2]=int(C[2])
                    for Z in range(0,int(W)):
                        w=(Z/W)
                        (c,d)=((w*x+(1-w)*a),(w*y+(1-w)*b))
                        c=int(c)
                        d=int(d)
                        E=0
                        D=0
                        D+=(g1.getpixel((c,d))[0]-im.getpixel((c,d))[0])**2
                        D+=(g1.getpixel((c,d))[1]-im.getpixel((c,d))[1])**2
                        D+=(g1.getpixel((c,d))[2]-im.getpixel((c,d))[2])**2
                        F+=D**0.5
                        E+=(im.getpixel((c,d))[0]-C[0])**2
                        E+=(im.getpixel((c,d))[1]-C[1])**2
                        E+=(im.getpixel((c,d))[2]-C[2])**2
                        G+=E**0.5
                    #print((G/W,F/W))
                    if(G<F):
                        for Z in range(0,int(W)):
                            w=(Z/W)
                            (c,d)=((w*x+(1-w)*a),(w*y+(1-w)*b))
                            c=int(c)
                            d=int(d)
                            g1.putpixel((c,d),(int(C[0]),int(C[1]),int(C[2])))
                        g2.append((x,y,a,b,int(C[0]%256),int(C[1]%256),int(C[2]%256)))
        return(g1)
    def import_file(self):
        with open(self.filename, 'r') as infile:
            self.genome=json.loads(infile.read())
        print(len(self.genome))
    def save(self):
        with open(self.filename, 'w') as outfile:
            data = json.dumps(self.genome)
            outfile.write(data)
population.append(drawer([],0,'0.txt'))
G=0
g1=Image.new('RGB',(x1,y1),'black')
g1=population[0].initpoint(g1)
g1.save('1.png')

ゴシックアメリカ

エッシャー

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.