Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB6: Pikselien luku

setä [26.07.2010 17:33:19]

#

Pictureboxiin piirretyn kuvan pixelien väri on luettavissa Point-funktiolla, mikä vaikuttaa melko hitaalta. Onko siihen olemassa nopeampaa keinoa? Tarkoitus luoda kuvasta Long-tyypin taulukko. (VB5)

Merri [26.07.2010 22:47:42]

#

Tässä on Byte-taulukkoon versio:

Option Explicit

Private Declare Function GetBitmapBits Lib "gdi32" (ByVal Bitmap As Long, ByVal BufferSize As Long, Buffer As Any) As Long

Private Sub Form_Load()
    Dim Leveys As Long, Korkeus As Long, Rivi As Long, Tavut As Long
    Dim Pikselit() As Byte
    Leveys = Picture1.ScaleX(Picture1.Picture.Width, vbHimetric, vbPixels)
    Korkeus = Picture1.ScaleY(Picture1.Picture.Height, vbHimetric, vbPixels)
    Rivi = (Leveys * 3 + 3) And &HFFFFFFFC
    Tavut = Rivi * Korkeus
    ReDim Pikselit(0 To Tavut - 1)
    GetBitmapBits Picture1.Picture.Handle, Tavut, Pikselit(0)
    Debug.Print Hex$(Pikselit(0)), Hex$(Pikselit(1)), Hex$(Pikselit(2))
End Sub

Kuvaobjektit näyttäisivät säilövän kuvat aina 24-bittisinä, joten joutuisit luomaan oman 32-bittisen Device Independent Bitmapin APIn voimin ja sitten käyttämään esim. Picture1.Picture.Renderiä kopioidaksesi kuvan sinne, jonka jälkeen pystyt saamaan sieltä 32-bittistä dataa Long-taulukon täyttöä varten.

Vaihtoehto B on vähän helpompi: tee-se-itse -kopiointi. IDE:ssä aavistuksen hidas, mutta käännettynä salamannopea, varsinkin jos tärppää advanced optimizations -ikkunasta taulukoiden rajojen tarkistukset pois päältä. Jatkaen edellistä esimerkkiä:

    Dim Taulu() As Long, I As Long
    ReDim Taulu(((Leveys + 3) \ 4) * Korkeus - 1)
    For I = 0 To UBound(Taulu)
        Taulu(I) = Pikselit(I * 3) Or Pikselit(I * 3 + 1) * &H100& Or Pikselit(I * 3 + 2) * &H10000
    Next I
    Debug.Print Hex$(Taulu(0))

Ja nyt kuvan kaikki pikselit ovat suhteellisen nopeasti vietynä Long-taulukkossa.


Huom! Mikäli Picture on määrittelemättä, niin tämä ei tietenkään toimi. Tällöin voi myös Imagea käyttää Picturen sijasta, jolloin käytössä on PictureBoxin piirtobufferi. Tämä on kuitenkin huomattavasti isompi kuin mitä päälle päin näyttää ja saadut leveys- ja korkeustiedot ovat hieman eri luokkaa kuin mitä saatat odottaa. Image taisi myös toimia ainoastaan jos AutoRedraw on kytkettynä päälle, mutta en ole satavarma (mutten jaksa testata).

setä [26.07.2010 23:22:38]

#

Suuret kiitokset ! Bytetaulukko on oikeastaan jopa parempi, en vain tullut ajatelleeksi. Piirretty kuva on imagena, jonka voi sitten jäädyttää pictureksi ja siirtää byte-taulukkoon. Löytyykö tähän vielä käänteinen toiminto, eli byte-taulukko takaisin pikseleiksi. Pset-käskyllä tietysti onnistuu mutta on hidas.
AutoRedraw on todellakin oltava päällä.

Merri [26.07.2010 23:32:52]

#

Jep, SetBitmapBits. Sen määritys on sama kuin GetBitmapBitsillä, eli teet vaan kopion rivistä ja vaihdat yhden kirjaimen. Kunhan pidät huolta siitä, että rivileveys pikselitaulukossa on aina jaollinen neljällä, niin ongelmia ei synny (sen takia tuolla on riveihin liittyen vähän hassun näköistä matikkaa).

Tosin näyttäisi että MSDN:n dokumentaatio suosittelee käyttämään SetDIBitsiä ja GetDIBitsiä, koska nämä BitmapBits-funktiot on 16-bittisen Windowsin ohjelmien tukemista varten... valitettavasti DIBits-funktiot ovat vähän monimutkaisempia.

Toisaalta kun kerta käytät VB5:ttä, niin eipä sinulle taida olla väliä moisilla yhteensopivuusseikoilla :)

setä [26.07.2010 23:53:24]

#

Kiitoksia, tuo ainakin toimi hyvin, siis GetBitmapBits. Vielä en testannut nopeutta koska tuon Point-funktion nopeuden testaukseen riitti Timer-funktio.
Eikö rivin pituus pidä olla kolmella jaollinen eikä neljällä ?

Merri [27.07.2010 06:42:21]

#

Ei, koska jokainen bittikartta tallennetaan muistissa siten, että kuvan leveys on jaollinen neljällä. Jos sinulla on vaikka 1 x 2 -kokoinen 8-bittinen kuva, niin muistissa se vie 8 tavua, koska jokainen rivi vie 4 tavua, vaikka jokaiselta riviltä on käytössä vain se yksi tavu.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta