当前位置: 首页 > news >正文

学习 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. 定义结构元素:选择一个形状和大小合适的结构元素(内核)

    2. 扫描图像:将结构元素的中心对准图像中的每个像素

    3. 应用规则

      • 对于二值图像:如果结构元素覆盖的所有像素都是前景(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	×]
        [×	×	×	×	×]
        
    4. 输出结果:生成腐蚀后的图像

  • 结构元素

    结构元素是腐蚀操作的核心,常见的形状有:

    • 矩形: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: 十字形结构元素 : 主要影响水平和垂直方向

结构元素大小:

  • 较小尺寸:轻微腐蚀,保留更多细节

  • 较大尺寸:强烈腐蚀,可能丢失重要特征

迭代次数的影响:

  • 较少迭代:轻微腐蚀效果

  • 多次迭代:累积腐蚀效果,相当于使用更大的结构元素

处理流程:

  1. 图像加载:从资源文件加载图像

  2. 预处理:转换为灰度图并进行二值化,创建明显的目标对象

  3. 创建结构元素:定义腐蚀操作使用的内核形状和大小

  4. 应用腐蚀:使用erode函数对图像进行腐蚀操作

  5. 结果显示:将原图和腐蚀结果显示在ImageView中

26.2 应用场景

腐蚀操作在图像处理中有多种应用场景:

  1. 去除小噪声点

    • 消除图像中的孤立小白点(椒盐噪声)

    • 断开细小的连接

  2. 分离相连物体

    • 将轻微接触的物体分离开

    • 减少物体尺寸以便更好地计数

  3. 边缘检测预处理

    • 先腐蚀再膨胀(开运算)可以平滑物体轮廓

    • 去除细小毛刺

  4. 文本图像处理

    • 使文本笔画变细,提高OCR识别率

    • 分离粘连字符

  5. 医学图像处理

    • 分离接触的细胞或组织

    • 提取特定形状的结构

特点

  • 使前景对象变小

  • 消除小的孤立点

  • 平滑对象边界

  • 对二值图像和灰度图像都有效

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. 定义结构元素:选择一个形状和大小合适的结构元素(内核)

    2. 扫描图像:将结构元素的中心对准图像中的每个像素

    3. 应用规则

      • 对于二值图像:如果结构元素覆盖的区域中至少有一个像素是前景(1),则中心像素设置为前景(1)

      • 对于灰度图像:取结构元素覆盖区域内像素的最大值作为中心像素的值

    4. 输出结果:生成膨胀后的图像

  • 与腐蚀操作的关系

    膨胀和腐蚀是形态学操作中的一对基本操作:

    • 腐蚀:缩小前景区域,消除小物体

    • 膨胀:扩大前景区域,填充小孔洞

    • 两者结合可以形成更复杂的形态学操作(如开运算、闭运算)

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 应用场景

  • 开运算的应用场景

    1. 去除小噪声点

      • 消除图像中的孤立小点

      • 去除椒盐噪声

    2. 物体分离

      • 分离轻微接触的物体

      • 断开细小的连接

    3. 边缘平滑

      • 平滑物体边界

      • 去除毛刺

    4. 文本处理

      • 去除文档图像中的小噪点

      • 改善OCR识别效果

  • 闭运算的应用场景

    1. 填充孔洞

      • 填充物体内部的小孔

      • 修复不完整的轮廓

    2. 连接断裂

      • 连接断开的边缘

      • 修复断裂的文字笔画

    3. 平滑轮廓

      • 使轮廓更加连续

      • 减少轮廓上的缺口

    4. 前景提取

      • 填充前景物体中的小空隙

      • 改善分割结果

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 应用场景

  • 顶帽运算的应用场景

    1. 光照不均匀校正

      • 提取并去除不均匀的背景光照

      • 增强在明亮背景下的暗细节

    2. 微小物体检测

      • 检测图像中的小亮点、小物体

      • 工业检测中的缺陷检测

    3. 文本提取

      • 从复杂背景中提取文字

      • 增强文档图像中的文字区域

    4. 医学图像处理

      • 提取细胞图像中的微小结构

      • 增强X光图像中的细微特征

  • 黑帽运算的应用场景

    1. 暗细节增强

      • 突出图像中的暗区域和小孔洞

      • 增强阴影区域的细节

    2. 缺陷检测

      • 检测产品表面的暗缺陷

      • 工业质量控制的瑕疵检测

    3. 血管检测

      • 在医学图像中增强血管结构

      • 提取视网膜图像中的血管网络

    4. 目标提取

      • 从明亮背景中提取暗目标

      • 夜间图像中的目标检测

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);}
}

在这里插入图片描述
在这里插入图片描述


文章转载自:

http://7Wf2LBmK.nktyq.cn
http://fVwLliMR.nktyq.cn
http://iy9F45MT.nktyq.cn
http://jWM3MG0Y.nktyq.cn
http://jNK0v6ok.nktyq.cn
http://wFW0GUxb.nktyq.cn
http://raa1vMWn.nktyq.cn
http://AvktUH2P.nktyq.cn
http://7XOsuVzj.nktyq.cn
http://U5pwQwOk.nktyq.cn
http://kbxwpiOp.nktyq.cn
http://axzGSOCK.nktyq.cn
http://IW3IPfZw.nktyq.cn
http://fGngVfcW.nktyq.cn
http://vbcnfhF4.nktyq.cn
http://DBExIsMm.nktyq.cn
http://OpeUK7n7.nktyq.cn
http://NH7Vl8CC.nktyq.cn
http://nWDsSDUF.nktyq.cn
http://iHZvaDaQ.nktyq.cn
http://rIptHPTK.nktyq.cn
http://TAZqCPjk.nktyq.cn
http://7OscNxlS.nktyq.cn
http://AtBNQbfc.nktyq.cn
http://BQg639If.nktyq.cn
http://sEyO8nbf.nktyq.cn
http://CMgyaHGB.nktyq.cn
http://ixlFp7xY.nktyq.cn
http://8jvDerjk.nktyq.cn
http://DWkNpDnE.nktyq.cn
http://www.dtcms.com/a/368515.html

相关文章:

  • CodePerfAI体验:AI代码性能分析工具如何高效排查性能瓶颈、优化SQL执行耗时?
  • 【leetcode】46. 全排列
  • GD32入门到实战34--ARM启动流程
  • 针对nvm不能导致npm和node生效的解决办法
  • LeetCode 3027.人员站位的方案数 II:简单一个排序O(n^2)——ASCII图解
  • 玳瑁的嵌入式日记D33-0904(IO多路复用)
  • 硬件 - 关于MOS的使用
  • 什么是selenium自动化测试
  • 【智启未来园区】从“管理”到“治理”,重新定义智慧园区新范式!
  • 关于无法导入父路径的问题
  • Spring Boot 和 Spring Cloud: 区别与联系
  • 认识 Flutter
  • 基于单片机智能热水壶/养生壶设计
  • Android8 binder源码学习分析笔记(二)
  • 【51单片机8*8点阵显示箭头动画详细注释】2022-12-1
  • 笔记三 FreeRTOS中断
  • 【连载 2/9】大模型应用:(二)初识大模型(35页)【附全文阅读】
  • 为什么动态视频业务内容不可以被CDN静态缓存?
  • 【视频系统】技术汇编
  • 如何提升技术架构设计能力?
  • 【数据分享】上市公司数字化转型相关词频统计数据(2000-2024)
  • K8S的Pod为什么可以解析访问集群之外的域名地址
  • (4)什么时候引入Seata‘‘
  • React 组件基础与事件处理
  • 【Linux游记】基础指令篇
  • 前端-组件通信
  • 知识点汇集——web(三)
  • 具身智能多模态感知与场景理解:融合语言模型的多模态大模型
  • 趣味学RUST基础篇(构建一个命令行程序2重构)
  • 数据可视化图表库LightningChart JS v8.0上线:全新图例系统 + 数据集重构