一:方法原理
图像形态学操作的时候,可以通过自定义的结构元素实现结构元素对输入图像一些对象敏感,另一些不敏感。这样就会是敏感的对象改变而不敏感的对象保留输出。通过使用两个最基本的形态学操作:膨胀和腐蚀。使用不同的结构元素实现对输入图像的操作,得到不同的结果。
**膨胀:**输出的像素值是结构元素覆盖下输入图像的最大像素值。
**腐蚀:**输出的像素值是结构元素覆盖下输入图像的最小像素值。
二:示意图
二值图像和灰度图像上的膨胀操作:
Dilation on a binary image
Dilation on a grayscale image
二值图像和灰度图像上的腐蚀操作:
Erosion on a binary image
Erosion on a grayscale image
三:结构元素
- 上述的结构元素可以是任意的形状的结构元素。
- 常见的结构元素有,矩形 、圆、直线、菱形等等。
四:提取步骤
- 输入色彩图像
- 转为灰度图像
- 转为二值图像
- 定义结构元素
- 开操作 (膨胀 + 腐蚀)提取水平或垂直线
六:代码
提取线条:
static void Main(string[] args)
{
string imagePath = @"C:\Users\whx\Desktop\opcvImage\X1.jpg";
GetLine(imagePath);
}
/// <summary>
/// 提取线条
/// </summary>
private static void GetLine(string path)
{
using (Mat src = new Mat(path, ImreadModes.AnyColor | ImreadModes.AnyDepth))
{
//转为灰度图像
Mat dst = new Mat();
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY);
//转为二值图像
/*
* API AdaptiveThreshold:
* 参数:1:输入的灰度图像 '~' 符号是背景色取反
* 2:输出的二值化图像
* 3:二值化的最大值
* 4:自适应的方法(枚举类型,目前只有两个算法)
* 5:阀值类型(枚举类型,这里选择二进制)
* 6: 块大小
* 7: 常量 (可以是正数 0 负数)
*/
Mat binImage = new Mat();
Cv2.AdaptiveThreshold(~dst, binImage, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 15, -2);
int xSize = dst.Cols / 16; //宽
int ySize = dst.Rows / 16; //高
//定义结构元素 new Size(xSize, 1) 相当于横着的一条线:水平结构体 new Size(1, ySize) 相当于竖着的一条线:垂直结构体
InputArray kernelX = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(xSize, 1),new Point(-1,-1));
InputArray kernelY = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(1, ySize), new Point(-1, -1));
Mat result = new Mat();
腐蚀
//Cv2.Erode(binImage, result, kernelY);
膨胀
//Cv2.Dilate(result, result, kernelY);
//开操作代替 腐蚀和膨胀
Cv2.MorphologyEx(binImage, result, MorphTypes.Open, kernelY);
Cv2.Blur(result, result, new Size(3, 3), new Point(-1, -1)); //使用归一化框过滤器平滑图像
Cv2.BitwiseNot(result, result); //背景变成白色(背景值取反)
using(new Window("result", WindowMode.Normal, result))
using(new Window("binImage", WindowMode.Normal, binImage))
using(new Window("dst", WindowMode.Normal, dst))
using (new Window("SRC", WindowMode.Normal, src))
{
Cv2.WaitKey(0);
}
}
}
上面的代码,定义了一个相当于垂直直线的结构体。通过开操作,(先腐蚀后膨胀):
垂直结构体在图像上卷积操作,经过横线时和结构图不重合,先腐蚀,取(二值图像)的最小像素值=0,测像素就被擦除掉了。当经过竖线时和结构重合,像素值都是一样的(1),腐蚀操作后还是1,像素就被保留下来了。再经过膨胀取最大值 1。
下面换称 X 轴的结构体:
Cv2.MorphologyEx(binImage, result, MorphTypes.Open, kernelX);
提取文字:
/// <summary>
/// 实际应用,得到文字
/// </summary>
private static void GetTxt(string path)
{
using (Mat src = new Mat(path, ImreadModes.AnyColor | ImreadModes.AnyDepth))
using (Mat dst = new Mat())
using (Mat binImage = new Mat())
using (Mat result = new Mat())
{
Cv2.CvtColor(src, dst, ColorConversionCodes.BGR2GRAY);
//对数组应用自适应阈值。包含二值图像等多种操作
Cv2.AdaptiveThreshold(~dst, binImage, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 15, -2);
InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3), new Point(-1, -1));
Cv2.MorphologyEx(binImage, result, MorphTypes.Open, kernel, new Point(-1, -1));
Cv2.BitwiseNot(result, result);
using (new Window("Result", WindowMode.Normal, result))
using (new Window("SRC", WindowMode.Normal, src))
{
Cv2.WaitKey(0);
}
}
}
想要获取指定的内容,还需要合适的结构体元素,上图使用 (3 X 3)大小的结构体。如果换成(5 X 5)大小文字将要抹去掉。
7:API
Cv2.AdaptiveThreshold(): 对数组应用自适应阈值。
参数 | 描述 |
InputArray src | Source 8-bit single-channel image. 输入的灰度图像 |
OutputArray dst | Destination image of the same size and the same type as src .与src大小和类型相同的目标映像。 |
double maxValue | Non-zero value assigned to the pixels for which the condition is satisfied 二值化的最大值 |
AdaptiveThresholdTypes adaptiveMethod | 要使用的自适应阈值算法有adaptive_threshold _mean_c或adaptive_threshold _gaussian_c (枚举类型,目前只有两个算法) |
ThresholdTypes thresholdType | 阈值类型必须是阈值二进制或阈值binary_inv。 |
int blockSize | 用于计算像素阈值的像素邻域的大小:3,5,7,依此类推。块大小 |
double c | 常量 (可以是正数 0 负数)从平均值或加权平均值中减去的常数 |
两种阈值公式:第五个参数