8
votes

Casser une zone de Bitmapdata avec C #

J'ai un bitmap SourceImage.bmp

Verrouillage Il s'agit de bits: xxx

do analyse, Obtenez un clone : xxx

déverrouillage bits: xxx

est-il possible de spécifier quelle partie de "Dataoriginal" copier (x, y, w, h)? Ou de créer de nouvelles données à partir du dataoriginal, spécifiant les coordonnées X et Y ainsi que H et W?

L'objectif est de copier une petite zone de cette image. Cette méthode pourrait être plus rapide que le drawimage, c'est pourquoi je n'utilise pas ce dernier.

edit:

donc j'ai pris 29 Mo < / Strong> Bitmap et fait des tests hardcore! Crop totale (fondamentalement une copie) + 100 itérations.

http: // i. minus.com/ibmcust1qugw6f.png

code: xxx

EDIT2: (Aforged Crop Taille Crop .. ) méthode nr. 2 xxx

moyenne = 62 ms (40 ms de moins que la 1ère approche Aforge)

résultats:

  1. bitmapclone (0 ms) ?? (tricher, n'est-ce pas?)
  2. AFORGE # 2 (65 ms)
  3. Aforge # 1 (105 ms)
  4. Rectangle (170 ms)
  5. BITS LOCK (803 ms) (attendant des correctifs / nouveaux résultats de test ..)

4 commentaires

La réponse est oui, mais vous allez devoir écrire une fonction à faire si vous voulez que ce soit rapide. Vous devrez créer une nouvelle bitmapdata de la taille souhaitée et itérale sur les données d'origine comme des octets, copier dans un nouveau réseau d'octets, que vous pouvez ensuite faire monter dans le nouveau bitmapdata.


Cette question est extrêmement perspicace. J'essaie de contourner une grosse image dans de nombreux plus petits 8x8. Les méthodes graphiques.drawimage () et bitmap.clone () sont extrêmement lentes pour cela.


Vous avez raison, le clone Bitmap triche depuis que vous n'avez rien fait avec le clone, il effectue une copie sur l'écriture, de sorte que vous n'avez pas changé dans le clone qu'il ne copie pas du tout.


Les bits de verrouillage sont lents à cause de l'appel du maréchal, comme certains ont suggéré dans les réponses


5 Réponses :


2
votes

Vous pouvez essayer quelque chose comme ceci: xxx

et faire quelque chose comme celui-ci dans le code YOUT (échantillon): xxx

J'espère Il aide!


3 commentaires

"Var Croppedimagem = CropBitmap (Dataoriginal, 0, 0, 100, 100);" - Les programmes ne fonctionnent pas de cette façon .. Vous ne pouvez pas mettre (bitmapdata) dans le champ (bitmap), également cette méthode est similaire à celle des dessins. Je prévois de recadrer jusqu'à 30 images en même temps. Les deux dessins et le bitmap.clone sont très consommés / lents, donc je me demandais si je peux juste cultiver bitmapdata.


Désolé, vous devez passer une instance bitmap et non une instance de bitmapdata. J'ai testé ce code ici et ça fonctionne bien, de Couse Vous devez avoir une image à la bonne taille de la taille du rectangle que vous souhaitez couper. Si vous voulez aborder beaucoup d'images, je vous recommanderais de l'intégrer sur le thread pour obtenir des performances. Vous ne pouvez pas couper un imagément 0,0100 100, si cette image est 20x20 pixels. Pouvez-vous prendre le bitmap et Ingnore Bitmapdata? Pourquoi avez-vous besoin de l'instance BitmapData?


Bitmap.clone est très lent si vous voulez prendre une grosse image et le cultiver en petites images 8x8.



8
votes

J'ai fouillé une solution manuelle rapide (et certes agitée) qui démontre comment procéder à cela à l'aide de bitmaps verrouillés. Il devrait être considérablement plus rapide que les méthodes alternatives, mais implique beaucoup plus de code. xxx

J'ai utilisé cette image d'origine:

 original

Pour sortir cette image, recadré à 100x100 @ 15,15:

recadré

évidemment si vous utilisez ce code, vous souhaitez le nettoyer un peu et ajouter une erreur. manutention. Si je comprends votre question correctement, faites des choses de cette façon devrait éliminer la nécessité d'utiliser Aforge du tout.


10 commentaires

Tout d'abord, merci pour votre temps et vos efforts en train d'écrire ce code! Deuxièmement, j'ai fait des tests, mais malheureusement cette solution a les pires résultats! ;) N'hésitez pas à critiquer mon approche de test .. Peut-être que j'ai commis une erreur ou deux. (Voir Modifier)


Intéressant, je ne m'attendais pas à ça. Je vais faire un peu de mes propres tests et voir si mes résultats sont d'accord avec le vôtre.


ce serait bien! J'ai essayé de faire un cadre de test aussi simple que possible d'exclure des erreurs graves (code intégral en édition), mais peut-être que vous obtiendrez d'autres résultats en utilisant une approche différente. Dans l'attente de ça!


Hey, j'ai trébuché sur cette question et je ne comprends pas deux choses: pourquoi appelez-vous bmp.lockbits pour le rectangle couvrant une image entière et non seulement recto? Et pourquoi voudriez-vous le maréchal.copiez-vous, si vous pouvez lire directement du pointeur? J'ai déjà écrit pour moi-même un code qui ne verrouille que la zone nécessaire et la copie directement du pointeur sans maréchal (pour éviter les progrès étranges), mais tout le code que j'ai vu semble faire votre chemin, et je me demande simplement si Il y a une raison quelconque, à part cette méthode étant délicate.


@Trakos salut, vous souhaiteriez-vous un exemple de code pour votre méthode que je pourrais essayer s'il vous plaît?


@Fopedush Salut, j'ai utilisé une image de 1455x352 et j'ai essayé d'extraire un rectangle de 873,0,291,172, mais je reçois 'index d'exception hors de portée sur cette ligne: CuppedBytes [Croppedindex + K] = Origbytes [Origindex + K];


@Andrewsimpson J'ai ajouté une réponse ci-dessous, je l'ai cible ensemble à partir de deux de mes méthodes, il peut donc y avoir des bugs.


@Fopedush comme annuellement12 a souligné à moi (mais aussi peu de réputation encore;)), startex et starty sont commutés dans votre code. Cela semble être la raison pour laquelle @andrewsimpson avait l'index hors de portée d'exception.


Pour ceux qui veulent utiliser ce code: Changer int Origindex = (StartX * Raworiginal.stride) + (i * Raworiginal.stride) + (starty * BPP) + (j); to > int Origindex = (Starty * Raworiginal.Stride) + (i * RaworiGinal.Stride) + (startx * BPP) + (j);


Je pense que c'est une bonne solution, il suffit de définir le BPP car les octets-per-pixels sont un peu un problème. Que serait-il pour 1 bit par pixel (image monochrome)? C'est pourquoi, dans de tels scénarios, il est généralement défini comme un BPP - bits par pixel. SO 3 BPP = 24 BPP.



3
votes

La réponse de Fopedush bénéficie grandement lorsque nous sous-hésitants Marshal.copy avec MemCy, car de cette façon, nous n'avons pas à la copier à travers un tableau d'octets []. De cette façon, la mémoire n'est copiée qu'une seule fois, au lieu de trois fois!

for (int k = 0; k < Math.Abs(croppedBitmapData.Stride) * rectangle.Height; k++)
     *(croppedImagePointer++) = *(sourceImagePointer++);


6 commentaires

Pour une raison étrange, je reçois accèsViolationException à Memcpy en disant quelque chose sur la lecture / écriture à la mémoire protégée.


Peut-être que vous devez ajuster la constante BPP? Dans mon exemple, il suppose 32 bits, (ARGB), pour l'utilisation de 24 bits (RVB) 3. AccessViolationException signifie que vous essayez d'accéder à la mémoire des limites.


Je ne pense pas que cela aidera puisqu'il assigné, mais jamais utilisé.


Vous utilisez un pointeur d'octet tandis que MEMCY utilise un pointeur aligné UINT, voir Stackoverflow.com/q/19187562/640195


@Kosmos La raison pour laquelle il jette une erreur est parce qu'il met à jour la foulée de destination pour égale la foulée de source, mais cela ne peut être réussi que lorsque la largeur de la destination est identique à la largeur de la source.


En outre, ce code suppose que la destination X et Y seront identiques à la source X et Y car elle ne compense pas la traduction. Pour ces raisons, évitez d'utiliser le code dans cette réponse et utilisez plutôt le code dans la réponse de Trakos ci-dessous.



2
votes

Cette classe obtient votre bitmap Obj. puis les verrouilles. en CTOR. Lorsque vous appelez la méthode de la culture, il utilise memcpy pour copier la région souhaitée sur le nouveau BMP.

Lockbits : raconte le collecteur des ordures de ne pas bouger mes bits n'importe où, cuz im Je vais le modifier par des pointeurs (Scan0).

memcpy : la copie la plus rapide. peut copier des blocs de mémoire. Optimisé par certains experts.

Pourquoi memcpy rapide?

au lieu de copier octet par octet, (largeur hauteur) accès à la mémoire. Memcpy bloque-t-il par bloc, beaucoup plus moins que W h fois. xxx


2 commentaires

Bienvenue dans le débordement de pile. Peut-être que vous puissiez lire stackoverflow.com/help/how-to-answer d'abord pour rendre votre réponse mieux conforme à la Donc les normes.


Bien que cela soit gentil de votre part, donc une communauté de codage indépendante. Vous devez expliquer comment cela aide l'OP, puis fournir le code pertinent. Juste coller le code de travail ne répond pas vraiment à une question que cela fournit des travaux indépendants.



2
votes

Je suis un nouvel utilisateur et je ne peux pas encore voter, sinon j'aurais upé La réponse de Korwin80 car il fournit la solution de travail la plus efficace, À mon avis. La solution TRAKOS 'peut exécuter plus rapidement mais donne des images brouillées, au moins pour moi. Voici comment j'ai appliqué Solution Korwin80 , avec quelques améliorations mineures, dans mon propre code:

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
private unsafe static extern int memcpy(byte* dest, byte* src, long count);

private unsafe Bitmap Crop(Bitmap srcImg, Rectangle rectangle)
{
    if ((srcImg.Width == rectangle.Width) && (srcImg.Height == rectangle.Height))
        return srcImg;

    var srcImgBitmapData = srcImg.LockBits(new Rectangle(0, 0, srcImg.Width, srcImg.Height), ImageLockMode.ReadOnly, srcImg.PixelFormat);
    var bpp = srcImgBitmapData.Stride / srcImgBitmapData.Width; // 3 or 4
    var srcPtr = (byte*)srcImgBitmapData.Scan0.ToPointer() + rectangle.Y * srcImgBitmapData.Stride + rectangle.X * bpp;
    var srcStride = srcImgBitmapData.Stride;

    var dstImg = new Bitmap(rectangle.Width, rectangle.Height, srcImg.PixelFormat);
    var dstImgBitmapData = dstImg.LockBits(new Rectangle(0, 0, dstImg.Width, dstImg.Height), ImageLockMode.WriteOnly, dstImg.PixelFormat);
    var dstPtr = (byte*)dstImgBitmapData.Scan0.ToPointer();
    var dstStride = dstImgBitmapData.Stride;

    for (int y = 0; y < rectangle.Height; y++)
    {
        memcpy(dstPtr, srcPtr, dstStride);
        srcPtr += srcStride;
        dstPtr += dstStride;
    }

    srcImg.UnlockBits(srcImgBitmapData);
    dstImg.UnlockBits(dstImgBitmapData);
    return dstImg;
}


0 commentaires