Le même résultat en passant par une liste chainée.
L'exécution est bien plus rapide pour les grandes images, et un grand rayon (en comparaison avec la méthode Array)
Code : Tout sélectionner
;{ procedure
Procedure GetEdgeGray(Array image.a(2), rayon = 1)
w = ArraySize(image(), 1) - 1
h = ArraySize(image(), 2) - 1
Dim image_save.a(w + 1, h + 1)
Dim image_tab.a(w + 1, h + 1)
Dim image_tab2.a(w + 1, h + 1)
Dim *adr.POINT(w + 1, h + 1)
CopyArray(image(), image_tab2())
NewList coord.POINT()
NewList new_coord.POINT()
Macro AjoutPoint(_x_, _y_)
If *adr(_x_, _y_) = 0 And image_tab(_x_, _y_) = 0 And _x_ < w + 1 And _y_ < h + 1 And _x_ > 0 And _y_ > 0
AddElement(new_coord())
*adr(_x_, _y_) = @new_coord()
new_coord()\x = _x_
new_coord()\y = _y_
EndIf
EndMacro
CopyArray(image(), image_tab())
;{ init
For x = 1 To w
For y = 1 To h
If image_tab(x, y) < 255
deltaX_.l = (image_tab(x + 1, y - 1) + image_tab(x + 1, y) << 1 + image_tab(x + 1, y + 1)) - (image_tab(x - 1, y - 1) + image_tab(x - 1, y) << 1 + image_tab(x - 1, y + 1))
deltaY_.l = (image_tab(x - 1, y - 1) + image_tab(x, y - 1) << 1 + image_tab(x + 1, y - 1) ) - (image_tab(x - 1, y + 1) + image_tab(x, y + 1) << 1 + image_tab(x + 1, y + 1))
deltaX.d = deltaX_ / 3
deltaY.d = deltaY_ / 3
gray.l = Sqr(deltaX * deltaX + deltaY * deltaY)
If gray > 0 Or image_tab(x, y) > 0
If image_tab(x, y) > 0
gray = 255 - image_tab(x, y)
ElseIf gray > 255
gray = 255
EndIf
image_tab2(x, y) = gray
;{ ajout des points futurs
If *adr(x, y) <> 0
ChangeCurrentElement(new_coord(), *adr(x, y))
DeleteElement(new_coord())
*adr(x, y) = -1
EndIf
AjoutPoint(x+1, y)
AjoutPoint(x, y+1)
AjoutPoint(x-1, y)
AjoutPoint(x, y-1)
AjoutPoint(x+1, y+1)
AjoutPoint(x+1, y-1)
AjoutPoint(x-1, y+1)
AjoutPoint(x-1, y-1)
;}
If rayon > 1
image_save(x, y) = 255-image_tab(x, y)
Else
image_save(x, y) = gray
EndIf
;Plot(x, y, RGB(image_save(x, y), image_save(x, y), image_save(x, y)))
EndIf
EndIf
Next
Next
;}
;{ boucle normale
For i = 2 To rayon
CopyList(new_coord(), coord())
CopyArray(image_tab2(), image_tab())
Dim *adr.POINT(w + 1, h + 1)
ClearList(new_coord())
ForEach coord()
x = coord()\x
y = coord()\y
If image_save(x, y) < 255
deltaX_.l = (image_tab(x + 1, y - 1) + image_tab(x + 1, y) << 1 + image_tab(x + 1, y + 1)) - (image_tab(x - 1, y - 1) + image_tab(x - 1, y) << 1 + image_tab(x - 1, y + 1))
deltaY_.l = (image_tab(x - 1, y - 1) + image_tab(x, y - 1) << 1 + image_tab(x + 1, y - 1) ) - (image_tab(x - 1, y + 1) + image_tab(x, y + 1) << 1 + image_tab(x + 1, y + 1))
deltaX.d = deltaX_ / 3
deltaY.d = deltaY_ / 3
gray.l = Sqr(deltaX * deltaX + deltaY * deltaY)
If gray > 0 Or image_save(x, y) > 0
If image_tab(x, y) > 0
gray = 255 - image(x, y)
ElseIf gray > 255
gray = 255
EndIf
image_tab2(x, y) = gray
;{ ajout des points futurs
If *adr(x, y) <> 0
ChangeCurrentElement(new_coord(), *adr(x, y))
DeleteElement(new_coord())
*adr(x, y) = -1
EndIf
AjoutPoint(x+1, y)
AjoutPoint(x, y+1)
AjoutPoint(x-1, y)
AjoutPoint(x, y-1)
AjoutPoint(x+1, y+1)
AjoutPoint(x+1, y-1)
AjoutPoint(x-1, y+1)
AjoutPoint(x-1, y-1)
;}
If i < rayon
image_save(x, y) = 255
Else
image_save(x, y) = gray
EndIf
;Plot(x, y, RGB(image_save(x, y), image_save(x, y), image_save(x, y)))
EndIf
EndIf
Next
Next
;}
CopyArray(image_save(), image())
EndProcedure
Procedure DrawRotatedArrayGray(Array image.a(2), centre_x, centre_y, x, y, Angle.d, couleur.l, Antialiasing = #True)
Protected.d Angle_Cos, Angle_Sin
Protected.l w, h, iXc1, iYc1, iXc2, iYc2, iXs, iYs
x - 1
y - 1
red.d = Red(Couleur) / 255
green.d = Green(Couleur) / 255
blue.d = Blue(Couleur) / 255
x_max.l = OutputWidth() - 1
y_max.l = OutputHeight() - 1
Angle_Cos = Cos(Angle)
Angle_Sin = Sin(Angle)
w_source = ArraySize(image(), 1) ;- 1
h_source = ArraySize(image(), 2) ;- 1
w = Int(w_source * Abs(Angle_Cos) + h_source * Abs(Angle_Sin))
h = Int(h_source * Abs(Angle_Cos) + w_source * Abs(Angle_Sin))
iXc1 = w_source >> 1
iYc1 = h_source >> 1
iXc2 = w >> 1
iYc2 = h >> 1
c.d = x + iXc1
d.d = y + iYc1
new_angle.d = ATan2(c, d) + Angle; * #PI / 180
dist.d = Sqr(c * c + d * d)
c = centre_x + dist * Cos(new_angle) - iXc2
d = centre_y + dist * Sin(new_angle) - iYc2
Select Antialiasing
Case #False
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
iXs = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
iYs = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
If iXs >= 0 And iXs < w_source And iYs >= 0 And iYs < h_source
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
color.l = Point(a, b)
tmp.a = 255 - image(iXs, iYs)
; Plot(a, b, RGB(image(iXs, iYs) * red, image(iXs, iYs) * green, image(iXs, iYs) * blue))
Plot(a, b, RGB(image(iXs, iYs) * red + tmp * Red(color) / 255, image(iXs, iYs) * green + tmp * Green(color) / 255, image(iXs, iYs) * blue + tmp * Blue(color) / 255))
EndIf
EndIf
Next
Next
Case #True
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
fXs.d = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
fYs.d = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
; iXs0 = Int(fXs) ; Strange behaviour when pixel have color for fXs, fYs near 0
; iYs0 = Int(fYs)
iXs0 = Round(fXs, #PB_Round_Down)
iYs0 = Round(fYs, #PB_Round_Down)
If iXs0 >= 0 And iXs0 < w_source - 1 And iYs0 >= 0 And iYs0 < h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fYfs1.d = fYs - Int(fYs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0 + 1, iYs0) * fXfs1 + image(iXs0, iYs0) * fXfs1less
ic1.d = image(iXs0 + 1, iYs0 + 1) * fXfs1 + image(iXs0, iYs0 + 1) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0 + fYfs1 * ic1
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
ElseIf iXs0 = w_source - 1 And iYs0 >= 0 And iYs0 < h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fYfs1.d = fYs - Int(fYs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0, iYs0) * fXfs1less
ic1.d = image(iXs0, iYs0 + 1) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0 + fYfs1 * ic1
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
ElseIf iXs0 >= 0 And iXs0 < w_source - 1 And iYs0 = h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0 + 1, iYs0) * fXfs1 + image(iXs0, iYs0) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
EndIf
Next
Next
EndSelect
EndProcedure
;}
;{ fenetre
OpenWindow(0, 0, 0, 800, 600, "LIST", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)
SetActiveGadget(0)
;}
;{ load image
w = 800
h = 400
nb_font = 14
CreateImage(0, w+1, h+1)
Dim font(nb_font)
For i = 0 To nb_font
font(i) = LoadFont(#PB_Any, "Arial", i * 2 + 4)
Next
StartDrawing(ImageOutput(0))
y = 5
For i = 0 To nb_font
DrawingFont(FontID(font(i)))
DrawText(20, 5 + y, "Ceci est un TEST !", #White)
y = y + 1 + TextHeight(" ")
Next
Dim image.a(w+1, h+1)
Dim image2.a(w+1, h+1)
For x = 1 To w
For y = 1 To h
c = Point(x, y)
image(x, y) = (Red(c) + Green(c) + Blue(c)) / 3
Next
Next
StopDrawing()
;}
REDRAW = #True
angle = 20
rayon = 3
;{ boucle principale
Repeat
event = WaitWindowEvent()
;{ event
If event = #PB_Event_Gadget
If EventGadget() = 0
If EventType() = #PB_EventType_KeyDown
Select GetGadgetAttribute(0, #PB_Canvas_Key)
Case #PB_Shortcut_Escape
event = #PB_Event_CloseWindow
Case #PB_Shortcut_Up
REDRAW = #True
angle + 10
If angle > 360 : angle - 360 : EndIf
Case #PB_Shortcut_Down
REDRAW = #True
angle - 10
If angle < 0 : angle + 360 : EndIf
Case #PB_Shortcut_Left
REDRAW = #True
rayon + 1
If rayon > 10 : rayon = 10 : EndIf
Case #PB_Shortcut_Right
REDRAW = #True
rayon - 1
If rayon < 1 : rayon = 1 : EndIf
EndSelect
EndIf
EndIf
EndIf
;}
;{ dessin
If REDRAW
StartDrawing(CanvasOutput(0))
Box(0, 0, OutputWidth(), OutputHeight(), #Blue)
time = ElapsedMilliseconds()
CopyArray(image(), image2())
GetEdgeGray(image2(), rayon)
DrawRotatedArrayGray(image2(), 400, 0, 0, 0, angle * #PI / 180, #Red)
time = ElapsedMilliseconds() - time
DrawText(10, OutputHeight() - 20, Str(time) + " ms")
DrawText(10, OutputHeight() - 40, "Up / Down pour faire varier l'angle (alpha = " + Str(angle) + "°)")
DrawText(10, OutputHeight() - 60, "Left / Rigth pour faire varier le rayon (rayon = " + Str(rayon) + ")")
StopDrawing()
REDRAW = #False
EndIf
;}
Until event = #PB_Event_CloseWindow
;}
End