类库项目ImageProcessingLibrary代码
里面是几种图像处理函数,可以生成DLL文件被其他(下面)项目添加引用
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ImageProcessingLibrary
{
public static class ImageProcessing
{/// 获取直方图数组,并绘制直方图
/// <param name="image">需要处理的图像</param>
/// <param name="indexColor">处理的颜色索引值,Blue:0,Green:1,Red:2</param>
/// <param name="histogram">直方图统计数组</param>
/// <returns>绘制好的直方图</returns>
public static Bitmap GetHistogram(Bitmap image, int indexColor, out int[] histogram)
{
histogram = new int[256]; //直方图统计数组
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); //将图像锁定到内存中
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
for (int y = 0; y < image.Height * data.Stride; y += data.Stride) //data.Stride代表图像一行数据的字节总数/步长为data.Stride
{//外层循环是遍历行
for (int x = 0; x < image.Width * 3; x += 3)//遍历当前行中的每个像素/每个像素由三个字节(RGB)组成
//每个颜色分量(红色、绿色或蓝色)可以有的不同强度级别就是2^8,即256个级别
{
int index = y + x; //颜色在内存中的索引/每个索引偏移量3字节(对应R,G,B)
histogram[datas[index + indexColor]]++;//增加直方图中对应颜色分量出现的次数
}
}
image.UnlockBits(data);
byte maxValue = 0; //直方图中的最大值
for (int value = 1; value < 256; value++)
{
if (histogram[value] > histogram[maxValue]) maxValue = (byte)value;
}
Bitmap imageHistogram = new Bitmap(256, 256);
Graphics GHistogram = Graphics.FromImage(imageHistogram);
GHistogram.Clear(Color.Blue);
for (int value = 1; value< 256; value++)
{
int length = byte.MaxValue * histogram[value] / histogram[maxValue];
GHistogram.DrawLine(new Pen(Color.FromArgb(value, value, value), 1f), value,
256, value, 256 - length); //绘制直方图
}
Font font = new Font("宋体", 9f);
//绘制统计标识
for (int value = 32; value < 256; value += 32)
{
int count = histogram[maxValue] / 8 * value / 32;
Pen pen = new Pen(Color.Lime);
pen.DashStyle = DashStyle.DashDot;
SizeF sizeCount = GHistogram.MeasureString(count.ToString(), font);
GHistogram.DrawLine(pen, 0, 255 - value, 255, 255 - value);//绘制数量等级线
GHistogram.DrawString(count.ToString(), font, Brushes.Red, 5, 255 - value - sizeCount.Height / 2);
SizeF sizeValue = GHistogram.MeasureString(value.ToString(), font);
GHistogram.DrawLine(Pens.Red, value, 250, value, 255);//绘制颜色值等级线
GHistogram.DrawString(value.ToString(), font, Brushes.Red, value - sizeValue.Width / 2, 240);
}
font.Dispose();
return imageHistogram;
}
/// 将图像进行二值化处理
/// <param name="image">需要处理的图像</param>
/// <param name="indexColor">处理的颜色索引值,Blue:0,Green:1,Red:2</param>
/// <param name="thresholdMin">阈值下限</param>
/// <param name="thresholdMax">阈值上限</param>
public static void BinaryImage(Bitmap image, int indexColor, int thresholdMin, int thresholdMax)
{
//将图像锁定到内存中
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int index = y + x;
//根据阈值将图像分成黑色和白色,其中阈值内的为黑色,阈值外的为白色
if (datas[index + indexColor] >= thresholdMin && datas[index + indexColor] <= thresholdMax)
datas[index] = datas[index + 1] = datas[index + 2] = 0;
else
datas[index] = datas[index + 1] = datas[index + 2] = 255;
}
}
Marshal.Copy(datas, 0, data.Scan0, datas.Length); //将图像数组复制到内存中
image.UnlockBits(data); //将图像从内存中解锁
}
/// 将彩色图像转换成灰度图像
/// <param name="image">需要处理的图像</param>
/// <returns></returns>
public static void GreyImage(Bitmap image)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //将图像锁定到内存中
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
//计算灰度矩阵
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int index = y + x; //颜色在内存中的索引
byte Blue = datas[index]; //蓝色值
byte Green = datas[index + 1]; //绿色值
byte Red = datas[index + 2]; //红色值
datas[index] = datas[index + 1] = datas[index + 2] =
(byte)((Red * 19595 + Green * 38469 + Blue * 7472) >> 16);//灰度值
}
}
Marshal.Copy(datas, 0, data.Scan0, datas.Length); //将图像数组复制到内存中
image.UnlockBits(data);
}
/// 对图像进行边缘提取
/// <param name="image">灰度图像</param>
/// <param name="threshold">边缘阈值</param>
public static void ExtractEdge(Bitmap image)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //将图像锁定到内存中
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
byte[] edges = new byte[data.Stride * image.Height]; //图像边界
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
for (int y = data.Stride; y < image.Height * data.Stride - data.Stride; y += data.Stride)
{
for (int x = 3; x < image.Width * 3 - 3; x += 3)
{
int index = y + x;
byte grey = datas[index]; //像素灰度值
int value = 0;
//将像素点的灰度值与周围8个点的灰度值分别求差的绝对值,再求和
for (int yy = -data.Stride; yy <= data.Stride; yy += data.Stride)
{
for (int xx = -3; xx <= 3; xx += 3)
{
if (yy == 0 && xx == 0) continue;
index = x + y + xx + yy;
value += Math.Abs(grey - datas[index]);
}
}
//上一步求和的结果除以8,然后赋值给边界数组
edges[index] = edges[index + 1] = edges[index + 2] = (byte)(value >> 3);
}
}
Marshal.Copy(edges, 0, data.Scan0, datas.Length); //将边界数组复制到内存中
image.UnlockBits(data); //将图像从内存中解锁
}
/// 将图像进制中值滤波处理
/// <param name="image">需要处理的图像</param>
public static void MedianFilter(Bitmap image)
{
BitmapData dataImage = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//将图像锁定到内存中
unsafe
{
byte* pImage = (byte*)dataImage.Scan0.ToPointer(); //获取图像头指针
for (int y = 1; y < image.Height - 1; y++)
{
for (int x = 1; x < image.Width - 1; x++)
{
List<byte>[] datas = new List<byte>[3]; //创建存放八邻域像素颜色值的列表
for (int k = 0; k < 3; k++) datas[k] = new List<byte>();
for (int yy = -1; yy < 2; yy++)
{
for (int xx = -1; xx < 2; xx++)
{
int index = (y + yy) * dataImage.Stride + (x + xx) * 3; //八邻域像素索引
//将八邻域像素颜色值添加到列表中
for (int k = 0; k < 3; k++) datas[k].Add(pImage[index + k]);
}
}
for (int k = 0; k < 3; k++) datas[k].Sort(); //对八邻域颜色值排序
int indexMedian = y * dataImage.Stride + x * 3;
for (int k = 0; k < 3; k++)
{
pImage[indexMedian + k] = datas[k][4]; //取排序后的中间值作为像素颜色值
datas[k].Clear();
}
datas = null;
}
}
}
image.UnlockBits(dataImage);
}
/// <summary>
/// 利用自动对比度增强方法,对图像进行对比度增强处理
/// </summary>
/// <param name="image">需要处理的灰度图像</param>
/// <param name="sourceMin">定义原始图像中像素值的最小范围。</param>
/// <param name="sourceMax">定义原始图像中像素值的最大范围。</param>
/// <param name="destMin">定义增强后图像中像素值想要映射到的最小范围</param>
/// <param name="destMax">定义增强后图像中像素值想要映射到的最大范围</param>
public static void EnhanceImage(Bitmap image, int sourceMin, int sourceMax, int destMin, int destMax)
{
//将图像锁定到内存中
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int index = y + x; //颜色在内存中的索引
float value = (float)(destMax - destMin) / (float)(sourceMax - sourceMin)
* (float)(datas[index] - sourceMin) + destMin; //灰度值映射关系
datas[index] = datas[index + 1] = datas[index + 2]
= value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
}
}
Marshal.Copy(datas, 0, data.Scan0, datas.Length); //将图像数组复制到内存中
image.UnlockBits(data);
}
/// 连通区域标记
/// <param name="image">二值图像</param>
public static void ConnectRegion(Bitmap image)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //将图像锁定到内存中
byte[] datas = new byte[data.Stride * image.Height]; //图像数组
Marshal.Copy(data.Scan0, datas, 0, datas.Length); //将图像在内存中的数据复制到图像数组中
int sign = 40;
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int index = y + x; //颜色在内存中的索引
if (datas[index] == 0)
{
SignRegionIterative(datas, x, y, sign, data.Stride, image.Width, image.Height);
sign += 40;
}
}
}
Marshal.Copy(datas, 0, data.Scan0, datas.Length); //将图像数组复制到内存中
image.UnlockBits(data);
}
/// <summary>
/// 区域标记(可被迭代版本SignRegionIterative替换)
/// </summary>
/// <param name="datas"></param>
/// <param name="x">初始点(x, y)</param>
/// <param name="y"></param>
/// <param name="sign"></param>
/// <param name="stride"></param>
/// <param name="width"></param>
/// <param name="height"></param>
static void SignRegion(byte[] datas, int x, int y, int sign, int stride, int width, int height)
{
datas[y + x] = datas[y + x + 1] = datas[y + x + 2] = (byte)sign; //标记区域
if (x > 0 && datas[y + x - 3] == 0)
{
SignRegion(datas, x - 3, y, sign, stride, width, height); //搜索左边像素
}
if (x < width * 3 - 3 && datas[y + x + 3] == 0)
{
SignRegion(datas, x + 3, y, sign, stride, width, height); //搜索右边像素
}
if (y > 0 && datas[y - stride + x] == 0)
{
SignRegion(datas, x, y - stride, sign, stride, width, height); //搜索上边像素
}
if (y < stride * height && datas[y + stride + x] == 0)
{
SignRegion(datas, x, y + stride, sign, stride, width, height); //搜索下边像素
}
}
static void SignRegionIterative(byte[] datas, int x, int y, int sign, int stride, int width, int height)
{
Stack<Tuple<int, int>> stack = new Stack<Tuple<int, int>>();//使用了一个栈来保存待处理的像素坐标
stack.Push(Tuple.Create(x, y));//将初始坐标(x, y)压入栈中
while (stack.Count > 0)//循环会一直执行,直到栈为空
{
var current = stack.Pop();//每次循环中,我们从栈顶弹出一个坐标,并将其标记
int currentX = current.Item1;
int currentY = current.Item2;
// 标记当前点
if (currentX >= 0 && currentX < width * 3 && currentY >= 0 && currentY < height * stride)
{
int index = currentY + currentX;
datas[index] = datas[index + 1] = datas[index + 2] = (byte)sign;
// 搜索相邻的可标记像素并压入栈
if (currentX > 0 && datas[currentY + currentX - 3] == 0)
{
stack.Push(Tuple.Create(currentX - 3, currentY)); // 左边像素
}
if (currentX < width * 3 - 3 && datas[currentY + currentX + 3] == 0)
{
stack.Push(Tuple.Create(currentX + 3, currentY)); // 右边像素
}
if (currentY > 0 && datas[currentY - stride + currentX] == 0)
{
stack.Push(Tuple.Create(currentX, currentY - stride)); // 上边像素
}
if (currentY < stride * (height - 1) && datas[currentY + stride + currentX] == 0)
{
stack.Push(Tuple.Create(currentX, currentY + stride)); // 下边像素
}
}
}
}
/*在这个迭代版本中,我们使用了一个栈来保存待处理的像素坐标。开始时,我们将初始坐标(x, y)压入栈中。然后,
* 我们进入一个循环,该循环会一直执行,直到栈为空。
在每次循环中,我们从栈顶弹出一个坐标,并将其标记。然后,我们检查该坐标的左、右、上、下四个相邻像素,
如果它们的颜色值为0(即未被标记),我们就将它们压入栈中以便后续处理。
请注意,我们在压入相邻像素之前进行了边界检查,以确保我们不会尝试访问数组之外的元素。
这个迭代版本应该能够避免递归版本可能导致的栈溢出问题。*/
/// <summary>
/// 缩放函数
/// </summary>
/// <param name="image"></param>
/// <param name="horizon"></param>
/// <param name="verticale"></param>
public static void Dilation(Bitmap image, float horizon, float verticale)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//将图像锁定到内存中
byte[] datasOld = new byte[data.Stride * image.Height]; //图像数组
byte[] datasNew = new byte[data.Stride * image.Height]; //图像数组
//将图像在内存中的数据复制到图像数组中
Marshal.Copy(data.Scan0, datasOld, 0, datasOld.Length);
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int xNew = x / 3, yNew = y / data.Stride;
int xOld = (int)(xNew / horizon);
int yOld = (int)(yNew / verticale);
if (xOld < 0 || xOld >= image.Width || yOld < 0 || yOld >= image.Height) continue;
int indexOld = yOld * data.Stride + xOld * 3;
int indexNew = y + x;
datasNew[indexNew] = datasNew[indexNew + 1] = datasNew[indexNew + 2] = datasOld[indexOld];
}
}
Marshal.Copy(datasNew, 0, data.Scan0, datasOld.Length); //将图像数组复制到内存中
image.UnlockBits(data); //将图像从内存中解锁
}
/// <summary>
/// 平移函数
/// </summary>
/// <param name="image"></param>
/// <param name="horizon"></param>
/// <param name="verticale"></param>
public static void Translation(Bitmap image, float horizon, float verticale)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//将图像锁定到内存中
byte[] datasOld = new byte[data.Stride * image.Height]; //图像数组
byte[] datasNew = new byte[data.Stride * image.Height]; //图像数组
//将图像在内存中的数据复制到图像数组中
Marshal.Copy(data.Scan0, datasOld, 0, datasOld.Length);
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int xNew = x / 3, yNew = y / data.Stride;
int xOld = (int)(xNew - horizon);
int yOld = (int)(yNew - verticale);
if (xOld < 0 || xOld >= image.Width || yOld < 0 || yOld >= image.Height) continue;
int indexOld = yOld * data.Stride + xOld * 3;
int indexNew = y + x;
datasNew[indexNew] = datasNew[indexNew + 1] = datasNew[indexNew + 2] = datasOld[indexOld];
}
}
Marshal.Copy(datasNew, 0, data.Scan0, datasOld.Length); //将图像数组复制到内存中
image.UnlockBits(data); //将图像从内存中解锁
}
/// <summary>
/// 旋转函数
/// </summary>
/// <param name="image"></param>
/// <param name="angle"></param>
/// <param name="center"></param>
public static void Rotation(Bitmap image, float angle, Point center)
{
BitmapData data = image.LockBits(new Rectangle(new Point(), image.Size),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); //将图像锁定到内存中
byte[] datasOld = new byte[data.Stride * image.Height]; //图像数组
byte[] datasNew = new byte[data.Stride * image.Height]; //图像数组
//将图像在内存中的数据复制到图像数组中
Marshal.Copy(data.Scan0, datasOld, 0, datasOld.Length);
for (int y = 0; y < image.Height * data.Stride; y += data.Stride)
{
for (int x = 0; x < image.Width * 3; x += 3)
{
int xNew = x / 3, yNew = y / data.Stride;
int xOld = (int)((xNew - center.X) * Math.Cos(angle * Math.PI / 180)
- (yNew - center.Y) * Math.Sin(angle * Math.PI / 180) + center.X);
int yOld = (int)((xNew - center.X) * Math.Sin(angle * Math.PI / 180)
+ (yNew - center.Y) * Math.Cos(angle * Math.PI / 180) + center.Y);
if (xOld < 0 || xOld >= image.Width
|| yOld < 0 || yOld >= image.Height) continue;
int indexOld = yOld * data.Stride + xOld * 3;
int indexNew = y + x;
datasNew[indexNew] = datasNew[indexNew + 1] = datasNew[indexNew + 2] = datasOld[indexOld];
}
}
Marshal.Copy(datasNew, 0, data.Scan0, datasOld.Length); //将图像数组复制到内存中
image.UnlockBits(data); //将图像从内存中解锁
}
}
}
/*假设颜色分量是8位的,那么每个颜色分量(红色、绿色或蓝色)可以有的不同强度级别就是2^8,即256个级别。
* 这是因为8位可以表示从0到255的整数,总共256个不同的数值。在数字图像处理中,8位颜色深度是常见的,
* 因为它提供了足够的动态范围来表示大多数自然和人工颜色的细微差别,同时保持数据量相对较小。
当你说“直方图大小为256”时,你指的是直方图的横坐标(即颜色强度的可能值)有256个不同的条目,
每个条目对应一个特定的颜色强度值(从0到255)。直方图的纵坐标通常表示该颜色强度值在图像中出现的频率或像素数量。
因此,如果我们想为8位颜色分量的图像构建直方图,我们将创建一个大小为256的数组,数组的每个元素初始化为0。
然后,我们遍历图像的每个像素,对于每个像素的特定颜色分量(如红色、绿色或蓝色),我们增加直方图中对应颜色强度值的计数。
这个过程最终会给我们一个表示图像中每个颜色强度出现频率的直方图。*/
/*datas[index] = datas[index + 1] = datas[index + 2] = some_value;
这里实际上是在进行连续赋值。some_value首先被赋给datas[index + 2](蓝色通道),然后这个值又被赋给datas[index + 1]
(绿色通道),最后再次被赋给datas[index](红色通道)。由于赋值操作符=是从右到左结合的,
所以这行代码的效果是三个颜色通道都被赋予了相同的值。
在图像处理的上下文中,这种操作通常用于灰度化(将彩色图像转换为灰度图像,即每个通道具有相同的亮度值),
或者在进行某些类型的颜色校正或调整时,需要对所有颜色通道进行统一的变换。*/
/*datas[index] = datas[index + 1] = datas[index + 2]
= value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
value < byte.MinValue ? byte.MinValue : ... :这部分是一个条件运算符(也称作三元运算符)。
它检查value是否小于byte.MinValue(即0)。如果是,则直接返回byte.MinValue(0),因为负值在字节表示中是无效的。
... : (value > byte.MaxValue ? byte.MaxValue : ...) :如果value不小于byte.MinValue,
代码会进入这个分支,并检查value是否大于byte.MaxValue(即255)。如果是,则返回byte.MaxValue(255),
因为超出255的值也无法用一个字节表示。
... : (byte)value :如果value既不小于byte.MinValue也不大于byte.MaxValue,则将其强制转换为byte类型,
这会自动截去小数部分,只保留整数部分。*/
/*float value = (float)(destMax - destMin) / (float)(sourceMax - sourceMin)
* (float)(datas[index] - sourceMin) + destMin;
(float)(destMax - destMin):计算目标值域的范围,即最大值与最小值之间的差。
(float)(sourceMax - sourceMin):计算原始值域的范围,即原图像中像素值的最大值与最小值之间的差。
(float)(destMax - destMin) / (float)(sourceMax - sourceMin):计算目标值域范围与原始值域范围的比例。这个比例将用于调整原始像素值,使其适应新的值域。
(float)(datas[index] - sourceMin):计算当前像素值相对于原始值域最小值的偏移量。
* (float)(datas[index] - sourceMin):将上述比例与原始像素值的偏移量相乘,得到在新值域中的相对偏移量。
+ destMin:将新值域中的相对偏移量加上新值域的最小值,从而得到映射后的绝对像素值。
float value = ...:将最终计算出的映射后的像素值存储在value变量中*/
/*。像素灰度的变换公式如下:
GreyNew=(destMax - destMin) / (sourceMax - sourceMin) * (GreyOld - sourceMin) + destMin;
其中,GreyNew为增强后的灰度值,GreyOld为增强前的灰度值,sourceMax和sourceMin表示增强前的灰度范围,
destMax和destMin表示增强后的灰度范围。从实例效果图的直方图可以看出,图像在增强前的灰度分布在0到100之间,
所以图像整体颜色比较灰暗,增强后的灰度范围是整个灰度范围,所以增强后的图像更有层次感,也更清晰。*/
下面是各个独立窗体应用程序,都需要添加引用上面的类库(DLL),复制测试这些代码需要自己在......项目名\bin\Debug路径下添加命名自己的图片(可参考C#&图像第一章)
1.基于差分的边缘检测与提取
using ImageProcessingLibrary;
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 EdgeExtraction
{
public partial class FormEdgeExtraction : Form
{
public FormEdgeExtraction()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数
{
Graphics G = e.Graphics;
Bitmap image = new Bitmap("apple.jpg"); //加载图像
ImageProcessing.GreyImage(image); //生成灰度图像
Rectangle rectImage = new Rectangle(new Point(), image.Size);
G.DrawImage(image, rectImage);
rectImage.Offset(rectImage.Width, 0);
ImageProcessing.ExtractEdge(image); //提取边缘
G.DrawImage(image, rectImage);
rectImage.Offset(-rectImage.Width, rectImage.Height);
Bitmap image2 = image.Clone() as Bitmap;
ImageProcessing.BinaryImage(image2, 0, 20, 255); //在灰度20到255的范围提取边界
G.DrawImage(image2, rectImage);
image2.Dispose();
rectImage.Offset(rectImage.Width, 0);
ImageProcessing.BinaryImage(image, 0, 40, 255); //在灰度40到255的范围提取边界
G.DrawImage(image, rectImage);
image.Dispose();
}
}
}
2.利用中值滤波使图像变得平滑
using ImageProcessingLibrary;
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 MedianFilte
{
public partial class FormMedianFilter : Form
{
public FormMedianFilter()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数
{
Graphics G = e.Graphics;
Bitmap image = new Bitmap("apple.jpg"); //加载图像
Random random = new Random();
Rectangle rectImage = new Rectangle(new Point(), image.Size);
for (int i = 0; i < 500; i++)//随机产生噪点
{
image.SetPixel(random.Next(image.Width), random.Next(image.Height), Color.FromArgb(random.Next(int.MaxValue)));
}
G.DrawImage(image, rectImage); //绘制原始图像
ImageProcessing.MedianFilter(image);//中值滤波处理
rectImage.Offset(0, rectImage.Height);
G.DrawImage(image, rectImage); //绘制中值滤波后的图像
image.Dispose();
}
}
}
3.增强图像对比度
using ImageProcessingLibrary;
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 ImageEnhancement
{
public partial class FormImageEnhancement : Form
{
public FormImageEnhancement()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数
{
Graphics G = e.Graphics;
Bitmap image = new Bitmap("jdq.gif"); //加载图像
Size newSize = new Size(image.Width / 2, image.Height / 2);//图像尺寸缩半
Rectangle rectImage = new Rectangle(new Point(), newSize);
Rectangle rectHistogram = new Rectangle(rectImage.Width, rectImage.Top, 256, 256);
int[] histogram;
Bitmap imageHistogram = ImageProcessing.GetHistogram(image, 0, out histogram);
G.DrawImage(image, rectImage); //绘制原始图像
G.DrawImage(imageHistogram, rectHistogram); //绘制原始直方图
ImageProcessing.EnhanceImage(image, 0, 255, 0, 200);
imageHistogram = ImageProcessing.GetHistogram(image, 0, out histogram);
rectImage.Offset(0, Math.Max(rectImage.Height, 256));//位置最少偏移图片高度
rectHistogram.Offset(0, Math.Max(rectImage.Height, 256));
G.DrawImage(image, rectImage); //绘制增强图像
G.DrawImage(imageHistogram, rectHistogram); //绘制增强直方图
image.Dispose();
imageHistogram.Dispose();
}
}
}
4.目标提取与区域标记
using ImageProcessingLibrary;
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 ConnectRgeion
{
public partial class FormConnectRgeion : Form
{
public FormConnectRgeion()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数
{
Graphics G = e.Graphics;
Bitmap image = new Bitmap("657.png"); //加载图像
Rectangle rectImage = new Rectangle(new Point(), image.Size);
G.DrawImage(image, rectImage); //原始图
ImageProcessing.BinaryImage(image, 0, 0, 210); //通过二值化将目标分割出来
rectImage.Offset( rectImage.Width,0);
G.DrawImage(image, rectImage);
ImageProcessing.MedianFilter(image);//中值滤波处理;
rectImage.Offset(-rectImage.Width, image.Height);
G.DrawImage(image, rectImage);
ImageProcessing.ConnectRegion(image); //连通区域标记
rectImage.Offset(rectImage.Width, 0);
G.DrawImage(image, rectImage);
image.Dispose();
}
}
}
5.图像的变形
using ImageProcessingLibrary;
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 Transformation
{
public partial class FormTransformation : Form
{
public FormTransformation()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)//重写OnPaint事件函数
{
Graphics G = e.Graphics;
Bitmap image = new Bitmap("lina.jpg"); //加载图像
Size newSize = new Size(image.Width / 3, image.Height / 3);//图像尺寸缩半
Rectangle rectImage = new Rectangle(new Point(), newSize);
G.DrawImage(image, rectImage); //绘制原始图像
rectImage.Offset(rectImage.Width, 0);
ImageProcessing.Dilation(image, 0.8f, 0.8f); //对图像进行缩小处理
G.DrawImage(image, rectImage);
rectImage.Offset(-rectImage.Width, rectImage.Height);
ImageProcessing.Translation(image, image.Width / 10, image.Height / 10); //将图像平移居中-居中还和和图像缩小有关(0.5f-4/0.8f-10)
G.DrawImage(image, rectImage);
rectImage.Offset(rectImage.Width, 0);
//将图像围绕中心点逆时针旋转45°
ImageProcessing.Rotation(image, 45, new Point(image.Width / 2, image.Height / 2));
G.DrawImage(image, rectImage);
image.Dispose();
}
/// <summary>
/// 根据加载的图片大小动态调整Windows Forms窗口的大小
/// </summary>
/// <param name="imagePath"></param>
private void LoadImageAndResizeForm()
{
try
{
Bitmap image = new Bitmap("lina.jpg");
// 调整窗口大小以适应图片,并考虑额外的空间
this.Size = new Size(
image.Width*1+ SystemInformation.Border3DSize.Width * 10,
image.Height*1 + SystemInformation.CaptionHeight + SystemInformation.Border3DSize.Height * 10
);
}
catch (Exception ex)
{
MessageBox.Show("加载图片时出错: " + ex.Message);
}
}
private void MainForm_Load(object sender, EventArgs e)
{
// 使用绝对路径
//string imagePath = @"D:\Users\图像处理\WindowsFormsCeShi\bin\Debug\lina.jpg";
// LoadImageAndResizeForm(imagePath);
LoadImageAndResizeForm();
// MessageBox.Show("窗体正在初始化");
}
}
}