- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在尝试扫描 2 个图像(32bppArgb 格式),识别何时存在差异并将差异 block 的边界存储在矩形列表中。
我想获得不同的矩形边界(在我们的例子中是打开的目录窗口)。
这是我所做的:
private unsafe List<Rectangle> CodeImage(Bitmap bmp, Bitmap bmp2)
{
List<Rectangle> rec = new List<Rectangle>();
bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, 1920, 1080), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
bmData2 = bmp2.LockBits(new System.Drawing.Rectangle(0, 0, 1920, 1080), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int nWidth = bmp.Width;
int nHeight = bmp.Height;
int minX = int.MaxValue;;
int minY = int.MaxValue;
int maxX = 0;
bool found = false;
for (int y = 0; y < nHeight; y++)
{
byte* p = (byte*)scan0.ToPointer();
p += y * stride;
byte* p2 = (byte*)scan02.ToPointer();
p2 += y * stride2;
for (int x = 0; x < nWidth; x++)
{
if (p[0] != p2[0] || p[1] != p2[1] || p[2] != p2[2] || p[3] != p2[3]) //found differences-began to store positions.
{
found = true;
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y < minY)
minY = y;
}
else
{
if (found)
{
int height = getBlockHeight(stride, scan0, maxX, minY, scan02, stride2);
found = false;
Rectangle temp = new Rectangle(minX, minY, maxX - minX, height);
rec.Add(temp);
//x += minX;
y += height;
minX = int.MaxValue;
minY = int.MaxValue;
maxX = 0;
}
}
p += 4;
p2 += 4;
}
}
return rec;
}
public unsafe int getBlockHeight(int stride, IntPtr scan, int x, int y1, IntPtr scan02, int stride2) //a function to get an existing block height.
{
int height = 0;;
for (int y = y1; y < 1080; y++) //only for example- in our case its 1080 height.
{
byte* p = (byte*)scan.ToPointer();
p += (y * stride) + (x * 4); //set the pointer to a specific potential point.
byte* p2 = (byte*)scan02.ToPointer();
p2 += (y * stride2) + (x * 4); //set the pointer to a specific potential point.
if (p[0] != p2[0] || p[1] != p2[1] || p[2] != p2[2] || p[3] != p2[3]) //still change on the height in the increasing **y** of the block.
height++;
}
return height;
}
这实际上是我调用该方法的方式:
Bitmap a = Image.FromFile(@"C:\Users\itapi\Desktop\1.png") as Bitmap;//generates a 32bppRgba bitmap;
Bitmap b = Image.FromFile(@"C:\Users\itapi\Desktop\2.png") as Bitmap;//
List<Rectangle> l1 = CodeImage(a, b);
int i = 0;
foreach (Rectangle rec in l1)
{
i++;
Bitmap tmp = b.Clone(rec, a.PixelFormat);
tmp.Save(i.ToString() + ".png");
}
但我没有得到确切的矩形。我只得到了一半,有时甚至更糟。我认为代码的逻辑有问题。
@nico 的代码
private unsafe List<Rectangle> CodeImage(Bitmap bmp, Bitmap bmp2)
{
List<Rectangle> rec = new List<Rectangle>();
var bmData1 = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
var bmData2 = bmp2.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
int bytesPerPixel = 3;
IntPtr scan01 = bmData1.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride1 = bmData1.Stride;
int stride2 = bmData2.Stride;
int nWidth = bmp.Width;
int nHeight = bmp.Height;
bool[] visited = new bool[nWidth * nHeight];
byte* base1 = (byte*)scan01.ToPointer();
byte* base2 = (byte*)scan02.ToPointer();
for (int y = 0; y < nHeight; y += 5)
{
byte* p1 = base1;
byte* p2 = base2;
for (int x = 0; x < nWidth; x += 5)
{
if (!ArePixelsEqual(p1, p2, bytesPerPixel) && !(visited[x + nWidth * y]))
{
// fill the different area
int minX = x;
int maxX = x;
int minY = y;
int maxY = y;
var pt = new Point(x, y);
Stack<Point> toBeProcessed = new Stack<Point> ();
visited[x + nWidth * y] = true;
toBeProcessed.Push(pt);
while (toBeProcessed.Count > 0)
{
var process = toBeProcessed.Pop();
var ptr1 = (byte*)scan01.ToPointer() + process.Y * stride1 + process.X * bytesPerPixel;
var ptr2 = (byte*) scan02.ToPointer() + process.Y * stride2 + process.X * bytesPerPixel;
//Check pixel equality
if (ArePixelsEqual(ptr1, ptr2, bytesPerPixel))
continue;
//This pixel is different
//Update the rectangle
if (process.X < minX) minX = process.X;
if (process.X > maxX) maxX = process.X;
if (process.Y < minY) minY = process.Y;
if (process.Y > maxY) maxY = process.Y;
Point n;
int idx;
//Put neighbors in stack
if (process.X - 1 >= 0)
{
n = new Point(process.X - 1, process.Y);
idx = n.X + nWidth * n.Y;
if (!visited[idx])
{
visited[idx] = true;
toBeProcessed.Push(n);
}
}
if (process.X + 1 < nWidth)
{
n = new Point(process.X + 1, process.Y);
idx = n.X + nWidth * n.Y;
if (!visited[idx])
{
visited[idx] = true;
toBeProcessed.Push(n);
}
}
if (process.Y - 1 >= 0)
{
n = new Point(process.X, process.Y - 1);
idx = n.X + nWidth * n.Y;
if (!visited[idx])
{
visited[idx] = true;
toBeProcessed.Push(n);
}
}
if (process.Y + 1 < nHeight)
{
n = new Point(process.X, process.Y + 1);
idx = n.X + nWidth * n.Y;
if (!visited[idx])
{
visited[idx] = true;
toBeProcessed.Push(n);
}
}
}
if (((maxX - minX + 1) > 5) & ((maxY - minY + 1) > 5))
rec.Add(new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1));
}
p1 += 5 * bytesPerPixel;
p2 += 5 * bytesPerPixel;
}
base1 += 5 * stride1;
base2 += 5 * stride2;
}
bmp.UnlockBits(bmData1);
bmp2.UnlockBits(bmData2);
return rec;
}
最佳答案
我发现您的代码存在一些问题。如果我没理解错的话,你
到目前为止我说得对吗?
这里有两个明显的问题:
如果您的图像来自扫描仪或数码相机,或者如果它们包含有损压缩 (jpeg) 伪像,则第二个假设几乎肯定是错误的。为了说明这一点,当我将每个相同的像素标记为黑色链接的两个 jpg 图像,并将每个不同的像素标记为白色时,我得到的结果如下:
您看到的不是一个矩形。相反,您正在寻找的矩形周围的很多像素是不同的:
那是因为 jpeg 压缩伪像。但是,即使您使用无损源图像,边界处的像素也可能不会形成完美的矩形,因为抗锯齿或因为背景碰巧在该区域具有相似的颜色。
您可以尝试改进您的算法,但如果您查看该边界,您会发现所有 种针对您所做的任何几何假设的丑陋反例。
实现这种“正确的方式”可能会更好。含义:
连接组件标记通常要快一点,但比洪水填充要正确一些。
最后一个建议:如果我是你,我会重新考虑你的“禁止第 3 方图书馆”政策。即使您的最终产品不包含第 3 方库,如果您使用库中记录良好、经过良好测试且有用的构建 block ,然后用您自己的代码将它们一一替换,开发速度可能会快很多。 (谁知道呢,您甚至可能会找到一个具有合适许可证的开源库,它比您自己的代码快得多,以至于您最终会坚持使用它...)
添加:如果您想重新考虑您的“无库”立场:这是使用 AForge(它具有比 emgucv 更宽松的库)的快速简单实现:
private static void ProcessImages()
{
(* load images *)
var img1 = AForge.Imaging.Image.FromFile(@"compare1.jpg");
var img2 = AForge.Imaging.Image.FromFile(@"compare2.jpg");
(* calculate absolute difference *)
var difference = new AForge.Imaging.Filters.ThresholdedDifference(15)
{OverlayImage = img1}
.Apply(img2);
(* create and initialize the blob counter *)
var bc = new AForge.Imaging.BlobCounter();
bc.FilterBlobs = true;
bc.MinWidth = 5;
bc.MinHeight = 5;
(* find blobs *)
bc.ProcessImage(difference);
(* draw result *)
BitmapData data = img2.LockBits(
new Rectangle(0, 0, img2.Width, img2.Height),
ImageLockMode.ReadWrite, img2.PixelFormat);
foreach (var rc in bc.GetObjectsRectangles())
AForge.Imaging.Drawing.FillRectangle(data, rc, Color.FromArgb(128,Color.Red));
img2.UnlockBits(data);
img2.Save(@"compareResult.jpg");
}
实际差异+blob检测部分(没有加载和结果显示)需要大约43ms,第二次运行(第一次需要更长的时间,由于JITting,缓存等)
结果(由于 jpeg 伪像,矩形变大了):
关于c# - 如何扫描两个图像的差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32035320/
使用 C# (VS2008) 和 WIA - 扫描到 TIFF 格式; 当我在平板或文档进纸器上使用扫描仪扫描 1 页时,该方法执行没有任何问题。当我将多个表单加载到进纸器时,扫描第一页后执行停止(保
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
给定一个列表 :: [(Foo, Bar)] ,我想在 Bar 上执行 scanl1 s,但保留他们的 Foo “标签”。 IE。我想要一个类型为 :: [(a, b)] -> ([b] -> [c]
我有一个 HBase 表,我需要从多个范围获取结果。例如,我可能需要从不同范围获取数据,例如第 1-6 行、100-150..... 我知道对于每次扫描,我可以定义开始行和停止行。但是如果我有 6 个
我看到了这段代码。我是 C 语言的新手,所以请原谅。 while下面的循环将继续循环 if i = SIZE,则 == 是无关紧要的,因为它根本不会被执行。如果 i 小于 SIZE 那么 scanf(
这是一个关于编译过程的相当技术性的问题ABAP代码。 我知道有ABAP解析器和扫描器类实际上调用 C 内核函数来完成实际工作。然后就是代码补全事务的功能,该事务以 ABAP 列表或 XML 的形式返回
给定以下程序: int main(){ float x = non_det_float(); float y = NAN; if (isnan(y) && x == 1.0f){
我在工作中使用由供应商生成的二维码。实际上我需要通过网站手动记录所有这些项目。 QR 码包含所有这些数据,所以我想创建一个自动执行操作的应用。 例如,二维码表示“AAA|BBB|CCC|123”。我想
我有一个像这样的字符串:@"ololo width: 350px jijiji width:440px ... text=12... "我想将@"width: "之后的所有数字替换为280。所以在扫描
我在玩 scanf 时遇到了一个小问题……更具体地说,我想读取整个输入,然后忽略其余部分。让我告诉你我的意思: #include int main(void) { int number_of
我正在使用 matlab/octave 创建扫描/线性调频信号,我的结束信号似乎以错误的频率结束。我该如何修复它,以便信号以正确的频率结束。 PS:我不能在 Octave 音程中使用 chirp 命令
我正在寻找一个可以扫描 WiFi 网络并打印所有 SSID 的程序。我试过 scapy 但我失败了。我正在使用 pyCharm 编辑器。 我试过这段代码: from scapy.all import
概述 Linux 完全是用于大型服务器的最流行和最安全的操作系统之一。尽管它被广泛使用,但它仍然容易受到网络攻击。黑客以服务器为目标,窃取有价值的信息。所以迫切需要开发反黑客方法来应对安全漏洞和恶
如何获取我的 Git 存储库的某种统计信息? 我目前在 BitBucket 中托管 Git 存储库,想查找以下详细信息: 提交总数 使用过的编程语言 每种编程语言的总代码行数 您认为这可以实现吗?还是
我目前正在使用以下代码来扫描作为申请表的一部分上传的文件: $safe_path = escapeshellarg($dir . $file); $command = '/usr/bin/clamsc
我在存储库中有十几个项目。存储库结构如下所示: / ------- + project1 +------- trunk +------- tags +----
我正在使用 Dynamo DB 并想使用过滤器扫描一个表。例如,是否可以使用全局二级索引仅扫描表中的特定行? 最佳答案 这不可能!扫描始终针对基表中的所有行,当您扫描索引表作为响应时,您将仅获得该索引
我正在尝试从这里使用 SOLStumbler:Accessing & Using the MobileWiFi.framework扫描 wifi 网络。我知道苹果不支持这一点,但它是用于教育目的和实验
我知道 iPhone 蓝牙功能在 3.0 之前无法通过 SDK 访问,但是需要多长时间才能找到该区域的设备?它取决于该区域的设备数量吗?如果范围内有大约 5 个设备,扫描发现所有设备是否需要花费 30
我正在使用Elasticsearch 6.2,并且有一些查询可以分析大量文档。我正在对索引内的一个字段进行排序。 Elasticsearch检查10.000个文档(默认配置值),然后将它们分页返回。
我是一名优秀的程序员,十分优秀!