如何在WinForm的PictureBox1中展示两张图片的差异像素?
C# WinForm图片对比工具:新增差异像素可视化功能
先修正原代码的核心问题
原代码中发现差异像素后用break跳出内层循环,会导致只统计第一个差异像素就停止遍历,完全无法正确统计总差异数,必须先删除这个break。
UI调整准备
- 在窗体上添加两个单选按钮(RadioButton),Text分别设为「实时显示差异像素」和「对比完成后批量显示」,Name设为
radioRealTime和radioBatch,默认选中批量显示。 - 将
pictureBox1的SizeMode属性设置为Zoom,方便查看放大后的差异细节。
实现两种差异可视化模式
1. 实时逐像素显示差异
遍历过程中一旦发现差异,立刻标记到显示用的Bitmap上并刷新PictureBox,能直观看到对比过程,但频繁刷新会稍慢。
2. 批量显示差异
先收集所有差异像素的坐标,等整张图遍历完成后,一次性在Bitmap上标记所有差异,速度更快,适合大图片对比。
完整修改后的代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; namespace ImageComparison { public partial class Form1 : Form { string fname1, fname2; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { progressBar1.Visible = false; pictureBox1.Visible = false; // 默认选中批量显示模式 radioBatch.Checked = true; } private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { openFileDialog1.FileName = ""; openFileDialog1.Title = "选择第一张图片"; openFileDialog1.Filter = "图片文件|*.jpg; *.bmp; *.png"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { fname1 = openFileDialog1.FileName; // 预览第一张图 pictureBox1.Image = Image.FromFile(fname1); pictureBox1.Visible = true; } } private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { openFileDialog2.FileName = ""; openFileDialog2.Title = "选择第二张图片"; openFileDialog2.Filter = "图片文件|*.jpg; *.bmp; *.png"; if (openFileDialog2.ShowDialog() == DialogResult.OK) { fname2 = openFileDialog2.FileName; } } private void button1_Click(object sender, EventArgs e) { // 校验是否选择了两张图片 if (string.IsNullOrEmpty(fname1) || string.IsNullOrEmpty(fname2)) { MessageBox.Show("请先选择两张要对比的图片!"); return; } progressBar1.Visible = true; int samePixelCount = 0, diffPixelCount = 0; bool isSame = true; // 使用using自动释放Bitmap资源,避免内存泄漏 using (Bitmap img1 = new Bitmap(fname1)) using (Bitmap img2 = new Bitmap(fname2)) { if (img1.Width != img2.Width || img1.Height != img2.Height) { MessageBox.Show("两张图片尺寸不一致,无法对比!"); progressBar1.Visible = false; return; } // 创建基于第一张图的差异显示Bitmap Bitmap diffBitmap = new Bitmap(img1.Width, img1.Height); using (Graphics g = Graphics.FromImage(diffBitmap)) { g.DrawImage(img1, 0, 0); } progressBar1.Maximum = img1.Width; // 批量模式下存储差异像素坐标 List<Point> diffPoints = new List<Point>(); for (int i = 0; i < img1.Width; i++) { for (int j = 0; j < img1.Height; j++) { Color color1 = img1.GetPixel(i, j); Color color2 = img2.GetPixel(i, j); // 直接对比RGB值,比转字符串高效 if (color1.R != color2.R || color1.G != color2.G || color1.B != color2.B) { diffPixelCount++; isSame = false; if (radioRealTime.Checked) { // 实时标记差异像素为红色 diffBitmap.SetPixel(i, j, Color.Red); pictureBox1.Image = diffBitmap; Application.DoEvents(); // 防止界面假死 } else { // 批量模式记录坐标 diffPoints.Add(new Point(i, j)); } } else { samePixelCount++; } } progressBar1.Value = i + 1; } // 批量模式下一次性标记所有差异 if (radioBatch.Checked && !isSame) { foreach (Point p in diffPoints) { diffBitmap.SetPixel(p.X, p.Y, Color.Red); } pictureBox1.Image = diffBitmap; } // 显示对比结果 if (!isSame) { pictureBox1.Visible = true; MessageBox.Show($"图片不一致,共发现 {diffPixelCount} 个差异像素,{samePixelCount} 个相同像素"); } else { MessageBox.Show($"图片完全相同,共 {samePixelCount} 个相同像素"); pictureBox1.Image = img1; pictureBox1.Visible = true; } } progressBar1.Visible = false; } } }
额外优化说明
- 替换原代码中通过
ToString()对比像素的逻辑,改为直接对比RGB值,大幅提升效率。 - 添加文件选择校验,避免空路径报错。
- 实时显示时用
Application.DoEvents()刷新界面,防止程序假死。 - 差异像素默认用红色标记,可根据需求改为其他颜色(如
Color.Yellow)。
内容的提问来源于stack exchange,提问作者jhon last
相关产品推荐
相关产品推荐

