Bitmap Infinite [ditutup]


10

Saya ingin membangun bitmap selama runtime. Bitmap harus scalable di semua sisi dan akses pixel harus cukup efisien.

Beberapa ilustrasi http://img546.imageshack.us/img546/4995/maptm.jpg

Antara dan setelah perintah yang ditunjukkan pada gambar, Map.setPixel () dan Map.getPixel () harus mengatur / mengembalikan data yang disimpan dalam bitmap.

Saya tidak mengharapkan implementasi hanya konsep bagaimana mengalokasikan memori sedemikian rupa sehingga setPixel () / getPixel secepat mungkin.


Apakah bidang abu-abu selalu menjadi titik (0,0) atau dapatkah itu menjadi koordinat lain juga?
Falcon

2
Diperlukan lebih banyak detail. Apakah piksel yang disetel akan jarang? Seberapa lambat Anda bersedia untuk membuat extendXmetode untuk membuat setPixeldan getPixelyang cepat?
Peter Taylor

1
Akankah bitmap terlalu besar untuk muat dalam memori? Apa yang harus menjadi operasi cepat - ekspansi, setPixel (), getPixel ()?

1
@ Falcon: Tidak, ada cukup waktu tersedia
SecStone

3
Saya memberikan suara untuk menutup pertanyaan ini sebagai di luar topik karena pertanyaannya sangat bergantung pada gambar yang disertakan, yang sejak itu telah dihapus. Seperti yang ditulis saat ini, itu tidak masuk akal.

Jawaban:


9

Jika extend()operasi perlu cukup cepat, Quadtree mungkin cocok; sebenarnya bahkan tidak memerlukan operasi perluasan yang eksplisit. Memang, itu tidak akan menghasilkan kinerja yang optimal untuk akses acak ke piksel individu, tetapi komentar Anda mengatakan bahwa operasi utama Anda adalah iterasi dari piksel, yang quadtree bisa lakukan sangat cepat, mungkin hampir secepat implementasi berbasis matriks (dan lebih cepat jika iterasi tidak selalu terjadi dengan cara yang sama, matriks diletakkan).

Persyaratan Anda sebenarnya terdengar seperti Anda mencoba menerapkan otomat seluler seperti Game of Life. Anda mungkin ingin melihat Hashlife , cara yang sangat berkinerja tinggi untuk mengimplementasikan Game of Life di grid yang tak terbatas. Perhatikan bahwa ini didasarkan pada Quadtree, tetapi melakukan beberapa optimasi tambahan yang sangat cerdas berdasarkan lokalitas aturan permainan.


Terima kasih atas ide ini! Saya akan melakukan beberapa pengujian dan akan melaporkan hasilnya.
SecStone

2

@SecStone mengatakan bahwa ada cukup waktu untuk operasi ekspansi, jadi cara termudah dan paling efisien untuk menyimpan piksel adalah dengan menggunakan susunan datar tunggal atau susunan dua dimensi, karena piksel dapat diakses dalam waktu yang konstan.


4
Saya akan memilih ini jika Anda memberikan saran yang bagus tentang bagaimana Anda pikir ekspansi harus ditangani.
Doc Brown

@ Doc Brown: Jika ada cukup waktu maka geser saja array. Atau mungkin Anda dapat mengerjakan sesuatu dengan chunk dan fungsi penerjemah untuk point to array dan chunk index (yang berjalan dalam waktu yang konstan juga).
Falcon

2

Dengan tangan

Jika memori bukan sumber daya yang sangat jarang, saya menganggap bekerja di potongan yang lebih besar.
Berikut ini beberapa kode semu.

class Chunk {
    Chunk new(int size) {...}
    void setPixel(int x, int y, int value) {...}
    int getPixel(int x, int y) {...}
}

class Grid {
    Map<int, Map<Chunk>> chunks;
    Grid new(int chunkSize) {...}
    void setPixel(int x, int y, int value) {
         getChunk(x,y).setPixel(x % chunkSize, y % chunkSize, value);//actually the modulo could be right in Chunk::setPixel and getPixel for more safety
    }
    int getPixel(int x, int y) { /*along the lines of setPixel*/ }
    private Chunk getChunk(int x, int y) {
         x /= chunkSize;
         y /= chunkSize;
         Map<Chunk> row = chunks.get(y);
         if (row == null) chunks.set(y, row = new Map<Chunk>());
         Chunk ret = row.get(x);
         if (ret == null) row.set(x, ret = new Chunk(chunkSize));
         return ret;
    }
}

Implementasi ini cukup naif.
Untuk satu, itu menciptakan potongan di getPixel (pada dasarnya itu akan baik-baik saja untuk mengembalikan 0 atau lebih, jika tidak ada potongan didefinisikan untuk posisi itu). Kedua didasarkan pada asumsi, bahwa Anda memiliki implementasi Peta yang cukup cepat dan terukur. Setahu saya setiap bahasa yang baik memiliki satu.

Anda juga harus bermain dengan ukuran chunk. Untuk bitmap yang padat, ukuran chunk yang besar adalah baik, untuk bitmap yang jarang, ukuran chunk yang lebih kecil lebih baik. Bahkan untuk yang sangat jarang, "ukuran chunk" dari 1 adalah yang terbaik, menjadikan "chunk" itu sendiri usang dan mengurangi struktur data menjadi peta int dari peta piksel int.

Dari rak

Solusi lain mungkin dengan melihat beberapa perpustakaan grafis. Mereka sebenarnya cukup bagus dalam menggambar satu buffer 2D ke yang lain. Itu berarti Anda hanya akan mengalokasikan buffer yang lebih besar dan memiliki yang asli ditarik ke dalamnya di koordinat yang sesuai.

Sebagai strategi umum: Ketika memiliki "blok memori yang tumbuh secara dinamis", adalah ide yang baik untuk mengalokasikan beberapa dari itu, setelah digunakan. Ini agak menghabiskan banyak memori, tetapi secara signifikan memotong alokasi dan biaya penyalinan . Sebagian besar implementasi vektor mengalokasikan dua kali ukurannya, ketika terlampaui. Jadi terutama jika Anda menggunakan solusi yang tidak tersedia, jangan memperpanjang buffer Anda hanya dengan 1 pixel, karena hanya satu pixel yang diminta. Memori yang dialokasikan murah. Realokasi, menyalin, dan melepaskan itu mahal.


1

Hanya beberapa poin saran:

  • Jika Anda menerapkan ini sebagai array dari beberapa tipe integral (atau array array ...), Anda mungkin harus menumbuhkan array pendukung dengan sejumlah bit / piksel setiap kali untuk menghindari keharusan menggeser bit saat Anda menyalinnya. Sisi buruknya adalah Anda menggunakan lebih banyak ruang, tetapi proporsi ruang terbuang turun seiring bitmap semakin besar.

  • Jika Anda menggunakan struktur data berbasis Peta, Anda dapat memperbaiki masalah menumbuhkan bitmap hanya dengan memindahkan x, y mengoordinasikan argumen getPixeldan setPixelpanggilan.

  • Jika Anda menggunakan struktur data berbasis Peta, Anda hanya perlu entri peta untuk "yang". "Nol" dapat ditunjukkan dengan tidak adanya entri. Ini menghemat banyak ruang, terutama jika bitmap sebagian besar nol.

  • Anda tidak perlu menggunakan Peta. Anda dapat menyandikan intpasangan x, y sebagai satu long. Proses analog dapat digunakan untuk memetakan array array ke array.


Akhirnya, Anda perlu menyeimbangkan 3 hal:

  1. kinerja getPixeldan setPixel,
  2. kinerja extend*operasi, dan
  3. pemanfaatan ruang.

1

Sebelum mencoba hal lain yang lebih rumit, dan kecuali Anda tidak dapat menyimpan semuanya dalam memori, pertahankan segala sesuatunya sederhana dan gunakan array dua dimensi bersama dengan informasi tentang asal-usul sistem koordinat Anda. Untuk memperluasnya, gunakan strategi yang sama seperti, misalnya, vektor C ++ std ::: membuat perbedaan antara ukuran aktual array Anda dan kapasitas array, dan memperluas kapasitas dalam potongan setiap kali batas tercapai. "kapasitas" di sini harus didefinisikan dalam hal interval (from_x, to_x), (from_y, to_y).

Ini mungkin memerlukan realokasi memori yang lengkap dari waktu ke waktu, tetapi selama ini tidak terlalu sering terjadi, mungkin cukup cepat untuk tujuan Anda (sebenarnya, Anda harus mencoba / profil ini).


1

Cara tercepat mutlak untuk melakukan akses piksel adalah array dua dimensi dari piksel yang dapat dialamatkan secara individual.

Untuk ekstensi, mulailah dengan implementasi sederhana yang realokasi dan salin setiap waktu (karena Anda tetap membutuhkan kode itu). Jika profiling tidak menunjukkan bahwa Anda menghabiskan banyak waktu untuk itu, tidak perlu disempurnakan lagi.

Jika pembuatan profil menunjukkan kebutuhan untuk menjaga agar jumlah alokasi ulang tetap rendah dan Anda tidak dibatasi oleh memori, pertimbangkan untuk mengalokasikan terlalu banyak dengan persentase di setiap arah dan menyimpan offset ke titik asal. (Misalnya, jika Anda memulai bitmap baru pada 1x1 dan mengalokasikan array 9x9 untuk menahannya, yang awal xdan yoffset akan menjadi 4.) Trade-off di sini adalah harus melakukan matematika tambahan selama akses piksel untuk menerapkan offset.

Jika ekstensi ternyata sangat mahal, Anda dapat mencoba salah satu dari keduanya:

  • Menangani ekstensi vertikal dan horizontal secara berbeda. Memperluas array secara vertikal ke segala arah dapat dilakukan dengan mengalokasikan blok baru dan melakukan satu salinan dari seluruh array yang ada ke offset yang sesuai di memori baru. Bandingkan dengan ekstensi horisontal, di mana Anda harus melakukan operasi itu sekali per baris karena data yang ada tidak bersebelahan di blok baru.

  • Pantau jumlah dan arah ekstensi yang paling sering. Gunakan informasi itu untuk memilih ukuran dan offset baru yang akan mengurangi kemungkinan harus melakukan alokasi ulang dan salin untuk ekstensi apa pun.

Secara pribadi, saya ragu Anda akan membutuhkan keduanya kecuali rasio piksel-akses-terhadap-ekstensi rendah.


1
  • Ubin ukuran konstan (katakanlah, 256x256, tetapi dengan jumlah ubin yang tak terbatas)
  • Berikan pembungkus bitmap yang memungkinkan koordinat piksel negatif (untuk memberi kesan bahwa gambar dapat diperluas ke keempat arah tanpa harus menghitung ulang / menyinkronkan referensi ke nilai koordinat yang ada)
    • Kelas bitmap yang sebenarnya (bekerja di bawah pembungkus), bagaimanapun, seharusnya hanya mendukung koordinat absolut (non-negatif).
  • Di bawah pembungkus, berikan akses level ubin (level blok) menggunakan I / O yang dipetakan dengan memori
  • Selain Map.setPixel()dan Map.getPixel()yang memodifikasi satu piksel pada satu waktu, juga menyediakan metode yang menyalin dan mengubah satu persegi panjang piksel sekaligus. Ini akan memungkinkan pemanggil untuk memilih bentuk akses yang lebih efisien tergantung pada informasi yang tersedia untuk pemanggil.
    • Pustaka komersial juga menyediakan metode untuk memperbarui: satu baris piksel, satu kolom piksel, sebarkan / kumpulkan pembaruan, dan operasi penghitung aritmatika / logika dalam satu langkah (untuk meminimalkan penyalinan data).

(Mari kita tidak menjawab jawaban lucu ...)


0

Implementasi yang paling fleksibel dan mungkin dapat diandalkan adalah daftar tertaut dengan struct yang memberikan nilai x-koordinat, koordinat y, dan bit. Saya akan membangun itu dulu dan membuatnya bekerja.

Kemudian, jika terlalu lambat dan / atau besar, coba cara-cara biasa untuk mempercepatnya: array, matriks, bitmap, kompresi, caching, inversi, menyimpan hanya nilai '1', dll.

Lebih mudah untuk membuat implementasi benar lambat lebih cepat daripada memperbaiki implementasi cepat kereta. Dan saat menguji implementasi kedua 'cepat' Anda, Anda memiliki standar referensi untuk membandingkannya.

Dan, siapa tahu, Anda mungkin akan menemukan bahwa versi lambatnya cukup cepat. Selama seluruh struktur pas di memori, semuanya sudah luar biasa cepat.


3
-1: "membuatnya bekerja sebelum membuatnya cepat" bukan alasan yang baik untuk memulai dengan implementasi terburuk. Selain itu, praktis tidak akan ada kode yang tidak perlu diubah sepenuhnya dengan struktur data yang mendasarinya, sehingga iterasi pada tingkat itu adalah saran yang sepenuhnya tidak masuk akal di sini.
Michael Borgwardt

Itu sebabnya Anda memiliki API. API menyembunyikan implementasi yang mendasarinya. SetValue (MyMatrix, X, Y, Value) dan GetValue (MyMatrix, X, Y) menyembunyikan apakah MyMatrix adalah array yang difungsikan 1 atau 2, atau daftar tertaut, atau di-cache pada disk, atau tabel SQL, atau apa pun. Penelepon mungkin perlu mengkompilasi ulang, tetapi tidak mengubah kode.
Andy Canfield

0

Saya mengusulkan implementasi berikut dengan Python:

class Map(dict): pass

Ini memiliki keuntungan sebagai berikut:

  1. Dapatkan / Tetapkan akses melalui map[(1,2)]dapat dipertimbangkan O(1).
  2. Kebutuhan untuk memperluas jaringan secara eksplisit menghilang.
  3. Ada sedikit ruang untuk bug.
  4. Mudah ditingkatkan ke 3D, jika perlu.

0

Jika Anda benar - benar membutuhkan bitmap dari ukuran sembarang - dan maksud saya apa pun mulai dari 1x1 hingga 1000000x1000000 amd ke atas, dan perlu diperluas sesuai permintaan ... salah satu cara yang mungkin adalah dengan menggunakan database. Pada awalnya mungkin terlihat kontra intuitif, tetapi yang Anda miliki sebenarnya adalah masalah penyimpanan. Basis data akan memungkinkan Anda mengakses setiap piksel dan menyimpan sejumlah data secara esensial. Saya tidak perlu berarti SQL db, btw.

Apakah akan cukup cepat untuk keperluan Anda? Saya tidak bisa menjawab, karena tidak ada konteks di sini mengenai apa yang Anda lakukan dengan bitmap ini. Tetapi jika ini untuk tampilan layar, pertimbangkan bahwa Anda umumnya hanya perlu menarik kembali baris pindai tambahan untuk ditampilkan saat layar bergulir, tidak semua data.

Yang sedang berkata, saya tidak bisa membantu tetapi bertanya-tanya apakah Anda akan melakukan sesuatu yang salah. Apakah sebaiknya Anda menggunakan grafis berbasis vektor dan melacak setiap individu dalam memori, dan kemudian membuat bitmap hanya sebesar yang diperlukan untuk layar?


Mungkin server peta OSGeo.
rwong

0

Berikut langkah-langkah untuk membuatnya berfungsi dengan baik:

  1. gunakan penerusan dari satu antarmuka ke antarmuka lain untuk membangun pohon objek yang bersama-sama mewakili bitmap
  2. setiap "ekstensi" bitmap akan mengalokasikan memori itu sendiri dan menyediakan antarmuka lain untuk itu
  3. contoh implementasi adalah:

    template<class T, class P>
    class ExtendBottom {
    public:
       ExtendBottom(T &t, int count) : t(t), count(count),k(t.XSize(), count) { }
       P &At(int x, int y) const { if (y<t.YSize()) return t.At(x,y); else return k.At(x, y-t.YSize()); }
       int XSize() const { return t.XSize(); }
       int YSize() const { return t.YSize()+count; }
    private:
       T &t;
       int count;
       MemoryBitmap k;
    };
    

Jelas untuk implementasi nyata, XSize () dan YSize () tidak akan berfungsi, tetapi Anda akan membutuhkan MinX (), MaxX (), MinY (), MaxY () atau sesuatu seperti itu untuk menjaga angka indeks konsisten.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.