class for image manipulation (OOP)

Share your advanced PureBasic knowledge/code with the community.
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

class for image manipulation (OOP)

Post by pcfreak »

Here is some 2 years old code of me for someone who may has better use of :?
And because of the error I got at the first try posting it here (Your message contains 82945 characters. The maximum number of allowed characters is 60000.) it is split in 2 parts.
Part 1/2:

Code: Select all

Interface IImageFilter ;generates a new image id
;- public
 ;getter
  getImage()
  getWidth()
  getHeight()
  getPixelCount()
  getImageMem()
 ;image information
  getAverage.f(channel.i = -1)
  getStandardDeviation.f(channel.i = -1)
  getCenterOfMassX.f(channel.i = -1)
  getCenterOfMassY.f(channel.i = -1)
  getSemimajorAxisAngle.f(channel.i = -1)
  getExcentricity.f(channel.i = -1)
 ;color
  grayscale()
  invert()
  brightness(delta.i)
  contrast(factor.f)
  colorScale(factor.f = 1, delta.i = 0)
  gamma(g.f)
  normalize()
 ;transform
  mirrorVertical()
  mirrorHorizontal()
  rotate(angle.f, nonBilinear.i = #False, resize.i = #False)
  resize(newWidth.i, newHeight.i, mode.i)
 ;overlay
  add_(image.i, factor.f = 1, delta.i = 0)
  sub_(image.i, factor.f = 1, delta.i = 0)
  mul_(image.i, factor.f = 1, delta.i = 0)
  div_(image.i, factor.f = 1, delta.i = 0)
  xor_(image.i)
  and_(image.i)
  or_(image.i)
  weight(image.i, factor.f = 1, delta.i = 0)
  weightMask(image.i, mask.i, factor.f = 1, delta.i = 0)
  difference(image.i, factor.f = 1, delta.i = 0)
  euclidianNorm(image.i, offset.i)
  manhattenNorm(image.i, offset.i)
  addColorOverlay(color.i, opacity.f)
  removeColorOverlay(color.i, opacity.f)
 ;denoise
  median(size.i)
  nearMedian(normalSize.i, nearSize.i)
  binomial(size.i)
 ;edge detection
  minMax(size.i)
  DoG(q.i, p.i)
  houghTransformation(threshold.i)
 ;segmenting
  threshold(value.i, keepColor.i = #False) ;grayscale
  regionGrowing(x.i, y.i, maxDelta.i) ;H3, grayscale
 ;morphology
  dilate(label.i, mask$, times.i) ;segmented
  erode(label.i, mask$, times.i) ;segmented
  closing(label.i, mask$, times.i) ;segmented
  opening(label.i, mask$, times.i) ;segmented
  thin(label.i, times.i) ;segmented
  skeletonization(label.i) ;segmented
 ;others
  generic(filter$)
  bswap()
 ;call after filtering to update the source image
  output()
 ;free object
  delete()
;- private
  getColorArray()
  setColorArray(*mem)
  memBinomial(*mem, size.i)
  memGeneric(*mem, filter$)
EndInterface

;mask$:
; |   separates rows
; ,   separates columns
; first columns, then rows
; example: 0,1,0|1,1,1|0,1,0

;filter$
; |   separates rows
; ,   separates columns
; ;   separates parameters
; first columns, then rows
; first filter matrix, then divisor, then offset
; example: 1,2,1|2,4,2|1,2,1;16;0

Structure OImageFilter
 ;Address to the methods array
 methodAddress.i
 ;Class Attributes
  image.i
  width.i
  height.i
  pixels.i
  srcMem.i
EndStructure

Structure ImageFilter_RGBA
 StructureUnion
  rgba.l
  channel.b[4]
 EndStructureUnion
EndStructure

Structure ImageFilter_GrayPosition
 gray.i
 x.i
 y.i
EndStructure


#IF_UsedChannels = 4

CompilerIf #IF_UsedChannels = 4
 #IF_ImageDepth = 32
CompilerElse
 #IF_ImageDepth = 24
CompilerEndIf

Enumeration ;resize modes
 #IF_RM_NearestNeighbor
 #IF_RM_Bilinear ;not implemented yet
 #IF_RM_Bicubic ;not implemented yet
 #IF_RM_Spline ;not implemented yet
 #IF_RM_Lanczos ;not implemented yet
 #IF_RM_FFT ;not implemented yet
EndEnumeration


Macro getColorFromArray(addr, x, y, width)
 PeekL((addr) + (((y) * (width)) + (x)) * SizeOf(ImageFilter_RGBA))
EndMacro

Macro setColorFromArray(addr, x, y, width, color)
 PokeL((addr) + (((y) * (width)) + (x)) * SizeOf(ImageFilter_RGBA), (color))
EndMacro

Macro limit(var, l, u)
 If (var) < (l) : var = l : EndIf
 If (var) > (u) : var = u : EndIf
EndMacro

Macro Square(number)
 ((number) * (number))
EndMacro

Macro Gray(rgb)
 Round((Red(rgb) * 0.299) + (Green(rgb) * 0.587) + (Blue(rgb) * 0.114), #PB_Round_Nearest)
EndMacro

Macro MeanGray(rgb)
 Round((Red(rgb) + Green(rgb) + Blue(rgb)) / 3, #PB_Round_Nearest)
EndMacro

Macro Sgd(x)
 (1 / (1 + Pow(2.718281828459045, -(x))))
EndMacro


;public
Declare.i newImageFilter(Image.i)
Declare.i ImageFilter_getImage(*this.IImageFilter)
Declare.i ImageFilter_getWidth(*this.IImageFilter)
Declare.i ImageFilter_getHeight(*this.IImageFilter)
Declare.i ImageFilter_getPixelCount(*this.IImageFilter)
Declare.i ImageFilter_getImageMem(*this.IImageFilter)
Declare.f ImageFilter_getAverage(*this.IImageFilter, channel.i = -1)
Declare.f ImageFilter_getStandardDeviation(*this.IImageFilter, channel.i = -1)
Declare.f ImageFilter_getCenterOfMassX(*this.IImageFilter, channel.i = -1)
Declare.f ImageFilter_getCenterOfMassY(*this.IImageFilter, channel.i = -1)
Declare.f ImageFilter_getSemimajorAxisAngle(*this.IImageFilter, channel.i = -1)
Declare.f ImageFilter_getExcentricity(*this.IImageFilter, channel.i = -1)
Declare.i ImageFilter_grayscale(*this.IImageFilter)
Declare.i ImageFilter_invert(*this.IImageFilter)
Declare.i ImageFilter_brightness(*this.IImageFilter, delta.i)
Declare.i ImageFilter_contrast(*this.IImageFilter, factor.f)
Declare.i ImageFilter_colorScale(*this.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_gamma(*this.IImageFilter, g.f)
Declare.i ImageFilter_normalize(*this.IImageFilter)
Declare.i ImageFilter_mirrorVertical(*this.IImageFilter)
Declare.i ImageFilter_mirrorHorizontal(*this.IImageFilter)
Declare.i ImageFilter_rotate(*this.IImageFilter, angle.f, nonBilinear.i = #False, resize.i = #False)
Declare.i ImageFilter_resize(*this.IImageFilter, newWidth.i, newHeight.i, mode.i)
Declare.i ImageFilter_add(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_sub(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_mul(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_div(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_xor(*this.IImageFilter, *image.IImageFilter)
Declare.i ImageFilter_and(*this.IImageFilter, *image.IImageFilter)
Declare.i ImageFilter_or(*this.IImageFilter, *image.IImageFilter)
Declare.i ImageFilter_weight(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_weightMask(*this.IImageFilter, *image.IImageFilter, *mask.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_difference(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
Declare.i ImageFilter_euclidianNorm(*this.IImageFilter, *image.IImageFilter, offset.i)
Declare.i ImageFilter_manhattenNorm(*this.IImageFilter, *image.IImageFilter, offset.i)
Declare.i ImageFilter_addColorOverlay(*this.IImageFilter, color.i, opacity.f)
Declare.i ImageFilter_removeColorOverlay(*this.IImageFilter, color.i, opacity.f)
Declare.i ImageFilter_median(*this.IImageFilter, size.i)
Declare.i ImageFilter_nearMedian(*this.IImageFilter, normalSize.i, nearSize.i)
Declare.i ImageFilter_binomial(*this.IImageFilter, size.i)
Declare.i ImageFilter_minMax(*this.IImageFilter, size.i)
Declare.i ImageFilter_DoG(*this.IImageFilter, q.i, p.i)
Declare.i ImageFilter_houghTransformation(*this.IImageFilter, threshold.i)
Declare.i ImageFilter_threshold(*this.IImageFilter, value.i, keepColor.i = #False)
Declare.i ImageFilter_regionGrowing(*this.IImageFilter, x.i, y.i, maxDelta.i)
Declare.i ImageFilter_dilate(*this.IImageFilter, label.i, mask$, times.i)
Declare.i ImageFilter_erode(*this.IImageFilter, label.i, mask$, times.i)
Declare.i ImageFilter_closing(*this.IImageFilter, label.i, mask$, times.i)
Declare.i ImageFilter_opening(*this.IImageFilter, label.i, mask$, times.i)
Declare.i ImageFilter_thin(*this.IImageFilter, label.i, times.i)
Declare.i ImageFilter_skeletonization(*this.IImageFilter, label.i)
Declare.i ImageFilter_generic(*this.IImageFilter, filter$)
Declare.i ImageFilter_bswap(*this.IImageFilter)
Declare.i ImageFilter_output(*this.IImageFilter)
Declare   ImageFilter_delete(*this.IImageFilter)
;private
Declare.i ImageFilter_getColorArray(*this.IImageFilter)
Declare.i ImageFilter_setColorArray(*this.IImageFilter, *mem.ImageFilter_RGBA)
Declare.i ImageFilter_memBinomial(*this.IImageFilter, *mem.ImageFilter_RGBA, size.i)
Declare.i ImageFilter_memGeneric(*this.IImageFilter, *mem.ImageFilter_RGBA, filter$)


DataSection
 OImageFilter_methods:
  Data.i @ImageFilter_getImage()
  Data.i @ImageFilter_getWidth()
  Data.i @ImageFilter_getHeight()
  Data.i @ImageFilter_getPixelCount()
  Data.i @ImageFilter_getImageMem()
  Data.i @ImageFilter_getAverage()
  Data.i @ImageFilter_getStandardDeviation()
  Data.i @ImageFilter_getCenterOfMassX()
  Data.i @ImageFilter_getCenterOfMassY()
  Data.i @ImageFilter_getSemimajorAxisAngle()
  Data.i @ImageFilter_getExcentricity()
  Data.i @ImageFilter_grayscale()
  Data.i @ImageFilter_invert()
  Data.i @ImageFilter_brightness()
  Data.i @ImageFilter_contrast()
  Data.i @ImageFilter_colorScale()
  Data.i @ImageFilter_gamma()
  Data.i @ImageFilter_normalize()
  Data.i @ImageFilter_mirrorVertical()
  Data.i @ImageFilter_mirrorHorizontal()
  Data.i @ImageFilter_rotate()
  Data.i @ImageFilter_resize()
  Data.i @ImageFilter_add()
  Data.i @ImageFilter_sub()
  Data.i @ImageFilter_mul()
  Data.i @ImageFilter_div()
  Data.i @ImageFilter_xor()
  Data.i @ImageFilter_and()
  Data.i @ImageFilter_or()
  Data.i @ImageFilter_weight()
  Data.i @ImageFilter_weightMask()
  Data.i @ImageFilter_difference()
  Data.i @ImageFilter_euclidianNorm()
  Data.i @ImageFilter_manhattenNorm()
  Data.i @ImageFilter_addColorOverlay()
  Data.i @ImageFilter_removeColorOverlay()
  Data.i @ImageFilter_median()
  Data.i @ImageFilter_nearMedian()
  Data.i @ImageFilter_binomial()
  Data.i @ImageFilter_minMax()
  Data.i @ImageFilter_DoG()
  Data.i @ImageFilter_houghTransformation()
  Data.i @ImageFilter_threshold()
  Data.i @ImageFilter_regionGrowing()
  Data.i @ImageFilter_dilate()
  Data.i @ImageFilter_erode()
  Data.i @ImageFilter_closing()
  Data.i @ImageFilter_opening()
  Data.i @ImageFilter_thin()
  Data.i @ImageFilter_skeletonization()
  Data.i @ImageFilter_generic()
  Data.i @ImageFilter_bswap()
  Data.i @ImageFilter_output()
  Data.i @ImageFilter_delete()
  Data.i @ImageFilter_getColorArray()
  Data.i @ImageFilter_setColorArray()
  Data.i @ImageFilter_memBinomial()
  Data.i @ImageFilter_memGeneric()
EndDataSection


Procedure.i newImageFilter(Image.i)
 Protected *object.OImageFilter
 If IsImage(Image) = #Null
  ProcedureReturn #Null
 EndIf
 *object = AllocateMemory(SizeOf(OImageFilter))
 If *object = #Null
  ProcedureReturn #Null
 EndIf
 *object\methodAddress = ?OImageFilter_methods
 *object\image = Image
 *object\width = ImageWidth(Image)
 *object\height = ImageHeight(Image)
 *object\pixels = *object\width * *object\height
 *object\srcMem = ImageFilter_getColorArray(*object)
 *object\image = CreateImage(#PB_Any, *object\width, *object\height, #IF_ImageDepth)
 FreeImage(Image)
 If *object\srcMem = #Null
  FreeMemory(*object)
  ProcedureReturn #Null
 EndIf
 ProcedureReturn *object
EndProcedure


Procedure.i ImageFilter_getImage(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object = *this
 ProcedureReturn *object\image
EndProcedure


Procedure.i ImageFilter_getWidth(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object = *this
 ProcedureReturn *object\width
EndProcedure


Procedure.i ImageFilter_getHeight(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object = *this
 ProcedureReturn *object\height
EndProcedure


Procedure.i ImageFilter_getPixelCount(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object = *this
 ProcedureReturn *object\pixels
EndProcedure


Procedure.i ImageFilter_getImageMem(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn #Null
 EndIf
 *object = *this
 ProcedureReturn *object\srcMem
EndProcedure


Procedure.f ImageFilter_getAverage(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i, sum.q
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn -1
 EndIf
 *object = *this
 *src = *object\srcMem
 sum = 0
 If channel = -1
  For i = 0 To *object\pixels - 1
   int = Gray(*src\rgba)
   sum + int
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 Else
  For i = 0 To *object\pixels - 1
   int = *src\channel[channel] & $FF
   sum + int
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 EndIf
 ProcedureReturn sum / *object\pixels
EndProcedure


Procedure.f ImageFilter_getStandardDeviation(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i, sum.q, sqsum.q, m.d
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn -1
 EndIf
 *object = *this
 *src = *object\srcMem
 sum = 0
 sqsum = 0
 If channel = -1
  For i = 0 To *object\pixels - 1
   int = Gray(*src\rgba)
   sum + int
   sqsum + Square(int)
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 Else
  For i = 0 To *object\pixels - 1
   int = *src\channel[channel] & $FF
   sum + int
   sqsum + Square(int)
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 EndIf
 m = sum / *object\pixels
 ProcedureReturn Sqr((sqsum / *object\pixels) - Square(m))
EndProcedure


Procedure.f ImageFilter_getCenterOfMassX(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i, m.q, sum.q
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn -1
 EndIf
 *object = *this
 *src = *object\srcMem
 m = 0
 sum = 0
 If channel = -1
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = Gray(*src\rgba)
    m + (int * x)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 Else
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = *src\channel[channel] & $FF
    m + (int * x)
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 EndIf
 ProcedureReturn m / sum
EndProcedure


Procedure.f ImageFilter_getCenterOfMassY(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i, mx.q, my.q, sum.q
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn -1
 EndIf
 *object = *this
 *src = *object\srcMem
 m = 0
 sum = 0
 If channel = -1
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = Gray(*src\rgba)
    m + (int * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 Else
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = *src\channel[channel] & $FF
    m + (int * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 EndIf
 ProcedureReturn m / sum
EndProcedure


Procedure.f ImageFilter_getSemimajorAxisAngle(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i
 Protected mx.q, my.q, mxx.q, mxy.q, myy.q, sum.q
 Protected _mx.d, _my.d, _mxx.d, _mxy.d, _myy.d
 Protected phi.d
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn 0
 EndIf
 *object = *this
 *src = *object\srcMem
 mx = 0
 my = 0
 mxx = 0
 mxy = 0
 myy = 0
 sum = 0
 If channel = -1
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = Gray(*src\rgba)
    mx + (int * x)
    my + (int * y)
    mxx + (int * x * x)
    mxy + (int * x * y)
    myy + (int * y * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 Else
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = *src\channel[channel] & $FF
    mx + (int * x)
    my + (int * y)
    mxx + (int * x * x)
    mxy + (int * x * y)
    myy + (int * y * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 EndIf
 _mx = mx / sum
 _my = my / sum
 _mxx = (mxx / sum) - (_mx * _mx)
 _mxy = (mxy / sum) - (_mx * _my)
 _myy = (myy / sum) - (_my * _my)
 If _mxx = 0 And _myy = 0
  ProcedureReturn 0
 EndIf
 If _mxy = 0
  If _mxx > _myy
   phi = 0
  Else
   phi = #PI / 2
  EndIf
 Else
  phi = -ATan((2 * _mxy) / ((_mxx - _myy) + Sqr(Square(_mxx - _myy) + (4 * _mxy * _mxy))))
 EndIf
 phi = (phi * 180) / #PI
 ProcedureReturn phi
EndProcedure


Procedure.f ImageFilter_getExcentricity(*this.IImageFilter, channel.i = -1)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i
 Protected mx.q, my.q, mxx.q, mxy.q, myy.q, sum.q
 Protected _mx.d, _my.d, _mxx.d, _mxy.d, _myy.d
 If *this = #Null Or channel >= #IF_UsedChannels
  ProcedureReturn 0
 EndIf
 *object = *this
 *src = *object\srcMem
 mx = 0
 my = 0
 mxx = 0
 mxy = 0
 myy = 0
 sum = 0
 If channel = -1
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = Gray(*src\rgba)
    mx + (int * x)
    my + (int * y)
    mxx + (int * x * x)
    mxy + (int * x * y)
    myy + (int * y * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 Else
  For y = *object\height - 1 To 0 Step -1
   For x = 0 To *object\width - 1
    int = *src\channel[channel] & $FF
    mx + (int * x)
    my + (int * y)
    mxx + (int * x * x)
    mxy + (int * x * y)
    myy + (int * y * y)
    sum + int
    *src + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 EndIf
 _mx = mx / sum
 _my = my / sum
 _mxx = (mxx / sum) - (_mx * _mx)
 _mxy = (mxy / sum) - (_mx * _my)
 _myy = (myy / sum) - (_my * _my)
 If _mxx = 0 And _myy = 0
  ProcedureReturn 0
 EndIf
 ProcedureReturn (Square(_mxx - _myy) + (4 * _mxy * _mxy)) / Square(_mxx + _myy)
EndProcedure


Procedure.i ImageFilter_grayscale(*this.IImageFilter)
 Protected *object.OImageFilter, gray.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  gray = Gray(*src\rgba)
  *src\channel[0] = gray
  *src\channel[1] = gray
  *src\channel[2] = gray
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_invert(*this.IImageFilter)
 Protected *object.OImageFilter, gray.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  *src\rgba ! $FFFFFF
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_brightness(*this.IImageFilter, delta.i)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn #False
 EndIf
 ProcedureReturn *this\colorScale(1, delta)
EndProcedure


Procedure.i ImageFilter_contrast(*this.IImageFilter, factor.f)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn #False
 EndIf
 ProcedureReturn *this\colorScale(factor, 0)
EndProcedure


Procedure.i ImageFilter_colorScale(*this.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter, int.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int = *src\channel[channel] & $FF
   int = Int(factor * (int + delta))
   limit(int, 0, $FF)
   *src\channel[channel] = int
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_gamma(*this.IImageFilter, g.f)
 Protected *object.OImageFilter, int.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 If g = 1
  ProcedureReturn #True
 EndIf
 *object = *this
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int = *src\channel[channel] & $FF
   int = Pow(int, g)
   limit(int, 0, $FF)
   *src\channel[channel] = int
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_normalize(*this.IImageFilter)
 Protected *object.OImageFilter, int.i, *src.ImageFilter_RGBA
 Protected Dim g.i(#IF_UsedChannels - 1,1), Dim c.f(#IF_UsedChannels - 1,1)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 For channel = 0 To #IF_UsedChannels - 1
  g(channel, 0) = $FF
  g(channel, 1) = 0
 Next channel
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int = *src\channel[channel] & $FF
   If g(channel, 0) > int : g(channel, 0) = int : EndIf
   If g(channel, 1) < int : g(channel, 1) = int : EndIf
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 For channel = 0 To #IF_UsedChannels - 1
  c(channel, 0) = -g(channel, 0)
  c(channel, 1) = $FF / (g(channel, 1) - g(channel, 0))
 Next channel
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int = *src\channel[channel] & $FF
   int = Int(c(channel, 1) * (c(channel, 0) + int))
   limit(int, 0, $FF)
   *src\channel[channel] = int
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_mirrorVertical(*this.IImageFilter)
 Protected *object.OImageFilter, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   *dest\rgba = getColorFromArray(*object\srcMem, x, *object\height - 1 - y, *object\width)
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_mirrorHorizontal(*this.IImageFilter)
 Protected *object.OImageFilter, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   *dest\rgba = getColorFromArray(*object\srcMem, *object\width - 1 - x, y, *object\width)
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_rotate(*this.IImageFilter, angle.f, nonBilinear.i = #False, resize.i = #False)
 Protected *object.OImageFilter, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected halfWidth.f, halfHeight.f, cosAngle.f, sinAngle.f, oX.f, oY.f, oXr.i, oYr.i, difX.f, difY.f
 Protected s00.ImageFilter_RGBA, s01.ImageFilter_RGBA, s10.ImageFilter_RGBA, s11.ImageFilter_RGBA
 Protected int00.i, int01.i, int10.i, int11.i, int.i
 Protected newImage.i, newWidth.i, newHeight.i, newPixels.i
 Protected newHalfWidth.f, newHalfHeight.f
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 cosAngle = Cos(((-angle) / 180) * #PI)
 sinAngle = Sin(((-angle) / 180) * #PI)
 halfWidth = *object\width / 2
 halfHeight = *object\height / 2
 If resize
  Protected x1.f, x2.f, x3.f, x4.f, minX.f, maxX.f
  Protected y1.f, y2.f, y3.f, y4.f, minY.f, maxY.f
  x1 = ((-sinAngle) * (0 - halfHeight)) + (cosAngle * (0 - halfWidth)) + halfWidth
  y1 = (cosAngle * (0 - halfHeight)) + (sinAngle * (0 - halfWidth)) + halfHeight
  x2 = ((-sinAngle) * (0 - halfHeight)) + (cosAngle * (*object\width - 1 - halfWidth)) + halfWidth
  y2 = (cosAngle * (0 - halfHeight)) + (sinAngle * (*object\width - 1 - halfWidth)) + halfHeight
  x3 = ((-sinAngle) * (*object\height - 1 - halfHeight)) + (cosAngle * (0 - halfWidth)) + halfWidth
  y3 = (cosAngle * (*object\height - 1 - halfHeight)) + (sinAngle * (0 - halfWidth)) + halfHeight
  x4 = ((-sinAngle) * (*object\height - 1 - halfHeight)) + (cosAngle * (*object\width - 1 - halfWidth)) + halfWidth
  y4 = (cosAngle * (*object\height - 1 - halfHeight)) + (sinAngle * (*object\width - 1 - halfWidth)) + halfHeight
  minX = x1
  minY = y1
  If minX > x2 : minX = x2 : EndIf
  If minY > y2 : minY = y2 : EndIf
  If minX > x3 : minX = x3 : EndIf
  If minY > y3 : minY = y3 : EndIf
  If minX > x4 : minX = x4 : EndIf
  If minY > y4 : minY = y4 : EndIf
  maxX = x1
  maxY = y1
  If maxX < x2 : maxX = x2 : EndIf
  If maxY < y2 : maxY = y2 : EndIf
  If maxX < x3 : maxX = x3 : EndIf
  If maxY < y3 : maxY = y3 : EndIf
  If maxX < x4 : maxX = x4 : EndIf
  If maxY < y4 : maxY = y4 : EndIf
  newWidth = maxX - minX + 1
  newHeight = maxY - minY + 1
  newPixels = newWidth * newHeight
  newHalfWidth = (maxX - minX + 1) / 2
  newHalfHeight = (maxY - minY + 1) / 2
  newImage = CreateImage(#PB_Any, newWidth, newHeight, #IF_ImageDepth)
  If newImage = #Null
   ProcedureReturn #False
  EndIf
 Else
  newWidth = *object\width
  newHeight = *object\height
  newPixels = *object\pixels
  newHalfWidth = halfWidth
  newHalfHeight = halfHeight
 EndIf
 *destMem = AllocateMemory(newPixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  If IsImage(newImage)
   FreeImage(newImage)
  EndIf
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 If nonBilinear
  For y = 0 To newHeight - 1
   For x = 0 To newWidth - 1
    oXr = Round(((-sinAngle) * (y - newHalfHeight)) + (cosAngle * (x - newHalfWidth)) + halfWidth, #PB_Round_Nearest)
    oYr = Round((cosAngle * (y - newHalfHeight)) + (sinAngle * (x - newHalfWidth)) + halfHeight, #PB_Round_Nearest)
    If 0 <= oYr And oYr < *object\height And 0 <= oXr And oXr < *object\width
     s00\rgba = getColorFromArray(*object\srcMem, oXr, oYr, *object\width)
    Else : s00\rgba = 0 : EndIf
    For channel = 0 To #IF_UsedChannels - 1
     int = s00\channel[channel] & $FF
     limit(int, 0, $FF)
     *dest\channel[channel] = int
    Next channel
    *dest + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 Else
  For y = 0 To newHeight - 1
   For x = 0 To newWidth - 1
    oX = ((-sinAngle) * (y - newHalfHeight)) + (cosAngle * (x - newHalfWidth)) + halfWidth
    oY = (cosAngle * (y - newHalfHeight)) + (sinAngle * (x - newHalfWidth)) + halfHeight
    oXr = Round(oX, #PB_Round_Down)
    oYr = Round(oY, #PB_Round_Down)
    If 0 <= oYr And oYr < *object\height And 0 <= oXr And oXr < *object\width
     s00\rgba = getColorFromArray(*object\srcMem, oXr, oYr, *object\width)
    Else : s00\rgba = 0 : EndIf
    If 0 <= oYr And oYr < *object\height And 0 <= oXr + 1 And oXr + 1 < *object\width
     s01\rgba = getColorFromArray(*object\srcMem, oXr + 1, oYr, *object\width)
    Else : s01\rgba = 0 : EndIf
    If 0 <= oYr + 1 And oYr + 1 < *object\height And 0 <= oXr And oXr < *object\width
     s10\rgba = getColorFromArray(*object\srcMem, oXr, oYr + 1, *object\width)
    Else : s10\rgba = 0 : EndIf
    If 0 <= oYr + 1 And oYr + 1 < *object\height And 0 <= oXr + 1 And oXr + 1 < *object\width
     s11\rgba = getColorFromArray(*object\srcMem, oXr + 1, oYr + 1, *object\width)
    Else : s11\rgba = 0 : EndIf
    difX = oX - oXr
    difY = oY - oYr
    For channel = 0 To #IF_UsedChannels - 1
     int00 = s00\channel[channel] & $FF
     int01 = s01\channel[channel] & $FF
     int10 = s10\channel[channel] & $FF
     int11 = s11\channel[channel] & $FF
     int = Int(((1 - difY) * ((int00 * (1 - difX)) + (int01 * difX))) + (difY * ((int10 * (1 - difX)) + (int11 * difX))))
     limit(int, 0, $FF)
     *dest\channel[channel] = int
    Next channel
    *dest + SizeOf(ImageFilter_RGBA)
   Next x
  Next y
 EndIf
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 If resize
  If IsImage(*object\image)
   FreeImage(*object\image)
  EndIf
  *object\image = newImage
  *object\width = newWidth
  *object\height = newHeight
  *object\pixels = newPixels
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_resize(*this.IImageFilter, newWidth.i, newHeight.i, mode.i)
 Protected *object.OImageFilter, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected color.ImageFilter_RGBA
 Protected newImage.i, newPixels.i
 Protected scaleX.f, scaleY.f, wX.f, wY.f
 Protected sX.i, eX.i, sY.i, eY.i, refPixels.i
 Protected Dim newColor.i(#IF_UsedChannels - 1), int.i
 If *this = #Null Or newWidth < 1 Or newHeight < 1
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width = newWidth And *object\height = newHeight
  ProcedureReturn #True
 EndIf
 scaleX = *object\width / newWidth
 scaleY = *object\height / newHeight
 wX = scaleX / 2
 wY = scaleY / 2
 newPixels = newWidth * newHeight
 newImage = CreateImage(#PB_Any, newWidth, newHeight, #IF_ImageDepth)
 If newImage = #Null
  ProcedureReturn #False
 EndIf
 *destMem = AllocateMemory(newPixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  If IsImage(newImage)
   FreeImage(newImage)
  EndIf
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 Select mode
  Case #IF_RM_NearestNeighbor
   For y = 0 To newHeight - 1
    For x = 0 To newWidth - 1
     For channel = 0 To #IF_UsedChannels - 1
      newColor(channel) = 0
     Next channel
     refPixels = 0
     sX = Round((x * scaleX) - wX, #PB_Round_Nearest)
     eX = Round((x * scaleX) + wX, #PB_Round_Nearest)
     limit(sX, 0, *object\width - 1)
     limit(eX, 0, *object\width - 1)
     sY = Round((y * scaleY) - wY, #PB_Round_Nearest)
     eY = Round((y * scaleY) + wY, #PB_Round_Nearest)
     limit(sY, 0, *object\height - 1)
     limit(eY, 0, *object\height - 1)
     For yn = sY To eY
      For xn = sX To eX
       color\rgba = getColorFromArray(*object\srcMem, xn, yn, *object\width)
       For channel = 0 To #IF_UsedChannels - 1
        int = color\channel[channel] & $FF
        newColor(channel) + int
       Next channel
       refPixels + 1
      Next xn
     Next yn
     For channel = 0 To #IF_UsedChannels - 1
      int = Round(newColor(channel) / refPixels, #PB_Round_Nearest)
      limit(int, 0, $FF)
      *dest\channel[channel] = int
     Next channel
     *dest + SizeOf(ImageFilter_RGBA)
    Next x
   Next y
  Default
   If IsImage(newImage)
    FreeImage(newImage)
   EndIf
   If *destMem
    FreeMemory(*destMem)
   EndIf
   ProcedureReturn #False
 EndSelect
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 If IsImage(*object\image)
  FreeImage(*object\image)
 EndIf
 *object\image = newImage
 *object\width = newWidth
 *object\height = newHeight
 *object\pixels = newPixels
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_add(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int(((d + s) * factor) + delta)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_sub(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int(((d - s) * factor) + delta)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_mul(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int((d * s * factor) + delta)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_div(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   If s > 0
    int = Int((d * factor / s) + delta)
   Else
    int = $FF
   EndIf
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_xor(*this.IImageFilter, *image.IImageFilter)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  *dest\rgba ! *src\rgba
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_and(*this.IImageFilter, *image.IImageFilter)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  *dest\rgba & *src\rgba
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_or(*this.IImageFilter, *image.IImageFilter)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  *dest\rgba | *src\rgba
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

Re: class for image manipulation (OOP)

Post by pcfreak »

Part 2/2

Code: Select all


Procedure.i ImageFilter_weight(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   If s > 0
    int = Int((factor * d * 255 / s) + delta)
   Else
    int = 0
   EndIf
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_weightMask(*this.IImageFilter, *image.IImageFilter, *mask.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *msk.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, m.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null Or *mask = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight() Or *object\width <> *mask\getWidth() Or *object\height <> *mask\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *msk = *mask\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   m = (*msk\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int((((d * ($FF - m)) + (s * m)) * factor / $FF) + delta)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *msk + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_difference(*this.IImageFilter, *image.IImageFilter, factor.f = 1, delta.i = 0)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int((factor * Abs(d - s)) + delta)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_euclidianNorm(*this.IImageFilter, *image.IImageFilter, offset.i)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int(Sqr(Square(d - offset) + Square(s - offset)) + offset)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_manhattenNorm(*this.IImageFilter, *image.IImageFilter, offset.i)
 Protected *object.OImageFilter
 Protected *src.ImageFilter_RGBA, *dest.ImageFilter_RGBA
 Protected s.i, d.i
 Protected int.i
 If *this = #Null Or *image = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If *object\width <> *image\getWidth() Or *object\height <> *image\getHeight()
  ProcedureReturn #False
 EndIf
 *src = *image\getImageMem()
 *dest = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   s = (*src\channel[channel] & $FF)
   d = (*dest\channel[channel] & $FF)
   int = Int(Abs(d - offset) + Abs(s - offset) + offset)
   limit(int, 0, $FF)
   *dest\channel[channel] = int
  Next
  *src + SizeOf(ImageFilter_RGBA)
  *dest + SizeOf(ImageFilter_RGBA)
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_addColorOverlay(*this.IImageFilter, color.i, opacity.f)
 Protected *object.OImageFilter, dest.ImageFilter_RGBA
 Protected *src.ImageFilter_RGBA
 Protected int1.i, int2.i
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If opacity < 0 Or opacity > 1
  ProcedureReturn #False
 EndIf
 dest\rgba = color
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int1 = *src\channel[channel] & $FF
   int2 = dest\channel[channel] & $FF
   int1 = Int((int1 * (1 - opacity)) + (int2 * opacity))
   limit(int1, 0, $FF)
   *src\channel[channel] = int1
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_removeColorOverlay(*this.IImageFilter, color.i, opacity.f)
 Protected *object.OImageFilter, dest.ImageFilter_RGBA
 Protected *src.ImageFilter_RGBA
 Protected int1.i, int2.i
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If opacity <= 0 Or opacity >= 1
  ProcedureReturn #False
 EndIf
 dest\rgba = color
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  For channel = 0 To #IF_UsedChannels - 1
   int1 = *src\channel[channel] & $FF
   int2 = dest\channel[channel] & $FF
   int1 = Int(((int2 * opacity) - int1) / (opacity - 1))
   limit(int1, 0, $FF)
   *src\channel[channel] = int1
  Next channel
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_median(*this.IImageFilter, size.i)
 Protected *object.OImageFilter, src.ImageFilter_RGBA, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected Dim radix.i(255), half.i, median.i, index.i
 If *this = #Null Or size < 1
  ProcedureReturn #False
 EndIf
 *object = *this
 half = ((size * 2 + 1) * (size * 2 + 1)) >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   For channel = 0 To #IF_UsedChannels - 1
    For yi = y - size To y + size
     For xi = x - size To x + size
      If xi > 0 And yi > 0 And xi < *object\width And yi < *object\height
       src\rgba = getColorFromArray(*object\srcMem, xi, yi, *object\width)
       radix(src\channel[channel] & $FF) + 1
      EndIf
     Next xi
    Next yi
    median = 0
    index = 255
    For i = 0 To 255
     median + radix(i)
     radix(i) = 0
     If median >= half
      index = i
      For j = i + 1 To 255
       radix(j) = 0
      Next j
      Break 1
     EndIf
    Next i
    *dest\channel[channel] = index
   Next channel
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_nearMedian(*this.IImageFilter, normalSize.i, nearSize.i)
 Protected *object.OImageFilter, src.ImageFilter_RGBA, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected Dim radix.i(255), half.i, median.i, index.i
 Protected dif.i, minDif.i, minDifColor.ImageFilter_RGBA, int1.i, int2.i
 If *this = #Null Or normalSize < 1 Or nearSize < 1
  ProcedureReturn #False
 EndIf
 *object = *this
 half = ((normalSize * 2 + 1) * (normalSize * 2 + 1)) >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   For channel = 0 To #IF_UsedChannels - 1
    For yi = y - normalSize To y + normalSize
     For xi = x - normalSize To x + normalSize
      If xi > 0 And yi > 0 And xi < *object\width And yi < *object\height
       src\rgba = getColorFromArray(*object\srcMem, xi, yi, *object\width)
       radix(src\channel[channel] & $FF) + 1
      EndIf
     Next xi
    Next yi
    median = 0
    index = 255
    For i = 0 To 255
     median + radix(i)
     radix(i) = 0
     If median >= half
      index = i
      For j = i + 1 To 255
       radix(j) = 0
      Next j
      Break 1
     EndIf
    Next i
    *dest\channel[channel] = index
   Next channel
   minDif = $300
   minDifColor\rgba = *dest\rgba
   For yi = y - nearSize To y + nearSize
    For xi = x - nearSize To x + nearSize
     If xi > 0 And yi > 0 And xi < *object\width And yi < *object\height
      src\rgba = getColorFromArray(*object\srcMem, xi, yi, *object\width)
      dif = 0
      For channel = 0 To #IF_UsedChannels - 1
       int1 = src\channel[channel] & $FF
       int2 = *dest\channel[channel] & $FF
       dif + Abs(int1 - int2)
      Next channel
      If dif < minDif
       minDif = dif
       minDifColor\rgba = src\rgba
      EndIf
     EndIf
    Next xi
   Next yi
   *dest\rgba = minDifColor\rgba
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_binomial(*this.IImageFilter, size.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 If *this = #Null Or size < 2
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = *this\memBinomial(*object\srcMem, size)
 If *destMem
  FreeMemory(*object\srcMem)
  *object\srcMem = *destMem
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_minMax(*this.IImageFilter, size.i)
 Protected *object.OImageFilter, src.ImageFilter_RGBA, *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected Dim radix.i(255), min.i, max.i
 If *this = #Null Or size < 1
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 *dest = *destMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   For channel = 0 To #IF_UsedChannels - 1
    For yi = y - size To y + size
     For xi = x - size To x + size
      If xi > 0 And yi > 0 And xi < *object\width And yi < *object\height
       src\rgba = getColorFromArray(*object\srcMem, xi, yi, *object\width)
       radix(src\channel[channel] & $FF) + 1
      EndIf
     Next xi
    Next yi
    min = -1
    max = -1
    For i = 0 To 255
     If radix(i) = 0
      If max = -1
       min = i
      EndIf
     Else
      max = i
     EndIf
     radix(i) = 0
    Next i
    *dest\channel[channel] = max - min - 1
   Next channel
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 FreeMemory(*object\srcMem)
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_DoG(*this.IImageFilter, q.i, p.i)
 Protected *object.OImageFilter, *qMem.ImageFilter_RGBA, *pMem.ImageFilter_RGBA
 Protected *src.ImageFilter_RGBA, *q.ImageFilter_RGBA, *p.ImageFilter_RGBA
 Protected int.i
 If *this = #Null Or p < 1 Or p < 1
  ProcedureReturn #False
 EndIf
 *object = *this
 *pMem = *this\memBinomial(*object\srcMem, p)
 If *pMem = #Null
  ProcedureReturn #False
 EndIf
 *qMem = *this\memBinomial(*pMem, q)
 If *qMem = #Null
  FreeMemory(*pMem)
  ProcedureReturn #False
 EndIf
 *src = *object\srcMem
 *p = *pMem
 *q = *qMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   For channel = 0 To #IF_UsedChannels - 1
    int = (4 * ((*q\channel[channel] & $FF) - (*p\channel[channel] & $FF))) + 128
    limit(int, 0, $FF)
    *src\channel[channel] = int
   Next
   *src + SizeOf(ImageFilter_RGBA)
   *p + SizeOf(ImageFilter_RGBA)
   *q + SizeOf(ImageFilter_RGBA)
  Next
 Next
 FreeMemory(*pMem)
 FreeMemory(*qMem)
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_houghTransformation(*this.IImageFilter, threshold.i)
 Protected *object.OImageFilter, *src.ImageFilter_RGBA, int.i
 Protected *dest.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected halfWidth.i, halfHeight.i, imgId.i
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 halfWidth = *object\width >> 1
 halfHeight = *object\height >> 1
 limit(threshold, 0, $FF)
 Protected width.i, height.i, thetaCos.i, d.i
 width = 360 ;degree
 height = Int(Sqr((halfWidth * halfWidth) + (halfHeight * halfHeight))) ;diagonal
 *destMem = AllocateMemory(width * height * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #False
 EndIf
 Protected Dim thetaSin.f(360 + 90 - 1)
 Protected Dim houghField.i(width - 1, height - 1, #IF_UsedChannels - 1)
 Protected Dim maxValue.i(#IF_UsedChannels - 1)
 For theta = 0 To 360 + 90 - 1
  thetaSin(theta) = Sin(theta * 0.017453292519943295)
 Next theta
 *src = *object\srcMem
 For y = 0 To *object\height - 1
  For x = 0 To *object\width - 1
   For theta = 0 To 360 - 1
    d = Int(Abs(((y - halfHeight) * thetaSin(theta)) + ((x - halfWidth) * thetaSin(theta + 90))))
    If d >= 0 And d < height
     For channel = 0 To #IF_UsedChannels - 1
      int = *src\channel[channel] & $FF
      If int >= threshold
       houghField(theta, d, channel) + int
      EndIf
     Next channel
    EndIf
   Next theta
   *src + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 For channel = 0 To #IF_UsedChannels - 1
  maxValue(channel) = 1
 Next channel
 For y = 0 To height - 1
  For x = 0 To width - 1
   For channel = 0 To #IF_UsedChannels - 1
    If houghField(x, y, channel) > maxValue(channel)
     maxValue(channel) = houghField(x, y, channel)
    EndIf
   Next channel
  Next x
 Next y
 imgId = CreateImage(#PB_Any, width, height, #IF_ImageDepth)
 If IsImage(imgId) = #Null
  ProcedureReturn #False
 EndIf
 If IsImage(*object\image)
  FreeImage(*object\image)
 EndIf
 FreeMemory(*object\srcMem)
 *object\image = imgId
 *object\width = width
 *object\height = height
 *dest = *destMem
 For y = 0 To height - 1
  For x = 0 To width - 1
   For channel = 0 To #IF_UsedChannels - 1
    int = Int(houghField(x, y, channel) / maxValue(channel) * 255)
    limit(int, 0, $FF)
    *dest\channel[channel] = int
   Next channel
   *dest + SizeOf(ImageFilter_RGBA)
  Next x
 Next y
 *object\srcMem = *destMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_threshold(*this.IImageFilter, value.i, keepColor.i = #False)
 Protected *object.OImageFilter, gray.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *src = *object\srcMem
 If keepColor
  For i = 0 To *object\pixels - 1
   gray = Gray(*src\rgba)
   If gray < value
    *src\rgba = $000000
   Else
    *src\rgba = RGB(gray, gray, gray)
   EndIf
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 Else
  For i = 0 To *object\pixels - 1
   gray = Gray(*src\rgba)
   If gray < value
    *src\rgba = $000000
   Else
    *src\rgba = $FFFFFF
   EndIf
   *src + SizeOf(ImageFilter_RGBA)
  Next i
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_regionGrowing(*this.IImageFilter, x.i, y.i, maxDelta.i)
 Protected *object.OImageFilter, rgb.ImageFilter_RGBA, *src.ImageFilter_RGBA
 Protected *maskMem.ImageFilter_RGBA, *mask.ImageFilter_RGBA
 Protected c1.ImageFilter_RGBA, c2.ImageFilter_RGBA
 Protected NewList stack.POINT()
 If *this = #Null Or x < 0 Or y < 0 Or maxDelta < 0 Or maxDelta > $FF
  ProcedureReturn #False
 EndIf
 *object = *this
 If x >= *object\width Or y >= *object\height
  ProcedureReturn #False
 EndIf
 *maskMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *maskMem = 0
  ProcedureReturn #False
 EndIf
 y = *object\height - y - 1
 AddElement(stack())
 stack()\x = x
 stack()\y = y
 setColorFromArray(*maskMem, x, y, *object\width, $FFFFFF)
 While ListSize(stack()) > 0
  FirstElement(stack())
  sx = stack()\x
  sy = stack()\y
  DeleteElement(stack())
  For yi = sy - 1 To sy + 1
   If yi >= 0 And yi < *object\height
    For xi = sx - 1 To sx + 1
     If xi >= 0 And xi < *object\width
      For yb = yi - 1 To yi + 1
       If yb >= 0 And yb < *object\height
        For xb = xi - 1 To xi + 1
         If xb >= 0 And xb < *object\width
          If getColorFromArray(*maskMem, xb, yb, *object\width) <> 0 And getColorFromArray(*maskMem, xi, yi, *object\width) = 0
           delta = 0
           c1\rgba = getColorFromArray(*object\srcMem, xb, yb, *object\width)
           c2\rgba = getColorFromArray(*object\srcMem, xi, yi, *object\width)
           If Abs(Red(c1\rgba) - Red(c2\rgba)) + Abs(Green(c1\rgba) - Green(c2\rgba)) + Abs(Blue(c1\rgba) - Blue(c2\rgba)) <= maxDelta
            AddElement(stack())
            stack()\x = xi
            stack()\y = yi
            setColorFromArray(*maskMem, xi, yi, *object\width, $FFFFFF)
            Break 2
           EndIf
          EndIf
         EndIf
        Next xb
       EndIf
      Next yb
     EndIf
    Next xi
   EndIf
  Next yi
 Wend
 FreeMemory(*object\srcMem)
 *object\srcMem = *maskMem
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_dilate(*this.IImageFilter, label.i, mask$, times.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 Protected maskWidth.i, maskHeight.i, maskValues.i
 Protected maskOffsetX.i, maskOffsetY.i
 Protected oldValue.i, maskValue.i
 Protected continueFor.i
 Protected modified.i = #False
 If *this = #Null Or times < 1 Or mask$ = ""
  ProcedureReturn #False
 EndIf
 *object = *this
 maskWidth = CountString(StringField(mask$, 1, "|"), ",") + 1
 maskHeight = CountString(mask$, "|") + 1
 Protected Dim mask.i((maskWidth * maskHeight) - 1)
 maskValues = 0
 For x = 0 To maskWidth - 1
  For y = 0 To maskHeight - 1
   If Val(Trim(StringField(StringField(mask$, y + 1, "|"), x + 1, ",")))
    mask(maskValues) = ((y - (maskHeight / 2)) * *object\width) + x - (maskWidth / 2)
    maskValues + 1
   EndIf
  Next
 Next
 maskOffsetX = maskWidth >> 1
 maskOffsetY = maskHeight >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = 0
  ProcedureReturn #False
 EndIf
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue = label
      If oldValue <> label
       setColorFromArray(*destMem, x, y, *object\width, label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 FreeMemory(*destMem)
 ProcedureReturn modified
EndProcedure


Procedure.i ImageFilter_erode(*this.IImageFilter, label.i, mask$, times.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 Protected maskWidth.i, maskHeight.i, maskValues.i
 Protected maskOffsetX.i, maskOffsetY.i
 Protected oldValue.i, maskValue.i
 Protected continueFor.i
 Protected modified.i = #False
 If *this = #Null Or times < 1 Or mask$ = ""
  ProcedureReturn #False
 EndIf
 *object = *this
 maskWidth = CountString(StringField(mask$, 1, "|"), ",") + 1
 maskHeight = CountString(mask$, "|") + 1
 Protected Dim mask.i((maskWidth * maskHeight) - 1)
 maskValues = 0
 For x = 0 To maskWidth - 1
  For y = 0 To maskHeight - 1
   If Val(Trim(StringField(StringField(mask$, y + 1, "|"), x + 1, ",")))
    mask(maskValues) = ((y - (maskHeight / 2)) * *object\width) + x - (maskWidth / 2)
    maskValues + 1
   EndIf
  Next
 Next
 maskOffsetX = maskWidth >> 1
 maskOffsetY = maskHeight >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = 0
  ProcedureReturn #False
 EndIf
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue <> label
      If oldValue = label
       setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 FreeMemory(*destMem)
 ProcedureReturn modified
EndProcedure


Procedure.i ImageFilter_closing(*this.IImageFilter, label.i, mask$, times.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 Protected maskWidth.i, maskHeight.i, maskValues.i
 Protected maskOffsetX.i, maskOffsetY.i
 Protected oldValue.i, maskValue.i
 Protected continueFor.i
 Protected modified.i = #False
 If *this = #Null Or times < 1 Or mask$ = ""
  ProcedureReturn #False
 EndIf
 *object = *this
 maskWidth = CountString(StringField(mask$, 1, "|"), ",") + 1
 maskHeight = CountString(mask$, "|") + 1
 Protected Dim mask.i((maskWidth * maskHeight) - 1)
 maskValues = 0
 For x = 0 To maskWidth - 1
  For y = 0 To maskHeight - 1
   If Val(Trim(StringField(StringField(mask$, y + 1, "|"), x + 1, ",")))
    mask(maskValues) = ((y - (maskHeight / 2)) * *object\width) + x - (maskWidth / 2)
    maskValues + 1
   EndIf
  Next
 Next
 maskOffsetX = maskWidth >> 1
 maskOffsetY = maskHeight >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = 0
  ProcedureReturn #False
 EndIf
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue = label
      If oldValue <> label
       setColorFromArray(*destMem, x, y, *object\width, label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue <> label
      If oldValue = label
       setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 FreeMemory(*destMem)
 ProcedureReturn modified
EndProcedure


Procedure.i ImageFilter_opening(*this.IImageFilter, label.i, mask$, times.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 Protected maskWidth.i, maskHeight.i, maskValues.i
 Protected maskOffsetX.i, maskOffsetY.i
 Protected oldValue.i, maskValue.i
 Protected continueFor.i
 Protected modified.i = #False
 If *this = #Null Or times < 1 Or mask$ = ""
  ProcedureReturn #False
 EndIf
 *object = *this
 maskWidth = CountString(StringField(mask$, 1, "|"), ",") + 1
 maskHeight = CountString(mask$, "|") + 1
 Protected Dim mask.i((maskWidth * maskHeight) - 1)
 maskValues = 0
 For x = 0 To maskWidth - 1
  For y = 0 To maskHeight - 1
   If Val(Trim(StringField(StringField(mask$, y + 1, "|"), x + 1, ",")))
    mask(maskValues) = ((y - (maskHeight / 2)) * *object\width) + x - (maskWidth / 2)
    maskValues + 1
   EndIf
  Next
 Next
 maskOffsetX = maskWidth >> 1
 maskOffsetY = maskHeight >> 1
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = 0
  ProcedureReturn #False
 EndIf
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue <> label
      If oldValue = label
       setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For x = maskOffsetX To *object\width - maskOffsetX - 1
   For y = maskOffsetY To *object\height - maskOffsetY - 1
    oldValue = getColorFromArray(*object\srcMem, x, y, *object\width)
    continueFor = #False
    For i = 0 To maskValues - 1
     maskValue = getColorFromArray(*object\srcMem, x + mask(i), y, *object\width)
     If maskValue = label
      If oldValue <> label
       setColorFromArray(*destMem, x, y, *object\width, label)
       modified = #True
      EndIf
      continueFor = #True
      Break 1
     EndIf
    Next i
    If oldValue = label And continueFor = #False
     setColorFromArray(*destMem, x, y, *object\width, $FFFFFF ! label)
     modified = #True
    EndIf
   Next y
  Next x
  Swap *destMem, *object\srcMem
 Next t
 FreeMemory(*destMem)
 ProcedureReturn modified
EndProcedure


Procedure.i ImageFilter_thin(*this.IImageFilter, label.i, times.i)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA, *tmpMem.ImageFilter_RGBA
 Protected Dim indexedFilterMask.i(7)
 Protected Dim neighbors.i(7)
 Protected numNeighbors.i, numTransitions.i
 Protected modified.i = #False
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = 0
  ProcedureReturn #False
 EndIf
 indexedFilterMask(0) = -*object\width
 indexedFilterMask(1) = -*object\width + 1
 indexedFilterMask(2) = 1
 indexedFilterMask(3) = *object\width + 1
 indexedFilterMask(4) = *object\width
 indexedFilterMask(5) = *object\width - 1
 indexedFilterMask(6) = -1
 indexedFilterMask(7) = -*object\width - 1
 For t = 1 To times
  CopyMemory(*object\srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For y = 1 To *object\height - 2
   For x = 1 To *object\width - 2
    If getColorFromArray(*object\srcMem, x, y, *object\width) = label
     numNeighbors = 0
     For i = 0 To 7
      If getColorFromArray(*object\srcMem, x + indexedFilterMask(i), y, *object\width) = label
       neighbors(i) = #True
       numNeighbors + 1
      Else
       neighbors(i) = #False
      EndIf
     Next i
     If numNeighbors < 2 Or numNeighbors > 6
      Continue
     EndIf
     numTransitions = 0
     For i = 0 To 7
      If neighbors(i) = #False And neighbors((i + 1) % 8) = #True
       numTransitions + 1
      EndIf
     Next i
     If numTransitions <> 1
      Continue
     EndIf
     If neighbors(0) And neighbors(2) And neighbors(4)
      Continue
     EndIf
     If neighbors(2) And neighbors(4) And neighbors(6)
      Continue
     EndIf
     setColorFromArray(*destMem, x, y, *object\width, $FFFFFF - label)
     modified = #True
    EndIf
   Next x
  Next y
  CopyMemory(*destMem, *object\srcMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  For y = 1 To *object\height - 2
   For x = 1 To *object\width - 2
    If getColorFromArray(*object\srcMem, x, y, *object\width) = label
     numNeighbors = 0
     For i = 0 To 7
      If getColorFromArray(*object\srcMem, x + indexedFilterMask(i), y, *object\width) = label
       neighbors(i) = #True
       numNeighbors + 1
      Else
       neighbors(i) = #False
      EndIf
     Next i
     If numNeighbors < 2 Or numNeighbors > 6
      Continue
     EndIf
     numTransitions = 0
     For i = 0 To 7
      If neighbors(i) = #False And neighbors((i + 1) % 8) = #True
       numTransitions + 1
      EndIf
     Next i
     If numTransitions <> 1
      Continue
     EndIf
     If neighbors(0) And neighbors(2) And neighbors(6)
      Continue
     EndIf
     If neighbors(0) And neighbors(4) And neighbors(6)
      Continue
     EndIf
     setColorFromArray(*destMem, x, y, *object\width, $FFFFFF - label)
     modified = #True
    EndIf
   Next x
  Next y
  *tmpMem = *destMem
  *destMem = *object\srcMem
  *object\srcMem = *tmpMem
 Next t
 FreeMemory(*destMem)
 ProcedureReturn modified
EndProcedure


Procedure.i ImageFilter_skeletonization(*this.IImageFilter, label.i)
 If *this = #Null
  ProcedureReturn #False
 EndIf
 While *this\thin(label, 1) : Wend
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_generic(*this.IImageFilter, filter$)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 If *this = #Null Or filter$ = ""
  ProcedureReturn #False
 EndIf
 *object = *this
 *destMem = *this\memGeneric(*object\srcMem, filter$)
 If *destMem
  FreeMemory(*object\srcMem)
  *object\srcMem = *destMem
 Else
  ProcedureReturn #False
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_bswap(*this.IImageFilter)
 Protected *object.OImageFilter, gray.i, *src.ImageFilter_RGBA
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *src = *object\srcMem
 For i = 0 To *object\pixels - 1
  Swap *src\channel[0], *src\channel[3]
  Swap *src\channel[1], *src\channel[2]
  *src + SizeOf(ImageFilter_RGBA)
 Next i
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_output(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 ProcedureReturn *this\setColorArray(*object\srcMem)
EndProcedure


Procedure ImageFilter_delete(*this.IImageFilter)
 Protected *object.OImageFilter
 If *this = #Null
  ProcedureReturn
 EndIf
 *object = *this
 FreeMemory(*object\srcMem)
 FreeMemory(*object)
EndProcedure


Procedure.i ImageFilter_getColorArray(*this.IImageFilter)
 Protected *object.OImageFilter, *mem.ImageFilter_RGBA, *addr.ImageFilter_RGBA, *src.BYTE, *lineStart.BYTE
 If *this = #Null
  ProcedureReturn #Null
 EndIf
 *object = *this
 *mem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *mem = 0
  ProcedureReturn #Null
 EndIf
 If StartDrawing(ImageOutput(*object\image)) = 0
  FreeMemory(*mem)
  ProcedureReturn #Null
 EndIf
 Select DrawingBufferPixelFormat() & $FF
  Case #PB_PixelFormat_24Bits_RGB
   *src = DrawingBuffer()
   If *src = 0
    FreeMemory(*mem)
    StopDrawing()
    ProcedureReturn #Null
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *src + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[3] = $FF
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart - DrawingBufferPitch()
    Next y
   Else   
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[3] = $FF
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_24Bits_BGR
   *src = DrawingBuffer()
   If *src = 0
    FreeMemory(*mem)
    StopDrawing()
    ProcedureReturn #Null
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *src + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[3] = $FF
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart - DrawingBufferPitch()
    Next y
   Else   
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[3] = 0
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_32Bits_RGB
   *src = DrawingBuffer()
   If *src = 0
    FreeMemory(*mem)
    StopDrawing()
    ProcedureReturn #Null
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *src + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[3] = *src\b : *src + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart - DrawingBufferPitch()
    Next y
   Else   
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[3] = *src\b : *src + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_32Bits_BGR
   *src = DrawingBuffer()
   If *src = 0
    FreeMemory(*mem)
    StopDrawing()
    ProcedureReturn #Null
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *src + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[3] = *src\b : *src + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart - DrawingBufferPitch()
    Next y
   Else   
    For y = 0 To *object\height - 1
     *lineStart = *src
     For x = 0 To *object\width - 1
      *addr\channel[2] = *src\b : *src + 1
      *addr\channel[1] = *src\b : *src + 1
      *addr\channel[0] = *src\b : *src + 1
      *addr\channel[3] = *src\b : *src + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *src = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Default
   *addr = *mem
   If OutputDepth() = 32
    For y = 0 To *object\height - 1
     For x = 0 To *object\width - 1
      *addr\rgba = Point(x, y)
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
    Next y
   Else
    For y = 0 To *object\height - 1
     For x = 0 To *object\width - 1
      *addr\rgba = Point(x, y)
      *addr\channel[3] = $FF
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
    Next y
   EndIf
  EndSelect
 StopDrawing()
 ProcedureReturn *mem
EndProcedure


Procedure.i ImageFilter_setColorArray(*this.IImageFilter, *mem.ImageFilter_RGBA)
 Protected *object.OImageFilter, *addr.ImageFilter_RGBA, *dest.BYTE, *lineStart.BYTE
 If *this = #Null Or *mem = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 If StartDrawing(ImageOutput(*object\image)) = 0
  ProcedureReturn #False
 EndIf
 Select DrawingBufferPixelFormat() & $FF
  Case #PB_PixelFormat_24Bits_RGB
   *dest = DrawingBuffer()
   If *dest = 0
    StopDrawing()
    ProcedureReturn #False
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *dest + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[0] : *dest + 1
      *dest\b = *addr\channel[1] : *dest + 1
      *dest\b = *addr\channel[2] : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart - DrawingBufferPitch()
    Next y
   Else
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[0] : *dest + 1
      *dest\b = *addr\channel[1] : *dest + 1
      *dest\b = *addr\channel[2] : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_24Bits_BGR
   *dest = DrawingBuffer()
   If *dest = 0
    StopDrawing()
    ProcedureReturn #False
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *dest + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[2] : *dest + 1
      *dest\b = *addr\channel[1] : *dest + 1
      *dest\b = *addr\channel[0] : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart - DrawingBufferPitch()
    Next y
   Else
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[2] & $FF : *dest + 1
      *dest\b = *addr\channel[1] & $FF : *dest + 1
      *dest\b = *addr\channel[0] & $FF : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_32Bits_RGB
   *dest = DrawingBuffer()
   If *dest = 0
    StopDrawing()
    ProcedureReturn #False
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *dest + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[0] : *dest + 1
      *dest\b = *addr\channel[1] : *dest + 1
      *dest\b = *addr\channel[2] : *dest + 1
      *dest\b = *addr\channel[3] : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart - DrawingBufferPitch()
    Next y
   Else
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[0] & $FF : *dest + 1
      *dest\b = *addr\channel[1] & $FF : *dest + 1
      *dest\b = *addr\channel[2] & $FF : *dest + 1
      *dest\b = *addr\channel[3] & $FF : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Case #PB_PixelFormat_32Bits_BGR
   *dest = DrawingBuffer()
   If *dest = 0
    StopDrawing()
    ProcedureReturn #False
   EndIf
   *addr = *mem
   If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY = #PB_PixelFormat_ReversedY
    *dest + ((*object\height - 1) * DrawingBufferPitch())
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[2] : *dest + 1
      *dest\b = *addr\channel[1] : *dest + 1
      *dest\b = *addr\channel[0] : *dest + 1
      *dest\b = *addr\channel[3] : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart - DrawingBufferPitch()
    Next y
   Else
    For y = 0 To *object\height - 1
     *lineStart = *dest
     For x = 0 To *object\width - 1
      *dest\b = *addr\channel[2] & $FF : *dest + 1
      *dest\b = *addr\channel[1] & $FF : *dest + 1
      *dest\b = *addr\channel[0] & $FF : *dest + 1
      *dest\b = *addr\channel[3] & $FF : *dest + 1
      *addr + SizeOf(ImageFilter_RGBA)
     Next x
     *dest = *lineStart + DrawingBufferPitch()
    Next y
   EndIf
  Default
   *addr = *mem
   If OutputDepth() = 32
    DrawingMode(#PB_2DDrawing_AlphaChannel)
    Box(0, 0, *object\width, *object\height, $00000000)
    DrawingMode(#PB_2DDrawing_AlphaBlend)
   EndIf
   For y = 0 To *object\height - 1
    For x = 0 To *object\width - 1
     Plot(x, y, *addr\rgba)
     *addr + SizeOf(ImageFilter_RGBA)
    Next x
   Next y
  EndSelect
 StopDrawing()
 ProcedureReturn #True
EndProcedure


Procedure.i ImageFilter_memBinomial(*this.IImageFilter, *mem.ImageFilter_RGBA, size.i)
 Protected *object.OImageFilter, src1.ImageFilter_RGBA, src2.ImageFilter_RGBA, *srcMem.ImageFilter_RGBA, *destMem.ImageFilter_RGBA
 Protected int.i, offset.i
 If *this = #Null Or *mem = #Null
  ProcedureReturn #Null
 EndIf
 *object = *this
 *srcMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *srcMem = #Null
  ProcedureReturn #Null
 EndIf
 If size < 2
  CopyMemory(*mem, *srcMem, *object\pixels * SizeOf(ImageFilter_RGBA))
  ProcedureReturn *srcMem
 EndIf
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #Null
 EndIf
 CopyMemory(*mem, *srcMem, *object\pixels * SizeOf(ImageFilter_RGBA))
 offset = 1
 For p = 2 To size
  For y = 0 To *object\height - 1
   For x = offset To *object\width - 2 + offset
    src1\rgba = getColorFromArray(*srcMem, x - offset, y, *object\width)
    src2\rgba = getColorFromArray(*srcMem, x + 1 - offset, y, *object\width)
    For channel = 0 To #IF_UsedChannels - 1
     int = (src1\channel[channel] & $FF) + (src2\channel[channel] & $FF)
     src1\channel[channel] = Int(int / 2)
    Next channel
    setColorFromArray(*destMem, x, y, *object\width, src1\rgba)
   Next x
   If offset = 0
    src1\rgba = getColorFromArray(*srcMem, *object\width - 1, y, *object\width)
    setColorFromArray(*destMem, *object\width - 1, y, *object\width, src1\rgba)
   Else
    src1\rgba = getColorFromArray(*srcMem, 0, y, *object\width)
    setColorFromArray(*destMem, 0, y, *object\width, src1\rgba)
   EndIf
  Next y
  For x = 0 To *object\width - 1
   For y = offset To *object\height - 2 + offset
    src1\rgba = getColorFromArray(*destMem, x, y - offset, *object\width)
    src2\rgba = getColorFromArray(*destMem, x, y + 1 - offset, *object\width)
    For channel = 0 To #IF_UsedChannels - 1
     int = (src1\channel[channel] & $FF) + (src2\channel[channel] & $FF)
     src1\channel[channel] = Int(int / 2)
    Next channel
    setColorFromArray(*srcMem, x, y, *object\width, src1\rgba)
   Next y
   If offset = 0
    src1\rgba = getColorFromArray(*destMem, x, *object\height - 1, *object\width)
    setColorFromArray(*srcMem, x, *object\height - 1, *object\width, src1\rgba)
   Else
    src1\rgba = getColorFromArray(*destMem, x, 0, *object\width)
    setColorFromArray(*srcMem, x, 0, *object\width, src1\rgba)
   EndIf
  Next x
  offset = 1 - offset
 Next
 FreeMemory(*destMem)
 ProcedureReturn *srcMem
EndProcedure


Procedure.i ImageFilter_memGeneric(*this.IImageFilter, *srcMem.ImageFilter_RGBA,filter$)
 Protected *object.OImageFilter, *destMem.ImageFilter_RGBA
 Protected src.ImageFilter_RGBA, dest.ImageFilter_RGBA, curColor.i
 Protected filterWidth.i, filterHeight.i, filterOffsetX.i, filterOffsetY.i
 Protected filterMatrix$, divide.f, offset.f
 Protected newValue.f
 If *this = #Null Or *srcMem = #Null
  ProcedureReturn #Null
 EndIf
 *object = *this
 *destMem = AllocateMemory(*object\pixels * SizeOf(ImageFilter_RGBA))
 If *destMem = #Null
  ProcedureReturn #Null
 EndIf
 CopyMemory(*srcMem, *destMem, *object\pixels * SizeOf(ImageFilter_RGBA))
 filterMatrix$ = Trim(StringField(filter$, 1, ";"))
 divide = ValF(Trim(StringField(filter$, 2, ";")))
 offset = ValF(Trim(StringField(filter$, 3, ";")))
 filterWidth = CountString(StringField(filterMatrix$, 1, "|"), ",") + 1
 filterHeight = CountString(filterMatrix$, "|") + 1
 Protected Dim filter.f(filterWidth - 1, filterHeight - 1)
 For x = 0 To filterWidth - 1
  For y = 0 To filterHeight - 1
   filter(x, y) = ValF(Trim(StringField(StringField(filterMatrix$, y + 1, "|"), x + 1, ",")))
  Next
 Next
 filterOffsetX = filterWidth >> 1
 filterOffsetY = filterHeight >> 1
 For x = filterOffsetX To *object\width - filterOffsetX - 1
  For y = filterOffsetY To *object\height - filterOffsetY - 1
   For channel = 0 To #IF_UsedChannels - 1
    newValue = 0
    For xi = x - filterOffsetX To x + filterOffsetX
     For yi = y - filterOffsetY To y + filterOffsetY
      src\rgba = getColorFromArray(*srcMem, xi, yi, *object\width)
      curColor = src\channel[channel] & $FF
      newValue = newValue + (curColor * filter(xi - x + filterOffsetX, yi - y + filterOffsetY))
     Next yi
    Next xi
     newValue = (newValue / divide) + offset
     limit(newValue, 0, 255)
     dest\channel[channel] = newValue
   Next channel
   setColorFromArray(*destMem, x, y, *object\width, dest\rgba)
  Next y
 Next x
 ProcedureReturn *destMem
EndProcedure


; ;########################################
; UseJPEGImageDecoder()
; 
; img = LoadImage(#PB_Any, "D:\Downloads\Backgrounds\getme.jpg")
; 
; filter1.IImageFilter = newImageFilter(img)
; filter2.IImageFilter = newImageFilter(img)
; filter3.IImageFilter = newImageFilter(img)
; 
; filter1\median(1)
; filter1\generic("1,2,1|0,0,0|-1,-2,-1;8;128")
; 
; filter2\median(1)
; filter2\generic("1,0,-1|2,0,-2|1,0,-1;8;128")
; filter2\euclidianNorm(filter1, 0)
; filter2\invert()
; filter2\grayscale()
; 
; filter3\median(1)
; filter3\weight(filter2, 1, -128)
; filter3\median(1)
; filter3\output()
; 
; filter1\delete()
; filter2\delete()
; filter3\delete()
; 
; OpenWindow(0, 0, 0, ImageWidth(img), ImageHeight(img), "CImageFilter", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
; ImageGadget(0, 0, 0, ImageWidth(img), ImageHeight(img), ImageID(img))
; Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: class for image manipulation (OOP)

Post by idle »

very useful thanks.
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
dobro
Enthusiast
Enthusiast
Posts: 766
Joined: Sun Oct 31, 2004 10:54 am
Location: France
Contact:

Re: class for image manipulation (OOP)

Post by dobro »

hi ,

with the example code:

Code: Select all

; ;########################################
 UseJPEGImageDecoder()
;
file$=OpenFileRequester("ouvrir un jpg","e:\","images|*.jpg",0)
img = LoadImage(#PB_Any, file$)

filter1.IImageFilter = newImageFilter(img)
filter2.IImageFilter = newImageFilter(img)
filter3.IImageFilter = newImageFilter(img)

filter1\median(1)
filter1\generic("1,2,1|0,0,0|-1,-2,-1;8;128")

filter2\median(1)
filter2\generic("1,0,-1|2,0,-2|1,0,-1;8;128")
filter2\euclidianNorm(filter1, 0)
filter2\invert()
filter2\grayscale()

filter3\median(1)
filter3\weight(filter2, 1, -128)
filter3\median(1)
filter3\output()

filter1\delete()
filter2\delete()
filter3\delete()

Enumeration
#window
#gadget_image
EndEnumeration

OpenWindow(#window, 0, 0, ImageWidth(img), ImageHeight(img), "CImageFilter", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
ImageGadget(#gadget_image, 0, 0, ImageWidth(img), ImageHeight(img), ImageID(img))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
; ***************************************************************************
and this picture
http://michel.dobro.free.fr/Forum_pb/Image17.jpg


I get an error line 243: (filter2\median(1) )
"Invalid memory access (read error at address 0)"
" Acces memoire invalide (erreur de lecture a l'adresse 0 ")



:cry:
Image
Windows 98/7/10 - PB 5.42
■ sites : http://michel.dobro.free.fr/
User avatar
pcfreak
User
User
Posts: 75
Joined: Sat May 22, 2004 1:38 am

Re: class for image manipulation (OOP)

Post by pcfreak »

Way too old code.. seems the example was broken ;)

Code: Select all

;########################################
 UseJPEGImageDecoder()
;
file$=OpenFileRequester("ouvrir un jpg","e:\","images|*.jpg",0)
img1 = LoadImage(#PB_Any, file$)
img2 = CopyImage(img1, #PB_Any)
img3 = CopyImage(img1, #PB_Any)

filter1.IImageFilter = newImageFilter(img1)
img1 = filter1\getImage() ; image was adjusted to a different color depth
filter2.IImageFilter = newImageFilter(img2)
img2 = filter2\getImage() ; image was adjusted to a different color depth
filter3.IImageFilter = newImageFilter(img3)
img3 = filter3\getImage() ; image was adjusted to a different color depth

filter1\median(1)
filter1\generic("1,2,1|0,0,0|-1,-2,-1;8;128")

filter2\median(1)
filter2\generic("1,0,-1|2,0,-2|1,0,-1;8;128")
filter2\euclidianNorm(filter1, 0)
filter2\invert()
filter2\grayscale()

filter3\median(1)
filter3\weight(filter2, 1, -128)
filter3\median(1)
filter3\output()

filter1\delete()
filter2\delete()
filter3\delete()

FreeImage(img1)
FreeImage(img2)

Enumeration
#window
#gadget_image
EndEnumeration

OpenWindow(#window, 0, 0, ImageWidth(img3), ImageHeight(img3), "CImageFilter", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
ImageGadget(#gadget_image, 0, 0, ImageWidth(img3), ImageHeight(img3), ImageID(img3))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
; ***************************************************************************
Well I did quite a couple of adjustments when I used it for a scripting interpreter back then.

CHashTableS.pbi

Code: Select all

Prototype.i HashFunctionS(key$, limit.i)

Interface IHashTableS
 addKey(key$)   ;return pointer to data memory
 getKey(key$)   ;return pointer to data memory
 delKey(key$)   ;return pointer to data memory which has been deleted
 size()         ;return number of elments in the hash table
 clear()        ;remove all elements in the hash table
 ;hash function
 getHashFunction() ;returns the address of the hash function
 setHashFunction(hash.HashFunctionS) ;returns the old hash function or #Null if failed
 ;free object
 delete()
EndInterface

Structure EHashTableS
 *after.EHashTableS
 key.s
EndStructure

Structure OHashTableS
 ;Address to the methods array
 methodAddress.i
 ;Class Attributes
  ;Constants
  elementSize.i
  tableSize.i
  ;Variables
  size.i
  table.i
  hash.HashFunctionS
EndStructure


Declare.i newHashTableS(dataSize.i, tableSize.i)
Declare.i HashTableS_addKey(*this.IHashTableS, key$)
Declare.i HashTableS_getKey(*this.IHashTableS, key$)
Declare.i HashTableS_delKey(*this.IHashTableS, key$)
Declare.i HashTableS_size(*this.IHashTableS)
Declare.i HashTableS_clear(*this.IHashTableS)
Declare.i HashTableS_getHashFunction(*this.IHashTableS)
Declare.i HashTableS_setHashFunction(*this.IHashTableS, hash.HashFunctionS)
Declare   HashTableS_delete(*this.IHashTableS)

Declare.i HashTableS_defaultHashFunction(key$, limit.i)


DataSection
 OHashTableS_methods:
  Data.i @HashTableS_addKey()
  Data.i @HashTableS_getKey()
  Data.i @HashTableS_delKey()
  Data.i @HashTableS_size()
  Data.i @HashTableS_clear()
  Data.i @HashTableS_getHashFunction()
  Data.i @HashTableS_setHashFunction()
  Data.i @HashTableS_delete()
EndDataSection


Procedure.i newHashTableS(dataSize.i, tableSize.i)
 Protected *object.OHashTableS
 *object = AllocateMemory(SizeOf(OHashTableS))
 If *object = #Null
  ProcedureReturn #Null
 EndIf
 *object\methodAddress = ?OHashTableS_methods
 *object\elementSize = SizeOf(EHashTableS) + dataSize
 *object\tableSize = tableSize
 *object\size    = 0
 *object\table   = AllocateMemory(SizeOf(INTEGER) * tableSize)
 *object\hash    = @HashTableS_defaultHashFunction()
 If *object\table = #Null
  FreeMemory(*object)
  ProcedureReturn #Null
 EndIf
 ProcedureReturn *object
EndProcedure


Procedure.i HashTableS_addKey(*this.IHashTableS, key$)
 Protected *object.OHashTableS, *element.EHashTableS, *nextElement.EHashTableS
 Protected tablePosition.i
 If *this = #Null Or key$ = ""
  ProcedureReturn #Null
 EndIf
 *object = *this
 *element = *this\getKey(key$)
 If *element
  ProcedureReturn *element
 EndIf
 *element = AllocateMemory(*object\elementSize)
 If *element = #Null
  ProcedureReturn #Null
 EndIf
 *element\after = #Null
 *element\key = key$
 tablePosition = SizeOf(INTEGER) * *object\hash(key$, *object\tableSize)
 *nextElement = PeekI(*object\table + tablePosition)
 If *nextElement = #Null
  PokeI(*object\table + tablePosition, *element)
 Else
  While *nextElement\after
   *nextElement = *nextElement\after
  Wend
  *nextElement\after = *element
 EndIf
 *object\size + 1
 ProcedureReturn *element + SizeOf(EHashTableS)
EndProcedure


Procedure.i HashTableS_getKey(*this.IHashTableS, key$)
 Protected *object.OHashTableS, *nextElement.EHashTableS
 Protected tablePosition.i
 If *this = #Null Or key$ = ""
  ProcedureReturn #Null
 EndIf
 *object = *this
 tablePosition = SizeOf(INTEGER) * *object\hash(key$, *object\tableSize)
 *nextElement = PeekI(*object\table + tablePosition)
 If *nextElement
  While *nextElement\after And *nextElement\key <> key$
   *nextElement = *nextElement\after
  Wend
  If *nextElement\key = key$
   ProcedureReturn *nextElement + SizeOf(EHashTableS)
  EndIf
 EndIf
 ProcedureReturn #Null
EndProcedure


Procedure.i HashTableS_delKey(*this.IHashTableS, key$)
 Protected *object.OHashTableS, *lastElement.EHashTableS, *nextElement.EHashTableS
 Protected tablePosition.i
 If *this = #Null Or key$ = ""
  ProcedureReturn #Null
 EndIf
 *object = *this
 tablePosition = SizeOf(INTEGER) * *object\hash(key$, *object\tableSize)
 *nextElement = PeekI(*object\table + tablePosition)
 If *nextElement
  If *nextElement\key = key$
   PokeI(*object\table + tablePosition, *nextElement\after)
   FreeMemory(*nextElement)
   *object\size - 1
   ProcedureReturn *nextElement + SizeOf(EHashTableS)
  Else
   While *nextElement\after And *nextElement\key <> key$
    *lastElement = *nextElement
    *nextElement = *nextElement\after
   Wend
   If *nextElement\key = key$
    *lastElement\after = *nextElement\after
    FreeMemory(*nextElement)
    *object\size - 1
    ProcedureReturn *nextElement + SizeOf(EHashTableS)
   EndIf
  EndIf
 EndIf
 ProcedureReturn #Null
EndProcedure


Procedure.i HashTableS_size(*this.IHashTableS)
 Protected *object.OHashTableS
 If *this = #Null
  ProcedureReturn 0
 EndIf
 *object = *this
 ProcedureReturn *object\size
EndProcedure


Procedure.i HashTableS_clear(*this.IHashTableS)
 Protected *object.OHashTableS, *entry.INTEGER, *element.EHashTableS, *nextElement.EHashTableS
 If *this = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *entry = *object\table
 For i = 1 To *object\tableSize
  *nextElement = *entry\i
  If *nextElement
   Repeat
    *element = *nextElement
    *nextElement = *nextElement\after
    FreeMemory(*element)
   Until *nextElement = #Null
  EndIf
  *entry\i = #Null
  *entry + SizeOf(INTEGER)
 Next
 *object\size = 0
 ProcedureReturn #True
EndProcedure


Procedure.i HashTableS_getHashFunction(*this.IHashTableS)
 Protected *object.OHashTableS
 If *this = #Null
  ProcedureReturn #Null
 EndIf
 *object = *this
 ProcedureReturn *object\hash
EndProcedure


Procedure.i HashTableS_setHashFunction(*this.IHashTableS, hash.HashFunctionS)
 Protected *object.OHashTableS
 If *this = #Null Or hash = #Null
  ProcedureReturn #False
 EndIf
 *object = *this
 *object\hash = hash
 ProcedureReturn #True
EndProcedure


Procedure HashTableS_delete(*this.IHashTableS)
 Protected *object.OHashTableS
 If *this = #Null
  ProcedureReturn
 EndIf
 *object = *this
 *this\clear()
 FreeMemory(*object\table)
 FreeMemory(*object)
EndProcedure


Procedure.i HashTableS_defaultHashFunction(key$, limit.i)
 ProcedureReturn (CRC32Fingerprint(@key$, StringByteLength(key$), $00000000) & $7FFFFFFF) % limit
EndProcedure
FilterInterpreter.pb

Code: Select all

XIncludeFile "CImageFilter.pbi"
XIncludeFile "CHashTableS.pbi"

UseJPEG2000ImageDecoder()
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTGAImageDecoder()
UseTIFFImageDecoder()

UseJPEGImageEncoder()
UsePNGImageEncoder()


;string to type macros
Macro s_(var,  i) : StringField(var + Chr(1), i, Chr(1))            : EndMacro
Macro st_(var, i) : TrimQuote(StringField(var + Chr(1), i, Chr(1))) : EndMacro
Macro i_(var,  i) : Val(StringField(var + Chr(1), i, Chr(1)))       : EndMacro
Macro f_(var,  i) : ValF(StringField(var + Chr(1), i, Chr(1)))      : EndMacro
Macro out_(text = " ") : PrintR("", text) : EndMacro


#MaxImageInstancesPerLine = 3
CompilerIf #PB_Compiler_Unicode
 #P_Version = "1.00 Unicode Beta"
CompilerElse
 #P_Version = "1.00 Ascii Beta"
CompilerEndIf

Structure COMMAND_STRUC
 method.s
 params.s
 line.i
EndStructure

Structure IMAGE_STRUC
 name.s
 file.s
 id.i
 instance.IImageFilter
EndStructure

Structure GARBAGE_STRUC
 nameCount.i
 imgNames.s[#MaxImageInstancesPerLine]
EndStructure

Structure GCINIT_STRUC
 lastLine.i
EndStructure


Global NewList prog.COMMAND_STRUC()
Global images.IHashTableS = newHashTables(SizeOf(IMAGE_STRUC), 100)
Global Dim gc.GARBAGE_STRUC(0)


Declare   PrintR(String$, Line$ = "")
Declare.s TrimQuote(String$)
Declare.i parseLine(Line$, Number.i)
Declare.i GarbageCollectorInit()
Declare.i GarbageCollectorTest(Line.i)
Declare.i NewInstanceOf(namedImage$, file$)
Declare.i CopyInstanceOf(namedImage$, otherNamedImage$)
Declare.i GetInstanceOf(namedImage$)
Declare.i UpdateInstanceOf(namedImage$)
Declare.i FreeInstanceOf(namedImage$)
Declare.i callCommand(command$, params$) ;functions mapping is done here
Declare   ExitProgram()


Procedure PrintR(String$, Line$ = "")
 If Line$
  PrintN(LSet(Line$, 78, " "))
 EndIf
 If String$
  Print(LSet(String$, 78, " ") + Chr(13))
 EndIf
EndProcedure


Procedure.s TrimQuote(String$)
 If Asc(Left(String$, 1)) = '"' And Asc(Right(String$, 1)) = '"'
  ProcedureReturn Mid(String$, 2, Len(String$) - 2)
 EndIf
 ProcedureReturn String$
EndProcedure


Procedure.i parseLine(Line$, Number.i)
 Protected *char.CHARACTER, *finalChar.CHARACTER, isLoad.i, isCommand.i, inString.i
 Protected strLen.i, stringStart.c
 Line$ = Trim(Line$)
 If Line$ = "" Or Left(Line$, 1) = ";"
  ProcedureReturn #True
 EndIf
 *char = @Line$
 *finalChar = *char + (Len(Line$) * SizeOf(CHARACTER))
 isLoad = #False
 isCommand = #False
 inString = #False
 While *char < *finalChar
  If inString
   Select *char\c
    Case stringStart
     If isCommand
      *char\c = '"'
      inString = #False
     EndIf
   EndSelect
  Else
   Select *char\c
    Case '(', '[', '{', '<'
     If isLoad = #False
      If *char <> @Line$
       isCommand = #True
      EndIf
      *char\c = '('
     EndIf
    Case ')', ']', '}', '>'
     If isLoad = #False
      *char\c = ')'
     EndIf
    Case '"', 39 ;'
     If isCommand
      stringStart = *char\c
      *char\c = '"'
      inString = #True
     EndIf
    Case ','
     If isCommand
      *char\c = 1
     EndIf
    Case 9
     *char\c = ' '
    Case '='
     If isCommand = #False
      isLoad = #True
     EndIf
   EndSelect
  EndIf
  *char + SizeOf(CHARACTER)
 Wend
 If LCase(Line$) = "end"
  AddElement(prog())
  prog()\method = "end"
  prog()\params = ""
  prog()\line = Number
 ElseIf isLoad
  AddElement(prog())
  prog()\method = "loadImage"
  prog()\params = Trim(StringField(Line$, 1, "=")) + Chr(1) + Trim(StringField(Line$, 2, "="))
  prog()\line = Number
 ElseIf isCommand
  Repeat
   strLen = Len(Line$)
   Line$ = ReplaceString(Line$, " ", "")
  Until strLen = Len(Line$)
  If Left(Line$, 1) = ";"
   ProcedureReturn #True
  EndIf
  AddElement(prog())
  prog()\method = StringField(Line$, 1, "(")
  prog()\params = StringField(StringField(Line$, 2, "("), 1, ")")
  prog()\line = Number
 Else
  ProcedureReturn #False
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure.i GarbageCollectorInit()
 Protected gcinit.IHashTableS, *element.GCINIT_STRUC
 Protected paramImgCount.i, lineCount.i
 Protected NewList imgNames.s()
 gcinit = newHashTables(SizeOf(GCINIT_STRUC), 100)
 If gcinit = #Null
  ProcedureReturn #False
 EndIf
 LastElement(prog())
 lineCount = prog()\line
 ForEach prog()
  ;-- auto free images - <
  Select LCase(prog()\method)
   Case "end"
    Break
   Case LCase("loadImage")
    If gcinit\getKey(LCase(s_(prog()\params, 2)))
     paramImgCount = 2
    Else
     paramImgCount = 1
    EndIf
   Case "add", "sub", "mul", "div", "xor", "and", "or", "weight", "difference", LCase("euclidianNorm"), LCase("manhattenNorm")
    paramImgCount = 2
   Case LCase("weightMask")
    paramImgCount = 3
   Default
    paramImgCount = 1
  EndSelect
  For i = 1 To paramImgCount
   If LCase(s_(prog()\params, i)) <> "clipboard" And s_(prog()\params, i) <> ""
    If gcinit\getKey(LCase(s_(prog()\params, i))) = #Null
     AddElement(imgNames())
     imgNames() = LCase(s_(prog()\params, i))
    EndIf
    *element = gcinit\addKey(LCase(s_(prog()\params, i)))
    If *element = #Null
     gcinit\delete()
     ProcedureReturn #False
    EndIf
    *element\lastLine = prog()\line
   EndIf
  Next i
 Next
 ReDim gc(lineCount)
 ForEach imgNames()
  *element = gcinit\getKey(imgNames())
  If *element = #Null
   gcinit\delete()
   ProcedureReturn #False
  EndIf
  If *element\lastLine > lineCount
   gcinit\delete()
   ProcedureReturn #False
  EndIf
  If gc(*element\lastLine)\nameCount >= #MaxImageInstancesPerLine
   gcinit\delete()
   ProcedureReturn #False
  EndIf
  gc(*element\lastLine)\imgNames[gc(*element\lastLine)\nameCount] = imgNames()
  gc(*element\lastLine)\nameCount + 1
 Next
 ClearList(imgNames())
 gcinit\delete()
 ProcedureReturn #True
EndProcedure


Procedure.i GarbageCollectorTest(Line.i)
 If gc(Line)\nameCount = 0
  ProcedureReturn #True
 EndIf
 For i = 0 To gc(Line)\nameCount - 1
  FreeInstanceOf(gc(Line)\imgNames[i])
 Next
 ProcedureReturn #True
EndProcedure


Procedure.i NewInstanceOf(namedImage$, file$)
 Protected nameInUse.i = #False, newImage.i, *element.IMAGE_STRUC
 Protected newInstance.IImageFilter
 namedImage$ = LCase(namedImage$)
 If namedImage$ = ""
  ProcedureReturn #False
 EndIf
 If file$ = "clipboard"
  newImage = GetClipboardImage(#PB_Any)
 Else
  newImage = LoadImage(#PB_Any, file$)
 EndIf
 If newImage = #Null
  ProcedureReturn #False
 EndIf
 If namedImage$ = "clipboard"
  SetClipboardImage(newImage)
  FreeImage(newImage)
  ProcedureReturn #True
 EndIf
 newInstance = newImageFilter(newImage)
 If newInstance = #Null
  FreeImage(newImage)
  ProcedureReturn #False
 EndIf
 newImage = newInstance\getImage()
 *element = images\addKey(namedImage$)
 If *element = #Null
  newInstance\delete()
  FreeImage(newImage)
  ProcedureReturn #False
 EndIf
 If IsImage(*element\id)
  FreeImage(*element\id)
  *element\id = #Null
  *element\instance\delete()
  *element\instance = #Null
 EndIf
 *element\name = namedImage$
 *element\file = file$
 *element\id = newImage
 *element\instance = newInstance
 ProcedureReturn #True
EndProcedure


Procedure.i CopyInstanceOf(namedImage$, otherNamedImage$)
 Protected nameInUse.i = #False, *element.IMAGE_STRUC
 Protected newInstance.IImageFilter, otherInstance.IImageFilter
 namedImage$ = LCase(namedImage$)
 otherNamedImage$ = LCase(otherNamedImage$)
 If namedImage$ = "" Or otherNamedImage$ = "" Or namedImage$ = otherNamedImage$
  ProcedureReturn #False
 EndIf
 otherInstance = GetInstanceOf(otherNamedImage$)
 If otherInstance = #Null
  ProcedureReturn #False
 EndIf
 otherInstance\output()
 If namedImage$ = "clipboard"
  SetClipboardImage(otherInstance\getImage())
  ProcedureReturn #True
 EndIf
 newInstance = newImageFilter(CopyImage(otherInstance\getImage(), #PB_Any))
 If newInstance = #Null
  ProcedureReturn #False
 EndIf
 *element = images\addKey(namedImage$)
 If *element = #Null
  ProcedureReturn #False
 EndIf
 If IsImage(*element\id)
  FreeImage(*element\id)
  *element\id = #Null
  *element\instance\delete()
  *element\instance = #Null
 EndIf
 *element\name = namedImage$
 *element\file = file$
 *element\id = newInstance\getImage()
 *element\instance = newInstance
 ProcedureReturn #True
EndProcedure


Procedure.i GetInstanceOf(namedImage$)
 Protected *element.IMAGE_STRUC
 namedImage$ = LCase(namedImage$)
 If namedImage$ = ""
  ProcedureReturn #Null
 EndIf
 *element = images\getKey(namedImage$)
 If *element
  ProcedureReturn *element\instance
 EndIf
 ProcedureReturn #Null
EndProcedure


Procedure.i UpdateInstanceOf(namedImage$)
 Protected *element.IMAGE_STRUC
 namedImage$ = LCase(namedImage$)
 If namedImage$ = ""
  ProcedureReturn #False
 EndIf
 *element = images\getKey(namedImage$)
 If *element
  If *element\instance
   *element\id = *element\instance\getImage()
   ProcedureReturn #True
  EndIf
 EndIf
 ProcedureReturn #False
EndProcedure


Procedure.i FreeInstanceOf(namedImage$)
 Protected *element.IMAGE_STRUC
 namedImage$ = LCase(namedImage$)
 If namedImage$ = ""
  ProcedureReturn #False
 EndIf
 If namedImage$ = "clipboard"
  ClearClipboard()
  ProcedureReturn #True
 EndIf
 *element = images\getKey(namedImage$)
 If *element
  FreeImage(*element\id)
  *element\instance\delete()
  If images\delKey(namedImage$)
   ProcedureReturn #True
  EndIf
 EndIf
EndProcedure


Procedure.i callCommand(command$, params$) ;functions mapping is done here
 Protected *instance.IImageFilter, *instance2.IImageFilter, *instance3.IImageFilter
 If LCase(command$) = "end"
  out_()
  PrintR("Done.")
  ExitProgram()
 ElseIf LCase(command$) = LCase("loadImage")
  *instance2 = GetInstanceOf(s_(params$, 2))
  If *instance2
   ProcedureReturn CopyInstanceOf(s_(params$, 1), s_(params$, 2))
  Else
   ProcedureReturn NewInstanceOf(s_(params$, 1), s_(params$, 2))
  EndIf
 Else
  *instance = GetInstanceOf(s_(params$, 1))
  If *instance = #Null
   ProcedureReturn #False
  EndIf
  ;-- execute commands - <
  Select LCase(command$)
   Case LCase("saveImage")
    *instance\output()
    Select LCase(GetExtensionPart(st_(params$, 2)))
     Case "bmp"
      If SaveImage(*instance\getImage(), st_(params$, 2), #PB_ImagePlugin_BMP) = #Null
       ProcedureReturn #False
      EndIf
     Case "jpg", "jpe", "jpeg"
      If SaveImage(*instance\getImage(), st_(params$, 2), #PB_ImagePlugin_JPEG, 8) = #Null
       ProcedureReturn #False
      EndIf
     Case "png"
      If SaveImage(*instance\getImage(), st_(params$, 2), #PB_ImagePlugin_PNG) = #Null
       ProcedureReturn #False
      EndIf
     Default
      ProcedureReturn #False
    EndSelect
   Case LCase("free") : ProcedureReturn FreeInstanceOf(s_(params$, 1))
   Case LCase("getWidth")
    out_("width = " + Str(*instance\getWidth()))
   Case LCase("getHeight")
    out_("height = " + Str(*instance\getHeight()))
   Case LCase("getResolution")
    out_("resolution = " + Str(*instance\getWidth()) + "x" + Str(*instance\getHeight()))
   Case LCase("getPixelCount")
    out_("pixels = " + Str(*instance\getPixelCount()))
   Case LCase("getAverage")
    out_("average = " + StrF(*instance\getAverage(i_(params$, 2))))
   Case LCase("getStandardDeviation")
    out_("standard deviation = " + StrF(*instance\getStandardDeviation(i_(params$, 2))))
   Case LCase("getCenterOfMassX")
    out_("center of mass x = " + StrF(*instance\getCenterOfMassX(i_(params$, 2))))
   Case LCase("getCenterOfMassY")
    out_("center of mass y = " + StrF(*instance\getCenterOfMassY(i_(params$, 2))))
   Case LCase("getCenterOfMass")
    out_("center of mass = " + StrF(*instance\getCenterOfMassX(i_(params$, 2))) + ", " + StrF(*instance\getCenterOfMassY(i_(params$, 2))))
   Case LCase("getSemimajorAxisAngle")
    out_("semi-major axis angle = " + StrF(*instance\getSemimajorAxisAngle(i_(params$, 2))))
   Case LCase("getExcentricity")
    out_("excentricity = " + StrF(*instance\getExcentricity(i_(params$, 2))))
   Case LCase("grayscale") : *instance\grayscale()
   Case LCase("invert") : *instance\invert()
   Case LCase("brightness") : *instance\brightness(i_(params$, 2))
   Case LCase("contrast") : *instance\contrast(f_(params$, 2))
   Case LCase("colorScale") : *instance\colorScale(f_(params$, 2), i_(params$, 3))
   Case LCase("gamma") : *instance\gamma(f_(params$, 2))
   Case LCase("normalize") : *instance\normalize()
   Case LCase("mirrorVertical") : *instance\mirrorVertical()
   Case LCase("mirrorHorizontal") : *instance\mirrorHorizontal()
   Case LCase("rotate")
    *instance\rotate(f_(params$, 2), i_(params$, 3), i_(params$, 4))
    ProcedureReturn UpdateInstanceOf(s_(params$, 1))
   Case LCase("resize")
    *instance\resize(i_(params$, 2), i_(params$, 3), i_(params$, 4))
    ProcedureReturn UpdateInstanceOf(s_(params$, 1))
   Case LCase("add")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\add_(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("sub")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\sub_(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("mul")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\mul_(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("div")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\div_(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("xor")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\xor_(*instance2)
   Case LCase("and")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\and_(*instance2)
   Case LCase("or")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\or_(*instance2)
   Case LCase("weight")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\weight(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("weightMask")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance3 = GetInstanceOf(s_(params$, 3))
    If *instance3 = #Null : ProcedureReturn #False : EndIf
    *instance\weightMask(*instance2, *instance3, f_(params$, 4), i_(params$, 5))
   Case LCase("difference")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\difference(*instance2, f_(params$, 3), i_(params$, 4))
   Case LCase("euclidianNorm")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\euclidianNorm(*instance2, i_(params$, 3))
   Case LCase("manhattenNorm")
    *instance2 = GetInstanceOf(s_(params$, 2))
    If *instance2 = #Null : ProcedureReturn #False : EndIf
    *instance\manhattenNorm(*instance2, i_(params$, 3))
   Case LCase("addColorOverlay") : *instance\addColorOverlay(i_(params$, 2), f_(params$, 3))
   Case LCase("removeColorOverlay") : *instance\removeColorOverlay(i_(params$, 2), f_(params$, 3))
   Case LCase("median") : *instance\median(i_(params$, 2))
   Case LCase("nearMedian") : *instance\nearMedian(i_(params$, 2), i_(params$, 3))
   Case LCase("binomial") : *instance\binomial(i_(params$, 2))
   Case LCase("minMax") : *instance\minMax(i_(params$, 2))
   Case LCase("DoG") : *instance\DoG(i_(params$, 2), i_(params$, 3))
   Case LCase("houghTransformation")
    *instance\houghTransformation(i_(params$, 2))
    ProcedureReturn UpdateInstanceOf(s_(params$, 1))
   Case LCase("threshold") : *instance\threshold(i_(params$, 2), i_(params$, 3))
   Case LCase("regionGrowing") : *instance\regionGrowing(i_(params$, 2), i_(params$, 3), i_(params$, 4))
   Case LCase("dilate") : *instance\dilate(i_(params$, 2), st_(params$, 3), i_(params$, 4))
   Case LCase("erode") : *instance\erode(i_(params$, 2), st_(params$, 3), i_(params$, 4))
   Case LCase("closing") : *instance\closing(i_(params$, 2), st_(params$, 3), i_(params$, 4))
   Case LCase("opening") : *instance\opening(i_(params$, 2), st_(params$, 3), i_(params$, 4))
   Case LCase("thin") : *instance\thin(i_(params$, 2), i_(params$, 3))
   Case LCase("skeletonization") : *instance\skeletonization(i_(params$, 2))
   Case LCase("generic") : *instance\generic(st_(params$, 2))
   Case LCase("bswap") : *instance\bswap()
   Default
    ProcedureReturn #False
  EndSelect
 EndIf
 ProcedureReturn #True
EndProcedure


Procedure ExitProgram()
;  Input()
 End
EndProcedure



;----------main--------- <
OpenConsole()

file$ = ProgramParameter(0)

stdin.i = #False
Select LCase(ProgramParameter(0))
 Case "-i", "/i"
  stdin = #True
 Case "-v", "/v", "-version", "--version"
  PrintN("FilterInterpreter " + #P_Version + " - coded by pcfreak")
  ExitProgram()
 Default
  If FileSize(file$) <= 0
   PrintN("FilterInterpreter " + #P_Version + " - coded by pcfreak")
   PrintN("Syntax: [option] [file]")
   PrintN("")
   PrintN("   file    the script file which shell be interpreted")
   PrintN("")
   PrintN("Options:")
   PrintN("   -i      use standard input instead of a file")
   PrintN("   -v      displays the version of the program")
   PrintN("")
   PrintN("no or wrong input will show this help")
   ExitProgram()
  EndIf
EndSelect

If FileSize(file$) > 0 Or stdin
 out_("Reading script file...")
 If stdin
  Index.i = 1
  Repeat
   Line$ = Trim(Input())
   If Line$ <> #PB_Input_Eof
    CompilerIf #PB_Compiler_Unicode
     If Index = 1 And Asc(Left(Line$, 1)) = $FEFF
      Line$ = Right(Line$, Len(Line$) - 1)
     EndIf
    CompilerEndIf
    PrintR("parsing line...", Line$)
    If parseLine(Line$, Index) = #False
     PrintR("error in line " + Str(Index))
     ExitProgram()
    EndIf
    Index + 1
   EndIf
  Until Line$ = #PB_Input_Eof
  If Index = 1
   ExitProgram()
  EndIf
 Else
  FileID.i = ReadFile(#PB_Any, file$)
  If FileID
    BOM = ReadStringFormat(FileID)
    Index.i = 1
    While Eof(FileID) = #False
     Line$ = Trim(ReadString(FileID, BOM))
     PrintR("parsing line...", Line$)
     If parseLine(Line$, Index) = #False
      PrintR("error in line " + Str(Index))
      ExitProgram()
     EndIf
     Index + 1
    Wend
   CloseFile(FileID)
  Else
   out_("Couldn't open file.")
   ExitProgram()
  EndIf
 EndIf
 If GarbageCollectorInit() = #False
  PrintR("internal memory management error")
  ExitProgram()
 EndIf
 out_()
 PrintR("", "Executing commands...")
 ForEach prog()
  PrintR("processing command...", prog()\method + "(" + ReplaceString(prog()\params, Chr(1), ", ") + ")")
  If callCommand(prog()\method, prog()\params) = #False
   PrintR("error in line " + Str(prog()\line))
   ExitProgram()
  EndIf
  GarbageCollectorTest(prog()\line)
 Next
 out_()
 PrintR("Done.")
 ExitProgram()
EndIf
Well it's more like a batch processor.
Here is also some quick guide about the batch processor I just found :p

Code: Select all

Use:
----

FilterInterpreter.exe scriptFile


Input formats:
--------------

 - bmp
 - jp2, jpx
 - jpg, jpe, jpeg
 - png
 - tga
 - tif, tiff


Output formats:
---------------

 - bmp
 - jpg, jpe, jpeg
 - png


Scripting:
----------

Note:
 - each command stands in _one_ line
 - no calculation possible, like 1 + 2
 - every parameter of a function needs to be specified
 - the type of the parameter is given as in the definitions below
 - the default value of each parameter can be used as given in the definitions below
 - image stands for the loaded image and needs to be specified for each command
 - parameters are separated by comma
 - strings can be used by surrounding the expressing with " or '
 - colors can be defined in hex with $AABBGGRR (A = Alpha, B = Blue, G = Green, R = Red)
   example for light gray: $00C0C0C0

Integers:
	1658
	0
	-56156
	%1011010110
	$A3D10C5B

Floats:
	123.518
	1.00
	-32.15

Strings:
	"Hello World!"
	'Testing...'

Comment:
	; in front of each line which shall be a comment


Load file:
	image = C:\file.jpg

Load image from clipboard:
	image = clipboard

Copy image:
	newImage = image

Copy image to clipbaord:
	clipboard = image

Save image:
	saveImage(image, "C:\file.jpg")

Free image:
	free(image)

Free clipboard:
	free(clipboard)

End execution:
	end


Commands:
 information:
	Integer: getWidth(image)
	Integer: getHeight(image)
	String: getResolution(image)
	Integer: getPixelCount(image)
	Float: getAverage(image, Integer: channel = -1)
	Float: getStandardDeviation(image, Integer: channel = -1)
	Float: getCenterOfMassX(image, Integer: channel = -1)
	Float: getCenterOfMassY(image, Integer: channel = -1)
	String: getCenterOfMass(image, Integer: channel = -1)
	Float: getSemimajorAxisAngle(image, Integer: channel = -1)
	Float: getExcentricity(image, Integer: channel = -1)
 color:
	grayscale(image)
	invert(image)
	brightness(image, Integer: delta)
	contrast(image, Float: factor)
	colorScale(image, Float: factor = 1, Integer: delta = 0)
	multiColorScale(image, Float: factor = 1, Integer: deltaColor = 0)
	gamma(image, Float: value)
	normalize(image)
 transform:
	mirrorVertical(image)
	mirrorHorizontal(image)
	rotate(image, Float: angle, Integer: nonBilinear = 0, Integer: resize = 0)
	resize(image, Integer: width, Integer: height, Integer: mode)
	  mode:
	    0 - nearest neighbor
 overlay:
	add(image, srcImage, Float: factor = 1, Integer: delta = 0)
	sub(image, srcImage, Float: factor = 1, Integer: delta = 0)
	mul(image, srcImage, Float: factor = 1, Integer: delta = 0)
	div(image, srcImage, Float: factor = 1, Integer: delta = 0)
	xor(image, srcImage)
	and(image, srcImage)
	or(image, srcImage)
	weight(image, srcImage, Float: factor = 1, Integer: delta = 0)
	weightMask(image, otherImage, maskImage, Float: factor = 1, Integer: delta = 0)
	difference(image, srcImage, Float: factor = 1, Integer: delta = 0)
	euclidianNorm(image, srcImage, Integer: offset)
	manhattenNorm(image, srcImage, Integer: offset)
	addColorOverlay(image, Integer: color, Float: opacity)
	removeColorOverlay(image, Integer: color, Float: opacity)
 denoise:
	median(image, Integer: size)
	nearMedian(image, Integer: normalSize, Integer: nearSize)
	binomial(image, Integer: size)
 edge detection:
	minMax(image, Integer: size)
	DoG(image, Integer: q, Integer: p)
	houghTransformation(image, Integer: threshold)
 segmenting (grayscale):
	threshold(image, Integer: value, Integer: keepColor = 0)
	regionGrowing(image, Integer: x, Integer: y, Integer: maxDelta)
 morphology (segmented):
	dilate(image, Integer: label, String: mask, Integer: times)
	erode(image, Integer: label, String: mask, Integer: times)
	closing(image, Integer: label, String: mask, Integer: times)
	opening(image, Integer: label, String: mask, Integer: times)
	thin(image, Integer: label, Integer: times)
	skeletonization(image, Integer: label)
 others:
	generic(image, String: filter)
	bswap()


Parameter definitions:
 mask:
	|   separates rows
	,   separates columns
	first columns, then rows
	example: "0,1,0|1,1,1|0,1,0"
 filter:
	|   separates rows
	,   separates columns
	;   separates parameters
	first columns, then rows
	first filter matrix, then divisor, then offset
	example: "1,2,1|2,4,2|1,2,1;16;0"
User avatar
dobro
Enthusiast
Enthusiast
Posts: 766
Joined: Sun Oct 31, 2004 10:54 am
Location: France
Contact:

Re: class for image manipulation (OOP)

Post by dobro »

Thanks :)
Image
Windows 98/7/10 - PB 5.42
■ sites : http://michel.dobro.free.fr/
Post Reply