在Android上玩转Opencv 系列:10.基础知识 水漫填充

79 阅读4分钟

在 Android 中使用 OpenCV 进行 水漫填充(Flood Fill) 操作,通常用于图像处理,尤其是分割和标记区域。水漫填充算法是一个经典的图像处理算法,其核心思想类似于“填色”操作,它从某个点开始,向四周填充相同的颜色或区域,直到遇到边界或区域不再满足特定条件。

基本概念

Flood Fill:从一个种子点开始,按照一定的条件(如颜色相似度)逐步填充周围的像素,直到遇到边界或填充条件不满足为止。

OpenCV floodFill 函数:OpenCV 提供了一个内置的 floodFill() 函数,用于实现水漫填充操作。

OpenCV floodFill 方法

OpenCV 中的 floodFill() 函数签名如下:

int cv::floodFill(
    Mat &image,              // 输入/输出图像,填充操作会修改图像
    Point seedPoint,         // 种子点 (填充的起始点)
    Scalar newColor,         // 新的颜色,用于填充区域
    Rect *rect = 0,          // 填充区域的边界矩形,可选
    Scalar loDiff = Scalar(), // 颜色容差下限
    Scalar upDiff = Scalar(), // 颜色容差上限
    int flags = 4            // 填充的标志(控制方式)
);

参数说明:

  1. image: 输入和输出图像。填充操作将修改这个图像。

  2. seedPoint: 种子点,即水漫填充的起始点。

  3. newColor: 填充区域的颜色。

  4. rect: 可选参数,返回一个矩形,表示填充区域的边界。

  5. loDiffupDiff: 这两个参数控制颜色的差异范围。填充操作会根据这些颜色差异来决定是否继续填充。loDiff 是下限差异,upDiff 是上限差异。

  6. flags: 填充的标志,常见的有:

• 4 (默认): 四连通填充

• 8: 八连通填充

• FLOODFILL_FIXED_RANGE: 颜色范围为固定范围,填充时只根据 newColor 与像素的差异来判断。

基本用法

下面是一个在 Android 中使用 OpenCV 进行水漫填充的简单示例。

1. 添加 OpenCV 到 Android 项目

首先,确保在你的 build.gradle 文件中包含 OpenCV 依赖:

implementation 'org.opencv:opencv-android:4.5.1'

2. 示例代码

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import org.opencv.android.Utils;
import org.opencv.core.Scalar;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    static {
        // 加载OpenCV库
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取ImageView组件
        ImageView imageView = findViewById(R.id.imageView);

        // 从资源文件中加载Bitmap
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample_image);
        
        // 将Bitmap转换为OpenCV的Mat格式
        Mat imgMat = new Mat();
        Utils.bitmapToMat(bitmap, imgMat);

        // 确保图像为RGB(或其他合适的格式)
        Imgproc.cvtColor(imgMat, imgMat, Imgproc.COLOR_RGB2BGR);

        // 选择种子点
        Point seedPoint = new Point(100, 100); // 例如从坐标 (100, 100) 开始填充

        // 设置新的填充颜色,RGB格式
        Scalar newColor = new Scalar(255, 0, 0); // 红色

        // 设置颜色差异范围
        Scalar loDiff = new Scalar(10, 10, 10);  // 允许的颜色下差异
        Scalar upDiff = new Scalar(10, 10, 10);  // 允许的颜色上差异

        // 使用FloodFill算法进行填充
        Rect rect = new Rect();  // 用于存储填充区域的矩形
        Imgproc.floodFill(imgMat, new Mat(), seedPoint, newColor, rect, loDiff, upDiff, 4);

        // 将修改后的Mat转回Bitmap
        Bitmap resultBitmap = Bitmap.createBitmap(imgMat.cols(), imgMat.rows(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(imgMat, resultBitmap);

        // 在ImageView中显示结果
        imageView.setImageBitmap(resultBitmap);
    }
}

代码解释:

  1. 加载图像:从资源文件加载图像,并将其转换为 OpenCV 的 Mat 格式,Mat 是 OpenCV 中处理图像的基本数据结构。

  2. 设置种子点:我们选择了坐标 (100, 100) 作为种子点,即水漫填充的起始位置。

  3. 填充颜色:我们选择了红色作为填充颜色(Scalar(255, 0, 0) 表示红色)。

  4. 颜色容差:通过设置 loDiff 和 upDiff 参数来控制哪些颜色可以被填充。这里设置的容差是 10,可以根据实际需要调整。

  5. 执行 floodFill 操作:使用 Imgproc.floodFill() 进行水漫填充操作。填充后的区域被保存到 rect 矩形中(如果需要,您可以用它来获取填充区域的坐标和大小)。

  6. 显示结果:最后,我们将填充后的图像转换回 Bitmap,并将其显示在 ImageView 中。

参数解释:

• newColor:定义了填充的颜色,Scalar 是一个用于表示颜色的类(蓝色、绿色和红色的值),格式为 (B, G, R)。

• loDiff 和 upDiff:这些参数控制颜色的容差范围。loDiff 是下限,upDiff 是上限。它们定义了哪些颜色可以被认为是与种子点颜色相似的颜色。通过调整这两个值,可以控制填充的灵敏度。

3. 应用场景

图像分割:在图像处理或计算机视觉应用中,水漫填充可以用来标记一个区域,常见于分割应用,比如标记同类区域。

图像修复:使用水漫填充来填补图像中的空白区域(如去除杂色或修复损坏的区域)。

动态标记:在用户交互界面中,可以让用户点击某个点,然后用不同颜色标记该区域。

总结:

floodFill 是一个非常实用的图像处理操作,可以在 Android 中通过 OpenCV 库轻松实现。它不仅可以用于填充图像的特定区域,还可以帮助在复杂的图像处理任务中进行区域标记和分割。