www.pudn.com > hbp0.1.zip > ClassTopMap.cls
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "ClassTopMap"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'Rodney robot - topological map
'Copyright (C) 2004 Bob Mottram
'
'This program is free software; you can redistribute it and/or modify
'it under the terms of the GNU General Public License as published by
'the Free Software Foundation; either version 2 of the License, or
'(at your option) any later version.
'
'This program is distributed in the hope that it will be useful,
'but WITHOUT ANY WARRANTY; without even the implied warranty of
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
'GNU General Public License for more details.
'
'You should have received a copy of the GNU General Public License
'along with this program; if not, write to the Free Software
'Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Option Explicit
Public Name As String
Public width As Integer
Public height As Integer
Public inputs_width As Integer
Public inputs_height As Integer
Dim unit() As Single
Dim image() As Byte
Dim outputs() As Single
Dim hits() As Long
Dim max_hits As Long
Dim minValue As Single
Dim h As Single
Dim average_similarity As Single
'a number used to classify a point on the map
Dim classification() As Integer
Dim classificationMulti() As Long
Dim ClassificationColour(1000) As Long
Dim ClassificationName(20, 20) As Byte 'name of each class
Dim Portrait(20, 150) As Byte 'filename of a jpg image associated with the class
Public learningRate As Single 'o<=r<=1
Public randomness As Single '0<=r<=1
Public RadiusExcite As Integer
Dim inputs() As Single
Public WinnerX As Integer
Public WinnerY As Integer
Public Threshold As Single
Public Sub init(InputsWidth As Integer, InputsHeight As Integer, mapWidth As Integer, mapHeight As Integer)
On Error GoTo init_err
Dim x As Integer
Dim y As Integer
inputs_width = InputsWidth
inputs_height = InputsHeight
ReDim inputs(inputs_width, inputs_height)
width = mapWidth
height = mapHeight
ReDim unit(width, height, inputs_width, inputs_height)
ReDim image(width, height, inputs_width, inputs_height)
ReDim outputs(width, height)
ReDim hits(width, height)
ReDim classification(width, height)
ReDim classificationMulti(width, height, 10)
learningRate = 0.5
RadiusExcite = 1
randomness = 0.01
Threshold = 0#
Call initWeights
'zero some parameters
For x = 0 To width - 1
For y = 0 To height - 1
hits(x, y) = 0
outputs(x, y) = 0
classification(x, y) = 0
Next
Next
init_exit:
Exit Sub
init_err:
MsgBox "classTopmap/init/" & Error$(Err)
Resume init_exit
End Sub
Public Sub setPortrait(index As Integer, filename As String)
'stores a filename associated with the given class index
Dim i As Integer
Dim l As Integer
filename = Left$(filename, 150)
l = Len(filename)
For i = 0 To l
If (i < l) Then
Portrait(index, i) = Asc(Mid$(filename, i + 1, 1))
Else
Portrait(index, i) = 13
End If
Next
End Sub
Public Function getPortrait(index As Integer) As String
'returns a filename associated with the given class index
Dim i As Integer
Dim filename As String
Dim b As Byte
filename = ""
i = 0
b = 0
While (i < 150) And (b <> 13)
b = Portrait(index, i)
If (b <> 13) Then
filename = filename & Chr(b)
End If
i = i + 1
Wend
getPortrait = filename
End Function
Public Sub setClassificationColour(classificationID, Red As Integer, Green As Integer, Blue As Integer)
'sets the colour associated with a classification
ClassificationColour(classificationID) = RGB(Red, Green, Blue)
End Sub
Public Function getClassificationColour(classificationID) As Long
'gets the colour associated with a classification
getClassificationColour = ClassificationColour(classificationID)
End Function
Public Sub setInput(x As Integer, y As Integer, Value As Single)
inputs(x, y) = Value
End Sub
Public Function getOutput(x As Integer, y As Integer) As Single
getOutput = outputs(x, y)
End Function
Private Function similarity(x As Integer, y As Integer) As Single
'returns the similarity between the input array and the map unit
On Error GoTo similarity_err
Dim xx As Integer
Dim yy As Integer
Dim Value As Single
Dim dv As Single
Value = 0
For xx = 0 To inputs_width - 1
For yy = 0 To inputs_height - 1
dv = Abs(unit(x, y, xx, yy) - inputs(xx, yy))
Value = Value + dv
Next
Next
similarity = ((1 - randomness) * (Value / (inputs_width * inputs_height))) + (randomness * Rnd)
similarity_exit:
Exit Function
similarity_err:
MsgBox "classTopmap/similarity/" & Error$(Err)
Resume similarity_exit
End Function
Public Sub Update()
On Error GoTo update_err
Dim x As Integer
Dim y As Integer
Dim least_hits As Integer
Dim Value As Single
Dim min As Single
WinnerX = -1
WinnerY = -1
min = 9999
average_similarity = 0
For x = 0 To width - 1
For y = 0 To height - 1
Value = similarity(x, y)
average_similarity = average_similarity + Value
If (Value < Threshold) Then
If (Value < min) Then
min = Value
WinnerX = x
WinnerY = y
End If
outputs(x, y) = (1 - Value) * (1 - Value)
Else
outputs(x, y) = 0
End If
Next
Next
'calculate the average similarity across the map
average_similarity = average_similarity / (width * height)
'update hit score
If (WinnerX > -1) Then
hits(WinnerX, WinnerY) = hits(WinnerX, WinnerY) + 1
If (hits(WinnerX, WinnerY) > max_hits) Then
max_hits = hits(WinnerX, WinnerY)
If (max_hits > 32000) Then Call rescaleHits
End If
Else
'find the least used unit
least_hits = max_hits + 1
For x = 0 To width - 1
For y = 0 To height - 1
If ((hits(x, y) < least_hits) And (classification(x, y) = 0)) Then
least_hits = hits(x, y)
WinnerX = x
WinnerY = y
End If
Next
Next
End If
update_exit:
Exit Sub
update_err:
MsgBox "classTopmap/update/" & Error$(Err)
Resume update_exit
End Sub
Private Function dist(x As Integer, y As Integer) As Single
dist = (((x - WinnerX) * (x - WinnerX)) + ((y - WinnerY) * (y - WinnerY)))
End Function
Private Function randVal(Value As Single) As Single
'adds randomness to a value
randVal = ((1 - randomness) * Value) + (randomness * Rnd)
End Function
Private Sub adjustWeights(x As Integer, y As Integer, Value As Single)
'adjusts weights of the unit in accordance with its value
On Error GoTo adjustWeights_err
Dim xx As Integer
Dim yy As Integer
Dim dw As Single
Dim w As Single
If (classification(x, y) = 0) Then
For xx = 0 To inputs_width - 1
For yy = 0 To inputs_height - 1
w = unit(x, y, xx, yy)
dw = inputs(xx, yy) - w
w = w + (learningRate * dw * Exp(-Value * Value))
unit(x, y, xx, yy) = w
Next
Next
End If
adjustWeights_exit:
Exit Sub
adjustWeights_err:
MsgBox "classTopmap/adjustWeights/" & Error$(Err)
Resume adjustWeights_exit
End Sub
Public Sub learn()
On Error GoTo learn_err
Dim x As Integer
Dim y As Integer
Dim d As Single
Dim e As Single
Dim i As Integer
Dim Value As Single
Dim max As Single
'store the current input image on the winning unit
If (WinnerX > -1) Then
max = RadiusExcite * RadiusExcite
For x = (WinnerX - RadiusExcite) To (WinnerX + RadiusExcite)
For y = (WinnerY - RadiusExcite) To (WinnerY + RadiusExcite)
If ((x >= 0) And (x < width) And (y >= 0) And (y < height)) Then
d = dist(x, y) / (2 * max)
If (d < 1) Then
Value = randVal(d)
Call adjustWeights(x, y, Value)
If (Not ((x = WinnerX) And (y = WinnerY))) Then
For i = 0 To 9
classificationMulti(x, y, i) = classificationMulti(x, y, i) + ((classificationMulti(WinnerX, WinnerY, i) - classificationMulti(x, y, i)) * (1 - d) * learningRate)
Next
End If
End If
End If
Next
Next
'update the threshold based upon the average similarity
Threshold = (Threshold + (average_similarity * 10)) / 2
For x = 0 To inputs_width - 1
For y = 0 To inputs_height - 1
image(WinnerX, WinnerY, x, y) = inputs(x, y)
Next
Next
End If
learn_exit:
Exit Sub
learn_err:
MsgBox "classTopmap/learn/" & Error$(Err)
Resume learn_exit
End Sub
Public Sub initWeights(Optional minVal As Variant, Optional maxVal As Variant)
'randomly initialises the weights within the given range
On Error GoTo initWeights_err
Dim min As Single
Dim max As Single
Dim x As Integer
Dim y As Integer
Dim xx As Integer
Dim yy As Integer
min = 0
max = 0.01
If (Not IsMissing(minVal)) Then
min = minVal
End If
If (Not IsMissing(maxVal)) Then
max = maxVal
End If
For x = 0 To width - 1
For y = 0 To height - 1
For xx = 0 To inputs_width - 1
For yy = 0 To inputs_height - 1
unit(x, y, xx, yy) = min + (Rnd * (max - min))
Next
Next
Next
Next
initWeights_exit:
Exit Sub
initWeights_err:
MsgBox "classTopmap/initWeights/" & Error$(Err)
Resume initWeights_exit
End Sub
Public Sub Show(canvas As Object)
On Error GoTo show_err
Dim x As Integer
Dim y As Integer
Dim tx As Single
Dim ty As Single
Dim bx As Single
Dim by As Single
Dim Value As Single
Dim c As Long
Dim i As Integer
canvas.FillStyle = 0
For x = 0 To width - 1
For y = 0 To height - 1
Value = outputs(x, y) * 255
tx = (x / width) * canvas.ScaleWidth
ty = (y / height) * canvas.ScaleHeight
bx = ((x + 1) / width) * canvas.ScaleWidth
by = ((y + 1) / height) * canvas.ScaleHeight
i = CInt(Value)
If (Not ((x = WinnerX) And (y = WinnerY))) Then
c = RGB(0, i, 255 - i)
Else
c = RGB(255, 255, 255)
End If
canvas.FillColor = c
canvas.Line (tx, ty)-(bx, by), c, B
Next
Next
show_exit:
Exit Sub
show_err:
MsgBox "classTopmap/show/" & Error$(Err)
Resume show_exit
End Sub
Public Sub showClassifications(canvas As Object)
'shows the distribution of classifications
On Error GoTo show_err
Dim x As Integer
Dim y As Integer
Dim screenX(2) As Single
Dim screenY(2) As Single
Dim c As Long
canvas.FillStyle = 0
For x = 0 To width - 1
For y = 0 To height - 1
screenX(0) = (x / width) * canvas.ScaleWidth
screenY(0) = (y / height) * canvas.ScaleHeight
screenX(1) = ((x + 1) / width) * canvas.ScaleWidth
screenY(1) = ((y + 1) / height) * canvas.ScaleHeight
c = ClassificationColour(getClassification(x, y))
canvas.FillColor = c
canvas.Line (screenX(0), screenY(0))-(screenX(1), screenY(1)), c, B
Next
Next
show_exit:
Exit Sub
show_err:
MsgBox "classTopmap/show/" & Error$(Err)
Resume show_exit
End Sub
Public Sub showClassificationsMulti(canvas As Object)
'shows the distribution of classifications
On Error GoTo show_err
Dim x As Integer
Dim y As Integer
Dim tx As Single
Dim ty As Single
Dim bx As Single
Dim by As Single
Dim Value As Integer
Dim c(3) As Long
Dim i As Integer
Dim col As Long
Dim c1 As Integer
Dim c2 As Integer
Dim c3 As Integer
canvas.FillStyle = 0
For x = 0 To width - 1
For y = 0 To height - 1
tx = (x / width) * canvas.ScaleWidth
ty = (y / height) * canvas.ScaleHeight
bx = ((x + 1) / width) * canvas.ScaleWidth
by = ((y + 1) / height) * canvas.ScaleHeight
For i = 0 To 2
Value = getClassificationMulti(x, y, i)
c(i) = Value + 150
If (c(i) > 255) Then c(i) = 255
Next
c1 = c(0)
c2 = c(1)
c3 = c(2)
col = RGB(c1, c2, c1)
canvas.FillColor = col
canvas.Line (tx, ty)-(bx, by), col, B
Next
Next
show_exit:
Exit Sub
show_err:
MsgBox "classTopmap/showClassificationsMulti/" & Error$(Err)
Resume 0
Resume show_exit
End Sub
Public Sub randomInputs()
On Error GoTo randomInputs_err
Dim x As Integer
Dim y As Integer
For x = 0 To inputs_width - 1
For y = 0 To inputs_height - 1
inputs(x, y) = Rnd
Next
Next
randomInputs_exit:
Exit Sub
randomInputs_err:
MsgBox "classTopmap/randomInputs/" & Error$(Err)
Resume randomInputs_exit
End Sub
Public Sub setImage(img As Object)
'loads in image into the inputs array
On Error GoTo setImage_err
Dim x As Integer
Dim y As Integer
Dim i As Integer
i = 0
For x = 0 To img.width - 1
For y = 0 To img.height - 1
inputs(i) = img.getPoint(x, y) / 255
i = i + 1
Next
Next
setImage_exit:
Exit Sub
setImage_err:
MsgBox "classTopmap/setImage/" & Error$(Err)
Resume setImage_exit
End Sub
Public Sub setImageWeights(x As Integer, y As Integer, img As Object)
'loads in image into the inputs array
On Error GoTo setImage_err
Dim xx As Integer
Dim yy As Integer
Dim i As Integer
Dim Value As Integer
For xx = 0 To img.width - 1
For yy = 0 To img.height - 1
Value = unit(x, y, xx, yy)
If (Value < 0) Then Value = 0
If (Value > 255) Then Value = 255
Call img.setPoint(xx, yy, 0, CByte(Value))
Call img.setPoint(xx, yy, 1, CByte(Value))
Call img.setPoint(xx, yy, 2, CByte(Value))
Next
Next
setImage_exit:
Exit Sub
setImage_err:
MsgBox "classTopmap/setImageWeights/" & Error$(Err)
Resume setImage_exit
End Sub
Public Sub setClassification(classificationID As Integer)
'sets the classification value of the winning unit
If (WinnerX > -1) Then
classification(WinnerX, WinnerY) = classificationID
End If
End Sub
Public Sub setClassificationName(classID As Integer, className As String)
'sets the name for the given classification ID
Dim i As Integer
Dim ch As String
Dim length As Integer
className = Left$(className, 19)
length = Len(className)
For i = 1 To 18
If (i <= length) Then
ch = Mid$(className, i, 1)
If (ch <> "") Then
ClassificationName(classID, i) = Asc(ch)
Else
ClassificationName(classID, i) = 13
End If
Else
ClassificationName(classID, i) = Asc(" ")
End If
Next
End Sub
Public Function getClassificationName(classID As Integer) As String
'gets the name for the given classification ID
Dim i As Integer
Dim className As String
className = ""
For i = 1 To 18
className = className & Chr(ClassificationName(classID, i))
Next
getClassificationName = Trim(className)
End Function
Public Sub setClassificationMulti(classificationIndex As Integer, Value As Integer)
'sets the multi-dimensional classification value of the winning unit
If (WinnerX > -1) Then
classificationMulti(WinnerX, WinnerY, classificationIndex) = Value
End If
End Sub
Public Function getClassification(x As Integer, y As Integer)
'returns the classification of the given unit
getClassification = classification(x, y)
End Function
Public Function getNearestClassification(x As Integer, y As Integer)
'returns the nearest classification of the given unit
Dim xx As Integer
Dim yy As Integer
Dim classID As Integer
Dim dx As Integer
Dim dy As Integer
Dim dist As Single
Dim minDist As Single
classID = classification(x, y)
'if this unit is unclassified then return the nearest classification on the map
If (classID = 0) Then
minDist = 9999
For xx = 0 To width - 1
For yy = 0 To height - 1
If (classification(xx, yy) > 0) Then
dx = xx - x
dy = yy - y
dist = Sqr((dx * dx) + (dy * dy))
If (dist < minDist) Then
minDist = dist
classID = classification(xx, yy)
End If
End If
Next
Next
End If
getNearestClassification = classID
End Function
Public Function getClassificationMulti(x As Integer, y As Integer, classificationIndex As Integer) As Integer
'returns the classification of the given unit
getClassificationMulti = classificationMulti(x, y, classificationIndex)
End Function
Public Sub classifyImage(img As Object, classificationID As Integer)
Call setImage(img)
Call Update
Call setClassification(classificationID)
Call learn
End Sub
Public Sub Save(filename As String)
On Error GoTo Save_err
Dim x As Integer
Dim y As Integer
Dim xx As Integer
Dim yy As Integer
Dim i As Integer
Dim j As Integer
Open filename For Output As #1
Print #1, width
Print #1, height
Print #1, inputs_width
Print #1, inputs_height
For x = 0 To width - 1
For y = 0 To height - 1
For xx = 0 To inputs_width - 1
For yy = 0 To inputs_height - 1
Print #1, unit(x, y, xx, yy)
Print #1, image(x, y, xx, yy)
Next
Next
Print #1, hits(x, y)
Print #1, classification(x, y)
For i = 0 To 9
Print #1, classificationMulti(x, y, i)
Next
Next
Next
For i = 0 To 19
For j = 0 To 19
Print #1, ClassificationName(i, j)
Next
Next
For i = 0 To 19
For j = 0 To 149
Print #1, Portrait(i, j)
Next
Next
Close #1
Save_exit:
Exit Sub
Save_err:
MsgBox "classTopMap/Save/" & Err & "/" & Error$(Err)
Resume Save_exit
End Sub
Public Sub Load(filename As String)
On Error GoTo Save_err
Dim x As Integer
Dim y As Integer
Dim xx As Integer
Dim yy As Integer
Dim i As Integer
Dim j As Integer
Dim w As Single
Dim c As Long
Dim ch As Byte
Open filename For Input As #1
Input #1, width
Input #1, height
Input #1, inputs_width
Input #1, inputs_height
max_hits = 0
For x = 0 To width - 1
For y = 0 To height - 1
For xx = 0 To inputs_width - 1
For yy = 0 To inputs_height - 1
Input #1, w
unit(x, y, xx, yy) = w
Input #1, i
image(x, y, xx, yy) = i
Next
Next
Input #1, c
hits(x, y) = c
If (c > max_hits) Then max_hits = c
Input #1, c
classification(x, y) = c
For i = 0 To 9
Input #1, c
classificationMulti(x, y, i) = c
Next
Next
Next
For i = 0 To 19
For j = 0 To 19
Input #1, ch
ClassificationName(i, j) = ch
Next
Next
For i = 0 To 19
For j = 0 To 149
Input #1, ch
Portrait(i, j) = ch
Next
Next
Close #1
Save_exit:
Exit Sub
Save_err:
If (Err = 62) Then 'input past the end of file
Close #1
Resume Save_exit
End If
MsgBox "classTopMap/Load/" & Err & "/" & Error$(Err)
Resume Save_exit
End Sub
Private Sub rescaleHits()
're-scale the hit scores if they get too big
Dim x As Integer
Dim y As Integer
Dim h As Long
For x = 0 To width - 1
For y = 0 To height - 1
h = hits(x, y)
h = (h * 1000) / 32000
hits(x, y) = h
Next
Next
End Sub