如何将此方法转换为更快地使用 LockBits 并且它将比较 3 个或更多图像?

Posted

技术标签:

【中文标题】如何将此方法转换为更快地使用 LockBits 并且它将比较 3 个或更多图像?【英文标题】:How can convert this method ot use LockBits to be faster and that it will compare 3 images or more? 【发布时间】:2014-11-28 17:23:38 【问题描述】:

该方法获取两个图像。一种是来自资源的始终相同的图像。 第二个是下载的图像,可能与资源中的图像相同或不同。 然后方法返回tre或false。

//*** This function compare images region specific area ( in this case the "radar close" text area ) ***\\
        public bool ImageComparison(Bitmap Image1, Bitmap Image2, Rectangle Rect, double tol)
        
            //Logger.Write("Rect >>>> " + Rect.ToString());
            double color_distance;
            int x;
            int y;
            bool different = false;
            textbox3 = Rect.ToString();
            //if pictures are not of same size, return that they are different
            if (Image1.Width != Image2.Width || Image1.Height != Image2.Height)
            
                Logger.Write("Image1 Width >>>> " + Image1.Width.ToString());
                Logger.Write("Image2 Width >>>> " + Image2.Width.ToString());
                Logger.Write("Image1 Height >>>> " + Image1.Height.ToString());
                Logger.Write("Image2 Height >>>> " + Image2.Height.ToString());
                Logger.Write("Returned False images were different size");
                MessageBox.Show("Images are different Size");
                textbox1 = "";
                textbox2 = "";
                textbox3 = "";
                return false;
            
            //Iterate over the Rect
            for (x = Rect.X; x < Rect.X + Rect.Width; ++x)
            
                for (y = Rect.Y; y < Rect.Y + Rect.Height; ++y)
                
                    //check, if x and y are inside the picture
                    if (x >= 0 && x < Image1.Width && y >= 0 && y < Image1.Height &&
                     x < Image2.Width && y < Image2.Height)
                    
                        Color c = Image1.GetPixel(x, y);
                        textbox1 = c.ToString();
                        Color c2 = Image2.GetPixel(x, y);
                        textbox2 = c2.ToString();


                            double Dr = c.R - c2.R;
                            double Dg = c.G - c2.G;
                            double Db = c.B - c2.B;

                            color_distance = Math.Sqrt(Dr * Dr + Dg * Dg + Db * Db);

                            if (color_distance > tol)
                            
                                different = true;
                                break;
                            
                    
                    else
                    
                        throw new Exception(" Hello!! your region is way off!!!.. major bug!");

                    
                

                if (different)
                    break;
            
            //Logger.Write("differenet bool is now >>>> " + different.ToString());
            return !different;

        

问题是我正在使用 GetPixel 和 SetPixel,它在某些下载的图像上可能太慢了。所以我想把它改成LockBits。 第二件事是我想改变方法,所以现在它会得到 3 张图片,不仅 2 张而且第三张图片也将来自资源。

这就是我在form1中使用方法的方式:

if (ImagesComparion1.ImageComparison(File1, file2, image_scan_text_rect, 50) == true)
                        
                            File1.Dispose();
                            Properties.Resources.RadarImageClose.Dispose();
                            label18.Text = "The Radar Is Not Active Now";
                            label18.Visible = true;
                        
                        else
                        
                            File1.Dispose();
                            Properties.Resources.RadarImageClose.Dispose();
                            label18.Text = "The Radar Is Active Now";
                            label18.Visible = true;
                        

而file2是资源中的图片:

file2 = Properties.Resources.RadarImageClose;

而File1是下载的图片:

File1 = new Bitmap(Properties.Resources.RadarImageClose);

现在我想改变制作这个东西的方法:

    使用 LockBits 代替 GetPixel 和 SetPixel。

    获取3张图片,进行两次对比处理:

    首先将第一个资源图像file2与File1进行比较,然后在将同样是资源图像的file3与File1进行比较的方法中进行另一个比较过程。

我将方法顶部更改为:

public bool ImageComparison(Bitmap Image1, Bitmap Image2, Bitmap Image3, Bitmap Image4, Rectangle Rect, double tol)

Image1 Image 3 和 Image4 都是从资源中获取资源图片。 Image2 是下载的图片。

我需要使用 LockBits 并首先将 Image1 与 Image2 进行比较,然后将 Image3 与 Image2 进行比较,然后将 Image4 与 Image2 进行比较。

如果其中一个比较结果为真,则该方法返回真,而不进行其余比较,如果所有比较均返回结果为假,则该方法返回假。

这是我做的一个测试,我拿了 3 个图片框并放在左边和中间的图像中,里面的文字都有不同的文字,但都意味着雷达接近。在右边我有一个打开的雷达图像。我在同一区域的所有它们上画了一个红色矩形,它们都在同一区域。

【问题讨论】:

【参考方案1】:

使用此功能比较两个图像:

private bool ImageComparison(Bitmap Image1, Bitmap Image2, Rectangle Rect, double tol)
    
        int x, y, p, stride1, stride2;
        int bytes, bytesPerPixel;
        byte[] rgbValues1;
        byte[] rgbValues2;
        double Dr, Dg, Db, color_distance;
        IntPtr ptr;
        Rectangle rect;
        BitmapData bitmap_Data;

        if ( (Image1.Width != Image2.Width) || (Image1.Height != Image2.Height) )
        
            MessageBox.Show("Images are different Size");

            return false;
        

        if (Rect.X < 0 || Rect.Y < 0 || ((Rect.X + Rect.Width) > Image1.Width) || ((Rect.Y + Rect.Height) > Image1.Height))
        
            MessageBox.Show("Hello!! your region is way off!!!.. major bug!");

            return false;
        



        rect = new Rectangle(0, 0, Image1.Width, Image1.Height);

        //Lock bitmap to copy its color information fast
        bitmap_Data = Image1.LockBits(rect, ImageLockMode.ReadWrite, Image1.PixelFormat);
        ptr = bitmap_Data.Scan0;
        stride1 = bitmap_Data.Stride;
        bytes = bitmap_Data.Stride * Image1.Height;

        rgbValues1 = new byte[bytes];

        //copy color information to rgbValues array
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues1, 0, bytes);

        //we are done copying so unlock bitmap. We dont need it anymore
        Image1.UnlockBits(bitmap_Data);



        rect = new Rectangle(0, 0, Image2.Width, Image2.Height);

        //Lock bitmap to copy its color information fast
        bitmap_Data = Image2.LockBits(rect, ImageLockMode.ReadWrite, Image2.PixelFormat);
        ptr = bitmap_Data.Scan0;
        stride2 = bitmap_Data.Stride;
        bytes = bitmap_Data.Stride * Image2.Height;

        rgbValues2 = new byte[bytes];

        //copy color information to rgbValues array
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues2, 0, bytes);

        //we are done copying so unlock bitmap. We dont need it anymore
        Image2.UnlockBits(bitmap_Data);


        if (stride1 != stride2) //different pixel format
        
            MessageBox.Show("Different pixel format");
            return false;
        


        bytesPerPixel = Image.GetPixelFormatSize(Image1.PixelFormat) / 8;

        //scan images pixel per pixel
        for (y = 0; y < Image1.Height; y++)
        
            for (x = 0; x < Image1.Width; x++)
            
                p = y * stride1 + x * bytesPerPixel;

                Dr = (double)(rgbValues1[p + 2] - rgbValues2[p + 2]);
                Dg = (double)(rgbValues1[p + 1] - rgbValues2[p + 1]);
                Db = (double)(rgbValues1[p] - rgbValues2[p]);

                color_distance = Math.Sqrt(Dr * Dr + Dg * Dg + Db * Db);

                if (color_distance > tol)
                
                    return false;
                
            
        


        return true;
    

如果您想比较多个,请将它们插入到 列表中:

List<Bitmap> bitmapListToCompare = new List<Bitmap>();

bitmapListToCompare.Add(....);
bitmapListToCompare.Add(....);
....

然后:

int i;
bool bl;
Bitmap bitmapToCompareWith = new Bitmap(...); //your bitmap to use as reference 
                                              //for your comparisons
for (i = 0; i < bitmapListToCompare.Count; i++)

    bl = ImageComparison(bitmapToCompareWith, bitmapListToCompare[i], ...., ....);
    if (bl == false)
    
        MessageBox.Show("Image " + i.ToString() + " was different!");
        break;
    

【讨论】:

比较有问题。现在图像已下载,资源中的图像完全相同。但是该方法返回 false 并显示“不同的像素格式”并且还显示“雷达现在处于活动状态”,而它假设返回 true 并且雷达现在不应该处于活动状态。这是为了比较两个下载的图片和资源。 @JamesAharon ...资源中的完全相同。你怎么知道?在您看来它可能看起来相同,但正如消息中所说,它们具有不同的格式,例如,一种可能是 24 位,另一种可能是其他格式。 你可以在这里看到ims.gov.il/IMS/tazpiot/RainRadar.htm雷达这是我正在下载的图像并将其与资源中的图像进行比较,它们是相同的,矩形应该告诉它是相同的并返回true并且雷达很近。 @JamesAharon 他们的文件大小一样吗? γηράσκω δ' 在我使用的旧方法中,当链接中的雷达与此图像和内部文本一起使用时,它工作正常,我确实将它与它显示的资源进行了比较,当有在没有此文本的链接图像中,它显示雷达处于打开状态。它在旧方法中起作用,也许扫描或比较不够好,但是当雷达打开和关闭并且它起作用时,我看到它确实起作用了。

以上是关于如何将此方法转换为更快地使用 LockBits 并且它将比较 3 个或更多图像?的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以比 for 循环更快地遍历数组吗?

更快地进行进制转换

将文件转换为字节值数字数组

需要一种更快的方法将 cv::Mat 转换为一维向量形式

有没有更快的方法将大文件从十六进制转换为二进制,二进制转换为int?

LockBits 图像旋转方法不起作用?