Kotlin Bytedeco OpenCV 图像图像51.1 KNN背景消除

Kotlin Bytedeco OpenCV 图像图像51.1 KNN背景消除

  • [1 添加依赖](#1 添加依赖)
  • [2 测试代码](#2 测试代码)
  • [3 测试结果](#3 测试结果)
方法 适用场景 优点 计算量
MOG2 复杂背景 可检测阴影 中等
KNN 动态背景 适用于波动场景 较高
Running Average 静态背景 计算简单
Frame Differencing 低光照变化场景 计算快
Optical Flow 复杂运动场景 精度高

如果你的场景是 一般的视频监控,推荐使用 MOG2 或 KNN。

如果你的场景是 背景变化缓慢,推荐 Running Average。

1 添加依赖

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xu</groupId>
    <artifactId>KotlinOpenCV</artifactId>
    <version>1.0</version>

    <properties>
        <kotlin.version>2.0.0</kotlin.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <kotlin.code.style>official</kotlin.code.style>
        <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
    </properties>

    <repositories>
        <repository>
            <id>mavenCentral</id>
            <url>https://repo1.maven.org/maven2/</url>
        </repository>
    </repositories>

    <dependencies>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.29</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.27.0</version>
        </dependency>

        <dependency>
            <groupId>org.tukaani</groupId>
            <artifactId>xz</artifactId>
            <version>1.10</version>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlinx</groupId>
            <artifactId>kotlinx-coroutines-core</artifactId>
            <version>1.9.0-RC</version>
        </dependency>

        <!--        <dependency>-->
        <!--            <groupId>org.opencv</groupId>-->
        <!--            <artifactId>opencv</artifactId>-->
        <!--            <version>4100</version>-->
        <!--            <scope>system</scope>-->
        <!--            <systemPath>${project.basedir}/lib/opencv/opencv-4100.jar</systemPath>-->
        <!--        </dependency>-->

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>opencv-platform</artifactId>
            <version>4.10.0-1.5.11</version>
        </dependency>

        <!--        <dependency>-->
        <!--            <groupId>org.bytedeco</groupId>-->
        <!--            <artifactId>ffmpeg-platform</artifactId>-->
        <!--            <version>6.1.1-1.5.10</version>-->
        <!--        </dependency>-->

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-test-junit5</artifactId>
            <version>2.0.0</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>2.0.0</version>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>src/main/kotlin</sourceDirectory>
        <testSourceDirectory>src/test/kotlin</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>2.0.0</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <configuration>
                    <mainClass>MainKt</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2 测试代码

kotlin 复制代码
package com.xu.com.xu.video

import org.bytedeco.javacpp.Loader
import org.bytedeco.opencv.global.opencv_core
import org.bytedeco.opencv.global.opencv_highgui
import org.bytedeco.opencv.global.opencv_imgproc
import org.bytedeco.opencv.global.opencv_video
import org.bytedeco.opencv.opencv_core.Mat
import org.bytedeco.opencv.opencv_core.MatVector
import org.bytedeco.opencv.opencv_core.Size
import org.bytedeco.opencv.opencv_videoio.VideoCapture

object BSM {

    init {
        Loader.load(opencv_core::class.java)
    }

    @JvmStatic
    fun main(args: Array<String>) {
        knn()
    }

    fun flow() {
        // 打开视频流
        val capture = VideoCapture("lib/video/video_003.avi")
        if (!capture.isOpened) {
            return
        }

        val prev = Mat()  // 存储上一帧灰度图像
        val gray = Mat()      // 当前帧灰度图像
        val flow = Mat()      // 存储光流结果

        val org = Mat()       // 存储当前原始帧
        val mask = Mat()      // 用于存储前景掩码

        while (true) {
            // 读取当前帧
            capture.read(org)
            if (org.empty()) break
            // 转换为灰度图
            opencv_imgproc.cvtColor(org, gray, opencv_imgproc.COLOR_BGR2GRAY)
            if (!prev.empty()) {
                // 计算光流
                opencv_video.calcOpticalFlowFarneback(
                    prev, gray, flow,
                    0.5, // `pyrScale` 适当降低(0.4-0.6),减少背景干扰
                    3,   // `levels` 适当增加(2-4),提高检测范围
                    1,   // `windowSize` 增大(3→5),增强检测
                    20,  // `iterations` 增加迭代次数,提高准确度
                    5,   // `polyN`(5-7),适当提高减少噪声
                    1.2, // `polySigma` 增大(1.2 → 1.5),平滑光流
                    0    // `flags` 默认为 0
                )
                // 计算光流的幅度
                val channels = MatVector()
                opencv_core.split(flow, channels) // 拆分 X / Y 分量
                val mag = Mat()
                opencv_core.magnitude(channels[0], channels[1], mag)
                // 归一化幅度(norm 的类型为 CV_32F)
                val norm = Mat()
                opencv_core.normalize(mag, norm, 0.0, 255.0, opencv_core.NORM_MINMAX, -1, Mat())
                // 将 norm 转换为 8 位图像(CV_8U)
                val calc = Mat()
                norm.convertTo(calc, opencv_core.CV_8U)
                // 进行二值化处理,提取运动区域(mask 的类型为 CV_8UC1)
                //opencv_imgproc.threshold(calc, mask, 10.0, 255.0, opencv_imgproc.THRESH_BINARY)
                opencv_imgproc.adaptiveThreshold(
                    calc, mask, 255.0,
                    opencv_imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
                    opencv_imgproc.THRESH_BINARY,
                    10, 2.0
                )
                // 形态学处理去噪声
                val kernel = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, Size(1, 1))
                opencv_imgproc.morphologyEx(mask, mask, opencv_imgproc.MORPH_OPEN, kernel)
                opencv_imgproc.morphologyEx(mask, mask, opencv_imgproc.MORPH_CLOSE, kernel)
                // 确保类型一致
                val comm = Mat()
                opencv_imgproc.cvtColor(mask, comm, opencv_imgproc.COLOR_GRAY2BGR)
                // 确保大小一致
                if (comm.size() != org.size()) {
                    opencv_imgproc.resize(comm, comm, org.size())
                }
                // 进行拼接显示
                val show = Mat()
                opencv_core.hconcat(org, comm, show)
                opencv_highgui.imshow("Optical Flow BSM", show)
            }
            // 复制当前帧用于下一次计算
            gray.copyTo(prev)
            // 检查用户按键
            if (opencv_highgui.waitKey(30) == 'q'.code) break
        }
        // 释放资源
        capture.release()
        opencv_highgui.destroyAllWindows()
    }

    fun gmm() {
        // 打开视频流(可使用摄像头或者视频文件路径)
        val capture = VideoCapture(0)
        capture.open("lib/video/video_003.avi")
        // 创建背景减除器
        val bg = opencv_video.createBackgroundSubtractorMOG2().apply {
            history = 500         // 历史帧数
            varThreshold = 16.0   // 方差阈值
            detectShadows = true  // 检测阴影
        }
        // 创建Mat对象用于存储视频帧和结果
        val org = Mat()
        val dst = Mat()

        while (true) {
            // 读取当前帧
            capture.read(org)
            if (org.empty()) break
            // 应用背景减除器
            bg.apply(org, dst)
            // 可选:对前景蒙版进行一些后处理(如形态学操作)
            val kernel = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, Size(1, 1))
            opencv_imgproc.morphologyEx(dst, dst, opencv_imgproc.MORPH_CLOSE, kernel)
            // 确保类型一致
            val mat = Mat()
            opencv_imgproc.cvtColor(dst, mat, opencv_imgproc.COLOR_GRAY2BGR)
            // 确保大小一致
            if (dst.size() != org.size()) {
                opencv_imgproc.resize(mat, mat, org.size())
            }
            // 进行拼接
            val show = Mat()
            opencv_core.hconcat(org, mat, show)
            opencv_highgui.imshow("MOG2 BSM", show)
            // 检查用户按键
            if (opencv_highgui.waitKey(30) == 'q'.code) break
        }
        // 释放资源
        capture.release()
        opencv_highgui.destroyAllWindows()
    }

    fun knn() {
        // 打开视频流(可使用摄像头或者视频文件路径)
        val capture = VideoCapture("lib/video/video_003.avi")
        if (!capture.isOpened) {
            return
        }
        // 创建 KNN 背景减除器
        val bg = opencv_video.createBackgroundSubtractorKNN().apply {
            history = 500         // 历史帧数
            dist2Threshold = 400.0 // 距离阈值,控制前景检测的敏感度
            detectShadows = true  // 是否检测阴影
        }
        // 创建 Mat 对象用于存储视频帧和结果
        val org = Mat()
        val dst = Mat()
        while (true) {
            // 读取当前帧
            capture.read(org)
            if (org.empty()) break
            // 应用背景减除器
            bg.apply(org, dst)
            // 可选:对前景蒙版进行一些后处理(如形态学操作)
            val kernel = opencv_imgproc.getStructuringElement(opencv_imgproc.MORPH_RECT, Size(3, 3))
            opencv_imgproc.morphologyEx(dst, dst, opencv_imgproc.MORPH_CLOSE, kernel)
            // 确保类型一致
            val mat = Mat()
            opencv_imgproc.cvtColor(dst, mat, opencv_imgproc.COLOR_GRAY2BGR)
            // 确保大小一致
            if (dst.size() != org.size()) {
                opencv_imgproc.resize(mat, mat, org.size())
            }
            // 进行拼接
            val show = Mat()
            opencv_core.hconcat(org, mat, show)
            // 显示结果
            opencv_highgui.imshow("KNN BSM", show)
            // 检查用户按键
            if (opencv_highgui.waitKey(30) == 'q'.code) break
        }
        // 释放资源
        capture.release()
        opencv_highgui.destroyAllWindows()
    }

}

3 测试结果

相关推荐
Kapaseker20 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z3 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton3 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream4 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam4 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker4 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
糖猫猫cc5 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
如此风景5 天前
kotlin协程学习小计
android·kotlin
sali-tec5 天前
C# 基于OpenCv的视觉工作流-章27-图像分割
图像处理·人工智能·opencv·算法·计算机视觉
saoys5 天前
Opencv 学习笔记:腐蚀操作 + 轮廓标记 + 分水岭分割
笔记·opencv·学习