Çizgileri kullanarak görüntüyü yeniden oluşturma


31

Gerçek renkli bir RGB görüntüsü I , L çizmek için maksimum satır sayısı ve her satırın minimum m ve maksimum M uzunluğunu alan bir program yazın . I gibi olabildiğince görünen ve L veya daha az düz çizgiler kullanarak çizilen ve tümü m ve M arasında Öklid uzunluğuna sahip bir O resmi verin .

Her satır tek bir düz renk olmalıdır, her iki uç noktanın da O sınırları dahilinde olması ve Bresenham'ın çizgi algoritması kullanılarak çizilmesi gerekir (çoğu grafik kütüphanesi sizin için zaten yapar). Tek tek çizgiler yalnızca 1 piksel kalınlığında olabilir.

Tüm çizgiler, 0 uzunluktakiler bile olsa, en az bir piksel almalıdır. Çizgiler üst üste çizilebilir.

Herhangi bir çizgi çizme önce arka plan ilklendiremezsiniz O herhangi bir katı renkli (bu bağlıdır I ).

ayrıntılar

  • O , benimle aynı boyutlara sahip olmalıdır .
  • L her zaman negatif olmayan bir tamsayı olacak. I bölgesinden daha büyük olabilir .
  • m ve M , M > = m olan negatif olmayan kayan nokta sayılarıdır . İki piksel arasındaki mesafe, merkezleri arasındaki Öklid mesafesidir. Bu mesafe m'den küçük veya M'den büyükse , o zaman bu pikseller arasındaki çizgiye izin verilmez.
  • Çizgiler antialiased olmamalıdır.
  • Opaklık ve alfa kullanılmamalıdır.
  • Programınızın, iyi bir modern bilgisayarda , bir milyon pikselden daha az ve L' den 10.000'den az görüntülerle çalışması için bir saatten fazla sürmemesi gerekir.

Test görüntüleri

Elbette bize en doğru veya ilginç çıktı resimlerinizi göstermelisiniz ( L' nin I'deki piksel sayısının% 5 ila% 25'i arasında olması beklenir ve m ve M köşegen boyutunun onda biri kadardır ).

İşte bazı test görüntüleri (orijinaller için tıklayınız). Ayrıca kendi gönderinizi de gönderebilirsiniz.

Mona Lisa Şelale Gece Kuşları Yıldızlı Gece Golden Gate Köprüsü

Basit görüntüler:

Penrose merdivenleriMobius şeridi Hilbert eğrisi

Bu bir popülerlik yarışması. En yüksek oyu alan başvuru kazanır.

notlar

  • L'nin I'deki toplam piksel yüzdesinden ve mutlak bir değerden türetilmesine izin vermek yararlı olabilir . örneğin >>> imageliner I=img.png L=50% m=10 M=20aynı şey olurdu >>> imageliner I=img.png L=32 m=10 M=20eğer img.pngbir 8 ile 8 piksel görüntü idi. Benzer bir şey m ve M için yapılabilir . Bu gerekli değil.
  • Çizgiler sınırların dışına çıkamadığından, mümkün olan en uzun çizgiler I köşegen uzunluğu olacaktır . Having M Bundan daha yüksek olsa şey kırmak olmamalıdır.
  • Doğal olarak, m, 0 ve L piksel sayısına eşit ya da bundan daha büyük olan I , O ile aynı olabilir I her bir piksel konumu ile uzunluğu 0 "sıralar" sahip olarak. Bu davranış gerekli değildir.
  • Muhtemelen, I şeklini çoğaltmak, rengi çoğaltmaktan daha önemlidir. Kenar tespiti içine bakmak isteyebilirsiniz .

Netleştirmek için: SimpleCV gibi kütüphanelere izin var mı? Ve cevaplar, m = 0 ve L = alan dahil, I, L, m ve M için herhangi bir seçeneğe sahip olabilir?
Rasyonel,

@ epicwisdom Evet, tüm kütüphanelere (bu görevi özel olarak yapanlar hariç) izin verilir. Tuş noktaları, kenar algılama, her neyse, kullanmaktan çekinmeyin. Kişisel algoritması için çalışması gerektiğini herhangi bir geçerli seçimler I , L , m , M dahil m = 0 ve L = alanı. (Tabii ki, algoritmanız parametrelerin belirli ayarları için daha iyi görünebilir.)
Calvin'in Hobileri

Sonra, örneğin, bu özel kütüphane algoritması geçersiz bir cevap olarak kabul edilir?
Rasyonel,

@picwisdom Aslında buna ve benzeri şeylere izin vereceğim. Size verdiği çizgilerin bir görüntüsünü oluşturmak için hala akıllıca ince ayarlamalar yapılıyor gibi görünüyor.
Calvin'in Hobileri,

1
Çizgilerin kalınlığı 1 olması mı gerekiyor?
aditsu

Yanıtlar:


21

C ++ - biraz rasgele çizgiler ve sonra bazı

İlk önce bazı rasgele çizgiler

Algoritmanın ilk adımı rasgele çizgiler oluşturur, hedef görüntü için bu boyunca piksellerin ortalamasını alır ve sonra yeni çizgiyi boyarsak tüm piksellerin rgb alan mesafelerinin toplanan karesinin daha düşük olup olmadığını hesaplar (ve sadece öyleyse boyayın). Bunun için yeni çizgi rengi, -15 / + 15 rasgele ilavesiyle, rgb değerlerinin kanal bazında ortalaması olarak seçilir.

Uygulamayı farkettiğim ve etkilediğim şeyler:

  • İlk renk, tam görüntünün ortalamasıdır. Bu, beyaz olunca ve alanın siyah olması gibi komik etkilere karşı koymak, o zaman zaten parlak bir yeşil çizgi gibi bir şey, zaten beyaz olandan daha siyah olduğu için daha iyi görülüyor.
  • Satır için ortalama saf rengin alınması, daha sonraki satırların üzerine yazılarak vurgu oluşturamadığı için iyi değildir. Biraz rastgele sapma yapmak biraz yardımcı olur, ancak yıldızlı geceye bakarsanız, yerel kontrastın birçok yerde yüksek olması durumunda başarısız olur.

Bazı sayıları deniyordum, ve L=0.3*pixel_count(I)seçip bıraktım m=10ve M=50. Etrafında başlayan güzel sonuçlar üretecek0.25 için 0.26hatların sayısı için, ama doğru detaylar için daha fazla oda ise 0.3 seçtik.

Tam boyutlu altın kapı görüntüsü için bu, 235929 çizginin boyanmasına neden oldu (bunun için yaklaşık 13 saniye sürdü). Buradaki tüm görüntülerin küçültülmüş boyutta görüntülendiğini ve tam çözünürlüğü görüntülemek için bunları yeni bir sekmede açmanız / indirmeniz gerektiğini unutmayın.

Değersiz silmek

Bir sonraki adım oldukça pahalıdır (235k hatlar için yaklaşık bir saat sürdü, ancak bu "1 megapiksellikteki 10k hatlar için bir saat" süresi içinde olmalı), ama biraz da şaşırtıcı. Daha önce boyanmış tüm çizgilerden geçiyorum ve görüntüyü daha iyi hale getirmeyenleri kaldırıyorum. Bu beni, bu görüntüde aşağıdaki resmi üreten sadece 97347 satır bırakıyor:

Muhtemelen çoğu farkı tespit etmek için bunları uygun bir resim görüntüleyicide indirmeniz ve karşılaştırmanız gerekir.

ve tekrar başla

Şimdi tekrar toplamda 235929 olacak şekilde boyayabileceğim çok fazla çizgim var. Söylenecek fazla bir şey yok, işte resim:

görüntü tanımını buraya girin

kısa analiz

Tüm prosedür yerel kontrast ve nesne boyutlarına duyarlı olan bulanık bir filtre gibi işliyor gibi görünüyor. Ancak satırların nerede boyandığını görmek de ilginç, bu nedenle program bunları da kaydeder (Her satır için, piksel rengi bir adım daha beyaz yapılır, sonuçta kontrast en üst düzeye çıkarılır). Yukarıdaki üç renkli karşılık gelenler.

animasyonlar

Ve hepimiz animasyonları sevdiğimiz için, işte küçük altın kapı görüntüsü için tüm sürecin animasyonlu gifleri. Gif formatından dolayı önemli bir titreme olduğunu unutmayın (ve gerçek renkli animasyon dosyası formatlarının ve tarayıcı üreticilerinin egolarına göre bir savaşta olduğundan, gerçek renk animasyonları için standart bir format yoktur, aksi halde .mng veya benzerini ekleyebilirdim ).

Biraz daha

İstenildiği gibi, diğer görüntülerin bazı sonuçları aşağıdadır (küçültülmemeleri için bunları yeni bir sekmede açmanız gerekebilir)

Gelecek düşünceler

Kodla uğraşmak bazı ilginç değişiklikler verebilir.

  • Çizgilerin rengini ortalamaya dayanmak yerine rastgele seçin. İkiden fazla devire ihtiyacınız olabilir.
  • Pastebindeki kod aynı zamanda genetik bir algoritma hakkında bazı fikirler içerir, ancak görüntü muhtemelen çok fazla nesiller alabilecek kadar iyidir ve bu kod "bir saat" kuralına uymayacak kadar yavaş da olabilir.
  • Başka bir silme / boyama, hatta iki kez yapın ...
  • Çizgilerin silinebileceği yerin sınırını değiştirin (örn. "Resmi en iyi N konumuna getirmeli")

Kod

Bunlar sadece iki ana kullanışlı fonksiyondur, kodun tamamı buraya uymaz ve bulunabilir. http://ideone.com/Z2P6L adresinde

bmpSınıflar rawve raw_linefonksiyon biçimi bmp yazılabilir bir nesne sırasıyla erişim piksel ve çizgiler yapmak (Sadece biraz kesmek ortalıkta oldu ve ben herhangi bir kütüphaneden bu biraz bağımsız kılan düşünce).

Giriş dosyası formatı PPM'dir

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, gerçekten çok hoş. Diğer test görüntüleri için sonuçlarınız var mı?
Nathaniel,

1
@ Nathaniel: Bazılarını ekledim. "Basit" görüntüler ilginçtir, çünkü eğlence neredeyse piksel mükemmeldir.
PlazmaHH

17

Java - rasgele çizgiler

Rasgele çizgiler çizen ve kaynak resim ortalama rengini hesaplayan çok basit bir çözüm. Arka plan rengi kaynak ortalama rengine ayarlanır.

L = 5000, m = 10, M = 50

görüntü tanımını buraya girin

L = 10000, m = 10, M = 50

görüntü tanımını buraya girin

DÜZENLE

Satır popülasyonunu işleyen genetik bir algoritma ekledim. Her nesilde, sadece% 50 en iyi çizgiyi koruyoruz, diğerlerini düşürüyor ve rastgele yenilerini üretiyoruz. Çizgileri koruma kriterleri:

  • kaynak resim renklerine uzaklığı azdır
  • diğer çizgilerle kesişme sayısı (ne kadar küçük olursa o kadar iyi)
  • uzunlukları (ne kadar uzun olursa o kadar iyi)
  • En yakın komşuya olan açıları (ne kadar küçük olursa o kadar iyi)

Benim büyük hayal kırıklığımı, algoritma gerçekten resim kalitesini artırmak için görünmüyor :-( Sadece çizgiler daha paralel hale geliyor.

İlk nesil (5000 satır)

görüntü tanımını buraya girin

Onuncu nesil (5000 satır)

görüntü tanımını buraya girin

Parametrelerle oynamak

görüntü tanımını buraya giringörüntü tanımını buraya giringörüntü tanımını buraya girin

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

Sonunda biri cevap verdi: D Daha fazla örnek görmeyi çok isterim.
Calvin'in Hobileri

@Calvin Tabii. Şu anda algoritmayı geliştirmek için bir çizgi popülasyonu tutarak ve örneğin% 20 daha kötü olanı ortadan kaldırarak ve yenilerini yeniden üretmeye çalışıyorum (bir tür genetik algoritma)
Arnaud

Aklımda böyle bir şey vardı ama yazmak için zamanım yok. Genetik alg için bekliyorum. sonuçlar :)
aditsu

Belki daha küçük açı kriterini kaldırmak istersiniz? Neden koydun Çizgiler küçük kesişme açısına sahip olmasa da orijinal görüntü iyi görünüyor.
justhalf

Sadece tamamlandı. Ressam fırçasını simüle etmek için açı ölçütünü ekledim.
Arnaud

9

C - düz çizgiler

Ppm dosyalarında çalışan C dilinde temel bir yaklaşım. Algoritma, tüm pikselleri doldurmak için en uygun çizgi uzunluğuna sahip dikey çizgiler yerleştirmeye çalışır. Arka plan rengi ve çizgi renkleri, orijinal görüntünün (her renk kanalının ortancası) ortalama değeri olarak hesaplanır:

#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

görüntü tanımını buraya girin


6

Python 3 - "biraz rasgele çizgiler ve sonra bazıları", artı sobel kenarı tespiti üzerine kuruludur.

Kod teorik olarak sonsuza kadar çalışabilir (bu yüzden eğlence için bir gecede çalıştırabilirim), ancak ilerlemesini kaydeder, böylece tüm görüntüler 1-10 dk işaretinden alınır.

Önce görüntüyü okur ve sonra tüm kenarların açısını bulmak için sobel kenarı algılamasını kullanır, böylece çizgilerin başka bir renkte geçmediğinden emin olun. İçinde rastgele uzunluktaki bir çizgi (uzunlukmin, uzunlukmax) ayarlandıktan sonra, genel görüntüye katkıda bulunup bulunmadığını görmek için test eder. Küçük çizgiler daha iyi olsa da, çizgi uzunluğunu 10-50 olarak ayarlarım.

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

Gotik amerikan

Escher

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.