X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=blobdiff_plain;f=Parasitemia%2FParasitemiaCore%2FImgTools%2FMorpho.fs;h=d2826bf732338762f8e35c42654aecf5d4b2733e;hp=b3a2e759a7e92315c3c23133f6e4e54d464528f6;hb=2d712781def419c9acc98368f7102b19b064f16d;hpb=3f8b0d281b3058faf23dbd0363de440bd04c6574 diff --git a/Parasitemia/ParasitemiaCore/ImgTools/Morpho.fs b/Parasitemia/ParasitemiaCore/ImgTools/Morpho.fs index b3a2e75..d2826bf 100644 --- a/Parasitemia/ParasitemiaCore/ImgTools/Morpho.fs +++ b/Parasitemia/ParasitemiaCore/ImgTools/Morpho.fs @@ -13,139 +13,124 @@ open Types /// /// Remove M-adjacent pixels. It may be used after thinning. /// -let suppressMAdjacency (img: Matrix) = +let suppressMAdjacency (img : Matrix) = let w = img.Width let h = img.Height - for i in 1 .. h - 2 do - for j in 1 .. w - 2 do - if img.[i, j] > 0uy && img.Data.[i + 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i - 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i - 1, j - 1] = 0uy) - then + for i = 1 to h - 2 do + for j = 1 to w - 2 do + if img.[i, j] > 0uy && img.Data.[i + 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i - 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i - 1, j - 1] = 0uy) then img.[i, j] <- 0uy - for i in 1 .. h - 2 do - for j in 1 .. w - 2 do - if img.[i, j] > 0uy && img.Data.[i - 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i + 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i + 1, j - 1] = 0uy) - then + for i = 1 to h - 2 do + for j = 1 to w - 2 do + if img.[i, j] > 0uy && img.Data.[i - 1, j] > 0uy && (img.Data.[i, j - 1] > 0uy && img.Data.[i + 1, j + 1] = 0uy || img.Data.[i, j + 1] > 0uy && img.Data.[i + 1, j - 1] = 0uy) then img.[i, j] <- 0uy type ExtremumType = | Maxima = 1 | Minima = 2 -let findExtremum (img: Image) (extremumType: ExtremumType) : IEnumerable = +let inline findExtremum (img : Image) (extremumType : ExtremumType) : IEnumerable when 'TDepth : unmanaged = let w = img.Width let h = img.Height let se = [| -1, 0; 0, -1; 1, 0; 0, 1 |] let imgData = img.Data - let suppress: bool[,] = Array2D.zeroCreate h w + let suppress : bool[,] = Array2D.zeroCreate h w - let result = List>() + let result = List> () - let flood (start: Point) : List> = - let sameLevelToCheck = Stack() - let betterLevelToCheck = Stack() - betterLevelToCheck.Push(start) + let flood (start : Point) : List> = + let sameLevelToCheck = Stack () + let betterLevelToCheck = Stack () + betterLevelToCheck.Push start - let result' = List>() + let result' = List> () while betterLevelToCheck.Count > 0 do - let p = betterLevelToCheck.Pop() - if not suppress.[p.Y, p.X] - then + let p = betterLevelToCheck.Pop () + if not suppress.[p.Y, p.X] then suppress.[p.Y, p.X] <- true - sameLevelToCheck.Push(p) - let current = List() + sameLevelToCheck.Push p + let current = List () let mutable betterExists = false while sameLevelToCheck.Count > 0 do - let p' = sameLevelToCheck.Pop() + let p' = sameLevelToCheck.Pop () let currentLevel = imgData.[p'.Y, p'.X, 0] - current.Add(p') |> ignore + current.Add p' |> ignore for i, j in se do let ni = i + p'.Y let nj = j + p'.X - if ni >= 0 && ni < h && nj >= 0 && nj < w - then + if ni >= 0 && ni < h && nj >= 0 && nj < w then let level = imgData.[ni, nj, 0] let notSuppressed = not suppress.[ni, nj] - if level = currentLevel && notSuppressed - then + if notSuppressed && level = currentLevel then suppress.[ni, nj] <- true - sameLevelToCheck.Push(Point(nj, ni)) - elif if extremumType = ExtremumType.Maxima then level > currentLevel else level < currentLevel - then + sameLevelToCheck.Push (Point (nj, ni)) + elif (if extremumType = ExtremumType.Maxima then level > currentLevel else level < currentLevel) then betterExists <- true - if notSuppressed - then - betterLevelToCheck.Push(Point(nj, ni)) + if notSuppressed then + betterLevelToCheck.Push (Point (nj, ni)) - if not betterExists - then - result'.Add(current) + if not betterExists then + result'.Add current result' - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do - let maxima = flood (Point(j, i)) - if maxima.Count > 0 - then - result.AddRange(maxima) + for i = 0 to h - 1 do + for j = 0 to w - 1 do + let maxima = flood (Point (j, i)) + if maxima.Count > 0 then + result.AddRange maxima - result.Select(fun l -> Points(l)) + result.Select (fun l -> Points l) -let findMaxima (img: Image) : IEnumerable = +let inline findMaxima (img : Image) : IEnumerable when 'TDepth : unmanaged = findExtremum img ExtremumType.Maxima -let findMinima (img: Image) : IEnumerable = +let inline findMinima (img : Image) : IEnumerable when 'TDepth : unmanaged = findExtremum img ExtremumType.Minima type PriorityQueue () = let size = 256 - let q: Points[] = Array.init size (fun i -> Points()) + let q : Points[] = Array.init size (fun i -> Points ()) let mutable highest = -1 // Value of the first elements of 'q'. let mutable lowest = size member this.NextMax () : byte * Point = - if this.IsEmpty - then + if this.IsEmpty then invalidOp "Queue is empty" else let l = q.[highest] - let next = l.First() - l.Remove(next) |> ignore + let next = l.First () + l.Remove next |> ignore let value = byte highest - if l.Count = 0 - then + if l.Count = 0 then highest <- highest - 1 while highest > lowest && q.[highest].Count = 0 do highest <- highest - 1 - if highest = lowest - then + if highest = lowest then highest <- -1 lowest <- size value, next member this.NextMin () : byte * Point = - if this.IsEmpty - then + if this.IsEmpty then invalidOp "Queue is empty" else let l = q.[lowest + 1] - let next = l.First() - l.Remove(next) |> ignore + let next = l.First () + l.Remove next |> ignore let value = byte (lowest + 1) - if l.Count = 0 - then + if l.Count = 0 then lowest <- lowest + 1 while lowest < highest && q.[lowest + 1].Count = 0 do lowest <- lowest + 1 - if highest = lowest - then + if highest = lowest then highest <- -1 lowest <- size @@ -157,35 +142,29 @@ type PriorityQueue () = member this.Min = lowest + 1 |> byte - member this.Add (value: byte) (p: Point) = + member this.Add (value : byte) (p : Point) = let vi = int value - if vi > highest - then + if vi > highest then highest <- vi - if vi <= lowest - then + if vi <= lowest then lowest <- vi - 1 - q.[vi].Add(p) |> ignore + q.[vi].Add p |> ignore - member this.Remove (value: byte) (p: Point) = + member this.Remove (value : byte) (p : Point) = let vi = int value - if q.[vi].Remove(p) && q.[vi].Count = 0 - then - if vi = highest - then + if q.[vi].Remove p && q.[vi].Count = 0 then + if vi = highest then highest <- highest - 1 while highest > lowest && q.[highest].Count = 0 do highest <- highest - 1 - elif vi - 1 = lowest - then + elif vi - 1 = lowest then lowest <- lowest + 1 while lowest < highest && q.[lowest + 1].Count = 0 do lowest <- lowest + 1 - if highest = lowest // The queue is now empty. - then + if highest = lowest then // The queue is now empty. highest <- -1 lowest <- size @@ -194,7 +173,7 @@ type PriorityQueue () = member this.Clear () = while highest > lowest do - q.[highest].Clear() + q.[highest].Clear () highest <- highest - 1 highest <- -1 lowest <- size @@ -209,130 +188,115 @@ type private AreaOperation = | Closing = 2 [] -type private Area (elements: Points) = +type private Area (elements : Points) = member this.Elements = elements member val Intensity = None with get, set member val State = AreaState.Unprocessed with get, set -let private areaOperation (img: Image) (area: int) (op: AreaOperation) = +let private areaOperation (img : Image) (area : int) (op : AreaOperation) = let w = img.Width let h = img.Height let imgData = img.Data let se = [| -1, 0; 0, -1; 1, 0; 0, 1 |] - let areas = List((if op = AreaOperation.Opening then findMaxima img else findMinima img) |> Seq.map Area) + let areas = List ((if op = AreaOperation.Opening then findMaxima img else findMinima img) |> Seq.map Area) - let pixels: Area[,] = Array2D.create h w null + let pixels : Area[,] = Array2D.create h w null for m in areas do for e in m.Elements do pixels.[e.Y, e.X] <- m - let queue = PriorityQueue() + let queue = PriorityQueue () - let addEdgeToQueue (elements: Points) = + let addEdgeToQueue (elements : Points) = for p in elements do for i, j in se do let ni = i + p.Y let nj = j + p.X - let p' = Point(nj, ni) - if ni >= 0 && ni < h && nj >= 0 && nj < w && not (elements.Contains(p')) - then + let p' = Point (nj, ni) + if ni >= 0 && ni < h && nj >= 0 && nj < w && not (elements.Contains p') then queue.Add (imgData.[ni, nj, 0]) p' // Reverse order is quicker. - for i in areas.Count - 1 .. -1 .. 0 do + for i = areas.Count - 1 downto 0 do let m = areas.[i] - if m.Elements.Count <= area && m.State <> AreaState.Removed - then - queue.Clear() + if m.Elements.Count <= area && m.State <> AreaState.Removed then + queue.Clear () addEdgeToQueue m.Elements let mutable intensity = if op = AreaOperation.Opening then queue.Max else queue.Min - let nextElements = Points() + let nextElements = Points () let mutable stop = false while not stop do let intensity', p = if op = AreaOperation.Opening then queue.NextMax () else queue.NextMin () let mutable merged = false - if intensity' = intensity // The intensity doesn't change. - then - if m.Elements.Count + nextElements.Count + 1 > area - then + if intensity' = intensity then // The intensity doesn't change. + if m.Elements.Count + nextElements.Count + 1 > area then m.State <- AreaState.Validated m.Intensity <- Some intensity stop <- true else - nextElements.Add(p) |> ignore + nextElements.Add p |> ignore - elif if op = AreaOperation.Opening then intensity' < intensity else intensity' > intensity - then - m.Elements.UnionWith(nextElements) + elif (if op = AreaOperation.Opening then intensity' < intensity else intensity' > intensity) then + m.Elements.UnionWith nextElements for e in nextElements do pixels.[e.Y, e.X] <- m - if m.Elements.Count = area - then + if m.Elements.Count = area then m.State <- AreaState.Validated m.Intensity <- Some (intensity') stop <- true else intensity <- intensity' - nextElements.Clear() - nextElements.Add(p) |> ignore + nextElements.Clear () + nextElements.Add p |> ignore else match pixels.[p.Y, p.X] with | null -> () | m' -> - if m'.Elements.Count + m.Elements.Count <= area - then + if m'.Elements.Count + m.Elements.Count <= area then m'.State <- AreaState.Removed for e in m'.Elements do pixels.[e.Y, e.X] <- m queue.Remove imgData.[e.Y, e.X, 0] e addEdgeToQueue m'.Elements - m.Elements.UnionWith(m'.Elements) + m.Elements.UnionWith m'.Elements let intensityMax = if op = AreaOperation.Opening then queue.Max else queue.Min - if intensityMax <> intensity - then + if intensityMax <> intensity then intensity <- intensityMax - nextElements.Clear() + nextElements.Clear () merged <- true - if not merged - then + if not merged then m.State <- AreaState.Validated m.Intensity <- Some (intensity) stop <- true - if not stop && not merged - then + if not stop && not merged then for i, j in se do let ni = i + p.Y let nj = j + p.X - let p' = Point(nj, ni) - if ni < 0 || ni >= h || nj < 0 || nj >= w - then + let p' = Point (nj, ni) + if ni < 0 || ni >= h || nj < 0 || nj >= w then m.State <- AreaState.Validated m.Intensity <- Some (intensity) stop <- true - elif not (m.Elements.Contains(p')) && not (nextElements.Contains(p')) - then + elif not (m.Elements.Contains p') && not (nextElements.Contains p') then queue.Add (imgData.[ni, nj, 0]) p' - if queue.IsEmpty - then - if m.Elements.Count + nextElements.Count <= area - then + if queue.IsEmpty then + if m.Elements.Count + nextElements.Count <= area then m.State <- AreaState.Validated m.Intensity <- Some intensity' - m.Elements.UnionWith(nextElements) + m.Elements.UnionWith nextElements stop <- true for m in areas do - if m.State = AreaState.Validated - then + if m.State = AreaState.Validated then match m.Intensity with | Some i -> for p in m.Elements do @@ -343,107 +307,101 @@ let private areaOperation (img: Image) (area: int) (op: AreaOperatio /// /// Area opening on byte image. /// -let areaOpen (img: Image) (area: int) = +let areaOpen (img : Image) (area : int) = areaOperation img area AreaOperation.Opening /// /// Area closing on byte image. /// -let areaClose (img: Image) (area: int) = +let areaClose (img : Image) (area : int) = areaOperation img area AreaOperation.Closing // A simpler algorithm than 'areaOpen' on byte image but slower. -let areaOpen2 (img: Image) (area: int) = +let areaOpen2 (img : Image) (area : int) = let w = img.Width let h = img.Height let imgData = img.Data let se = [| -1, 0; 0, -1; 1, 0; 0, 1 |] let histogram = Array.zeroCreate 256 - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do + for i = 0 to h - 1 do + for j = 0 to w - 1 do let v = imgData.[i, j, 0] |> int histogram.[v] <- histogram.[v] + 1 let flooded : bool[,] = Array2D.zeroCreate h w - let pointsChecked = HashSet() - let pointsToCheck = Stack() + let pointsChecked = HashSet () + let pointsToCheck = Stack () - for level in 255 .. -1 .. 0 do + for level = 255 downto 0 do let mutable n = histogram.[level] - if n > 0 - then - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do - if not flooded.[i, j] && imgData.[i, j, 0] = byte level - then + if n > 0 then + for i = 0 to h - 1 do + for j = 0 to w - 1 do + if not flooded.[i, j] && imgData.[i, j, 0] = byte level then let mutable maxNeighborValue = 0uy - pointsChecked.Clear() - pointsToCheck.Clear() - pointsToCheck.Push(Point(j, i)) + pointsChecked.Clear () + pointsToCheck.Clear () + pointsToCheck.Push (Point (j, i)) while pointsToCheck.Count > 0 do - let next = pointsToCheck.Pop() - pointsChecked.Add(next) |> ignore + let next = pointsToCheck.Pop () + pointsChecked.Add next |> ignore flooded.[next.Y, next.X] <- true for nx, ny in se do - let p = Point(next.X + nx, next.Y + ny) - if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h - then + let p = Point (next.X + nx, next.Y + ny) + if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h then let v = imgData.[p.Y, p.X, 0] - if v = byte level - then - if not (pointsChecked.Contains(p)) - then - pointsToCheck.Push(p) - elif v > maxNeighborValue - then + if v = byte level then + if not (pointsChecked.Contains p) then + pointsToCheck.Push p + elif v > maxNeighborValue then maxNeighborValue <- v - if int maxNeighborValue < level && pointsChecked.Count <= area - then + if int maxNeighborValue < level && pointsChecked.Count <= area then for p in pointsChecked do imgData.[p.Y, p.X, 0] <- maxNeighborValue [] -type Island (cmp: IComparer) = - member val Shore = Heap.Heap(cmp) with get +type Island (cmp : IComparer) = + member val Shore = Heap.Heap cmp with get member val Level = 0.f with get, set member val Surface = 0 with get, set member this.IsInfinite = this.Surface = Int32.MaxValue -let private areaOperationF (img: Image) (areas: (int * 'a) list) (f: ('a -> float32 -> unit) option) (op: AreaOperation) = +let private areaOperationF (img : Image) (areas : (int * 'a) list) (f : ('a -> float32 -> unit) option) (op : AreaOperation) = let w = img.Width let h = img.Height let earth = img.Data let se = [| -1, 0; 0, -1; 1, 0; 0, 1 |] - let comparer = if op = AreaOperation.Opening - then { new IComparer with member this.Compare(v1, v2) = v1.CompareTo(v2) } - else { new IComparer with member this.Compare(v1, v2) = v2.CompareTo(v1) } + let comparer = + if op = AreaOperation.Opening then + { new IComparer with member this.Compare (v1, v2) = v1.CompareTo v2 } + else + { new IComparer with member this.Compare (v1, v2) = v2.CompareTo v1 } - let ownership: Island[,] = Array2D.create h w null + let ownership : Island[,] = Array2D.create h w null // Initialize islands with their shore. - let islands = List() + let islands = List () let extremum = img |> if op = AreaOperation.Opening then findMaxima else findMinima for e in extremum do let island = - let p = e.First() - Island(comparer, Level = earth.[p.Y, p.X, 0], Surface = e.Count) - islands.Add(island) - let shorePoints = Points() + let p = e.First () + Island (comparer, Level = earth.[p.Y, p.X, 0], Surface = e.Count) + islands.Add island + let shorePoints = Points () for p in e do ownership.[p.Y, p.X] <- island for i, j in se do let ni = i + p.Y let nj = j + p.X - let neighbor = Point(nj, ni) - if ni >= 0 && ni < h && nj >= 0 && nj < w && Object.ReferenceEquals(ownership.[ni, nj], null) && not (shorePoints.Contains(neighbor)) - then - shorePoints.Add(neighbor) |> ignore + let neighbor = Point (nj, ni) + if ni >= 0 && ni < h && nj >= 0 && nj < w && Object.ReferenceEquals (ownership.[ni, nj], null) && not (shorePoints.Contains neighbor) then + shorePoints.Add neighbor |> ignore island.Shore.Add earth.[ni, nj, 0] neighbor for area, obj in areas do @@ -451,7 +409,7 @@ let private areaOperationF (img: Image) (areas: (int * 'a) list) let mutable stop = island.Shore.IsEmpty // 'true' if 'p' is owned or adjacent to 'island'. - let inline ownedOrAdjacent (p: Point) : bool = + let inline ownedOrAdjacent (p : Point) : bool = ownership.[p.Y, p.X] = island || (p.Y > 0 && ownership.[p.Y - 1, p.X] = island) || (p.Y < h - 1 && ownership.[p.Y + 1, p.X] = island) || @@ -461,54 +419,47 @@ let private areaOperationF (img: Image) (areas: (int * 'a) list) while not stop && island.Surface < area do let level, next = island.Shore.Max let other = ownership.[next.Y, next.X] - if other = island // During merging, some points on the shore may be owned by the island itself -> ignored. - then + if other = island then // During merging, some points on the shore may be owned by the island itself -> ignored. island.Shore.RemoveNext () else - if not <| Object.ReferenceEquals(other, null) - then // We touching another island. - if island.IsInfinite || other.IsInfinite || island.Surface + other.Surface >= area || comparer.Compare(island.Level, other.Level) < 0 - then + if not <| Object.ReferenceEquals (other, null) then + // We touching another island. + if island.IsInfinite || other.IsInfinite || island.Surface + other.Surface >= area || comparer.Compare (island.Level, other.Level) < 0 then stop <- true else // We can merge 'other' into 'surface'. island.Surface <- island.Surface + other.Surface island.Level <- other.Level - // island.Level <- if comparer.Compare(island.Level, other.Level) > 0 then other.Level else island.Level for l, p in other.Shore do let mutable currentY = p.Y + 1 while currentY < h && ownership.[currentY, p.X] = other do ownership.[currentY, p.X] <- island currentY <- currentY + 1 island.Shore.Add l p - other.Shore.Clear() + other.Shore.Clear () - elif comparer.Compare(level, island.Level) > 0 - then + elif comparer.Compare (level, island.Level) > 0 then stop <- true else island.Shore.RemoveNext () for i, j in se do let ni = i + next.Y let nj = j + next.X - if ni < 0 || ni >= h || nj < 0 || nj >= w - then + if ni < 0 || ni >= h || nj < 0 || nj >= w then island.Surface <- Int32.MaxValue stop <- true else - let neighbor = Point(nj, ni) - if not <| ownedOrAdjacent neighbor - then + let neighbor = Point (nj, ni) + if not <| ownedOrAdjacent neighbor then island.Shore.Add earth.[ni, nj, 0] neighbor - if not stop - then + if not stop then ownership.[next.Y, next.X] <- island island.Level <- level island.Surface <- island.Surface + 1 let mutable diff = 0.f - for i in 0 .. h - 1 do - for j in 0 .. w - 1 do + for i = 0 to h - 1 do + for j = 0 to w - 1 do match ownership.[i, j] with | null -> () | island -> @@ -524,13 +475,13 @@ let private areaOperationF (img: Image) (areas: (int * 'a) list) /// /// Area opening on float image. /// -let areaOpenF (img: Image) (area: int) = +let areaOpenF (img : Image) (area : int) = areaOperationF img [ area, () ] None AreaOperation.Opening /// /// Area closing on float image. /// -let areaCloseF (img: Image) (area: int) = +let areaCloseF (img : Image) (area : int) = areaOperationF img [ area, () ] None AreaOperation.Closing /// @@ -538,20 +489,20 @@ let areaCloseF (img: Image) (area: int) = /// For each area the function 'f' is called with the associated area value of type 'a and the volume difference /// Between the previous and the current closing. /// -let areaOpenFWithFun (img: Image) (areas: (int * 'a) list) (f: 'a -> float32 -> unit) = +let areaOpenFWithFun (img : Image) (areas : (int * 'a) list) (f : 'a -> float32 -> unit) = areaOperationF img areas (Some f) AreaOperation.Opening /// /// Same as 'areaOpenFWithFun' for closing operation. /// -let areaCloseFWithFun (img: Image) (areas: (int * 'a) list) (f: 'a -> float32 -> unit) = +let areaCloseFWithFun (img : Image) (areas : (int * 'a) list) (f : 'a -> float32 -> unit) = areaOperationF img areas (Some f) AreaOperation.Closing /// /// Zhang and Suen thinning algorithm. /// Modify 'mat' in place. /// -let thin (mat: Matrix) = +let thin (mat : Matrix) = let w = mat.Width let h = mat.Height let mutable data1 = mat.Data @@ -562,10 +513,9 @@ let thin (mat: Matrix) = while pixelChanged do pixelChanged <- false - for i in 0..h-1 do - for j in 0..w-1 do - if data1.[i, j] = 1uy - then + for i = 0 to h - 1 do + for j = 0 to w - 1 do + if data1.[i, j] = 1uy then let p2 = if i = 0 then 0uy else data1.[i-1, j] let p3 = if i = 0 || j = w-1 then 0uy else data1.[i-1, j+1] let p4 = if j = w-1 then 0uy else data1.[i, j+1] @@ -585,9 +535,10 @@ let thin (mat: Matrix) = (if p7 = 0uy && p8 = 1uy then 1 else 0) + (if p8 = 0uy && p9 = 1uy then 1 else 0) + (if p9 = 0uy && p2 = 1uy then 1 else 0) = 1 && - if oddIteration - then p2 * p4 * p6 = 0uy && p4 * p6 * p8 = 0uy - else p2 * p4 * p8 = 0uy && p2 * p6 * p8 = 0uy + if oddIteration then + p2 * p4 * p6 = 0uy && p4 * p6 * p8 = 0uy + else + p2 * p4 * p8 = 0uy && p2 * p6 * p8 = 0uy then data2.[i, j] <- 0uy pixelChanged <- true @@ -603,7 +554,7 @@ let thin (mat: Matrix) = /// Remove all 8-connected pixels with an area equal or greater than 'areaSize'. /// Modify 'mat' in place. /// -let removeArea (mat: Matrix) (areaSize: int) = +let removeArea (mat : Matrix) (areaSize : int) = let neighbors = [| (-1, 0) // p2 (-1, 1) // p3 @@ -614,57 +565,52 @@ let removeArea (mat: Matrix) (areaSize: int) = ( 0, -1) // p8 (-1, -1) |] // p9 - use mat' = new Matrix(mat.Size) + use mat' = new Matrix (mat.Size) let w = mat'.Width let h = mat'.Height - mat.CopyTo(mat') + mat.CopyTo mat' let data = mat.Data let data' = mat'.Data - for i in 0..h-1 do - for j in 0..w-1 do - if data'.[i, j] = 1uy - then - let neighborhood = List() - let neighborsToCheck = Stack() - neighborsToCheck.Push(Point(j, i)) + for i = 0 to h - 1 do + for j = 0 to w - 1 do + if data'.[i, j] = 1uy then + let neighborhood = List () + let neighborsToCheck = Stack () + neighborsToCheck.Push (Point (j, i)) data'.[i, j] <- 0uy while neighborsToCheck.Count > 0 do - let n = neighborsToCheck.Pop() - neighborhood.Add(n) + let n = neighborsToCheck.Pop () + neighborhood.Add n for (ni, nj) in neighbors do let pi = n.Y + ni let pj = n.X + nj - if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy - then - neighborsToCheck.Push(Point(pj, pi)) + if pi >= 0 && pi < h && pj >= 0 && pj < w && data'.[pi, pj] = 1uy then + neighborsToCheck.Push (Point (pj, pi)) data'.[pi, pj] <- 0uy - if neighborhood.Count <= areaSize - then + if neighborhood.Count <= areaSize then for n in neighborhood do data.[n.Y, n.X] <- 0uy -let connectedComponents (img: Image) (startPoints: List) : Points = +let connectedComponents (img : Image) (startPoints : List) : Points = let w = img.Width let h = img.Height - let pointChecked = Points() - let pointToCheck = Stack(startPoints); + let pointChecked = Points () + let pointToCheck = Stack startPoints; let data = img.Data while pointToCheck.Count > 0 do - let next = pointToCheck.Pop() - pointChecked.Add(next) |> ignore - for ny in -1 .. 1 do - for nx in -1 .. 1 do - if ny <> 0 && nx <> 0 - then - let p = Point(next.X + nx, next.Y + ny) - if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h && data.[p.Y, p.X, 0] > 0uy && not (pointChecked.Contains p) - then - pointToCheck.Push(p) + let next = pointToCheck.Pop () + pointChecked.Add next |> ignore + for ny = -1 to 1 do + for nx = -1 to 1 do + if ny <> 0 && nx <> 0 then + let p = Point (next.X + nx, next.Y + ny) + if p.X >= 0 && p.X < w && p.Y >= 0 && p.Y < h && data.[p.Y, p.X, 0] > 0uy && not (pointChecked.Contains p) then + pointToCheck.Push p pointChecked