问题描述
我有一个位图的 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.Clone(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的方法)
结果:
- BitmapClone(0毫秒)? (欺骗,不是吗?)
- Aforge#2(65毫秒)
- Aforge#1(105毫秒)
- 矩形(170毫秒)
- 锁定位(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:
- BitmapClone (0 ms) ?? (cheating, isn't it?)
- Aforge #2 (65 ms)
- Aforge #1 (105 ms)
- Rectangle (170 ms)
- 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#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!