本文介绍了从种植的BitmapData面积用C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个位图的 sourceImage.bmp

锁定它的位:

 的BitmapData dataOriginal = sourceImage.LockBits(新的Rectangle(0,0,sourceImage.Width,sourceImage.Height),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);

做分析,获取克隆

 位图originalClone = AForge.Imaging.Image.Clone(dataOriginal);

解锁位:

  sourceImage.UnlockBits(dataOriginal);

是可以指定复制其dataOriginal的一部分(X,Y,W,H)?或者从dataOriginal创建新的数据,并指定X和Y坐标以及H和W吗

其目的是从该图像复制的小区域。这种方法可能比快的DrawImage,这就是为什么我不使用后者。

编辑:

所以我把 29兆位图,并做了一些铁杆测试!全尺寸作物(主要副本)+ 100迭代。

code:

 使用系统;
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Data这;
使用System.Drawing中;
使用System.Linq的;
使用System.Text;
使用System.Windows.Forms的;
使用AForge;
使用AForge.Imaging;
使用System.Diagnostics程序;
使用System.Drawing.Imaging;
使用System.IO;
使用System.Runtime.InteropServices;
命名空间testCropClone
{
    公共部分Form1类:表格
    {
        公共Form1中()
        {
            的InitializeComponent();
        }        私人不安全的克隆位图(BMP位图,诠释startx的,诠释startY,诠释的宽度,高度INT)
        {
        矩形RECT =新的Rectangle(0,0,bmp.Width,bmp.Height);
        的BitmapData rawOriginal = bmp.LockBits(新的Rectangle(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);        INT origByteCount = rawOriginal.Stride * rawOriginal.Height;
        字节[] = origBytes新的字节[origByteCount]
        Marshal.Copy(rawOriginal.Scan0,origBytes,0,origByteCount);        INT BPP = 4; // 4 BPP = 32位,3 = 24等        字节[] = croppedBytes新的字节[宽*高* BPP]。        //迭代原始图像的所选区域,并且新的图像的整个区域
        的for(int i = 0; I<高度;我++)
        {
            对于(INT J = 0; J<宽度* BPP; J + = BPP)
            {
                INT origIndex =(startx的* rawOriginal.Stride)+(我* rawOriginal.Stride)+(startY * BPP)+(J);
                INT croppedIndex =(我*宽* BPP)+(J);                每个通道一次://复制数据
                对于(INT K = 0; K< BPP; k ++)
                {
                    croppedBytes [croppedIndex + K] = origBytes [origIndex + K]。
                }
            }
        }        //新数据复制成位图
        位图croppedBitmap =新位图(宽,高);
        的BitmapData croppedData = croppedBitmap.LockBits(新的Rectangle(0,0,宽度,高度),ImageLockMode.WriteOnly,PixelFormat.Format32bppArgb);
        Marshal.Copy(croppedBytes,0,croppedData.Scan0,croppedBytes.Length);        bmp.UnlockBits(rawOriginal);
        croppedBitmap.UnlockBits(croppedData);        返回croppedBitmap;
        }        私人位图cloneBitmap(BMP位图,诠释startx的,诠释startY,诠释的宽度,高度INT)
        {
            矩形srcRect = Rectangle.FromLTRB(startx的,startY,宽,高);
            位图cloneBitmap = bmp.C​​lone(srcRect,bmp.PixelFormat);
            返回cloneBitmap;
        }
        私人位图cloneRectangle(BMP位图,诠释startx的,诠释startY,诠释的宽度,高度INT)
        {
            矩形srcRect = Rectangle.FromLTRB(startx的,startY,宽,高);
            位图DEST =新位图(srcRect.Width,srcRect.Height);
            矩形destRect =新的Rectangle(0,0,srcRect.Width,srcRect.Height);
            使用(图形图像= Graphics.FromImage(DEST))
            {
                graphics.DrawImage(BMP,destRect,srcRect,GraphicsUnit.Pixel);
            }
            返回DEST;
        }
        私人位图cloneAforge(BMP位图,诠释startx的,诠释startY,诠释的宽度,高度INT)
        {
            的BitmapData rawOriginal = bmp.LockBits(新的Rectangle(0,0,宽度,高度),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);
            位图cloneBitmap = AForge.Imaging.Image.Clone(rawOriginal);
            bmp.UnlockBits(rawOriginal);
            返回cloneBitmap;
        }        私人无效的button1_Click(对象发件人,EventArgs的发送)
        {
            位图源=新位图(@C:\\ 9 \\ 01.bmp);            秒表S1 = Stopwatch.StartNew();
            的for(int i = 0; I< 100;我++)
            {
                位图Clone1 = cloneAforge(源,0,0,source.Width,source.Height);
                Clone1.Dispose();            }            / *位图Clone1 = cloneAforge(源,0,0,source.Width,source.Height);
            Clone1.Save(@C:\\ 9 \\ 01_aforge.bmp);
            Clone1.Dispose(); * /            s1.Stop();
            source.Dispose();
            textBox1.Text =(+ s1.ElapsedMilliseconds / 100 +毫秒);
        }        私人无效button2_Click(对象发件人,EventArgs的发送)
        {
            位图源=新位图(@C:\\ 9 \\ 01.bmp);            秒表S1 = Stopwatch.StartNew();
            的for(int i = 0; I< 100;我++)
            {
                位图Clone1 = cloneBitmap(源,0,0,source.Width,source.Height);
                Clone1.Dispose();            }            / *位图Clone1 = cloneBitmap(源,0,0,source.Width,source.Height);
            Clone1.Save(@C:\\ 9 \\ 01_bitmap.bmp);
            Clone1.Dispose(); * /            s1.Stop();
            source.Dispose();
            textBox2.Text =(+ s1.ElapsedMilliseconds / 100 +毫秒);
        }        私人无效button3_Click(对象发件人,EventArgs的发送)
        {
            位图源=新位图(@C:\\ 9 \\ 01.bmp);            秒表S1 = Stopwatch.StartNew();
            的for(int i = 0; I< 100;我++)
            {
                位图Clone1 =克隆(源,0,0,source.Width,source.Height);
                Clone1.Dispose();            }            / *位图Clone1 =克隆(源,0,0,source.Width,source.Height);
            Clone1.Save(@C:\\ 9 \\ 01_bits.bmp);
            Clone1.Dispose(); * /            s1.Stop();
            source.Dispose();
            textBox3.Text =(+ s1.ElapsedMilliseconds / 100 +毫秒);
        }        私人无效button4_Click(对象发件人,EventArgs的发送)
        {
            位图源=新位图(@C:\\ 9 \\ 01.bmp);            秒表S1 = Stopwatch.StartNew();
            的for(int i = 0; I< 100;我++)
            {
                位图Clone1 = cloneRectangle(源,0,0,source.Width,source.Height);
                Clone1.Dispose();            }
            / *位图Clone1 = cloneRectangle(源,0,0,source.Width,source.Height);
            Clone1.Save(@C:\\ 9 \\ 01_rect.bmp);
            Clone1.Dispose(); * /
            s1.Stop();
            source.Dispose();
            textBox4.Text =(+ s1.ElapsedMilliseconds / 100 +毫秒);
        }
    }
}

EDIT2:(Aforge全尺寸裁剪..)方法十五分。 2

 的for(int i = 0; I< 100;我++)
        {
            作物种植=新作(新的Rectangle(0,0,source.Width,source.Height));
            无功源2 = crop.Apply(源);
            source2.Dispose();        }

平均= 62ms(40毫秒小于1 Aforge的方法)

结果:


  1. BitmapClone(0毫秒)? (欺骗,不是吗?)

  2. Aforge#2(65毫秒)

  3. Aforge#1(105毫秒)

  4. 矩形(170毫秒)

  5. 锁定位(803毫秒)(等待修复/新的测试结果。)


解决方案

我刮起了演示如何使用位图锁定做一个快速的(诚然粗糙)手动解决方案。它应该比其他方法相当快,但确实涉及了很多code。

  BMP位图=新位图(@C:\\ original.jpg);
        矩形RECT =新的Rectangle(0,0,bmp.Width,bmp.Height);
        的BitmapData rawOriginal = bmp.LockBits(新的Rectangle(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadOnly,PixelFormat.Format32bppArgb);        INT origByteCount = rawOriginal.Stride * rawOriginal.Height;
        字节[] = origBytes新的字节[origByteCount]
        Marshal.Copy(rawOriginal.Scan0,origBytes,0,origByteCount);        //我想在15到裁剪100x100的部分开始,15。
        INT运行startx = 15;
        INT startY = 15;
        INT宽度= 100;
        INT高= 100;
        INT BPP = 4; // 4 BPP = 32位,3 = 24等        字节[] = croppedBytes新的字节[宽*高* BPP]。        //迭代原始图像的所选区域,并且新的图像的整个区域
        的for(int i = 0; I<高度;我++)
        {
            对于(INT J = 0; J<宽度* BPP; J + = BPP)
            {
                INT origIndex =(startx的* rawOriginal.Stride)+(我* rawOriginal.Stride)+(startY * BPP)+(J);
                INT croppedIndex =(我*宽* BPP)+(J);                每个通道一次://复制数据
                对于(INT K = 0; K< BPP; k ++)
                {
                    croppedBytes [croppedIndex + K] = origBytes [origIndex + K]。
                }
            }
        }        //新数据复制成位图
        位图croppedBitmap =新位图(宽,高);
        的BitmapData croppedData = croppedBitmap.LockBits(新的Rectangle(0,0,宽度,高度),ImageLockMode.WriteOnly,PixelFormat.Format32bppArgb);
        Marshal.Copy(croppedBytes,0,croppedData.Scan0,croppedBytes.Length);        bmp.UnlockBits(rawOriginal);
        croppedBitmap.UnlockBits(croppedData);        croppedBitmap.Save(@C:\\ TEST.BMP);

我用这个原始图像:

要输出这一形象,裁剪为100x100 @ 15,15:

显然,如果你使用这个code,你会想清理一下,添加错误处理。如果我没有理解你的问题,做事情就这样应无需在所有使用AForge。

I have a bitmap sourceImage.bmp

locking it's bits:

BitmapData dataOriginal = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

Do analysis, get a clone:

Bitmap originalClone = AForge.Imaging.Image.Clone(dataOriginal);

unlocking bits:

sourceImage.UnlockBits(dataOriginal);

is it possible to specify which part of "dataOriginal" to copy (x,y,w,h)? or to create new data from the dataOriginal, specifying X and Y coordinates as well as H and W?

The aim is to copy a small area from this image. This method might be faster than DrawImage, that's why I don't use the latter.

Edit:

So I took 29 Mb bitmap and did some hardcore testing! Full-size crop (basically a copy) + 100 iterations.

Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge;
using AForge.Imaging;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;


namespace testCropClone
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private unsafe Bitmap Clone(Bitmap bmp, int startX, int startY, int width, int height)
        {
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        BitmapData rawOriginal = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        int origByteCount = rawOriginal.Stride * rawOriginal.Height;
        byte[] origBytes = new Byte[origByteCount];
        Marshal.Copy(rawOriginal.Scan0, origBytes, 0, origByteCount);

        int BPP = 4;        //4 Bpp = 32 bits, 3 = 24, etc.

        byte[] croppedBytes = new Byte[width * height * BPP];

        //Iterate the selected area of the original image, and the full area of the new image
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width * BPP; j += BPP)
            {
                int origIndex = (startX * rawOriginal.Stride) + (i * rawOriginal.Stride) + (startY * BPP) + (j);
                int croppedIndex = (i * width * BPP) + (j);

                //copy data: once for each channel
                for (int k = 0; k < BPP; k++)
                {
                    croppedBytes[croppedIndex + k] = origBytes[origIndex + k];
                }
            }
        }

        //copy new data into a bitmap
        Bitmap croppedBitmap = new Bitmap(width, height);
        BitmapData croppedData = croppedBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
        Marshal.Copy(croppedBytes, 0, croppedData.Scan0, croppedBytes.Length);

        bmp.UnlockBits(rawOriginal);
        croppedBitmap.UnlockBits(croppedData);

        return croppedBitmap;
        }

        private Bitmap cloneBitmap(Bitmap bmp, int startX, int startY, int width, int height)
        {
            Rectangle srcRect = Rectangle.FromLTRB(startX, startY, width, height);
            Bitmap cloneBitmap = bmp.Clone(srcRect, bmp.PixelFormat);
            return cloneBitmap;
        }


        private Bitmap cloneRectangle(Bitmap bmp, int startX, int startY, int width, int height)
        {
            Rectangle srcRect = Rectangle.FromLTRB(startX, startY, width, height);
            Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height);
            Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
            using (Graphics graphics = Graphics.FromImage(dest))
            {
                graphics.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);
            }
            return dest;
        }


        private Bitmap cloneAforge(Bitmap bmp, int startX, int startY, int width, int height)
        {
            BitmapData rawOriginal = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            Bitmap cloneBitmap = AForge.Imaging.Image.Clone(rawOriginal);
            bmp.UnlockBits(rawOriginal);
            return cloneBitmap;
        }



        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap source = new Bitmap(@"C:\9\01.bmp");

            Stopwatch s1 = Stopwatch.StartNew();
            for (int i = 0; i < 100; i++)
            {
                Bitmap Clone1 = cloneAforge(source, 0, 0, source.Width, source.Height);
                Clone1.Dispose();

            }

            /*Bitmap Clone1 = cloneAforge(source, 0, 0, source.Width, source.Height);
            Clone1.Save(@"C:\9\01_aforge.bmp");
            Clone1.Dispose();*/

            s1.Stop();
            source.Dispose();
            textBox1.Text = ("" + s1.ElapsedMilliseconds / 100 + " ms");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Bitmap source = new Bitmap(@"C:\9\01.bmp");

            Stopwatch s1 = Stopwatch.StartNew();
            for (int i = 0; i < 100; i++)
            {
                Bitmap Clone1 = cloneBitmap(source, 0, 0, source.Width, source.Height);
                Clone1.Dispose();

            }

            /*Bitmap Clone1 = cloneBitmap(source, 0, 0, source.Width, source.Height);
            Clone1.Save(@"C:\9\01_bitmap.bmp");
            Clone1.Dispose();*/

            s1.Stop();


            source.Dispose();
            textBox2.Text = ("" + s1.ElapsedMilliseconds / 100 + " ms");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Bitmap source = new Bitmap(@"C:\9\01.bmp");

            Stopwatch s1 = Stopwatch.StartNew();
            for (int i = 0; i < 100; i++)
            {
                Bitmap Clone1 = Clone(source, 0, 0, source.Width, source.Height);
                Clone1.Dispose();

            }

            /*Bitmap Clone1 = Clone(source, 0, 0, source.Width, source.Height);
            Clone1.Save(@"C:\9\01_bits.bmp");
            Clone1.Dispose();*/

            s1.Stop();
            source.Dispose();
            textBox3.Text = ("" + s1.ElapsedMilliseconds / 100 + " ms");
        }

        private void button4_Click(object sender, EventArgs e)
        {
            Bitmap source = new Bitmap(@"C:\9\01.bmp");

            Stopwatch s1 = Stopwatch.StartNew();
            for (int i = 0; i < 100; i++)
            {
                Bitmap Clone1 = cloneRectangle(source, 0, 0, source.Width, source.Height);
                Clone1.Dispose();

            }


            /*Bitmap Clone1 = cloneRectangle(source, 0, 0, source.Width, source.Height);
            Clone1.Save(@"C:\9\01_rect.bmp");
            Clone1.Dispose();*/


            s1.Stop();
            source.Dispose();
            textBox4.Text = ("" + s1.ElapsedMilliseconds / 100 + " ms");
        }
    }
}

Edit2: (Aforge full-size Crop..) method Nr. 2

        for (int i = 0; i < 100; i++)
        {
            Crop crop = new Crop(new Rectangle(0, 0, source.Width, source.Height));
            var source2 = crop.Apply(source);
            source2.Dispose();

        }

Average = 62ms (40ms less that 1st Aforge approach)

Results:

  1. BitmapClone (0 ms) ?? (cheating, isn't it?)
  2. Aforge #2 (65 ms)
  3. Aforge #1 (105 ms)
  4. Rectangle (170 ms)
  5. Lock Bits (803 ms) (waiting for fixes/new test results..)
解决方案

I whipped up a quick (and admittedly rough) manual solution that demonstrates how to do this using locked bitmaps. It should be considerably faster than the alternative methods, but does involve a lot more code.

        Bitmap bmp = new Bitmap(@"C:\original.jpg");
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        BitmapData rawOriginal = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        int origByteCount = rawOriginal.Stride * rawOriginal.Height;
        byte[] origBytes = new Byte[origByteCount];
        Marshal.Copy(rawOriginal.Scan0, origBytes, 0, origByteCount);

        //I want to crop a 100x100 section starting at 15, 15.
        int startX = 15;
        int startY = 15;
        int width = 100;
        int height = 100;
        int BPP = 4;        //4 Bpp = 32 bits, 3 = 24, etc.

        byte[] croppedBytes = new Byte[width * height * BPP];

        //Iterate the selected area of the original image, and the full area of the new image
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width * BPP; j += BPP)
            {
                int origIndex = (startX * rawOriginal.Stride) + (i * rawOriginal.Stride) + (startY * BPP) + (j);
                int croppedIndex = (i * width * BPP) + (j);

                //copy data: once for each channel
                for (int k = 0; k < BPP; k++)
                {
                    croppedBytes[croppedIndex + k] = origBytes[origIndex + k];
                }
            }
        }

        //copy new data into a bitmap
        Bitmap croppedBitmap = new Bitmap(width, height);
        BitmapData croppedData = croppedBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
        Marshal.Copy(croppedBytes, 0, croppedData.Scan0, croppedBytes.Length);

        bmp.UnlockBits(rawOriginal);
        croppedBitmap.UnlockBits(croppedData);

        croppedBitmap.Save(@"C:\test.bmp");

I used this original image:

To output this image, cropped to 100x100 @ 15,15:

Obviously if you use this code, you'll want to clean it up a bit and add error handling. If I understand your question correctly, doing things this way should eliminate the need to use AForge at all.

这篇关于从种植的BitmapData面积用C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-25 13:33