Automatisch bijsnijden van grote hoeveelheden afbeeldingen
Het bijsnijden van afbeeldingen lijkt eenvoudig, zou je denken... start gewoon je favoriete fotobewerkingsprogramma, zoals Photoshop, Gimp of een van de vele andere keuzes...
Maar... het wordt veel moeilijker als je dit moet doen voor een groot aantal afbeeldingen, laten we zeggen enkele tienduizenden.
Dan wordt fotoshoppen een taak voor de rest van je leven, misschien interessant voor de eerste paar honderd foto's,
maar nogal saai na verloop van tijd. Tijd voor wat software om te hulp te schieten.
Bij Double Dig IT werden we met deze uitdaging geconfronteerd
terwijl we een grote batch Tiff-bestanden aan het omzetten waren van het
Medicinsk Museum (Medisch Museum) in Kopenhagen naar JPEG-formaat.
Een eenvoudige klus; gewoon elke Tiff een voor een in het geheugen lezen en dan opslaan als JPEG.
Terwijl we dit aan het doen waren, merkten we op dat de afbeeldingen bestonden uit foto's die op een inventarisatiekaart van het museum waren geplakt. Dit waren oude papieren inventarisatiekaarten die waren gescand door een derde partij. De inventarisatiekaarten hadden tekstvakken en hadden verschillende achtergrondkleuren, sommige waren blauw, andere groen en een heleboel waren gewoon wit.
Deze afbeeldingen waren bedoeld voor gebruik in het nieuwe Sara-systeem, een landelijk collectiebeheersysteem in Denemarken, aangedreven door Axiell Collections. In deze web- en op de cloud gebaseerde oplossing wordt de gegevens van meer dan 120 Deense musea beheerd in één systeem.
Alle gegevens staan al in het Collectiebeheersysteem, dus zou het niet goed zijn om al deze afbeeldingen bij te snijden en de achtergrond en tekst te verwijderen om alleen de 'echte' afbeelding over te houden. Na wat onderzoek op internet konden we niet snel een tool vinden om ons hierbij te helpen, dus besloten we om zelf wat code te testen:
De methodologie zou vrij eenvoudig zijn: detecteer de achtergrondkleur van een inventarisatiekaart door de rijen van de afbeelding te monsteren, ongeveer 10-20 pixels vanaf de randen werden bemonsterd en er werd een gemiddelde berekend. Vervolgens werd een filter toegepast om pixels in twee categorieën te verdelen: achtergrond en niet-achtergrond. Er werd een threshold toegepast, die de Euclidische afstand van elke pixel in de RGB-ruimte tot de gedetecteerde achtergrondkleur gebruikte. Het resultaat is een 'masker' dat kan worden gebruikt om de randen van de 'echte' afbeelding te detecteren.
De 'opgeplakte' afbeeldingen hadden allemaal de eigenschap dat ze allemaal rechthoekig waren, door horizontaal en verticaal het masker te 'scannen' konden we horizontale en verticale lijnen op de 'moeder' afbeelding bepalen. Een lijn zou bestaan uit minstens 50% meer of minder aaneengesloten pixels van de achtergrondkleur - hoewel we konden spelen met de threshold parameters.
De volgende stap zou zijn om het grootste rechthoek te detecteren dat was ingesloten door deze lijnen. Een complicerende factor waren de tekstvakken in de originele afbeelding, deze waren ook horizontale en verticale lijnen. De oplossing bleek simpelweg het instellen van een drempelwaarde voor de breedte van de horizontale en verticale lijnen te zijn. Hierdoor werden de lijnen die de tekstvakken vormden niet per ongeluk gedetecteerd als afbeeldingsranden.
We schreven een 'cropper' klasse in de C# programmeertaal en testten deze eerst in een Windows-gebruikersinterface. Dit stelde ons in staat om het origineel te zien, de achtergronddetectie en het bijgesneden resultaat naast elkaar. Nadat we enkele van deze drempelwaarden hadden aangepast, gebruikten we dezelfde klasse in een consoleprogramma om de hele batch te verwerken.
Het eindresultaat was behoorlijk bevredigend; we hebben in ongeveer een dag zo'n 20.000 afbeeldingen bijgesneden.
Leerpunten
De standaardmethoden om pixels in C# te manipuleren zijn behoorlijk traag. De reden hiervoor is het geheugenbeheer van C#. Om dit probleem te overwinnen, gebruikten we een 'Fastbitmap'-klasse, die het geheugengebied vergrendelt waar de afbeelding zich bevindt terwijl deze wordt verwerkt.
Alternatieve benadering... de resultaten van deze bijsnijd-oefening waren goed, maar deels kwam dit omdat de originele scans op elkaar leken, en de achtergrondkleurdetectie met horizontale en verticale lijnen goed werkte voor dit type afbeelding. Een alternatieve benadering zou kunnen zijn om een neuraal netwerk te gebruiken voor de randdetectie. Het voordeel van deze methode zou zijn dat er minder programmeren nodig is dan bij onze 'statistische' methode, geen aanpassingen van drempelwaarden vereist zijn, maar dan moet het neurale netwerk worden 'getraind'. Het zou interessant zijn om beide methoden te vergelijken op het gebied van nauwkeurigheid, snelheid en gebruiksgemak.
Broncode
– Demoprogramma, om deze principes te demonstreren, hebben we een klein demoprogramma geschreven. De broncode van dit programma is te vinden op Git: https://github.com/bertdd/autocrop
Referenties
– Museion, de startpagina van het Medisch Museum in Kopenhagen: www.museion.ku.dk
– Snelle bitmaps, informatie over het principe van snelle bitmaps in C#: http://csharpexamples.com/fast-image-processing-c/ & https://www.codeproject.com/Tips/240428/Work-with-Bitmaps-Faster-in-Csharp-3
– Axiell Collections, informatie over Axiell Collections: https://alm.axiell.com/collections-management-solutions/axiell-collections/