【问题标题】:How to effectively crop and scale image data如何有效地裁剪和缩放图像数据
【发布时间】:2014-03-27 15:42:46
【问题描述】:

我需要对图像中的像素值进行操作。所以我写了这样一个类:

public class image_class
{
    #region property
    public int width { get; private set; }
    public int height { get; private set; }

    byte[] buffer;
    #endregion

    #region constructors
    public image_class()
    {
        ;
    }
    public image_class(int Width, int Height, byte[] data)
    {
        if (data.Count() == (Width * Height * 3))
        {
            this.width = Width;
            this.height = Height;

            this.buffer = data;
        }
        else
            throw new Exception();
    }
    #endregion

    #region get bitmap
    public ImageSource bmp
    {
        get
        {
            try
            {
                var pixelFormat = PixelFormats.Rgb24;
                var bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
                var stride = bytesPerPixel * width;

                var bitmap = BitmapSource.Create(width, height, 96d, 96d, pixelFormat, null, buffer, stride);

                return bitmap;
            }

            catch { return null; }
        }
    }
    #endregion

    #region methods
    public void load_from_file(string path)
    {
            var bmp = new BitmapImage();
            bmp.BeginInit();
            bmp.UriSource = new Uri(ofd.FileName, UriKind.Absolute);
            bmp.EndInit();

            height = (int)bmp.Height;
            width = (int)bmp.Width;

            int stride = width * ((bmp.Format.BitsPerPixel + 7) / 8);

            int size = height * stride;

            var buffer2 = new byte[size];
            bmp.CopyPixels(buffer2, stride, 0);

            buffer = new byte[size * 3 / 4];
            for (int i = 0, j = 0; i < size; i += 4, j += 3)
            {
                buffer[j] = buffer2[i + 2];
                buffer[j + 1] = buffer2[i + 1];
                buffer[j + 2] = buffer2[i];
            }

    }

    public void load_from_file(string path, int Width, int Height)
    {
        this.width = Width;
        this.height = Height;

        var bmp = new BitmapImage();

        bmp.BeginInit();
        bmp.DecodePixelHeight = height;
        bmp.DecodePixelWidth = width;
        bmp.UriSource = new Uri(path, UriKind.Absolute);
        bmp.EndInit();

        int stride = width * ((bmp.Format.BitsPerPixel + 7) / 8);

        int size = height * stride;

        var buffer2 = new byte[size];
        bmp.CopyPixels(buffer2, stride, 0);

        buffer = new byte[size * 3 / 4];
        for (int i = 0, j = 0; i < size; i += 4, j += 3)
        {
            buffer[j] = buffer2[i + 2];
            buffer[j + 1] = buffer2[i + 1];
            buffer[j + 2] = buffer2[i];
        }

    }


    public void save_to_file(string path)
    {
        var pixelFormat = PixelFormats.Rgb24;
        var bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
        var stride = bytesPerPixel * width;

        var encoder = new JpegBitmapEncoder();

        encoder.Frames.Add(BitmapFrame.Create(BitmapSource.Create(width, height, 96d, 96d, pixelFormat, null, buffer, stride)));

        FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);



        encoder.Save(fs);

        fs.Close();
    }

    public image_class cut(int x0, int y0, int dx, int dy)
    {
        if (x0 >= 0 & y0 >= 0 & x0 + dx <= width & y0 + dy <= height)
        {
            byte[] buffer3 = new byte[dx * dy * 3];

            for (int y = 0, i = 0, j = -1; y < height; y++) for (int x = 0; x < width; x++, i += 3)
                    if (x >= x0 & x < x0 + dx & y >= y0 & y < y0 + dy)
                    {
                        buffer3[++j] = buffer[i];
                        buffer3[++j] = buffer[i + 1];
                        buffer3[++j] = buffer[i + 2];
                    }

            return new image_class(dx, dy, buffer3);

        }
        else
            throw new Exception();
    }
    #endregion
}

缓冲区数组是我使用的。

这个类工作得很好。 当我需要对图像片段中的数据进行操作时,我使用方法cut,例如:

image_class img1=new image_class();
image_class img2=img1.cut(5,5,20,20);

我需要将剪切图像缩放到其他值并保持像素数据的格式。例如,我想要一张图片中的 50x50 正方形,缩放为 20x20。我就是这样做的:

image_class img1=new image_class();
image_class img2=img1.cut(5,5,50,50);
img2.save_to_file(path);
image_class img3=new image_class();
img3.load_from_file(path, 20,20);

它有效,但当然是非常无效的。谁能告诉我更好的解决方案?

【问题讨论】:

  • 看起来你正在重新发明轮子。已经有一个 CroppedBitmap 类,它完全执行您的剪切操作。为了缩放或以其他方式转换作物,您可以使用TransformedBitmap
  • 你说的无效,是指性能吗?

标签: c# wpf bitmap


【解决方案1】:

你不需要这一切。为了从源位图中复制矩形部分并随后对其进行缩放,您可以简单地使用CroppedBitmapTransformedBitmap

BitmapSource original = ...
var crop = new CroppedBitmap(original, new Int32Rect(5, 5, 50, 50));
var result = new TransformedBitmap(crop, new ScaleTransform(0.4, 0.4));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 2010-10-14
    • 2012-07-21
    • 2015-04-20
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    相关资源
    最近更新 更多