le cadrage d'une zone de BitmapData avec C#
J'ai un bitmap sourceImage.bmp
de verrouillage, il est bits:
BitmapData dataOriginal = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Faire l'analyse, obtenir un clone:
Bitmap originalClone = AForge.Imaging.Image.Clone(dataOriginal);
déverrouillage bits:
sourceImage.UnlockBits(dataOriginal);
est-il possible de spécifier quelle partie de "dataOriginal" pour copier (x,y,w,h)? ou pour créer de nouvelles données à partir de la dataOriginal, en précisant les coordonnées X et Y ainsi que de H et W?
Le but est de copier une petite zone de cette image. Cette méthode pourrait être plus rapide que DrawImage, c'est pourquoi je n'utilise pas le dernier.
Edit:
J'ai donc pris 29 Mo bitmap et fait un peu de hardcore, des tests! Pleine taille de la récolte (en fait une copie) + 100 itérations.
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 pleine taille, Culture..) méthode N ° 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();
}
Moyenne = 62ms (40ms moins que le 1er Aforge approche)
Résultats:
- BitmapClone (0 ms) ?? (tricherie, n'est-ce pas?)
- Aforge #2 (65 ms)
- Aforge #1 (105 ms)
- Rectangle (170 ms)
- De verrouillage Bits (803 ms) (en attente de corrections/nouveaux résultats d'analyses..)
- La réponse est oui, mais vous allez avoir à écrire une fonction pour le faire, si vous voulez qu'il soit rapide. Vous devrez créer un nouveau bitmapdata de la taille désirée, et itérer sur les données d'origine des octets, la fonction de copie dans un nouveau tableau d'octets, que vous pouvez ensuite le maréchal dans le new bitmapData.
- Cette question est extrêmement perspicace. Je suis en train de rogner une image en plusieurs petites 8x8 ceux. Les graphiques.DrawImage() et Bitmap.Clone() les méthodes sont extrêmement lents pour que.
- Vous avez raison, Bitmap clone est de la triche, puisque vous n'avez rien faire d'autre que le clone, il fait une copie sur écriture donc, tant que vous n'avez pas de changements pour le clone, il ne copie pas du tout.
- Verrouillage de Bits est lente en raison de la Maréchal appel, comme certains l'ont suggéré dans les réponses
Vous devez vous connecter pour publier un commentaire.
J'ai préparé un rapide (et, certes, rugueux) solution manuelle qui montre comment le faire en utilisant verrouillé bitmaps. Il devrait être beaucoup plus rapide que les autres méthodes, mais n'impliquent beaucoup plus de code.
J'ai utilisé cette image d'origine:
À la sortie de cette image recadrée à 100x100 @ 15,15:
Évidemment, si vous utilisez ce code, vous aurez envie de nettoyer un peu et ajouter la gestion des erreurs. Si je comprends votre question correctement, faire les choses de cette manière, on doit éliminer la nécessité d'utiliser AForge à tous.
startX
etstartY
sont activés dans votre code. Cela semble être la raison pourquoi @AndrewSimpson avait l'index hors de portée de l'exception.Fopedush réponse bénéficie grandement lorsque nous substituer Maréchal.copie avec memcpy, parce que de cette façon nous n'avons pas à le copier par un byte[] tableau. De cette façon, la mémoire est copié qu'une seule fois, au lieu de trois fois!
Mes résultats sont:
Je n'ai pas AForge donc je n'ai pas compris, mais en regardant sur op résultats, il serait plus lent que cela. J'ai été le tester de couper l'image en deux.
Veuillez noter, que si nous voulons échanger avec memcpy:
il obtient 10x plus lent!
Vous pouvez essayer quelque chose comme ceci:
Et faire quelque chose comme ceci dans votre code (exemple):
J'espère que cela aide!
Je suis un nouvel utilisateur et ne peut pas voter encore, sinon je l'aurais upvoted Korwin80's réponse qu'il fournit le plus efficace de solution, à mon avis. trakos' solution peut exécuter plus rapidement, mais les rendements brouillés images, au moins pour moi. Voici comment j'ai appliqué de la Korwin80's solution, avec quelques améliorations mineures, dans mon propre code:
cette classe devient votre image bitmap obj . puis lockbits. dans ctor.
Lorsque vous appelez la méthode de culture, il utilise memcpy pour copier la région désirée pour la nouvelle bmp.
lockbits: indique le garbage collector de ne PAS déplacer mon bits n'importe où, parce que je vais le modifier par des pointeurs (scan0).
memcpy : le plus rapide de copier. pouvez copier des blocs de mémoire. optimisé par certains experts.
pourquoi memcpy rapide?
au lieu de la copie octet par octet (largeurhauteur) temps d'accès à la mémoire .
memcpy fait bloc par bloc, beaucoup plus de moins de wh fois .