我实现了填充孔算法,字节0的值被用作背景,因为我需要先实现一个填充算法算法。
如果我使用check8获取当前像素的TopLeft,Left或BotLeft的位置,我的代码会给我一个Stack Overflow异常。
但如果我只使用Top,TopRight,Right,BotRight和Bot,那就没问题了
我使用仪器分配工具进行了检查,是的,我收到了很多malloc调用。
但我不知道为什么会这样。
let FillHoles (img : Bitmap) =
let bd = img.LockBits(Rectangle(0,0,img.Width,img.Height),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb)
let mutable (p:nativeptr<byte>) = NativePtr.ofNativeInt (bd.Scan0)
let rec check8 (point:nativeptr<byte>) x y =
try
if (x>=0 && x<=img.Width-1 && y>=0 && y<=img.Height-1)then
if((NativePtr.get point 0)=(byte 0)) then
NativePtr.set point 0 (byte 255)
// if (x<>0) then
// check8 (NativePtr.add point -4) (x-1) y //Left -4
// if (x<>0 && y<>0) then
// check8 (NativePtr.add point -(bd.Stride + 4)) (x-1) (y-1) //TopLeft
if (y<>0) then
check8 (NativePtr.add point -(bd.Stride)) x (y-1) //Top
if (x<>img.Width-1 && y<>0) then
check8 (NativePtr.add point -(bd.Stride - 4)) (x+1) (y-1) //TopRight
if (x<img.Width-1) then
check8 (NativePtr.add point 4) (x+1) y //Right
if (x<>img.Width-1 && y<>img.Height-1) then
check8 (NativePtr.add point (bd.Stride + 4)) (x+1) (y+1) //BotRight
if (y<>img.Height-1) then
check8 (NativePtr.add point (bd.Stride)) x (y+1) //Bot
// if (x<>0 && y<>img.Height-1) then
// check8 (NativePtr.add point (bd.Stride - 4)) (x-1) (y+1) //BotLeft
with
| :? System.NullReferenceException as ex -> (printfn "%A" ex.Message)
| :? System.StackOverflowException as ex -> (printfn "%A" ex.Message)
for row in 0 .. img.Height-1 do
for col in 0 .. img.Width-1 do
if (row=0 || row=img.Height-1 || col=0 || col=img.Width-1) then
check8 p row col
p <- NativePtr.add p 4
done
done
img.UnlockBits(bd)
img
答案 0 :(得分:2)
在try-catch中不会发生尾调用。请参阅此blog post by the F# Team中的尾部调用是如何编译的?。
答案 1 :(得分:0)
我试图做一个尾递归填充但是我没时间了,所以我用堆栈实现了它。
我无法正确调试它的递归,我的IDE表现得很奇怪,所有堆栈帧可能都在搞乱它。
可能有一种更实用的方法。
let FloodFill (img : Bitmap) =
let bd = img.LockBits(Rectangle(0,0,img.Width,img.Height),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb)
let check4 x y =
let (checkPointer:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*y+x*4)
if(NativePtr.get checkPointer 0 = byte 0) then
let st = Stack()
st.Push(x,y)
while(st.Count > 0) do
let current = st.Pop()
let xx = fst current
let yy = snd current
let (pointer:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*yy+xx*4)
NativePtr.set pointer 0 (byte 255)
if(xx+1<=img.Width-1)then
let (point:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*yy+(xx+1)*4)
if(NativePtr.get point 0 = byte 0) then
st.Push(xx+1,yy)
if(xx-1>=0)then
let (point:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*yy+(xx-1)*4)
if(NativePtr.get point 0 = byte 0) then
st.Push(xx-1,yy)
if(yy+1<=img.Height-1)then
let (point:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*(yy+1)+xx*4)
if(NativePtr.get point 0 = byte 0) then
st.Push(xx,yy+1)
if(yy-1>=0)then
let (point:nativeptr<byte>) = NativePtr.add (NativePtr.ofNativeInt (bd.Scan0)) (bd.Stride*(yy-1)+xx*4)
if(NativePtr.get point 0 = byte 0) then
st.Push(xx,yy-1)
for row in 0 .. img.Height-1 do
for col in 0 .. img.Width-1 do
if (row=0 || row=img.Height-1 || col=0 || col=img.Width-1) then
check4 row col
done
done
img.UnlockBits(bd)
img