Skip to content

Commit 52dff2f

Browse files
committed
CLI using Argu
1 parent aff6163 commit 52dff2f

File tree

3 files changed

+90
-109
lines changed

3 files changed

+90
-109
lines changed

src/ImageProcessing/ImageProcessing.fs

Lines changed: 21 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ let loadAs2DArray (file: string) =
2424
let img = Image.Load<L8> file
2525
let res = Array2D.zeroCreate img.Height img.Width
2626

27-
for i in
28-
0 .. img.Width
29-
- 1 do
30-
for j in
31-
0 .. img.Height
32-
- 1 do
27+
for i in 0 .. img.Width - 1 do
28+
for j in 0 .. img.Height - 1 do
3329
res.[j, i] <- img.Item(i, j).PackedValue
3430

3531
printfn $"H=%A{img.Height} W=%A{img.Width}"
@@ -54,16 +50,8 @@ let save2DByteArrayAsImage (imageData: byte[,]) file =
5450

5551
let flat2Darray array2D =
5652
seq {
57-
for x in
58-
[
59-
0 .. (Array2D.length1 array2D)
60-
- 1
61-
] do
62-
for y in
63-
[
64-
0 .. (Array2D.length2 array2D)
65-
- 1
66-
] do
53+
for x in [0 .. (Array2D.length1 array2D) - 1] do
54+
for y in [0 .. (Array2D.length2 array2D) - 1] do
6755
yield array2D.[x, y]
6856
}
6957
|> Array.ofSeq
@@ -164,31 +152,17 @@ let applyFilter (filter: float32[][]) (img: byte[,]) =
164152
let imgH = img.GetLength 0
165153
let imgW = img.GetLength 1
166154

167-
let filterD =
168-
(Array.length filter)
169-
/ 2
155+
let filterD = (Array.length filter) / 2
170156

171157
let filter = Array.concat filter
172158

173159
let processPixel px py =
174160
let dataToHandle = [|
175-
for i in
176-
px
177-
- filterD .. px
178-
+ filterD do
179-
for j in
180-
py
181-
- filterD .. py
182-
+ filterD do
183-
if
184-
i < 0
185-
|| i >= imgH
186-
|| j < 0
187-
|| j >= imgW
188-
then
189-
float32 img.[px, py]
190-
else
191-
float32 img.[i, j]
161+
for i in px - filterD .. px + filterD do
162+
for j in py - filterD .. py + filterD do
163+
if i < 0 || i >= imgH || j < 0 || j >= imgW
164+
then float32 img.[px, py]
165+
else float32 img.[i, j]
192166
|]
193167

194168
Array.fold2 (fun s x y -> s + x * y) 0.0f filter dataToHandle
@@ -206,42 +180,17 @@ let applyFilterGPUKernel (clContext: ClContext) localWorkSize =
206180
let ph = p / imgW
207181
let mutable res = 0.0f
208182

209-
for i in
210-
ph
211-
- filterD .. ph
212-
+ filterD do
213-
for j in
214-
pw
215-
- filterD .. pw
216-
+ filterD do
183+
for i in ph - filterD .. ph + filterD do
184+
for j in pw - filterD .. pw + filterD do
217185
let mutable d = 0uy
186+
if i < 0 || i >= imgH || j < 0 || j >= imgW
187+
then d <- img.[p]
188+
else d <- img.[i * imgW + j]
218189

219-
if
220-
i < 0
221-
|| i >= imgH
222-
|| j < 0
223-
|| j >= imgW
224-
then
225-
d <- img.[p]
226-
else
227-
d <-
228-
img.[i * imgW
229-
+ j]
230-
231-
let f =
232-
filter.[(i - ph
233-
+ filterD)
234-
* (2
235-
* filterD
236-
+ 1)
237-
+ (j - pw
238-
+ filterD)]
239-
240-
res <-
241-
res
242-
+ (float32 d)
243-
* f
190+
let f = filter.[(i - ph + filterD) * (2 * filterD + 1) +
191+
(j - pw + filterD)]
244192

193+
res <- res + (float32 d) * f
245194
result.[p] <- byte (int res)
246195
@>
247196

@@ -280,23 +229,19 @@ let applyFiltersGPU (clContext: ClContext) localWorkSize =
280229
for filter in filters do
281230
let filter = Array.concat filter
282231

283-
let filterD =
284-
(Array.length filter)
285-
/ 2
232+
let filterD = (Array.length filter) / 2
286233

287234
let clFilter =
288235
clContext.CreateClArray<_>(filter, HostAccessMode.NotAccessible, DeviceAccessMode.ReadOnly)
289236

290237
let oldInput = input
291238
input <- kernel queue clFilter filterD input img.Height img.Width output
292239
output <- oldInput
240+
293241
queue.Post(Msg.CreateFreeMsg clFilter)
294242

295243
let result =
296-
Array.zeroCreate (
297-
img.Height
298-
* img.Width
299-
)
244+
Array.zeroCreate(img.Height * img.Width)
300245

301246
let result = queue.PostAndReply(fun ch -> Msg.CreateToHostMsg(input, result, ch))
302247
queue.Post(Msg.CreateFreeMsg input)

src/ImageProcessing/Main.fs

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,94 @@
11
namespace ImageProcessing
22

3+
open Argu
4+
open Argu.ArguAttributes
35
open Brahma.FSharp
46

7+
type Platforms = CPU = 1 | NVidia = 2 | IntelGPU = 3 | AnyGPU = 4
8+
9+
[<CliPrefix(CliPrefix.DoubleDash)>]
10+
[<NoAppSettings>]
11+
type ImageProcessingArguments =
12+
| [<Mandatory>] Input of string
13+
| Output of string
14+
| Platform of Platforms
15+
with
16+
interface IArgParserTemplate with
17+
member arg.Usage =
18+
match arg with
19+
| Input _ -> "Image to process."
20+
| Output _ -> "File to store result."
21+
| Platform _ -> "Where to run."
522
module Main =
6-
let pathToExamples = "/home/gsv/Projects/TestProj2020/src/ImgProcessing/Examples"
7-
let inputFolder = System.IO.Path.Combine(pathToExamples, "input")
23+
//let pathToExamples = "/home/gsv/Projects/TestProj2020/src/ImgProcessing/Examples"
24+
//let inputFolder = System.IO.Path.Combine(pathToExamples, "input")
25+
//let outputFolder = System.IO.Path.Combine(pathToExamples, "output")
826

9-
let demoFile =
10-
System.IO.Path.Combine(inputFolder, "armin-djuhic-ohc29QXbS-s-unsplash.jpg")
27+
//let demoFileName = "armin-djuhic-ohc29QXbS-s-unsplash.jpg"
28+
//let demoFile =
29+
// System.IO.Path.Combine(inputFolder, demoFileName)
1130

1231
[<EntryPoint>]
1332
let main (argv: string array) =
14-
let nvidiaDevice =
15-
ClDevice.GetAvailableDevices(platform = Platform.Nvidia)
16-
|> Seq.head
17-
18-
let intelDevice =
19-
ClDevice.GetAvailableDevices(platform = Platform.Intel)
20-
|> Seq.head
21-
//ClDevice.GetFirstAppropriateDevice()
22-
//printfn $"Device: %A{device.Name}"
23-
24-
let nvContext = ClContext(nvidiaDevice)
25-
let applyFiltersOnNvGPU = ImageProcessing.applyFiltersGPU nvContext 64
26-
27-
let intelContext = ClContext(intelDevice)
28-
let applyFiltersOnIntelGPU = ImageProcessing.applyFiltersGPU intelContext 64
29-
33+
let parser = ArgumentParser.Create<ImageProcessingArguments>(programName = "ImageProcessing")
34+
let results = parser.ParseCommandLine argv
35+
let inputFile = results.GetResult(Input, defaultValue = "")
36+
let outputFile = results.GetResult(Output, defaultValue = "out.jpg")
37+
let platform = results.GetResult(Platform, defaultValue = Platforms.CPU)
38+
3039
let filters = [
3140
ImageProcessing.gaussianBlurKernel
3241
ImageProcessing.gaussianBlurKernel
3342
ImageProcessing.edgesKernel
3443
]
3544

36-
//let grayscaleImage = ImageProcessing.loadAs2DArray demoFile
37-
//let blur = ImageProcessing.applyFilter ImageProcessing.gaussianBlurKernel grayscaleImage
38-
//let edges = ImageProcessing.applyFilter ImageProcessing.edgesKernel blur
39-
//let edges = applyFiltersGPU [ImageProcessing.gaussianBlurKernel; ImageProcessing.edgesKernel] grayscaleImage
40-
//ImageProcessing.save2DByteArrayAsImage edges "../../../../../out/demo_grayscale.jpg"
45+
46+
match platform with
47+
| Platforms.CPU ->
48+
let mutable image = ImageProcessing.loadAs2DArray inputFile
49+
let start = System.DateTime.Now
50+
for filter in filters do
51+
image <- ImageProcessing.applyFilter filter image
52+
printfn $"CPU processing time: {(System.DateTime.Now - start).TotalMilliseconds} ms"
53+
ImageProcessing.save2DByteArrayAsImage image outputFile
54+
| _ ->
55+
let device =
56+
match platform with
57+
| Platforms.AnyGPU -> ClDevice.GetFirstAppropriateDevice()
58+
| _ ->
59+
let platform =
60+
match platform with
61+
| Platforms.NVidia -> Platform.Nvidia
62+
| Platforms.IntelGPU -> Platform.Intel
63+
ClDevice.GetAvailableDevices(platform = platform)
64+
|> Seq.head
65+
printfn $"Device: %A{device.Name}"
66+
67+
let context = ClContext(device)
68+
let applyFiltersOnGPU = ImageProcessing.applyFiltersGPU context 64
69+
70+
71+
let start = System.DateTime.Now
72+
let grayscaleImage = ImageProcessing.loadAsImage inputFile
73+
printfn $"Image reading time: {(System.DateTime.Now - start).TotalMilliseconds} ms"
74+
75+
let start = System.DateTime.Now
76+
let result = applyFiltersOnGPU filters grayscaleImage
77+
printfn $"GPU processing time: {(System.DateTime.Now - start).TotalMilliseconds} ms"
78+
ImageProcessing.saveImage result outputFile
79+
80+
(*
4181
let start = System.DateTime.Now
4282
43-
Streaming.processAllFiles inputFolder "../../../../../out/" [
44-
applyFiltersOnNvGPU filters
83+
Streaming.processAllFiles inputFolder outputFolder [
84+
//applyFiltersOnNvGPU filters
4585
applyFiltersOnIntelGPU filters
4686
]
4787
4888
printfn
4989
$"TotalTime = %f{(System.DateTime.Now
5090
- start)
5191
.TotalMilliseconds}"
52-
92+
*)
93+
5394
0

src/ImageProcessing/Streaming.fs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,14 @@ let imgSaver outDir =
2626
saveImage img (outFile img.Name)
2727
return! loop ()
2828
}
29-
3029
loop ()
3130
)
3231

3332
let imgProcessor filterApplicator (imgSaver: MailboxProcessor<_>) =
34-
3533
let filter = filterApplicator
36-
3734
MailboxProcessor.Start(fun inbox ->
3835
let rec loop cnt = async {
3936
let! msg = inbox.Receive()
40-
4137
match msg with
4238
| EOS ch ->
4339
printfn "Image processor is ready to finish!"
@@ -50,7 +46,6 @@ let imgProcessor filterApplicator (imgSaver: MailboxProcessor<_>) =
5046
imgSaver.Post(Img filtered)
5147
return! loop (not cnt)
5248
}
53-
5449
loop true
5550
)
5651

0 commit comments

Comments
 (0)