当时也是用到了判断比较两副图片的差别作用,但好在Delphi的Bitmap类提供了ScanLines

           
(第一幅图片)                                                              
(第二幅图片)

 图片 1                     图片 2

先看个例证,那是对一张位图的各样像素按FF取补,然后输出到一个新图(代码有点啰嗦,可是相应可以表明难题了)。

图片 3                     图片 4

                        h += block.Height;
                    }

Bitmap bmpOut = new Bitmap(w, h, PixelFormat.Format24bppRgb);

 

将下边两幅图按20*20(px)大小“切分”:

pOut[0] = (byte)(255 – pIn[0]);
pOut[1] = (byte)(255 – pIn[1]);
pOut[2] = (byte)(255 – pIn[2]);

在程序处理时为增高速度,利用了Bitmap的LockBits方法,直接对图片的内存数据操作,并且“切分”图片的小块时,并不确实的“切图”,而是选用“内存指针”进行数量一定操作。如上面代码:

           
(第一幅图片)                                                              
(第二幅图片)

unsafe
{
byte* pIn = (byte*)(dataIn.Scan0.ToPointer());
byte * pOut = (byte*)(dataOut.Scan0.ToPointer());

 

                                        int bw = Math.Min(block.Width, bd1.Width – w);
                                        int bh = Math.Min(block.Height, bd1.Height – h);
                                        rects.Add(new Rectangle(w, h, bw, bh));

假设有一张图片宽度为6,因为是Format24bppRgb格式(每像素3字节。在偏下的切磋中,除非越发表达,否则Bitmap都被认为是24位RGB)的,分明,每一行必要6*3=18个字节存储。对于Bitmap就是这么。但对此BitmapData,即便BitmapData.Width如故等于Bitmap.Width,但大概是出于展现品质的考虑,每行的实际的字节数将改为大于等于它的丰裕离它近来的4的整倍数,此时的骨子里字节数就是Stride。就此例而言,18不是4的整倍数,而比18大的离18以来的4的倍数是20,所以这几个BitmapData.Stride
= 20。明显,当宽度本身就是4的翻番时,BitmapData.Stride = Bitmap.Width *
3。

 

 

BitmapData dataIn = m_Bmp.LockBits(new
Rectangle(0,0,w,h),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);
BitmapData dataOut = bmpOut.LockBits(new Rectangle(0, 0, w, h),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

           
(第一幅图片)                                                              
(第二幅图片)

大致完结形式就是:将两副图片同时按一定大小的小块“切分开”,再各自相比那么些小块,如若某个块里涌出有一个不比的象素点,那就以为此块所在的岗位是有差异的否则认为是如出一辙的,当比较完所有小块后,两副图中间的差别之处的职位也就出来了。因为要开展富有小块比较,所以最坏的情景下是要扫描比较图片的具有象素点(两副图完全相同的场馆时),最优良的动静就是只扫描比较所有小块的第一点(两副图完全分裂的景色时)。

本身在前两篇图片处理的稿子里大概都用BitmapData来做图片处理的,那么那几个东东到底是个什么玩意儿呢?
C#好是好,但拍卖图片时一个像素一个像素的操作像素可不是形似的慢,尤其是卡片机拍摄的大图片。其实Delphi也一如既往,但好在Delphi的Bitmap类提供了ScanLines,可以一行一行的读图,功效相比较高。C#应当也有接近的东东。经过一番查找,终于发现了BitmapData类。

 

                                    if (pc1->R != pc2->R || pc1->G != pc2->G || pc1->B != pc2->B)
                                    {
                                        //当前块有某个象素点颜色值不同.也就是有差别.

画个图可能更好掌握。R、G、B
分别代表3个原色分量字节,BGR就代表一个像素。为了看起来方便自己在每个像素之间插了个空格,实际上是从未有过的。X表示补足4的倍数而机关插入的字节。为了顺应人类的读书习惯自己分行了,其实在微机内存中应该作为三番五次的一大段。

                    while (h < bd1.Height && h < bd2.Height)
                    {
                        byte* p1 = (byte*)bd1.Scan0 + h * bd1.Stride;
                        byte* p2 = (byte*)bd2.Scan0 + h * bd2.Stride;

在程序处理时为增强速度,利用了Bitmap的LockBits方法,直接对图纸的内存数据操作,并且“切分”图片的小块时,并不真的的“切图”,而是接纳“内存指针”进行多少一定操作。如上边代码:

当今应该很好精晓了。首先用
BitmapData.Scan0找到第0个像素的第0个轻重的地址。那些地方指向的是个byte类型,所以登时定义为byte*
pIn。
行扫描时,在脚下指针地点(不妨看成当前像素的第0个颜色分量)一而再取出三个值(3个原色分量。注意,0
1 2意味着的次第是B G R。在取指针指向的值时,貌似p[n]和p +=
n再取p[0]是等价的),然后下移3个义务(pIn +=
3,看成指到下一个像素的第0个颜色分量)。做过Bitmap.Width次操作后,就到达了Bitmap.Width
* 3的岗位,应该要跳过图成功记为X的字节了(共有Stride – Width *
3个字节),代码中就是 pIn += dataIn.Stride – dataIn.Width * 3;
跳过将来指针就抵达下行的第0个像素了。按照此算法,一共须求做Bitmap.Height次行扫描(代码就是
for (int y = 0; y < dataIn.Height; y++))。

 

           
(第一幅图片)                                                              
(第二幅图片)

pIn += 3;
pOut += 3;
}

 

                    while (h < bd1.Height && h < bd2.Height)
                    {
                        byte* p1 = (byte*)bd1.Scan0 + h * bd1.Stride;
                        byte* p2 = (byte*)bd2.Scan0 + h * bd2.Stride;

pIn += dataIn.Stride – dataIn.Width * 3;
pOut += dataOut.Stride – dataOut.Width * 3;
}
}

以身作则项目代码下载:

 示例项目代码下载:/Files/kingthy/ImageComparer.zip

原文公布时间为:2009-01-16 —— 来源于本人的百度小说 [由搬家工具导入]

                        h += block.Height;
                    }

 

Scan0

|-------Stride-----------|
|-------Width---------|  |
BGR BGR BGR BGR BGR BGR XX
BGR BGR BGR BGR BGR BGR XX
BGR BGR BGR BGR BGR BGR XX
.
.
.

 

                                    ICColor* pc1 = (ICColor*)(p1 + wi * 3 + bd1.Stride * j);
                                    ICColor* pc2 = (ICColor*)(p2 + wi * 3 + bd2.Stride * j);

除此以外,因为使用了unsafe,所以编译的时候须要设置“允许不安全的代码”。

                                        int bw = Math.Min(block.Width, bd1.Width – w);
                                        int bh = Math.Min(block.Height, bd1.Height – h);
                                        rects.Add(new Rectangle(w, h, bw, bh));

                                for (int j = 0; j < block.Height; j++)
                                {
                                    int hj = h + j;
                                    if (hj >= bd1.Height || hj >= bd2.Height) break;

查找了多如牛毛材料,现在自家是那般了解的:

立时用的粗略完成方式就是:将两副图片同时按自然大小的小块“切分开”,再各自相比这几个小块,如若某个块里出现有一个区其余象素点,那就觉着此块所在的职位是有出入的否则认为是千篇一律的,当相比较完所有小块后,两副图中间的不一样之处的岗位也就出去了。因为要拓展富有小块比较,所以最坏的景色下是要扫描相比图片的保有象素点(两副图完全相同的情状时),最美妙的情状就是只扫描比较所有小块的首先点(两副图完全不等同的情况时)。

图片 5

int h = m_Bmp.Height;
int w = m_Bmp.Width;

 

 两副图都各自“切分”成四个20*20的小块,程序再分别对那几个小块进行判定,假若“扫描”到小块里的某个象素点是分歧的则记录此块的坐标地点并退出当前块的扫描,继续扫描下一个小块,直到所有小块“扫描”达成。

for (int y = 0; y < dataIn.Height; y++)
{
for (int x = 0; x < dataIn.Width; x++)
{

上面两幅图的出入比较后的截图:(两图中灰色与绿色框框内的小块就是标志有出入的小块)

地方两幅图的距离相比较后的截图:(两图中紫色与藏蓝色框框内的小块就是申明有反差的小块)

bmpOut.UnlockBits(dataOut);
m_Bmp.UnlockBits(dataIn);

两副图都分别“切分”成多个20*20的小块,程序再各自对那一个小块举行判断,要是“扫描”到小块里的某部象素点是不均等的则记录此块的坐标地点并脱离当前块的围观,继续扫描下一个小块,直到所有小块“扫描”完毕。

                        w = 0;
                        while (w < bd1.Width && w < bd2.Width)
                        {
                            //按块大小进行扫描
                            for (int i = 0; i < block.Width; i++)
                            {
                                int wi = w + i;
                                if (wi >= bd1.Width || wi >= bd2.Width) break;

一般比Delphi复杂得多,难道我实在天赋对指针过敏?仍旧Delphi的比较好通晓,就是扫描每一行,然后对现阶段像素点的四个轻重做拍卖,相当便宜。而且C#代码中的Stride是个怎么样东东?

 

 图片 6代码

图片 7

如有上面的两副图:(以下图借用了stg609 的《Dot
Net下落成显示器图像差距获取v1.0》文章里的截图,呵)

/Files/kingthy/ImageComparer.zip

                                        goto E;
                                    }
                                }
                            }
                        E:
                            w += block.Width;
                        }

                        w = 0;
                        while (w < bd1.Width && w < bd2.Width)
                        {
                            //按块大小进行扫描
                            for (int i = 0; i < block.Width; i++)
                            {
                                int wi = w + i;
                                if (wi >= bd1.Width || wi >= bd2.Width) break;

                                for (int j = 0; j < block.Height; j++)
                                {
                                    int hj = h + j;
                                    if (hj >= bd1.Height || hj >= bd2.Height) break;

那种办法的判断精确性是按照“块”大小来决定的,也就是一旦你将“块”设得过大,判断的“精确性”就越低(因为只要块里有少数不等同,就认为此块地点是有距离的),如将“块”设置得过小,则判断的“精确性”就越高,但需求时刻也有可能会越来越多!

如有上面的两副图:(以下图借用了stg609 的《Dot
Net下完成屏幕图像差别获取v1.0
》小说里的截图,呵)

图片 8                
    图片 9        

将方面两幅图按20*20(px)大小“切分”:

                                    if (pc1->R != pc2->R || pc1->G != pc2->G || pc1->B != pc2->B)
                                    {
                                        //当前块有某个象素点颜色值分歧.也就是有差异.

图片 10图片 11代码

上午来看stg609 写的《Dot
Net下完结显示屏图像差别获取v2.0
》文章,想起自己原先写过的一个《咱们来找茬》的游艺协助工具(就是作弊器了,嘿嘿),当时也是用到了判断比较两副图片的差别作用。现将及时写的歧异相比较代码发上来,给大家参考参考。

那种措施的判断精确性是依据“块”大小来决定的,也就是只要您将“块”设得过大,判断的“精确性”就越低(因为假诺块里有一些不平等,就觉得此块地方是有距离的),如将“块”设置得过小,则判断的“精确性”就越高,但须求时刻也有可能会越来越多!

                                    ICColor* pc1 = (ICColor*)(p1 + wi * 3 + bd1.Stride * j);
                                    ICColor* pc2 = (ICColor*)(p2 + wi * 3 + bd2.Stride * j);

图片 12                    
图片 13        

                                        goto E;
                                    }
                                }
                            }
                        E:
                            w += block.Width;
                        }

相关文章