Světlost barvy z jednotlivých složek se počítá podle vzorce 0.3 * R + 0.59 * G + 0.11 * B. Každá barevná složka totiž k výsledné světlosti přispívá jiným dílem. Pak již není problém udělat graf. Celý program by vydal na samostatný článek, takhle je to dost narychlo:
Public Class MainForm
Dim max As Integer = 0 'maximální počet pixelů stejné úrovně
Dim im As Bitmap
Dim pR(255) As Integer 'počet pixelů s červenou složkou dané intenzity
Dim pG(255) As Integer 'počet pixelů se zelenou složkou dané intenzity
Dim pB(255) As Integer 'počet pixelů s modrou složkou dané intenzity
Dim pS(255) As Integer 'počet pixelů se světlostí dané intenzity
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'nechat uživatele vybrat obrázek a načíst ho do proměnné im
If OpenFileDialog1.ShowDialog() <> Windows.Forms.DialogResult.OK Then End
im = Image.FromFile(OpenFileDialog1.FileName)
''TOHLE FUNGUJE POMALU PRO VELKÉ OBRÁZKY
''--------------------------------------
'For y As Integer = 0 To im.Height - 1 'projít všechny pixely obrázku
' For x As Integer = 0 To im.Width - 1
' Dim c As Color = im.GetPixel(x, y) 'GetPixel je pomalé, volejte jej jen jednou a výsledek si uložte
' pR(c.R) += 1 'přičíst červený pixel
' pG(c.G) += 1 'přičíst zelený pixel
' pB(c.B) += 1 'přičíst modrý pixel
' pS(c.R * 0.3 + c.G * 0.59 + c.B * 0.11) += 1 'přičíst světlost
' Next
'Next
'RYCHLEJŠÍ METODA
'----------------
'získá se bitová kopie obrázku
Dim bd As Imaging.BitmapData = im.LockBits(New Rectangle(0, 0, im.Width, im.Height), Imaging.ImageLockMode.ReadOnly, Imaging.PixelFormat.Format24bppRgb)
Dim pixely(bd.Width * bd.Height * 3 - 1) As Byte
Runtime.InteropServices.Marshal.Copy(bd.Scan0, pixely, 0, pixely.Length)
im.UnlockBits(bd)
'teď pracujeme s jednotlivými pixely jako s bajty
For i As Integer = 0 To pixely.Length - 1 Step 3 'skákat po 3 bajtech
Dim b As Byte = pixely(i) 'první bajt z trojice je modrá
Dim g As Byte = pixely(i + 1) 'druhý bajt z trojice je zelená
Dim r As Byte = pixely(i + 2) 'třetí bajt z trojice je červená
pR(r) += 1
pG(g) += 1
pB(b) += 1
pS(r * 0.3 + g * 0.59 + b * 0.11) += 1
Next
'zjistit maximum
For i As Integer = 0 To 255
If pR(i) > max Then max = pR(i)
If pG(i) > max Then max = pG(i)
If pB(i) > max Then max = pB(i)
If pS(i) > max Then max = pS(i)
Next
'uvolnit obrázek z paměti
im = Nothing
End Sub
Public Sub Graf(ByVal g As Graphics, ByVal p As Pen, ByVal pole() As Integer, ByVal vyska As Integer)
'vykreslit graf
For i As Integer = 0 To 255
Dim v As Integer = vyska * pole(i) / max
g.DrawLine(p, i, 255, i, 255 - v)
Next
End Sub
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Graf(e.Graphics, Pens.Red, pR, PictureBox1.Height)
End Sub
Private Sub PictureBox2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
Graf(e.Graphics, Pens.Green, pG, PictureBox2.Height)
End Sub
Private Sub PictureBox3_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox3.Paint
Graf(e.Graphics, Pens.Blue, pB, PictureBox3.Height)
End Sub
Private Sub PictureBox4_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox4.Paint
Graf(e.Graphics, Pens.Black, pS, PictureBox4.Height)
End Sub
End Class
Navíc protože je metoda GetPixel strašně pomalá (obrázek 800x600 mi trval na slabším stroji cca minutu), je lepší pomocí Marshal.Copy vytáhnout z obrázku pole bajtů. Pokud pole rozsekáme po třech bajtech, získáme jednotlivé pixely - první bajt je modrá složka, druhý zelená a třetí červená. Ještě k polím pR, pG, pB a pS - včechny sledované položky (červená, zelená, modrá i světlost) mají hodnoty od 0 do 255. Takže v poli pR(40) bude počet pixelů v celém obrázku, jejichž červená složka má hodnotu 40, v poli pS(150) bude zaser počet pixelů se světlostí 150. Pak již jednoduše vykreslím graf - abych 4x neopisoval de facto stejný kód, udělal jsem si proceduru. Pokud to chcete spustit, dejte na formulář 4 pictureboxy o velikosti 256x256 pixelů a jeden OpenFileDialog.
|