原稿完成于2020年5月19日,上传以做备份。
正文
希望从word复制粘贴过来的代码顺序没有乱,我已经懒得核查了。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ImageCut
{
public partial class Form1 : Form
{
Bitmap currentImage; // Bitmap (位图)是用于处理由像素数据定义的图像的对象
Bitmap cutImage;
public Form1()//构造函数
{
InitializeComponent();
}
Boolean ifgray = false;/是否灰度化,新打开图片时,该值会重置。
private void openFileToolStripMenuItem_Click(object sender, EventArgs e)//定义打开【文件】的ToolStripMenuItem (工具条形菜单项目)方法
{
OpenFileDialog ofd = new OpenFileDialog();//类的实例化,实例名为ofd,此类可用于检查文件是否存在并打开它。
ofd.Filter = "Jpeg Files (jpg)|*.jpg; | Bitmap Files (bmp)|*.bmp; | Gif Files (gif)|*.gif; | Png Files (png)|*.png; | All Files (*.*) | *.*;"; //文件类型过滤
string filename;
if(ofd.ShowDialog()==DialogResult.OK)//如果用户在对话框中点击了确定
{
filename = ofd.FileName; //则打开的文件命名为原文件名
}
else
{
return; //否则返回
}
currentImage = new Bitmap(filename);
pictureBox1.Image = currentImage;//显示选中的图片
ifgray = false;
cutImage = null;
pictureBox2.Image = null;
pictureBox3.Image = null;
}
private void openFolderToolStripMenuItem_Click(object sender, EventArgs e)//定义打开【文件夹】的ToolStripMenuItem (工具条形菜单项目)方法
{ //整体大致相同
FolderBrowserDialog fbd = new FolderBrowserDialog();
string path;
if (fbd.ShowDialog() == DialogResult.OK)
{
path = fbd.SelectedPath;//文件路径为用户选定的路径
}
else
{
return;
}
DirectoryInfo root = new DirectoryInfo(path);//DirectoryInfo类是System.IO命名空间的一部分,它用于创建,删除和移动目录。
//指将用户选定文件夹路径为根目录
foreach (FileInfo f in root.GetFiles())
{
string filename = f.FullName;
if (f.Extension.ToUpper() == ".BMP" || f.Extension.ToUpper() == ".JPG" || f.Extension.ToUpper() == ".PNG" || f.Extension.ToUpper() == ".GIF" || f.Extension.ToUpper() == ".TIF")
{
int newrow = dataGridView1.Rows.Add();//在数据网格显示栏中添加获取的文件夹中的文件,每多一个文件就新建一行
dataGridView1["image", newrow].Value = new Bitmap(filename);//new Bitmap(filename)
dataGridView1["id", newrow].Value = newrow;//id栏值为行值
dataGridView1["filename", newrow].Value = filename;//filename值为文件原名
}
}
}
private void clearAllToolStripMenuItem_Click(object sender, EventArgs e)//删除全部已添加的文件
{
dataGridView1.Rows.Clear();
pictureBox1.Image = null;
pictureBox2.Image = null;
pictureBox3.Image = null;
currentImage = null;
cutImage = null;
}
private void clearSelectedToolStripMenuItem_Click(object sender, EventArgs e)//删除所选的文件
{
int rowCount;
rowCount = dataGridView1.Rows.Count;
dataGridView1.ReadOnly = true;
for(int i=rowCount-1;i>=0;i--)//数据遍历
{
if(Convert.ToInt16(dataGridView1["selected",i].Value) == 1)//删除所有被标记为选择的文件
{
//string filename = dataGridView1.CurrentCell.Value.ToString();
//if (pictureBox1.Image. == filename)
//{
// pictureBox1.Image = null;
// pictureBox2.Image = null;
// currentImage = null;
// cutImage = null;
//}
dataGridView1.Rows.RemoveAt(i);
}
}
dataGridView1.ReadOnly = false;
rowCount = dataGridView1.Rows.Count;//更新文件数目
for(int i=0;i<rowCount;i++)
{
dataGridView1["id", i].Value = i;//重新编号
}
}
private void dataGridView1_Click(object sender, EventArgs e)//DataGridView 类:单元格//显示选中的图片//获取或设置当前处于活动状态的单元格
{
if (dataGridView1.Rows.Count==0)//修复bug
{
MessageBox.Show("列表为空", "Warning");
return;
}
else
{
if (dataGridView1.CurrentCell.ColumnIndex == 3)//在列表为空时点击列表,将出现【System.NullReferenceException:“未将对象引用设置到对象的实例。”】,程序无响应
{
string filename = dataGridView1.CurrentCell.Value.ToString();
currentImage = new Bitmap(filename);
pictureBox1.Image = currentImage;//显示当前照片
ifgray = false;
cutImage = null;
pictureBox2.Image = null;
pictureBox3.Image = null;
}
else;
}
}
//初始化关键值
int start_row = 0, start_col = 0;//起始行、列为0
int current_row = 0, current_col = 0;//当前行、列为0
int LU_row = 0, LU_col = 0;//ROI左上角坐标对为0
int rcw = 0, rch = 0;//ROI宽度、高度为0
Boolean if_draw = false;//该布尔量用来标记是否在图像中绘制ROI
private void button1_Click(object sender, EventArgs e)//设置储存子图像文件夹的按钮
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if(fbd.ShowDialog() == DialogResult.OK)
{
string path;
path = fbd.SelectedPath;//将路径设为指定的路径值
textBox1.Text = path;//显示用户选择的路径
}
}
private void button2_Click(object sender, EventArgs e)//保存子图像
{
if(cutImage == null)//如果没有创建子图像,按钮无效
{
MessageBox.Show("您还未创建子图像", "Warning");///错误提示
return;
}
string path = textBox1.Text;
if(path.Length == 0)//如果没有指定路径,按钮无效
{
MessageBox.Show("您还未添加指定路径", "Warning");///错误提示
return;
}
DirectoryInfo di = new DirectoryInfo(path);
int fileCount = di.GetFiles().Length;
string filename = path + "\\" + (fileCount + 1).ToString() + ".bmp";//命名子图像文件名
cutImage.Save(filename);//保存子图像至指定路径
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)//pictureBox控件用于显示图片//此方法属于绘制ROI的第一步,用于配置鼠标右击
{
if (currentImage == null)//未选定图像时此方法无效
{
return;
}
else if (ifgray == false)
{
MessageBox.Show("必须先进行灰度化才能选取ROI!");
return;
}
else;
int w, h;
w = currentImage.Width;
h = pictureBox1.Height;
if (e.Y >= 0 && e.Y <= h - 1 && e.X >= 0 && e.X <= w - 1)//判断鼠标点击的位置是否位于照片尺寸内
{
if_draw = true;//开始绘制ROI
start_row = e.Y;//设置起始坐标值
start_col = e.X;
pictureBox1.Cursor = Cursors.Cross;//鼠标由箭头变为十字标
}
else;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)//此方法属于绘制ROI的第二步,鼠标右击后,用于配置框图(即ROI区域)随鼠标移动
{
if(if_draw == true)//当已在绘制ROI时
{
current_row = e.Y;//设置当前坐标值
current_col = e.X;
}
pictureBox1.Invalidate();//松开鼠标后可重绘框图
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)//此方法属于绘制ROI的第三步,松开鼠标右键,框图绘制完成,程序将记录ROI
{
if (if_draw == true && ifgray == true)
{
if_draw = false;//ROI绘制完成
pictureBox1.Cursor = Cursors.Arrow;//松开鼠标右键,鼠标箭头恢复
if (rcw > 0 && rch > 0)/修复bug
{
cutImage = new Bitmap(rcw, rch);
Graphics g = Graphics.FromImage(cutImage);//错误:如果鼠标只点了一下图片而没有拖动,程序将异常
g.DrawImage(currentImage, 0, 0, new Rectangle(LU_col, LU_row, rcw, rch), GraphicsUnit.Pixel);//截取ROI
pictureBox2.Image = cutImage;//在左边的picturebox中显示ROI
}
}
else
return;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)//用于配置框图
{
if (if_draw == true)
{
Pen pen = new Pen(Color.Red, 1);//设定笔触参数
//设置虚线
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;//绘制虚线
//ROI左上角点
if (start_row <= current_row)//记录坐标对
{
LU_row = start_row;
}
else
{
LU_row = current_row;
}
if (start_col <= current_col)
{
LU_col = start_col;
}
else
{
LU_col = current_col;
}
rcw = Math.Abs(current_col - start_col) + 1;//计算ROI的宽度和高度
rch = Math.Abs(current_row - start_row) + 1;
e.Graphics.DrawRectangle(pen, LU_col, LU_row, rcw, rch);//绘制框图
}
}
private void VersionToolStripMenuItem_Click(object sender, EventArgs e)///显示版本信息
{
MessageBox.Show("修复以下bug:\n 1.点击空白列表程序会跳出\n 2.单击图片程序会跳出\n " +
"—\n 添加以下优化:\n 1.提示助手\n 2.快捷删除&快捷切换&快捷菜单\n 3.优化文件过滤器\n 4.全屏模式\n 5.自动清屏\n " +
"6.增添缩略图\n 7.添加帮助信息\n 8.其它细节优化及窗体美化\n " +
"—\n 添加以下功能:\n 1.图片旋转&镜像\n 2.图片灰度化\n 3.灰度直方图\n 4.图片二值化\n" +
"\n by Author\n", "About");
}
private void hotkey_Click(object sender, EventArgs e)
{
MessageBox.Show("当前可用的快捷操作:\n \n 1.选中列表中的图片,按方向键可切换图片\n 2.双击复选框可删除该图片;如若要删除一组照片," +
"可勾选待删除照片,在最后一张照片的复选框内双击即可删除这组照片;\n","快捷操作");
}
///灰度化
private void button5_click(object sender, EventArgs e)
{
if (currentImage == null)//如果没有创建子图像,按钮无效
{
MessageBox.Show("您还未选取图像!\n \n图像二值化操作步骤:\n 打开图片——点击【灰度化】——选取ROI——点击【二值化】\n");
return;
}
else
{
//MessageBox.Show("灰度化耗时较长,请耐心等待\n \n点击确定以继续");
for (int i = 0; i < currentImage.Width; i++)
{
for (int j = 0; j < currentImage.Height; j++)
{
//获取该点的像素的RGB的颜色
Color color = currentImage.GetPixel(i, j);
//利用公式计算灰度值
int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
Color newColor = Color.FromArgb(gray, gray, gray);
currentImage.SetPixel(i, j, newColor);
}
}
pictureBox1.Image = currentImage;
ifgray = true;
//MessageBox.Show("完成。");
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
//二值化
//基于二值化算法局限性,只能先选取ROI
private void button6_Click(object sender, EventArgs e)
{
if (currentImage == null)//如果没有创建子图像,按钮无效
{
MessageBox.Show("图像二值化操作步骤:\n 打开图片——点击【灰度化】——选取ROI——点击【二值化】\n");
return;
}
else if (cutImage == null)//如果没有创建子图像,按钮无效
{
if (ifgray == true)
{
MessageBox.Show("必须先选取ROI!\n \n 图像二值化操作步骤:\n 打开图片——点击【灰度化】——选取ROI——点击【二值化】\n");
return;
}
else
{
MessageBox.Show("必须先进行灰度化!\n \n图像二值化操作步骤:\n 打开图片——点击【灰度化】——选取ROI——点击【二值化】\n");
return;
}
}
else
{
if (ifgray == true)
{
//MessageBox.Show("二值化耗时较长,请耐心等待\n \n点击确定以继续");
int average = 0; //取图片的平均灰度作为阈值,低于该值的全都为0,高于该值的全都为255
for (int i = 0; i < cutImage.Width; i++)
{
for (int j = 0; j < cutImage.Height; j++)
{
Color color = cutImage.GetPixel(i, j);
average += color.B;//灰度化后只需取RGB中任意一值
}
}
average = (int)average / (cutImage.Width * cutImage.Height);//自适应阈值
//average = 127;//固定阈值
for (int i = 0; i < cutImage.Width; i++)
{
for (int j = 0; j < cutImage.Height; j++)
{
//获取该点的像素的RGB的颜色
Color color = cutImage.GetPixel(i, j);
int value = 255 - color.B;//反色
Color newColor = value > average ? Color.FromArgb(0, 0, 0) : Color.FromArgb(255, 255, 255);
cutImage.SetPixel(i, j, newColor);//更新颜色
}
}
pictureBox2.Image = cutImage;
// MessageBox.Show("完成。");
}
else
{
MessageBox.Show("在进行二值化前,必须进行灰度化!\n \n图像二值化操作步骤:\n 打开图片——点击【灰度化】——选取ROI——点击【二值化】\n");
}
}
}
//键盘快捷键
private void dataGridView1_Press(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
if (dataGridView1.Rows.Count == 0)//修复bug
{
return;
}
else
{
if (dataGridView1.CurrentCell.ColumnIndex == 3)
{
string filename = dataGridView1.CurrentCell.Value.ToString();
currentImage = new Bitmap(filename);
pictureBox1.Image = currentImage;
}
}
}
}
//灰度直方图
private void pictureBox2_Click(object sender, EventArgs e)
{
if (ifgray == false)
{
MessageBox.Show("必须先执行灰度化\n", "您希望显示灰度直方图吗?");
return;
}
else
{
if (cutImage == null)
{
MessageBox.Show("必须选取roi\n", "您希望显示灰度直方图吗?");
}
else
{
int[] values = new int[256];//创建数组
for (int i = 0; i < 256; i++) values[i] = 0;//初始化数组
for (int i = 0; i < cutImage.Width; i++)
{
for (int j = 0; j < cutImage.Height; j++)
{
Color color = cutImage.GetPixel(i, j);
int value = color.B;//获取每一个点的灰度值存到一个数组中
values[value]++;
}
}
//找出要画图像里数据的最高值
int max = 0;
foreach (int i in values) max = max > i ? max : i;
Image grayImage = null;
//画图,引用方法
draw(ref values, max, out grayImage);
}
}
}
//画直方图
private bool draw(ref int[] datas, int Height, out Image grayImage)
{
grayImage = new Bitmap(256, Height + 10); //图像y轴最大值比数据最大值高些
Graphics g = Graphics.FromImage(grayImage);
Pen pen = new Pen(Color.Black);//笔的颜色
for (int i = 0; i <= 255; i++)
{
g.DrawLine(pen, i, Height - datas[i] + 10, i, Height + 10);//画直线,灰度直方图由直线组成
}
pictureBox3.Image = grayImage;
return true;
}
private void label3_Click(object sender, EventArgs e)
{
MessageBox.Show("灰度直方图是将数字图像中的所有像素,按照灰度值的大小,统计其出现的频率。\n \n" +
"显示灰度直方图的操作:\n 【灰度化】-【选取ROI】-【点击roi】\n","灰度直方图显示教学");
}
// 顺时针旋转90度旋转图片
private void btnRotate_Click(object sender, EventArgs e)
{
if (currentImage == null)//如果没有创建子图像,按钮无效
{
return;
}
else
{
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
currentImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
pictureBox1.Image = currentImage;
}
}
// 逆时针旋转90度
private void btncounterclockwiseRotate_Click(object sender, EventArgs e)
{
if (currentImage == null)//如果没有创建子图像,按钮无效
{
return;
}
else
{
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
// 逆时针旋转90度的另外实现
currentImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
pictureBox1.Image = currentImage;
}
}
//镜像
private void Button7_Click(object sender, EventArgs e)
{
if (currentImage == null)//如果没有创建子图像,按钮无效
{
return;
}
else
{
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
currentImage.RotateFlip(RotateFlipType.Rotate180FlipY);
pictureBox1.Image = currentImage;
}
}
}
}