Foto einfügen von der Laptop Kamera



In 50 Zeilen F# Code, inklusive WinForm GUI, Spiegelung, Overlay, JPEG Speicherung und Clipboard.



Der Auslöser für diesen Blog war folgendes:
Ich wollte eine kleine Papier-Handskizze mal schnell in ein Dokument einfügen.

Meine Vorstellung davon:

  1. Zettel vor die Kamera halten
  2. Knopf drücken für das Foto
  3. Einfügen im Dokument via Ctrl+v

Realität in Windows 8.1

  • Also auf meinem Windows 8.1 die Camera-App (ist so eine Metro-App) starten.
  • Notiz vor die Kamera halten
  • Auf Fotografieren klicken.
  • Leeres Clipboard?
    • Da ist leider nichts im Clipboard. Hmmm..
  • Wo ist das Foto?
    • Zurück blättern, clicken bis ein Menu erscheint, da gibts ‘Open with’ und ‘Set as Lockscreen’.
    • Auch unter all den Edit Möglichkeiten, kann man das Foto nicht mit Ctrl+C abholen. Hmmm..
  • Wo sind die Fotos gespeichert?
    • Nach Googeln findet sich
    • C:\Users\DeinUser\Pictures\Camera Roll
    • Mit Drag&Drop ins Dokument damit. Hmmm..
  • Spiegelverkehrt?
    • Wenn ich eine Textnotiz vor die Kamera halte, erscheint diese Spiegelverkehrt. Hmmmm...
All die Hmmms.. verraten, ich finde es nicht praktisch! (Useability?)



Wieviele Zeilen F# Code braucht es dazu?

Kern Problem: Kamera Bild auslesen

Varianten:

  1. mit Windows Mitteln, z.B. WinRT (vorweg genommen, es macht kein Spass)
  2. Open Source Library ;-)

1. WinRT für Desktop! (nicht Windows Phone)

Die benötigte Windows.winmd findet man im Windows SDK:
  1. Installieren von Windows Software Development Kit (SDK) für Windows 8.1 http://msdn.microsoft.com/de-DE/windows/desktop/bg162891
  2. Referenzieren von Windows.winmd Winmd ist ein spezielles IL Format für Windows8 Metro Projekte.
    1: 
    #r "C:\ProgramFiles(x86)\WindowsKits\8.0\References\CommonConfiguration\Neutral\Windows.winmd"
  3. Um *.winmd Files zu nutzen muss das Projekt File noch angepasst werden. Innerhalb PropertyGroup ist TargetPlatformVersion zu wie folgt setzen:
    1: 
    <TargetPlatformVersion>8.0</TargetPlatformVersion>
  4. Die WinRT Unterstützung, d.h. das Referenzieren und Compilieren von .winmd Files, in Visual Studio 2012 ist für F# nicht voll unterstützt.
    1: 
    error FS0193: Could not load file or assembly 'file:///C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
    Man muss daher einen Teil in C# schreiben, um die WinRT auf dem Desktop zu nutzen. Hmmmm...
Ich suche nach einer reibungslosen Lösung. Also nach Open Source Camera Library suchen. AForge http://www.aforgenet.com/framework/ sieht vielversprechend aus!



2. AForge

  1. Via Nuget folgende ins Projekt holen:
    1: 
    2: 
    3: 
    AForge, 
    AForge.Video, 
    AForge.Video.DirectShow
  2. #r und open (siehe Code) und sehen ob meine Camera (im ASUS ZenBook) gefunden wird
    1: 
    FilterInfoCollection( FilterCategory.VideoInputDevice )
    wunderbar, da ist meine “USB2.0 HD UVC WebCam”
    1: 
    2: 
    3: 
    4: 
    5: 
    val it : FilterInfoCollection =
      seq
        [AForge.Video.DirectShow.FilterInfo
           {MonikerString = "@device:pnp:\\?\usb#vid_04f2&pid_b330&mi_00#7&1fa3e1a8&1&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global";
            Name = "USB2.0HDUVCWebCam";}]
  3. Das Bild kommt per NewFrame Event vom VideoCaptureDevice, also verpacken wir das in einer Funktion:
    1: 
    let onImage f = videoDevice.NewFrame.AddHandler(NewFrameEventHandler f)
  4. Die Bild Bearbeitung für die Anzeige soll wie folgt erfolgen.
    1: 
    let showImage _ e = e |> getImage |> mirror() |> overlay() |> show
    Das Datum-Zeit-Overlay dient nur der Anzeige.
  5. Beim Speichern den mirror() nochmals anwenden, falls dieser eingeschaltet war, damit es nicht spiegelverkehrt ist.
    1: 
    let save = getImage |> mirror() |> toClip |> toFile
  6. Um das Pipelining |> mit den GUI Einstellungen der mirrored und overlayed Checkboxen zu steuern, werden diese so definiert
    1: 
    2: 
    let mirror()  = ifThen (fun () -> mirrored.Checked)  (tee Image.mirror) 
    let overlay() = ifThen (fun () -> overlayed.Checked) (tee Overlay.draw)
    mit der Hilfsfunktion ifThen, die die Transformation mittels der Identity Funktion id abschalten kann. Auf tee wird später eingegangen.
    1: 
    let ifThen b f = if b() then f else id
  7. Um das Pipelining bei Seiten Effekten wie ClipBoard befüllen und File erzeugen im Fluss zu halten,
    1: 
    let save = getImage |> mirror() |> toClip |> toFile
    wird toClip mit Hilfe der tee Funktion definiert.
    1: 
    let tee f x = f x;x
    Damit lässt sich der Input wieder zurückgeben.
  8. So kleine Funktionen wie tee darf man nicht unterschätzen, denn deren Wiederverwendbarkeit ist sehr hoch! So auch beim Erstellen der Bedieneroberfläche, mit einem add das auf tee basiert, werden die Controls an die Form form gebunden. Was sich dann mit dem Rückwärts-Pipe <| ganz elegant liest let shot = add <| new Button
    1: 
    2: 
    3: 
    4: 
    5: 
    6: 
    let add x        = tee form.Controls.Add x
    
    let pic          = add <| new PictureBox(SizeMode=PictureBoxSizeMode.AutoSize)
    let shot         = add <| new Button  (Text="capture"  , Dock=DockStyle.Bottom)
    let mirrored     = add <| new CheckBox(Text="mirrored" , Dock=DockStyle.Bottom, Checked=true)
    let overlayed    = add <| new CheckBox(Text="overlayed", Dock=DockStyle.Bottom, Checked=false)
  9. Der Code ist absichtlich so formatiert, alle = untereinander, dass es auffällt, das er nur aus kurzen und lesbaren “Deklarationen” besteht. Ausführen kann man den Code direkt mit Alt+Enter im Visual-Studio.
     1: 
     2: 
     3: 
     4: 
     5: 
     6: 
     7: 
     8: 
     9: 
    10: 
    11: 
    12: 
    13: 
    14: 
    15: 
    16: 
    17: 
    18: 
    19: 
    20: 
    21: 
    22: 
    23: 
    24: 
    25: 
    26: 
    27: 
    28: 
    29: 
    30: 
    31: 
    32: 
    33: 
    34: 
    35: 
    36: 
    37: 
    38: 
    39: 
    40: 
    41: 
    42: 
    43: 
    44: 
    45: 
    46: 
    47: 
    48: 
    49: 
    50: 
    51: 
    // WebCam capture in 50 lines of F#
    #r "System.Windows.Forms.dll"
    #r @"..\packages\AForge.2.2.5\lib\AForge.dll"
    #r @"..\packages\AForge.Video.DirectShow.2.2.5\lib\AForge.Video.DirectShow.dll"
    #r @"..\packages\AForge.Video.2.2.5\lib\AForge.Video.dll"
    open System
    open System.Drawing
    open System.Windows.Forms
    open AForge
    open AForge.Video
    open AForge.Video.DirectShow
    [<AutoOpen>]
    module Composition   =
        let tee    f x   = f x;x        
        let ifThen b f   = if b() then f else id
    module Camera        =
        let myCamIndex   = 0
        let videoInput   = FilterInfoCollection(FilterCategory.VideoInputDevice).Item myCamIndex
        let videoDevice  = VideoCaptureDevice(videoInput.MonikerString)
        let start _      = videoDevice.Start()
        let stop _       = videoDevice.SignalToStop()
        let onImage f    = videoDevice.NewFrame.AddHandler(NewFrameEventHandler f)
    module Time          =      
        let now()        = DateTime.Now.ToString()
        let nowStamp()   = now().Replace('.','_').Replace(':','_').Replace(' ','_')
    module Overlay       =
        let x,y          = 2.0f, 2.0f
        let font,color   = new Font("Arial", 24.0f), Brushes.Green
        let draw image   = use g=Graphics.FromImage image in g.DrawString(Time.now(), font,color, x,y)
    module Image         =
        type I           = Image
        let toClip (i:I) = tee Clipboard.SetImage i
        let toFile (i:I) = i.Save <| @"C:\temp\cam1" + Time.nowStamp() + ".jpeg"
        let mirror (i:I) = i.RotateFlip RotateFlipType.Rotate180FlipY  
    module Gui           =
        type N           = NewFrameEventArgs
        let form         = new Form(TopMost=true, Visible=true, Width=660, Height=600, Text="WebCamcapturein50linesofF#")
        let add x        = tee form.Controls.Add x
        let pic          = add <| new PictureBox(SizeMode=PictureBoxSizeMode.AutoSize)
        let shot         = add <| new Button  (Text="capture"  , Dock=DockStyle.Bottom)
        let mirrored     = add <| new CheckBox(Text="mirrored" , Dock=DockStyle.Bottom, Checked=true)
        let overlayed    = add <| new CheckBox(Text="overlayed", Dock=DockStyle.Bottom, Checked=false)
        let show image   = pic.Image <- image
        let mirror()     = ifThen (fun () -> mirrored.Checked)  (tee Image.mirror)
        let overlay()    = ifThen (fun () -> overlayed.Checked) (tee Overlay.draw)
        let save         = tee shot.Click.Add (fun _ -> pic.Image |> mirror() |> Image.toClip |> Image.toFile)
        let getImage(e:N)= e.Frame.Clone() |> unbox
        let showImage _ e= e |> getImage |> mirror() |> overlay() |> show
    module App           =
        let run()        = Camera.onImage Gui.showImage;  Gui.form.Closing.Add Camera.stop;  Camera.start()
    App.run()
  10. Es macht was es soll an einen verschneiten Dezember Nachmittag. Es ist kein Production Code (mögliche Leaks und module privacy..)
  11. Weitere Ideen und Anregungen Stereo Image mit mehreren USB WebCams http://www.aforgenet.com/framework/samples/video.html Augmented Reality http://www.aforgenet.com/articles/glyph_recognition/ https://www.youtube.com/watch?v=3sEFk4rRcU4&feature=player_embedded
  12. Andere Publikationen zu WebCam Nutzung mit F#:
    1: 
    2: 
    3: 
    4: 
    5: 
    "UsingaWebcamwithDirectShowNETandF#" 
    DirectShow, DirectShowNET
    Luis Diego Fallas 
    Wednesday, February 24, 2010
    http://langexplr.blogspot.ch/2010/02/using-webcam-with-directshownet-and-f.html
    http://langexplr.blogspot.ch/2010/02/using-webcam-with-directshownet-and-f.html
    1: 
    2: 
    3: 
    4: 
    5: 
    "SilverlightF#(Fsharp+XAML)application.AccesstoWebCamusingonlyF#."
    Windows Phone Silverlight
    Vasily Kalugin 
    3/28/2014
    https://code.msdn.microsoft.com/windowsapps/WebCam-Silverlight-F-sharp-f4f50e85 
    https://code.msdn.microsoft.com/windowsapps/WebCam-Silverlight-F-sharp-f4f50e85
Keywords: Kamera, WebCam, AForge, .Net, dotNet, WinForm, F#, FSharp, Pipelining, id, tee, ifThen, DSL, Wiederverwendbarkeit, webcam fsharp, read camera, cam capture, cam recording, foto image captureing, Foto Aufnahme, integrierte Kamera, ASUS ZenBook camera, USB WebCams, PnP Devices
val not : value:bool -> bool Full name: Microsoft.FSharp.Core.Operators.not
Multiple items val seq : sequence:seq<‘T> -> seq<‘T> Full name: Microsoft.FSharp.Core.Operators.seq ——————– type seq<‘T> = System.Collections.Generic.IEnumerable<‘T> Full name: Microsoft.FSharp.Collections.seq<_>
module Checked from Microsoft.FSharp.Core.Operators
val id : x:’T -> ‘T Full name: Microsoft.FSharp.Core.Operators.id
namespace System
namespace System.Drawing
namespace System.Windows
namespace System.Windows.Forms
Multiple items type AutoOpenAttribute = inherit Attribute new : unit -> AutoOpenAttribute new : path:string -> AutoOpenAttribute member Path : string Full name: Microsoft.FSharp.Core.AutoOpenAttribute ——————– new : unit -> AutoOpenAttribute new : path:string -> AutoOpenAttribute
val unbox : value:obj -> ‘T Full name: Microsoft.FSharp.Core.Operators.unbox
namespace Windows

Apple Swift ein F# Klon?

Am 2. Juni hat Apple an der WWDC14 ihre neue Funktionale Programmiersprache präsentiert. Apple’s neue Programmiersprache Swift scheint auf den ersten Blick nahezu ein F# Klon zu sein. Die Syntax von Swift sieht abgesehen von den { } zu verwechseln ähnlich aus wie F#. Wie kommt das? Aus sicherer Quelle ist zu erfahren, dass bei Apple ein ehemaliger Microsoft Mitarbeiter aus dem F# Team für Swift verantwortlich ist. Nun haben jetzt alle dieser drei verbreiteten Plattformen den Schritt in die Funktionale Zukunft gemacht.
  • Microsoft, .Net, Mono :   C#  ->  F#
  • Oracle, JEE / JVM :         Java  ->  Scala
  • Apple, Cocoa, iOS /OSX :   Objective-C  ->  Swift
Interessant ist auch das Erscheinungsdatum der Version 1.0 von wegen Ausgereiftheit und Bekanntheit. Ideal ist es, wenn die Programmiersprache mit sich selber implementiert ist (Bootstrapping, Rekursiver Kompiler, Selbst-Compiler) und der Quellcode offen verfügbar ist (Open Source), denn so hat man die Möglichkeit beim Erlernen der Sprache eine grosse Codebasis zu entdecken und zu studieren. Und man kann sicher sein, dass die Programmiersprache funktioniert, d.h. korrekt ist, denn der Compiler selbst ist ein nicht trivialer Test der kompletten Sprache. Bei F# ist beides gegeben, im Gegensatz zu Scala, das in Java implementiert ist und* Swift das wie bei Apple üblich wohl Closed Source bleiben wird. Mit Roslyn hat Microsoft genau dies für C# und VB.Net vor ein paar Monaten nachgeholt.
  • F# (2005) implementiert in F# (Open Source)
  • Scala (2003) implementiert in Java* Scala (Open Source) 1      2     3       
  • Swift (2014) implementiert in ? (Objective-C or Swift?) (Closed Source)
Den Schritt in die Funktionale Zukunft schon geplant? *) Korrektur: Dank an Soc88 (er hat Wikipedia Scala Eintrag korrigiert)

Die Strukturierung von F# Quellcode

Eine neue Seite zum Thema der Strukturierung von F# Code ist dazugekommen. Es geht um: – warum F# Code so kompakt ist – wie einem die Type-Inferenz behilflich ist sich auf das wesentliche zu Konzentrieren - und wie man dadurch weniger Fehler macht weiterlesen…..

2014 das Jahr der Software Fehler und Sicherheitslecks?

Das Jahr 2014 beginnt mit der Aufdeckung der schlimmsten GOTO Fehlern in Betriebssystemen.

25. Februar : goto fail : Apple iOS, OS X :  SSL-Sicherheitsleck

Diese Lücke besteht angeblich seit 2012.
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail;
Quellen: apple-mac-update-go-fail-ssl-bug , new-ios-flaw , gotofail.com

4. März : goto cleanup : Linux : “GnuTLS bug”

Diese Lücke besteht angeblich seit 2005 ! corrected return codes - Gitorious_2014-03-05_15-18-32 Expertenmeinungen dazu:
It looks pretty terrible. — Matt Green, Johns Hopkins University professor cryptography
has a lot of side effects. — Kenneth White, principal security engineer
Quellen: Sicherheitsluecke-GnuTLS , critical-crypto-bug-linux

Wie lange werden wir noch mit Software Fehlern leben müssen?

Es sind massive Sicherheitsrisiken! Software steckt in vielen Geräten. Anwender und Hersteller sind betroffen. Die von genervten Anwendern, die eine andere Software oder Geräte vorziehen, bis zu Daten-, Geld- und Imageverlust reichen können. Man denke auch an Bereiche der Personensicherheit und Medizintechnik, wo es auch um Menschenleben gehen kann! Wie lange werden wir auch noch mit einer anderen Fehlerquelle der NULL Ausnahmen (Null Pointer Exception, Null Reference Exception) leben müssen?
“I call it my billion-dollar mistake. It was the invention of the null reference in 1965.” — Tony Hoare
Diese Problematik betrifft nahezu alle heute noch verwendeten älteren Programmiersprachen wie z.B. C, C++, Java, VB.Net, C# ! Der Grund ist der Stammbaum, also die Abstammung der Programmiersprachen und deren weitergegebenen Konzepte. Quellen: Null PointerZeiger

Was können wir dagegen tun?

Wie kann man die Software Qualität in seinen Wurzeln verbessern? Indem man für die Softwareentwicklung eine Programmiersprache anwendet, die weder GOTO noch NULL benötigt, die kapitalen Fehler nicht zulässt und dabei den Entwickler aktiv und wachsam unterstützt, so z.B. die immer populärer werdende Programmiersprache F#, die hier auf Functional Software .NET das Thema ist.   Nebenbei bemerkt, wer eine TLS Implementation in F# betrachten will, kann dies hier tun “miTLS A verified reference TLS implementation” und es ist auf den Tag genau ein Jahr her, hier gibt es den F# Quellcode: “5 March 2013 Our paper on TLS security has been accepted at the IEEE Symposium on Security & Privacy. A draft technical report of this work is available from the download page.”. Siehe auch F7: Refinement Types for F#