Yüksek Kaliteli Görüntü Ölçekleme Kütüphanesi [kapalı]


141

Photoshop'ta olduğu gibi kalite düzeyindeki bir görüntüyü C # ile ölçeklendirmek istiyorum. Bu şeyi yapmak için kullanılabilir herhangi bir C # görüntü işleme kütüphanesi var mı?


47
Bu C #, bu diğer soru C ++, bu yüzden hiç bir kopya değil.
Doctor Jones

7
İmageresizing.net alabilirsiniz boyutlandırma en yüksek kalitede ve en yüksek performanslı görüntü kütüphane sunuyor. Kabul edilen cevap , birçok GDI + tuzağından birine kurban gelir ve ürettiği her görüntünün etrafında 1 piksel genişliğinde bir sınır artefaktına neden olur. Bu, DrawImage çağrısının son parametresi için TileModeXY ayarlı bir ImageAttributes örneği kullanılarak düzeltildi.
Lilith River

2
@Bilgisayar Dilbilimi - TileModeXY bir yazım hatası mı? Bu yorumu birkaç yanıta yapıştırdınız ve tam olarak "TileModeXY" için bir google araması yalnızca yayınlarınızı açar. System.Drawing.Drawing2D.WrapMode için aşağıdaki bağlantı yalnızca 5 olası değeri gösterir: Tile, TileFlipX, TileFlipY, TileFlipXY, Kelepçe msdn.microsoft.com/en-us/library/…
JasDev

1
Evet, TileFlipXY olmalı, düzeltme için teşekkürler!
Lilith River

Yanıtlar:


233

İşte bakabileceğiniz ve kullanabileceğiniz güzel yorumlanmış bir Image Manipulation yardımcı sınıfı. Ben C # belirli görüntü işleme görevleri gerçekleştirmek için bir örnek olarak yazdım. İlginizi çekecekBağımsız değişken olarak bir System.Drawing.Image, genişlik ve yükseklik ResizeImage işlevi .

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;

namespace DoctaJonez.Drawing.Imaging
{
    /// <summary>
    /// Provides various image untilities, such as high quality resizing and the ability to save a JPEG.
    /// </summary>
    public static class ImageUtilities
    {    
        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>
        private static Dictionary<string, ImageCodecInfo> encoders = null;

        /// <summary>
        /// A lock to prevent concurrency issues loading the encoders.
        /// </summary>
        private static object encodersLock = new object();

        /// <summary>
        /// A quick lookup for getting image encoders
        /// </summary>
        public static Dictionary<string, ImageCodecInfo> Encoders
        {
            //get accessor that creates the dictionary on demand
            get
            {
                //if the quick lookup isn't initialised, initialise it
                if (encoders == null)
                {
                    //protect against concurrency issues
                    lock (encodersLock)
                    {
                        //check again, we might not have been the first person to acquire the lock (see the double checked lock pattern)
                        if (encoders == null)
                        {
                            encoders = new Dictionary<string, ImageCodecInfo>();

                            //get all the codecs
                            foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
                            {
                                //add each codec to the quick lookup
                                encoders.Add(codec.MimeType.ToLower(), codec);
                            }
                        }
                    }
                }

                //return the lookup
                return encoders;
            }
        }

        /// <summary>
        /// Resize the image to the specified width and height.
        /// </summary>
        /// <param name="image">The image to resize.</param>
        /// <param name="width">The width to resize to.</param>
        /// <param name="height">The height to resize to.</param>
        /// <returns>The resized image.</returns>
        public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
        {
            //a holder for the result
            Bitmap result = new Bitmap(width, height);
            //set the resolutions the same to avoid cropping due to resolution differences
            result.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            //use a graphics object to draw the resized image into the bitmap
            using (Graphics graphics = Graphics.FromImage(result))
            {
                //set the resize quality modes to high quality
                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //draw the image into the target bitmap
                graphics.DrawImage(image, 0, 0, result.Width, result.Height);
            }

            //return the resulting bitmap
            return result;
        }

        /// <summary> 
        /// Saves an image as a jpeg image, with the given quality 
        /// </summary> 
        /// <param name="path">Path to which the image would be saved.</param> 
        /// <param name="quality">An integer from 0 to 100, with 100 being the 
        /// highest quality</param> 
        /// <exception cref="ArgumentOutOfRangeException">
        /// An invalid value was entered for image quality.
        /// </exception>
        public static void SaveJpeg(string path, Image image, int quality)
        {
            //ensure the quality is within the correct range
            if ((quality < 0) || (quality > 100))
            {
                //create the error message
                string error = string.Format("Jpeg image quality must be between 0 and 100, with 100 being the highest quality.  A value of {0} was specified.", quality);
                //throw a helpful exception
                throw new ArgumentOutOfRangeException(error);
            }

            //create an encoder parameter for the image quality
            EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
            //get the jpeg codec
            ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");

            //create a collection of all parameters that we will pass to the encoder
            EncoderParameters encoderParams = new EncoderParameters(1);
            //set the quality parameter for the codec
            encoderParams.Param[0] = qualityParam;
            //save the image using the codec and the parameters
            image.Save(path, jpegCodec, encoderParams);
        }

        /// <summary> 
        /// Returns the image codec with the given mime type 
        /// </summary> 
        public static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            //do a case insensitive search for the mime type
            string lookupKey = mimeType.ToLower();

            //the codec to return, default to null
            ImageCodecInfo foundCodec = null;

            //if we have the encoder, get it to return
            if (Encoders.ContainsKey(lookupKey))
            {
                //pull the codec from the lookup
                foundCodec = Encoders[lookupKey];
            }

            return foundCodec;
        } 
    }
}

Güncelleme

Birkaç kişi yorumlarda ImageUtilities sınıfını nasıl kullanacağınıza dair örnekler istiyor, işte burada.

//resize the image to the specified height and width
using (var resized = ImageUtilities.ResizeImage(image, 50, 100))
{
    //save the resized image as a jpeg with a quality of 90
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}

Not

Resimlerin tek kullanımlık olduğunu unutmayın, bu nedenle yeniden boyutlandırmanın sonucunu kullanarak bir bildirime atamanız gerekir (veya nihayet bir denemeyi kullanabilir ve nihayetinde imha çağrısı yaptığınızdan emin olabilirsiniz).


ImageCodecInfo jpegCodec = getEncoderInfo ("image / jpeg"); - getEncoderInfo'u nerede tanımladınız çünkü onu
derleyemiyorum

3
GetEncoderInfo okumalı ve getEncoderInfo okumalıdır. Yazım hatalarını giderdim ve sınıf derleyicileri şimdi.
Doktor Jones

5
+1 bu harika çalışıyor! Bu kodda düzeltmeniz gereken bir sorun, kalite değişkenini kodlayıcı parametresine geçirmeden çok önce dönüştürmek veya geçersiz bir parametre çalışma zamanı istisnası elde etmektir.
James

1
@Behzad, bakarsanız SaveJpeg işlevi, kalite adı verilen bir int parametresi alır. Bunu aramanız ve quality parametresi için doğru değeri belirtmeniz gerekir (0 ile 100 arasında bir değeri kabul eder).
Doktor Jones

1
Uzun bir aramadan sonra, bu yanıtın boyutlandırma kısmı ( tüm kodu kullanmadı ) kalite kaybı olmadan qrcode yeniden boyutlandırma için çalıştı. Sonuç kalitesi için doğru ayarlar önemlidir.
Furkan Ekinci

15

Resmi GDI + kullanarak çizdiğinizde, bence oldukça iyi ölçekleniyor. Ölçekli bir görüntü oluşturmak için bunu kullanabilirsiniz.

Resminizi GDI + ile ölçeklendirmek istiyorsanız, böyle bir şey yapabilirsiniz:

Bitmap original = ...
Bitmap scaled = new Bitmap(new Size(original.Width * 4, original.Height * 4));
using (Graphics graphics = Graphics.FromImage(scaled)) {
  graphics.DrawImage(original, new Rectangle(0, 0, scaled.Width, scaled.Height));
}

Kod değiştiyse emin değilim, ama new Sizebeyanında atlamak zorunda kaldım scaled:new Bitmap(original.Width * 4, original.Height * 4);
Kirk Woll

10

Imagemagick ve GD gibi test edilmiş kütüphaneler .NET için kullanılabilir

Ayrıca bikubik enterpolasyon gibi şeyleri okuyabilir ve kendiniz yazabilirsiniz.




4

Graphics.InterpolationMode için farklı değerleri deneyin. GDI + 'da kullanılabilen birkaç tipik ölçekleme algoritması vardır. Bunlardan biri ihtiyaçlarınız için yeterliyse, harici bir kütüphaneye güvenmek yerine bu rotaya gidebilirsiniz.


3

Çeşitli kalite seviyeleri için 18 filtre türüne sahip görüntüleri yeniden örneklemek için bir nesne içeren şirketimin ürünlerinden biri olan dotImage'ı deneyebilirsiniz .

Tipik kullanım:

// BiCubic is one technique available in PhotoShop
ResampleCommand resampler = new ResampleCommand(newSize, ResampleMethod.BiCubic);
AtalaImage newImage = resampler.Apply(oldImage).Image;

Buna ek olarak, dotImage, aradığınız şey buysa, PhotoShop'takine benzer birçok filtre de dahil olmak üzere 140 bazı garip görüntü işleme komutu içerir.


Bu özelliğe sahip SDK artık yaygın fotoğraf formatları (JPEG, PNG, vb.) İçin ücretsiz olarak kullanılabilir atalasoft.com/photofree
Lou Franco

/ Lou Franco: Ortak format ücretsiz sürümü üretim dağıtımlarında da ücretsiz olarak kullanılabilir mi?
Oskar Austegard

Evet, DotImage Photo Free uygulaması ücretsizdir.
Lou Franco

2

Bu yardımcı olabilir

    public Image ResizeImage(Image source, RectangleF destinationBounds)
    {
        RectangleF sourceBounds = new RectangleF(0.0f,0.0f,(float)source.Width, (float)source.Height);
        RectangleF scaleBounds = new RectangleF();

        Image destinationImage = new Bitmap((int)destinationBounds.Width, (int)destinationBounds.Height);
        Graphics graph = Graphics.FromImage(destinationImage);
        graph.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

        // Fill with background color
        graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), destinationBounds);

        float resizeRatio, sourceRatio;
        float scaleWidth, scaleHeight;

        sourceRatio = (float)source.Width / (float)source.Height;

        if (sourceRatio >= 1.0f)
        {
            //landscape
            resizeRatio = destinationBounds.Width / sourceBounds.Width;
            scaleWidth = destinationBounds.Width;
            scaleHeight = sourceBounds.Height * resizeRatio;
            float trimValue = destinationBounds.Height - scaleHeight;
            graph.DrawImage(source, 0, (trimValue / 2), destinationBounds.Width, scaleHeight);
        }
        else
        {
            //portrait
            resizeRatio = destinationBounds.Height/sourceBounds.Height;
            scaleWidth = sourceBounds.Width * resizeRatio;
            scaleHeight = destinationBounds.Height;
            float trimValue = destinationBounds.Width - scaleWidth;
            graph.DrawImage(source, (trimValue / 2), 0, scaleWidth, destinationBounds.Height);
        }

        return destinationImage;

    }

InterpolationMode.HighQualityBicubic-> Bu genellikle performans ve sonuçlar arasında iyi bir denge olduğunu unutmayın .


2

Bu temel kod snippet'ini deneyin:

private static Bitmap ResizeBitmap(Bitmap srcbmp, int width, int height )
{
    Bitmap newimage = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(newimage))
           g.DrawImage(srcbmp, 0, 0, width, height);
    return newimage;
}

0

Code Project'te GDI + for .NET'in fotoğraf boyutlandırma yapmak için kullanılmasıyla ilgili bir makale var , örneğin Bicubic enterpolasyonu.

Bu konuyla ilgili başka bir blogda da başka bir makale vardı (MS çalışanı, sanırım), ancak bağlantıyı hiçbir yerde bulamıyorum. :( Belki başka biri bulabilir?



0

Bu, Paint.NET'in görüntü yeniden örnekleme kodunda atıfta bulunduğum bir makale: Paul Bourke'nin Çeşitli Basit Görüntü İşleme Teknikleri .


1: Güzel makale. Bağlantıya erişilemedi, ancak başka bir tane buldu: local.wasp.uwa.edu.au/~pbourke/texture_colour/imageprocess
Thomas Bratt

Thomas'ın bağlantısı da koptuğu için orijinal gönderideki
Oskar Austegard

Bu cevap, bağlantıya dayanmak yerine cevabın ilgili kısımlarını açıklarsa daha iyi olurdu.
KatieK

0

Sihirli çekirdeği deneyebilirsin . Ölçeklendirme sırasında bikubik yeniden örneklemeden daha az pikselleşme artefaktı üretir ve ölçek küçültme sırasında da çok iyi sonuçlar verir. Kaynak kodu, web sitesinden c # dilinde mevcuttur.


0

Doctor Jones'un cevabı için bazı iyileştirmelerim var.

Görüntüyü orantılı olarak yeniden boyutlandırmak isteyenlere çalışır. Test etti ve benim için çalıştı.

Sınıf I'in eklediği yöntemler:

public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, Size size)
{
    return ResizeImage(image, size.Width, size.Height);
}


public static Size GetProportionedSize(Image image, int maxWidth, int maxHeight, bool withProportion)
{
    if (withProportion)
    {
        double sourceWidth = image.Width;
        double sourceHeight = image.Height;

        if (sourceWidth < maxWidth && sourceHeight < maxHeight)
        {
            maxWidth = (int)sourceWidth;
            maxHeight = (int)sourceHeight;
        }
        else
        {
            double aspect = sourceHeight / sourceWidth;

            if (sourceWidth < sourceHeight)
            {
                maxWidth = Convert.ToInt32(Math.Round((maxHeight / aspect), 0));
            }
            else
            {
                maxHeight = Convert.ToInt32(Math.Round((maxWidth * aspect), 0));
            }
        }
    }

    return new Size(maxWidth, maxHeight);
}

ve bu kodlara göre yeni kullanılabilir:

using (var resized = ImageUtilities.ResizeImage(image, ImageUtilities.GetProportionedSize(image, 50, 100)))
{
    ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.