学习 Android (二十) 学习 OpenCV (五)
学习 Android (二) 学习 OpenCV (五)
在上一章节,我们对于 OpenCV 中的边缘检测有了进一步的学习和了解,这一章节我们将对图像形态学操作进行学习和了解;
26. 图像腐蚀
26.1 什么是图像腐蚀
腐蚀(Erosion)是图像处理中一种基本的形态学操作,它通过使用结构元素(内核)对图像进行扫描,根据结构元素与图像的交集关系来"收缩"或"细化"图像中的前景对象。
-
数学定义
从数学角度,腐蚀操作可以定义为:
A ⊖ B = {z | (B)z ⊆ A}
其中:
-
A
是输入图像(二值图像或灰度图像) -
B
是结构元素(内核) -
(B)z
表示将结构元素B平移z -
结果是所有使B完全包含在A中的平移位置z的集合
-
-
操作过程
腐蚀操作的工作流程:
-
定义结构元素:选择一个形状和大小合适的结构元素(内核)
-
扫描图像:将结构元素的中心对准图像中的每个像素
-
应用规则:
-
对于二值图像:如果结构元素覆盖的所有像素都是前景(1),则中心像素保留为前景,否则变为背景(0)
原始图像: [1, 1, 1, 0, 0] [1, 1, 1, 0, 0] [1, 1, 1, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] 3×3 矩形结构元素 结构元素: [1, 1, 1] [1, 1, 1] [1, 1, 1] 腐蚀过程 我们可以理解为,原始图像中,以每个像素坐标为中心点,能够完全映射结构元素,即像素保留前期1,否则变为背景0腐蚀结果 [0, 0, 0, 0, 0] [0, 1, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0]
-
对于灰度图像:取结构元素覆盖区域内像素的最小值作为中心像素的值
原始图像: [90 85 80 75 70] [95 90 85 80 75] [100 95 90 85 80] [105 100 95 90 85] [110 105 100 95 90]3×3 矩形结构元素 结构元素: [1, 1, 1] [1, 1, 1] [1, 1, 1] 腐蚀过程 和二值图像过程一样,不过是将能够完全映射结构元素的中心点,变为该映射矩阵中最小的值,需要留意的是,在切换中心点进行下一个腐蚀操作时,映射到的矩阵的值要以原始图像为准,不能带入上一个已经腐蚀过的中心点值腐蚀结果 [× × × × ×] [× 80 75 70 ×] [× 85 80 75 ×] [× 90 85 80 ×] [× × × × ×]
-
-
输出结果:生成腐蚀后的图像
-
-
结构元素
结构元素是腐蚀操作的核心,常见的形状有:
-
矩形:MORPH_RECT
-
椭圆形:MORPH_ELLIPSE
-
十字形:MORPH_CROSS
结构元素的大小决定了腐蚀的程度,较大的结构元素会产生更强烈的腐蚀效果。
-
26.2 关键代码分析
腐蚀核心函数:
Imgproc.erode(binaryMat, erosionMat, kernel, new Point(-1, -1), ITERATIONS);
参数说明:
-
binaryMat
: 输入图像(二值图像或灰度图像) -
erosionMat
: 输出图像 -
kernel
: 结构元素(定义腐蚀操作的形状和大小) -
new Point(-1, -1)
: 锚点位置(默认中心点) -
ITERATIONS
: 迭代次数(腐蚀操作执行的次数)
结构元素创建:
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(KERNEL_SIZE, KERNEL_SIZE));
结构元素类型:
-
Imgproc.MORPH_RECT
: 矩形结构元素 : 产生规则的腐蚀效果,各方向均匀收缩 -
Imgproc.MORPH_ELLIPSE
: 椭圆形结构元素 : 产生更自然的圆形腐蚀效果 -
Imgproc.MORPH_CROSS
: 十字形结构元素 : 主要影响水平和垂直方向
结构元素大小:
-
较小尺寸:轻微腐蚀,保留更多细节
-
较大尺寸:强烈腐蚀,可能丢失重要特征
迭代次数的影响:
-
较少迭代:轻微腐蚀效果
-
多次迭代:累积腐蚀效果,相当于使用更大的结构元素
处理流程:
-
图像加载:从资源文件加载图像
-
预处理:转换为灰度图并进行二值化,创建明显的目标对象
-
创建结构元素:定义腐蚀操作使用的内核形状和大小
-
应用腐蚀:使用erode函数对图像进行腐蚀操作
-
结果显示:将原图和腐蚀结果显示在ImageView中
26.2 应用场景
腐蚀操作在图像处理中有多种应用场景:
-
去除小噪声点
-
消除图像中的孤立小白点(椒盐噪声)
-
断开细小的连接
-
-
分离相连物体
-
将轻微接触的物体分离开
-
减少物体尺寸以便更好地计数
-
-
边缘检测预处理
-
先腐蚀再膨胀(开运算)可以平滑物体轮廓
-
去除细小毛刺
-
-
文本图像处理
-
使文本笔画变细,提高OCR识别率
-
分离粘连字符
-
-
医学图像处理
-
分离接触的细胞或组织
-
提取特定形状的结构
-
特点:
-
使前景对象变小
-
消除小的孤立点
-
平滑对象边界
-
对二值图像和灰度图像都有效
26.3 示例
ErosionActivity.java
public class ErosionActivity extends AppCompatActivity {private ActivityErosionBinding mBinding;static {System.loadLibrary("opencv_java4");}private Mat originalMat;private Mat binaryMat; // 新增:用于存储二值化图像private Mat erosionRectMat;private Mat erosionEllipseMat;private Mat erosionCrossMat;private Mat grayMat;// 腐蚀参数private static final int KERNEL_SIZE = 4;private static final int ITERATIONS = 1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityErosionBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());try {// 加载原始图像originalMat = Utils.loadResource(this, R.drawable.lxh);if (originalMat == null || originalMat.empty()) {Toast.makeText(this, "Failed to load image", Toast.LENGTH_SHORT).show();return;}// 显示原图OpenCVHelper.showMat(mBinding.ivOriginal, originalMat);// 转换为灰度图grayMat = new Mat();Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);// 二值化处理,创建明显的目标对象binaryMat = new Mat(); // 使用新的Mat对象存储二值化结果Imgproc.threshold(grayMat, binaryMat, 127, 255, Imgproc.THRESH_BINARY);// 应用不同类型的腐蚀applyRectErosion();applyEllipseErosion();applyCrossErosion();} catch (Exception e) {e.printStackTrace();Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();}}/*** 应用矩形结构元素的腐蚀操作*/private void applyRectErosion() {applyErosion(Imgproc.MORPH_RECT, mBinding.ivErosionRect, "矩形");}/*** 应用椭圆结构元素的腐蚀操作*/private void applyEllipseErosion() {applyErosion(Imgproc.MORPH_ELLIPSE, mBinding.ivErosionEllipse, "椭圆");}/*** 应用十字形结构元素的腐蚀操作*/private void applyCrossErosion() {applyErosion(Imgproc.MORPH_CROSS, mBinding.ivErosionCross, "十字形");}/*** 通用的腐蚀操作方法** @param shape 结构元素形状* @param imageView 显示结果的ImageView* @param shapeName 形状名称(用于错误提示)*/private void applyErosion(int shape, ImageView imageView, String shapeName) {Mat kernel = null;Mat resultMat = null;try {// 创建结构元素kernel = Imgproc.getStructuringElement(shape, new Size(KERNEL_SIZE, KERNEL_SIZE));// 创建结果MatresultMat = new Mat();// 应用腐蚀操作Imgproc.erode(binaryMat, resultMat, kernel, new Point(-1, -1), ITERATIONS);// 显示结果OpenCVHelper.showMat(imageView, resultMat);// 根据形状保存结果switch (shape) {case Imgproc.MORPH_RECT:erosionRectMat = resultMat;break;case Imgproc.MORPH_ELLIPSE:erosionEllipseMat = resultMat;break;case Imgproc.MORPH_CROSS:erosionCrossMat = resultMat;break;}} catch (Exception e) {e.printStackTrace();Toast.makeText(this, shapeName + "腐蚀操作失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();// 确保异常时也释放资源if (resultMat != null) {resultMat.release();}} finally {// 释放内核资源if (kernel != null) {kernel.release();}}}@Overrideprotected void onDestroy() {super.onDestroy();// 释放所有Mat资源if (originalMat != null) OpenCVHelper.safeRelease(originalMat);if (binaryMat != null) OpenCVHelper.safeRelease(binaryMat);if (grayMat != null) OpenCVHelper.safeRelease(grayMat);if (erosionRectMat != null) OpenCVHelper.safeRelease(erosionRectMat);if (erosionEllipseMat != null) OpenCVHelper.safeRelease(erosionEllipseMat);if (erosionCrossMat != null) OpenCVHelper.safeRelease(erosionCrossMat);}
}
作者的示例图并不能很明显的体现出各个结构元素模式的差异,希望读者能够自己处理(不是因为作者懒得去找图)
27. 图像膨胀
27.1 什么是图像膨胀
图像膨胀(Dilation)是形态学操作中的一种基本操作,与腐蚀操作相反。它通过使用结构元素(内核)对图像进行扫描,根据结构元素与图像的并集关系来"扩大"或"增厚"图像中的前景对象。
-
数学定义
膨胀操作可以定义为:
A ⊕ B = {z | (B)z ∩ A ≠ ∅}
其中:
-
A
是输入图像(二值图像或灰度图像) -
B
是结构元素(内核) -
(B)z
表示将结构元素B平移z -
结果是所有使B与A有交集的平移位置z的集合
-
-
操作过程
膨胀操作的工作流程完全和腐蚀相反:
-
定义结构元素:选择一个形状和大小合适的结构元素(内核)
-
扫描图像:将结构元素的中心对准图像中的每个像素
-
应用规则:
-
对于二值图像:如果结构元素覆盖的区域中至少有一个像素是前景(1),则中心像素设置为前景(1)
-
对于灰度图像:取结构元素覆盖区域内像素的最大值作为中心像素的值
-
-
输出结果:生成膨胀后的图像
-
-
与腐蚀操作的关系
膨胀和腐蚀是形态学操作中的一对基本操作:
-
腐蚀:缩小前景区域,消除小物体
-
膨胀:扩大前景区域,填充小孔洞
-
两者结合可以形成更复杂的形态学操作(如开运算、闭运算)
-
27.2 关键代码分析
函数原型
public static void dilate(Mat src, Mat dst, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
参数详解
-
src
:输入图像,可以是二值或灰度图像 -
dst
:输出图像,与输入图像相同的尺寸和类型 -
kernel
:结构元素,可以通过getStructuringElement
创建 -
anchor
:锚点位置,默认为中心点(-1, -1) -
iterations
:膨胀操作的迭代次数 -
borderType
:边界处理类型(如BORDER_CONSTANT
) -
borderValue
:边界值,当边界类型为BORDER_CONSTANT
时使用
27.3 应用场景
膨胀操作在图像处理中有多种应用场景:
连接断裂部分
-
修复断裂的文字笔画
-
连接断开的边缘线
填充小孔洞
-
填充物体内部的小孔
-
平滑物体边界
增加物体尺寸
-
使细小的物体变得更明显
-
增加边缘厚度
与腐蚀操作结合
-
开运算:先腐蚀后膨胀,用于去除小物体和平滑边界
-
闭运算:先膨胀后腐蚀,用于填充小孔和连接断点
边缘检测后处理
-
使检测到的边缘更加连续
-
增加边缘的明显度
27.4 示例
DilationDemoActivity.java
public class DilationDemoActivity extends AppCompatActivity {private ActivityDilationDemoBinding mBinding;static {System.loadLibrary("opencv_java4");}private Mat originalMat;private Mat binaryMat; // 新增:用于存储二值化图像private Mat dilationRectMat;private Mat dilationEllipseMat;private Mat dilationCrossMat;private Mat grayMat;// 膨胀参数private static final int KERNEL_SIZE = 3;private static final int ITERATIONS = 1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityDilationDemoBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());try {originalMat = Utils.loadResource(this, R.drawable.lxh);if (originalMat.empty()) {Toast.makeText(this, "Failed to load image", Toast.LENGTH_SHORT).show();return;}showMat(mBinding.ivOriginal, originalMat);// 转换为灰度图grayMat = new Mat();Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);// 二值化处理,创建明显的目标对象binaryMat = new Mat(); // 使用新的Mat对象存储二值化结果Imgproc.threshold(grayMat, binaryMat, 127, 255, Imgproc.THRESH_BINARY);// 应用不同类型的腐蚀applyRectErosion();applyEllipseErosion();applyCrossErosion();} catch (Exception e) {e.printStackTrace();}}private void applyRectErosion() {try {// 创建结构元素(内核)// 使用矩形结构元素,大小5×5Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(KERNEL_SIZE, KERNEL_SIZE));// 应用膨胀操作// 参数说明:// - binaryMat: 输入图像(二值图像)// - dilationMat: 输出图像// - kernel: 结构元素// - anchor: 锚点位置(默认中心点(-1,-1))// - ITERATIONS: 迭代次数(膨胀操作的执行次数)dilationRectMat = new Mat();Imgproc.dilate(binaryMat, dilationRectMat, kernel, new Point(-1, -1), ITERATIONS);// 显示结果showMat(mBinding.ivDilationRect, dilationRectMat);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in dilation operation: " + e.getMessage());}}private void applyEllipseErosion() {try {Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE,new Size(KERNEL_SIZE, KERNEL_SIZE));dilationEllipseMat = new Mat();Imgproc.dilate(binaryMat, dilationEllipseMat, kernel, new Point(-1, -1), ITERATIONS);// 显示结果showMat(mBinding.ivDilationEllipse, dilationEllipseMat);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in dilation operation: " + e.getMessage());}}private void applyCrossErosion() {try {Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_CROSS,new Size(KERNEL_SIZE, KERNEL_SIZE));dilationCrossMat = new Mat();Imgproc.dilate(binaryMat, dilationCrossMat, kernel, new Point(-1, -1), ITERATIONS);// 显示结果showMat(mBinding.ivDilationCross, dilationCrossMat);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in dilation operation: " + e.getMessage());}}@Overrideprotected void onDestroy() {super.onDestroy();if (originalMat != null) OpenCVHelper.safeRelease(originalMat);if (binaryMat != null) OpenCVHelper.safeRelease(binaryMat);if (dilationRectMat != null) OpenCVHelper.safeRelease(dilationRectMat);if (dilationEllipseMat != null) OpenCVHelper.safeRelease(dilationEllipseMat);if (dilationCrossMat != null) OpenCVHelper.safeRelease(dilationCrossMat);if (grayMat != null) OpenCVHelper.safeRelease(grayMat);}
}
28. 开运算与闭运算
开运算(Opening)和闭运算(Closing)是形态学图像处理中的两种重要操作,它们都是由基本的腐蚀和膨胀操作组合而成的。
28.1 什么是开运算
定义:先腐蚀后膨胀
开运算(A) = 膨胀(腐蚀(A))
A ∘ B = (A ⊖ B) ⊕ B
作用:
-
消除小物体(在腐蚀阶段被移除)
-
平滑物体轮廓(在膨胀阶段部分恢复)
-
断开细小的连接
-
保持大体形状不变
28.2 什么是闭运算
定义:先膨胀后腐蚀
闭运算(A) = 腐蚀(膨胀(A))
A • B = (A ⊕ B) ⊖ B
作用:
-
填充小孔洞(在膨胀阶段被填充)
-
连接邻近物体
-
平滑轮廓
-
保持大体形状不变
28.3 关键代码分析
OpenCV提供了专门的函数来进行开运算和闭运算:
// 形态学操作通用函数
public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
参数详解
-
src
:输入图像 -
dst
:输出图像 -
op
:操作类型-
Imgproc.MORPH_OPEN
:开运算 -
Imgproc.MORPH_CLOSE
:闭运算
-
-
kernel
:结构元素 -
anchor
:锚点位置(默认-1,-1) -
iterations
:操作次数 -
borderType
:边界类型 -
borderValue
:边界值
28.4 应用场景
-
开运算的应用场景
-
去除小噪声点
-
消除图像中的孤立小点
-
去除椒盐噪声
-
-
物体分离
-
分离轻微接触的物体
-
断开细小的连接
-
-
边缘平滑
-
平滑物体边界
-
去除毛刺
-
-
文本处理
-
去除文档图像中的小噪点
-
改善OCR识别效果
-
-
-
闭运算的应用场景
-
填充孔洞
-
填充物体内部的小孔
-
修复不完整的轮廓
-
-
连接断裂
-
连接断开的边缘
-
修复断裂的文字笔画
-
-
平滑轮廓
-
使轮廓更加连续
-
减少轮廓上的缺口
-
-
前景提取
-
填充前景物体中的小空隙
-
改善分割结果
-
-
28.5 示例
MorphologyOpsActivity.java
public class MorphologyOpsActivity extends AppCompatActivity {private ActivityMorphologyOpsBinding mBinding;static {System.loadLibrary("opencv_java4");}private Mat originalMat;// 形态学操作参数private static final int KERNEL_SIZE = 5;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityMorphologyOpsBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());try {// 从资源加载图像originalMat = Utils.loadResource(this, R.drawable.lena);if (originalMat.empty()) {Toast.makeText(this, "Failed to load image", Toast.LENGTH_SHORT).show();return;}// 显示原图showMat(mBinding.ivOriginal, originalMat);// 创建测试图像(包含小物体和小孔洞)Mat testImage = createTestImage();// 应用开运算和闭运算applyMorphologyOperations(testImage);// 释放测试图像testImage.release();} catch (Exception e) {e.printStackTrace();}}/*** 创建包含小物体和小孔洞的测试图像*/private Mat createTestImage() {// 转换为灰度图Mat grayMat = new Mat();Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);// 二值化处理Mat binary = new Mat();Imgproc.threshold(grayMat, binary, 127, 255, Imgproc.THRESH_BINARY);// 添加一些小物体(噪声)Mat withNoise = binary.clone();addSmallObjects(withNoise);// 添加一些小孔洞Mat withHoles = withNoise.clone();addSmallHoles(withHoles);// 释放临时资源grayMat.release();binary.release();withNoise.release();return withHoles;}/*** 添加小物体(模拟噪声)*/private void addSmallObjects(Mat image) {// 在随机位置添加小白色方块(模拟噪声)for (int i = 0; i < 20; i++) {int x = (int) (Math.random() * (image.cols() - 5));int y = (int) (Math.random() * (image.rows() - 5));Imgproc.rectangle(image,new Point(x, y),new Point(x + 3, y + 3),new Scalar(255), -1);}}/*** 添加小孔洞*/private void addSmallHoles(Mat image) {// 在随机位置添加小黑色方块(模拟孔洞)for (int i = 0; i < 15; i++) {int x = (int) (Math.random() * (image.cols() - 5));int y = (int) (Math.random() * (image.rows() - 5));Imgproc.rectangle(image,new Point(x, y),new Point(x + 3, y + 3),new Scalar(0), -1);}}private void applyMorphologyOperations(Mat testImage) {try {// 显示结果demonstrateKernelEffects(testImage);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in morphology operations: " + e.getMessage());}}/*** 演示不同结构元素的影响*/private void demonstrateKernelEffects(Mat testImage) {// 创建不同形状的结构元素Mat rectKernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(KERNEL_SIZE, KERNEL_SIZE));Mat ellipseKernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(KERNEL_SIZE, KERNEL_SIZE));Mat crossKernel = Imgproc.getStructuringElement(Imgproc.MORPH_CROSS, new Size(KERNEL_SIZE, KERNEL_SIZE));Mat openRect = new Mat();Mat openEllipse = new Mat();Mat openCross = new Mat();Mat closeRect = new Mat();Mat closeEllipse = new Mat();Mat closeCross = new Mat();try {// 应用不同结构元素的开运算Imgproc.morphologyEx(testImage, openRect, Imgproc.MORPH_OPEN, rectKernel);Imgproc.morphologyEx(testImage, openEllipse, Imgproc.MORPH_OPEN, ellipseKernel);Imgproc.morphologyEx(testImage, openCross, Imgproc.MORPH_OPEN, crossKernel);// 应用不同结构元素的闭运算Imgproc.morphologyEx(testImage, closeRect, Imgproc.MORPH_CLOSE, rectKernel);Imgproc.morphologyEx(testImage, closeEllipse, Imgproc.MORPH_CLOSE, ellipseKernel);Imgproc.morphologyEx(testImage, closeCross, Imgproc.MORPH_CLOSE, crossKernel);showMat(mBinding.ivOpen, openRect);showMat(mBinding.ivClose, closeRect);} finally {// 释放资源rectKernel.release();ellipseKernel.release();crossKernel.release();openRect.release();openEllipse.release();openCross.release();closeRect.release();closeEllipse.release();closeCross.release();}}@Overrideprotected void onDestroy() {super.onDestroy();if (originalMat != null) OpenCVHelper.safeRelease(originalMat);}
}
29. 顶帽与黑帽
顶帽(Top-hat)和黑帽(Black-hat)是形态学图像处理中的两种高级操作,它们都是基于基础的开运算和闭运算衍生而来的。
29.1 什么是顶帽
定义:原图像与开运算结果的差
顶帽 = 原图像 - 开运算(原图像)
顶帽(A) = A - (A ∘ B)
物理意义:
-
突出比背景亮的细小物体
-
增强图像中的亮细节特征
-
在均匀背景上提取微小亮物体
29.2 什么是黑帽
定义:闭运算结果与原图像的差
黑帽 = 闭运算(原图像) - 原图像
黑帽(A) = (A • B) - A
物理意义:
-
突出比背景暗的细小物体
-
增强图像中的暗细节特征
-
在均匀背景上提取微小暗物体
29.3 关键代码分析
OpenCV使用统一的 morphologyEx 函数来实现顶帽和黑帽运算:
public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
参数详解
-
src
:输入图像(通常是灰度图像) -
dst
:输出图像 -
op
:操作类型-
Imgproc.MORPH_TOPHAT
:顶帽运算 -
Imgproc.MORPH_BLACKHAT
:黑帽运算
-
-
kernel
:结构元素 -
anchor
:锚点位置(默认-1,-1) -
iterations
:操作次数(通常为1) -
borderType
:边界类型 -
borderValue
:边界值
29.4 应用场景
-
顶帽运算的应用场景
-
光照不均匀校正
-
提取并去除不均匀的背景光照
-
增强在明亮背景下的暗细节
-
-
微小物体检测
-
检测图像中的小亮点、小物体
-
工业检测中的缺陷检测
-
-
文本提取
-
从复杂背景中提取文字
-
增强文档图像中的文字区域
-
-
医学图像处理
-
提取细胞图像中的微小结构
-
增强X光图像中的细微特征
-
-
-
黑帽运算的应用场景
-
暗细节增强
-
突出图像中的暗区域和小孔洞
-
增强阴影区域的细节
-
-
缺陷检测
-
检测产品表面的暗缺陷
-
工业质量控制的瑕疵检测
-
-
血管检测
-
在医学图像中增强血管结构
-
提取视网膜图像中的血管网络
-
-
目标提取
-
从明亮背景中提取暗目标
-
夜间图像中的目标检测
-
-
29.5 示例
HatTransformsActivity.java
public class HatTransformsActivity extends AppCompatActivity {private ActivityHatTransformsBinding mBinding;static {System.loadLibrary("opencv_java4");}private Mat originalMat, grayMat;// 形态学操作参数private static final int KERNEL_SIZE = 15;private static final int ITERATIONS = 1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityHatTransformsBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());try {// 从资源加载图像originalMat = Utils.loadResource(this, R.drawable.twgx);if (originalMat.empty()) {Toast.makeText(this, "Failed to load image", Toast.LENGTH_SHORT).show();return;}// 转换为灰度图grayMat = new Mat();Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);// 显示原图showMat(mBinding.ivOriginal, grayMat);// 应用顶帽和黑帽运算applyHatTransforms();// 演示文本增强应用demonstrateTextEnhancement();} catch (Exception e) {e.printStackTrace();Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();}}private void applyHatTransforms() {// 创建结构元素Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(KERNEL_SIZE, KERNEL_SIZE));Mat tophatResult = new Mat();Mat blackhatResult = new Mat();try {// 应用顶帽运算(突出亮细节)Imgproc.morphologyEx(grayMat, tophatResult, Imgproc.MORPH_TOPHAT, kernel,new Point(-1, -1), ITERATIONS);// 应用黑帽运算(突出暗细节)Imgproc.morphologyEx(grayMat, blackhatResult, Imgproc.MORPH_BLACKHAT, kernel,new Point(-1, -1), ITERATIONS);// 显示结果showMat(mBinding.ivTophat, tophatResult);showMat(mBinding.ivBlackhat, blackhatResult);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in hat transforms: " + e.getMessage());} finally {// 释放资源kernel.release();tophatResult.release();blackhatResult.release();}}/*** 演示文本增强应用*/private void demonstrateTextEnhancement() {Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(KERNEL_SIZE, KERNEL_SIZE));Mat enhancedText = new Mat();try {// 使用顶帽运算增强文本(假设文本比背景暗)// 对于暗文本 on 亮背景,使用顶帽运算可以增强文本Imgproc.morphologyEx(grayMat, enhancedText, Imgproc.MORPH_TOPHAT, kernel);// 增强对比度使文本更清晰Core.multiply(enhancedText, new Scalar(2.0), enhancedText);// 显示增强后的文本showMat(mBinding.ivTextEnhanced, enhancedText);} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in text enhancement: " + e.getMessage());} finally {kernel.release();enhancedText.release();}}/*** 演示光照校正应用*/private void demonstrateIlluminationCorrection() {Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,new Size(KERNEL_SIZE * 2, KERNEL_SIZE * 2) // 使用更大的核);Mat background = new Mat();Mat corrected = new Mat();try {// 使用开运算估计背景Imgproc.morphologyEx(grayMat, background, Imgproc.MORPH_OPEN, kernel);// 从原图中减去背景(类似顶帽运算)Core.subtract(grayMat, background, corrected);// 可以显示或保存校正结果} catch (Exception e) {e.printStackTrace();Log.e("TAG", "Error in illumination correction: " + e.getMessage());} finally {kernel.release();background.release();corrected.release();}}/*** 演示不同结构元素的影响*/private void demonstrateKernelEffects() {// 创建不同形状的结构元素Mat rectKernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(KERNEL_SIZE, KERNEL_SIZE));Mat ellipseKernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(KERNEL_SIZE, KERNEL_SIZE));Mat tophatRect = new Mat();Mat tophatEllipse = new Mat();try {// 应用不同结构元素的顶帽运算Imgproc.morphologyEx(grayMat, tophatRect, Imgproc.MORPH_TOPHAT, rectKernel);Imgproc.morphologyEx(grayMat, tophatEllipse, Imgproc.MORPH_TOPHAT, ellipseKernel);// 比较不同结构元素的效果// 矩形核:产生更规则的响应// 椭圆核:产生更平滑的响应} finally {// 释放资源rectKernel.release();ellipseKernel.release();tophatRect.release();tophatEllipse.release();}}@Overrideprotected void onDestroy() {super.onDestroy();if (originalMat != null) safeRelease(originalMat);if (grayMat != null) safeRelease(grayMat);}
}