Vraag Efficiëntie van afbeeldingen wijzigen in C # en .NET 3.5


Ik heb een webservice geschreven om het formaat van door gebruikers geüploade afbeeldingen en alle werken correct vanuit een functioneel oogpunt te wijzigen, maar het zorgt ervoor dat het CPU-gebruik elke keer dat het wordt gebruikt, piekt. Het draait op Windows Server 2008 64 bit. Ik heb geprobeerd te compileren tot 32 en 64 bit en ongeveer dezelfde resultaten behaald.

Het hart van de service is deze functie:

private Image CreateReducedImage(Image imgOrig, Size NewSize)
{
    var newBM = new Bitmap(NewSize.Width, NewSize.Height);
    using (var newGrapics = Graphics.FromImage(newBM))
    {
        newGrapics.CompositingQuality = CompositingQuality.HighSpeed;
        newGrapics.SmoothingMode = SmoothingMode.HighSpeed;
        newGrapics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        newGrapics.DrawImage(imgOrig, new Rectangle(0, 0, NewSize.Width, NewSize.Height));
    }

    return newBM;
}  

Ik heb een profiler op de service gezet en het leek erop te wijzen dat het grootste deel van de tijd in de GDI + -bibliotheek zelf wordt doorgebracht en dat er niet veel te winnen valt in mijn code.

vragen: Doe ik hier iets schokkend inefficiënt in mijn code? Het lijkt in overeenstemming te zijn met het voorbeeld dat ik heb gezien.

Zijn er voordelen te behalen bij het gebruik van andere bibliotheken dan GDI +? De benchmarks die ik heb gezien lijken aan te geven dat GDI + goed vergelijkbaar is met andere bibliotheken, maar ik vond er niet genoeg van om zelfverzekerd te zijn.

Zijn er winsten te behalen met behulp van "onveilige code" -blokken?

Laat me alsjeblieft weten of ik genoeg van de code heb ingesproken ... Ik ben blij om zoveel als gevraagd op te geven maar wil niet onaangenaam zijn in de post.


15
2017-08-31 12:36


oorsprong


antwoorden:


Beeldverwerking is meestal een dure operatie. U moet onthouden dat een 32-bits kleurenafbeelding in het geheugen wordt uitgebreid tot een pixellengte van 4 * pixelbreedte * voordat uw app zelfs maar enige bewerking start. Een piek is zeker te verwachten, vooral bij het doen van elke vorm van pixelverwerking.

Dat gezegd hebbende, de enige plaats die ik u kon zien om het proces te versnellen of de impact op uw processor te verminderen, is door een interpolatiemodus van mindere kwaliteit te proberen.


6
2017-08-31 12:45



Ik weet dat de DirectX die wordt uitgebracht met Windows 7 naar verluidt 2D-hardwareversnelling levert. Of dit impliceert dat het GDI + zal verslaan in dit soort operaties, ik weet het niet. MS heeft een vrij onflatteuze beschrijving van GDI hier wat impliceert dat het langzamer is dan het zou moeten zijn, onder andere.

Als je echt wilt proberen om dit soort dingen zelf te doen, is er een geweldig GDI-zelfstudie dat laat het zien. De auteur maakt gebruik van zowel SetPixel als 'onveilige blokken' in verschillende delen van zijn tutorials.

Even terzijde, multi-threading zal je hier waarschijnlijk helpen, ervan uitgaande dat je server meer dan één CPU heeft. Dat wil zeggen, u kunt meer dan één afbeelding tegelijk verwerken en waarschijnlijk snellere resultaten krijgen.


3
2017-08-31 12:52



Je kan het proberen

newGrapics.InterpolationMode = InterpolationMode.Low;

als HighQualityBicubic is de meest processorintensieve van de resampling-bewerkingen, maar u verliest dan uiteraard de beeldkwaliteit.

Afgezien daarvan kan ik niet echt iets zien dat kan worden gedaan om uw code te versnellen. GDI + zal bijna zeker de snelste zijn op een Windows-machine (geen code geschreven in C # zal een pure C-bibliotheek overtreffen), en het gebruik van andere beeldbibliotheken brengt het potentiële risico met zich mee. unsafe en / of buggy-code.

De bottom line is, het formaat van een afbeelding aanpassen is een dure operatie, ongeacht wat je doet. De eenvoudigste oplossing is dat uw geval eenvoudigweg de CPU van uw server kan vervangen door een sneller model.


2
2017-08-31 12:55



Wanneer je schrijft

Ik heb een webservice geschreven om het formaat te wijzigen   door gebruiker geüploade afbeeldingen

Het klinkt me dat de gebruiker een afbeelding uploadt naar een (web?) -Server en de server vervolgens een webservice belt om de schaal te wijzigen?

Als dat het geval is, zou ik de schaalvergroting gewoon naar de server verplaatsen. Imho, het schalen van een afbeelding rechtvaardigt zijn eigen webservice niet. En je krijgt behoorlijk wat onnodig verkeer van de server naar de webservice en terug. In het bijzonder omdat de afbeelding waarschijnlijk is gecodeerd met base64, waardoor het dataverkeer nog groter wordt.

Maar ik gok alleen maar hier.

postscriptum Onveilige blokken op zichzelf geven geen winst, ze laten alleen toe om onveilige code te compileren. Dus tenzij je je eigen schaalrouting schrijft, zal een onveilig blok niet helpen.


2
2017-08-31 13:04



Misschien wilt u ImageMagick proberen. Het is gratis en er is ook een .NET-wrapper: Klik hier. Of hier. Of u kunt een opdracht naar een DOS-shell sturen.

We hebben af ​​en toe ImageMagick op Windows-servers gebruikt, voor batchverwerking en soms voor een meer flexibele beeldconversie.

Natuurlijk zijn er ook commerciële componenten, zoals die van Leadtools en Atalasoft. We hebben die nog nooit geprobeerd.


2
2017-08-31 16:24



Ik vermoed dat de spike is omdat je de interpolatiemodus hebt aangezwengeld. Alle interpolatiemodi werken per pixel en BiCubic High Quality is ongeveer zo hoog als je met GDI + kunt doen, dus ik vermoed dat de berekeningen per pixel je CPU opkauwen.
Probeer als test de interpolatiemodus naar beneden te zetten InterpolationModeNearestNeighbor en kijk of de CPU-piek daalt - zo ja, dan is dat je schuldige.
Als dat zo is, doe dan wat vallen en opstaan ​​voor kosten versus kwaliteit, de kans is groot dat u BiCubic van hoge kwaliteit misschien niet nodig hebt om fatsoenlijke resultaten te krijgen


0
2017-08-31 13:00