本文介绍了与lockbits图像处理,替代getpixel?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用提高我lockbits图像检测类,但用这个代码导致问题,因此它不运行。我怎么能去,以加快图像检测使用lockbits和getpixel的同时,也可有人告诉我另一种是一样快?



代码

 静态的IntPtr IPTR = IntPtr.Zero; 
静态的BitmapData位图数据= NULL;
静态公共字节[] {像素搞定;组; }
静态公众诠释深度{搞定;私人集; }
静态公众诠释宽度{获得;私人集; }
静态公众诠释身高{获得;私人集; }

静态公共无效LockBits(位图源)

{
//获取宽度和位图
的高度宽度= source.Width;
高度= source.Height;

//获得总像素锁定计数
INT PixelCount =宽*高;

//创建一个矩形锁定
矩形RECT =新的Rectangle(0,0,宽度,高度);

//获取源位图的像素格式大小
深度= System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);


//锁位并返回位图数据
位图数据= source.LockBits(RECT,ImageLockMode.ReadWrite,
source.PixelFormat);

//创建字节数组复制像素值
INT步=深度/ 8;
像素=新的字节[PixelCount *步]
IPTR = bitmapData.Scan0;

//复制从指针数组
Marshal.Copy(IPTR,像素,0,Pixels.Length)的数据;

}


静态公共布尔SimilarColors(INT R1,诠释G1,诠释B1,诠释R2,诠释G2,诠释B2,INT公差)
{
布尔的returnValue = TRUE;
如果(Math.Abs​​(R1 - R2)>公差|| Math.Abs​​(G1 - G2)GT;公差|| Math.Abs​​(B1 - B2)>宽容)
$ { b $ b =的returnValue虚假的;
}
返回的returnValue;
}


公共BOOL findImage(位图小,位图大,出点位置)
{
不安全
{
LockBits(小);
LockBits(大);
//循环大的图像宽度
为(INT largeX = 0; largeX< large.Width; largeX ++)
{
//和高度
为( INT largeY = 0; largeY< large.Height; largeY ++)
{
//循环通过小宽度
为(INT smallX = 0; smallX< small.Width; smallX ++)
{
//和高度
为(INT smallY = 0; smallY< small.Height; smallY ++)
{
//获取当前像素为图像
颜色currentSmall = small.GetPixel(smallX,smallY);
颜色currentLarge = large.GetPixel(largeX + smallX,largeY + smallY);
//如果他们不匹配(即图像是不存在的)

如果(!colorsMatch(currentSmall,currentLarge))
//转到大的图像中的下一个像素

转到nextLoop;
}
}
//如果所有像素相匹配,则返回true,并改变点位置到发现
位置=新点左上角的坐标( largeX,largeY);
返回真;
//转到大型图像
nextLoop下一个像素:
继续;
}
}
//返回假,如果图像不被发现,并设置一个空的点
位置= Point.Empty;
返回FALSE;
}
}


解决方案

您不想依靠与getPixel(),图像处理;它的好,使一个偶然的电话拿到一分值(如鼠标悬停),但在总体上是最好做的图像处理图像存储器或在某些二维数组,你可以在必要时转换为位图。



要开始,你可以尝试编写方法,使用LockBits / UnlockBits提取一个数组,它是方便操控。一旦你完成操作数组,可以使用不同的LockBits / UnlockBits功能写回位图。



下面是我在使用的一些示例代码过去。第一个函数返回从位图值的一维数组。既然你知道了位图的宽度,可以将此一维数组转换为二维数组作进一步处理。一旦你完成处理,就可以调用第二个函数的(修改)一维数组再次转换成位图。

 公共静态的byte [] Array1DFromBitmap(BMP位图){
如果(BMP == NULL)抛出新的NullReferenceException(位图为空);

矩形RECT =新的Rectangle(0,0,bmp.Width,bmp.Height);
的BitmapData数据= bmp.LockBits(RECT,ImageLockMode.ReadWrite,bmp.PixelFormat);
IntPtr的PTR = data.Scan0;

//声明数组来保存位
INT的numBytes = data.Stride * bmp.Height的字节;
字节[]字节=新的字节[的numBytes]

//复制的RGB值到数组
System.Runtime.InteropServices.Marshal.Copy(PTR,字节,0的numBytes);

bmp.UnlockBits(数据);

返回字节;
}

公共静态位图BitmapFromArray1D(字节[]字节,INT宽度,诠释高)
{
位图grayBmp =新位图(宽度,高度的PixelFormat。 Format8bppIndexed);
矩形grayRect =新的Rectangle(0,0,grayBmp.Width,grayBmp.Height);
的BitmapData grayData = grayBmp.LockBits(grayRect,ImageLockMode.ReadWrite,grayBmp.P​​ixelFormat);
IntPtr的grayPtr = grayData.Scan0;

INT grayBytes = grayData.Stride * grayBmp.Height;
ColorPalette PAL = grayBmp.P​​alette;

为(INT G = 0; G< 256; G ++){$​​ B $ B pal.Entries [G] = Color.FromArgb(G,G,G);
}

grayBmp.P​​alette = PAL;

System.Runtime.InteropServices.Marshal.Copy(字节,0,grayPtr,grayBytes);

grayBmp.UnlockBits(grayData);
返回grayBmp;
}



这些方法使得对位图像素格式假设可能不适合你的工作,但我希望的总体思路是明确的:使用LockBits / UnlockBits从位图中提取的字节数组,这样你可以很容易地编写和调试算法,然后再次使用LockBits / UnlockBits试写入阵列位图

有关可移植性,我建议你的方法返回所需的数据类型,而不是操纵方法本身中的全局变量。



如果您已经使用getPixel(),然后从上述可以为编码工作的一个小的投资大大加快你的代码的数组转换成/。


I am trying to increase my image detection class using lockbits, yet this cause problems with the code and thus it does not run. How can i go about using lockbits and getpixel at the same time in order to speed up image detection, or can someone show me an alternative which is just as fast?

code:

static IntPtr Iptr = IntPtr.Zero;
    static BitmapData bitmapData = null;
    static public byte[] Pixels { get; set; }
    static public int Depth { get; private set; }
    static public int Width { get; private set; }
    static public int Height { get; private set; }

    static public void LockBits(Bitmap source)

    {
            // Get width and height of bitmap
            Width = source.Width;
            Height = source.Height;

            // get total locked pixels count
            int PixelCount = Width * Height;

            // Create rectangle to lock
            Rectangle rect = new Rectangle(0, 0, Width, Height);

            // get source bitmap pixel format size
            Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);


            // Lock bitmap and return bitmap data
            bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
                                         source.PixelFormat);

            // create byte array to copy pixel values
            int step = Depth / 8;
            Pixels = new byte[PixelCount * step];
            Iptr = bitmapData.Scan0;

            // Copy data from pointer to array
            Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);

    }


     static public bool SimilarColors(int R1, int G1, int B1, int R2, int G2, int B2, int Tolerance)
    {
        bool returnValue = true;
        if (Math.Abs(R1 - R2) > Tolerance || Math.Abs(G1 - G2) > Tolerance || Math.Abs(B1 - B2) > Tolerance)
        {
            returnValue = false;
        }
        return returnValue;
    }


     public bool findImage(Bitmap small, Bitmap large, out Point location)
     {
         unsafe
         {
             LockBits(small);
             LockBits(large);
             //Loop through large images width
             for (int largeX = 0; largeX < large.Width; largeX++)
             {
                 //And height
                 for (int largeY = 0; largeY < large.Height; largeY++)
                 {
                     //Loop through the small width
                     for (int smallX = 0; smallX < small.Width; smallX++)
                     {
                         //And height
                         for (int smallY = 0; smallY < small.Height; smallY++)
                         {
                             //Get current pixels for both image
                             Color currentSmall = small.GetPixel(smallX, smallY);
                             Color currentLarge = large.GetPixel(largeX + smallX, largeY + smallY);
                             //If they dont match (i.e. the image is not there)

                             if (!colorsMatch(currentSmall, currentLarge))
                                 //Goto the next pixel in the large image

                                 goto nextLoop;
                         }
                     }
                     //If all the pixels match up, then return true and change Point location to the top left co-ordinates where it was found
                     location = new Point(largeX, largeY);
                     return true;
                 //Go to next pixel on large image
                 nextLoop:
                     continue;
                 }
             }
             //Return false if image is not found, and set an empty point
             location = Point.Empty;
             return false;
         }
     }
解决方案

You wouldn't want to rely on getPixel() for image processing; it's okay to make an occasional call to get a point value (e.g. on mouseover), but in general it's preferable to do image processing in image memory or in some 2D array that you can convert to a Bitmap when necessary.

To start, you might try writing a method that using LockBits/UnlockBits to extract an array that is convenient to manipulate. Once you're done manipulating the array, you can write it back to a bitmap using a different LockBits/UnlockBits function.

Here's some sample code I've used in the past. The first function returns a 1D array of values from a Bitmap. Since you know the bitmap's width, you can convert this 1D array to a 2D array for further processing. Once you're done processing, you can call the second function to convert the (modified) 1D array into a bitmap again.

public static byte[] Array1DFromBitmap(Bitmap bmp){
    if (bmp == null) throw new NullReferenceException("Bitmap is null");

    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
    IntPtr ptr = data.Scan0;

    //declare an array to hold the bytes of the bitmap
    int numBytes = data.Stride * bmp.Height;
    byte[] bytes = new byte[numBytes];

    //copy the RGB values into the array
    System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes);

    bmp.UnlockBits(data);

    return bytes;
}

public static Bitmap BitmapFromArray1D(byte[] bytes, int width, int height)
{
    Bitmap grayBmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
    Rectangle grayRect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height);
    BitmapData grayData = grayBmp.LockBits(grayRect, ImageLockMode.ReadWrite, grayBmp.PixelFormat);
    IntPtr grayPtr = grayData.Scan0;

    int grayBytes = grayData.Stride * grayBmp.Height;
    ColorPalette pal = grayBmp.Palette;

    for (int g = 0; g < 256; g++){
        pal.Entries[g] = Color.FromArgb(g, g, g);
    }

    grayBmp.Palette = pal;

    System.Runtime.InteropServices.Marshal.Copy(bytes, 0, grayPtr, grayBytes);

    grayBmp.UnlockBits(grayData);
    return grayBmp;
}

These methods makes assumptions about the Bitmap pixel format that may not work for you, but I hope the general idea is clear: use LockBits/UnlockBits to extract an array of bytes from a Bitmap so that you can write and debug algorithms most easily, and then use LockBits/UnlockBits again to write the array to a Bitmap again.

For portability, I would recommend that your methods return the desired data types rather than manipulating global variables within the methods themselves.

If you've been using getPixel(), then converting to/from arrays as described above could speed up your code considerably for a small investment of coding effort.

这篇关于与lockbits图像处理,替代getpixel?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-09 18:41