小目标识别——基于K近邻的白酒杂质检测算法实现

news2024/11/11 7:28:10

文章目录

      • 实现思路
      • 配置opencv
      • 位置剪裁
        • 实现代码
      • 自适应中值滤波
        • 实现代码
      • 动态范围增强
        • 实现代码
      • 形态学处理
        • 实现代码
      • 图片预处理效果
      • 计算帧差
        • 连续帧帧差法原理和实现代码
        • 实现代码
      • K近邻实现
        • 基本介绍
      • 实现过程
      • 参考

实现思路

  • 使用C++进行实现,开发平台是clion,并没有使用深度学习,使用opencv进行开发

在这里插入图片描述

配置opencv

  • 一开始就出来幺蛾子,之前装好的opencv怎么都找不到包,弄了一个小时,夹着红框后面的三句,告诉clion我安装的opencv包的具体位置,可能是因为我之前没有编译成功,直接间别人编译好的直接下载下来的,不过我为什么不用python上面的opencv那。

  • 在这里插入图片描述

位置剪裁

在这里插入图片描述

  • 相机位置固定,拍摄的位置固定,背景干扰很少,只需要保存红框右半部分的内容即可,左半部分去除。

实现代码

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;


struct RectPoint{
    int x,y;
    int width,height;
    RectPoint(int x,int y,int width,int height):x(x),y(y),width(width),height(height){}
};

void ClipImage(String ImagePath,RectPoint rect,String TargetPath){

    // 声明Mat保存图片
    Mat img;
    Rect m_select;
    string line;

    // 判定文件存在
    ifstream input_file(ImagePath);
    if (!input_file.is_open()) {
        cerr << "Could not open the file - '"
             << ImagePath << "'" << endl;
        return;
    }

    while(getline(input_file,line)){
        // 获取文件后缀名,并进行拼接成目标文件名
        string ImageName = line.substr(line.find_last_of('\\',line.size())+1);
        string TargetName = TargetPath;
        TargetName.append(ImageName);

        // 读取并剪裁图片到特定大小保存
        img = imread(line);
        m_select = Rect(rect.x,rect.y,rect.width,rect.height);
        Mat ROI = img(m_select);
        imwrite(TargetName,ROI);

    }
}

int main()
{
    String TargetImage = R"(E:\CProject\impurityDetection\ClippedImage\)";
    String SourceImage = R"(E:\CProject\impurityDetection\image\path.txt)";
    ClipImage(SourceImage,RectPoint(600,0,1780,1480),TargetImage);
    return 0;
}

自适应中值滤波

  • 自适应中值滤波,是为了去除照相机的噪声同时,又不损坏原来的杂质信息,这里使用自适应中值滤波,具体实现如下。

在这里插入图片描述

实现代码

void Convolution(Mat &SourceImage,vector<int> &pixels,int x,int y ,int border){


    for (int k = -border; k <= border; k++)
    {
        for (int l = -border; l <= border; l++)
        {
            pixels.push_back(SourceImage.at<uchar>(x+k, y+l));
        }
    }
}

Mat SelfAdaptMedianFilter(const Mat& SourceImage){
    // 复制原图
    Mat result = SourceImage.clone();
    // 掩膜大小为3
    int ksize = 3;
    int border = ksize /2 ;

    for (int i = border; i < SourceImage.rows - border; i++)
    {
        for (int j = border; j < SourceImage.cols - border; j++)
        {
            while(1){
                // 提取当前像素的邻域
                vector<int> pixels;
                Convolution(result, pixels, i, j, border);

                // 对邻域像素值进行排序
                sort(pixels.begin(), pixels.end());

                // 取中值作为当前像素的新值
                int median = pixels[pixels.size() / 2];
                int PMax = pixels[pixels.size() - 1];
                int PMin = pixels[0];

                //判定是否为异常值
                if (median == PMax || median == PMin) {
                    // 掩膜再加2,重新计算
                    ksize += 2;
                    if (ksize + 2 > Nmax) {
                        result.at<uchar>(i, j) = median;
                        break;
                    }else{
                        // 判定传入的值,是否出现越界的情况
                        if((i - ksize / 2 < 0 || i + ksize / 2 < SourceImage.cols) ||
                             j - ksize / 2 < 0 || j + ksize / 2 > SourceImage.rows)
                            result.at<uchar>(i,j) = (PMax + PMin) / 2;
                    }
                } else {
                    //中值不是极值,判定原像素点是不是极值,然后在进行输出
                    if (result.at<uchar>(i, j) == PMax || result.at<uchar>(i, j) == PMin)
                        result.at<uchar>(i,j) = median;
                    break;
                }

            }
        }
    }

    return result;
}

动态范围增强

  • 这里就是图像的直方图均衡化,使得整个模型的图片颜色对比度更大,显示出更多的细节。

实现代码

   //对图片进行直方图均衡化,凸显出前后差异
        Mat equalized;
        // 转成二值化,并变为直方图均衡化
        cvtColor(ROI, equalized, COLOR_BGR2GRAY);
        equalizeHist(equalized, equalized);

形态学处理

  • 膨胀操作 :通过增加图像中的物体的像素数量,使得物体的大小和面积增加,边缘变得更加明显,改变了原来字体粗细

在这里插入图片描述

  • 腐蚀操作 :在卷积核大小中对图片进行卷积。取图像中(3 * 3)区域内的最小值。可以消除图像中的毛刺和噪声。改变了原来字体粗细
    在这里插入图片描述
  • 开运算 :先腐蚀运算,在进行膨胀运算。在不损害字体信息的情况下,去除了噪声和毛刺。通过调整卷积可以进一步减少噪声

在这里插入图片描述

  • 闭运算 :先膨胀运算,在进行腐蚀运算。在不去除任何噪声的情况下,补全了缺失的信息。

在这里插入图片描述

  • 这里选择开运算,具体实现代码如下,别的可以参考知乎链接

实现代码

   // 对图像进行开运算,
        Mat morphologied;
        int size = 3;
        // shape是内核的形状,size是内核的尺寸,锚点的位置,对于矩形来说,全部都是 1 ,不用调整
        cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT,
                                                    cv::Size(2*size + 1, 2*size+1),
                                                    cv::Point(size, size));
        cout<<element<<endl;
        morphologyEx(equalized, morphologied, cv::MORPH_OPEN, element);

图片预处理效果

在这里插入图片描述

计算帧差

  • 主要有两种方法,分别是静态参考帧差分法和连续帧帧差法,下图为两个效果,很明显的可以就看到连续帧帧差法的效果更好,常见的静态帧是将多个帧进行平均,然后以平均之后的帧作为参考帧,然后后面每帧都是和当前帧作比较,没有动作的连续性。

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

连续帧帧差法原理和实现代码

  • 实现原理如下图
    在这里插入图片描述

  • 使用absdiff函数,具体描述如下,计算frame1和frame2的帧差,然后将结果保存到framediff中

cv::Mat frameDiff;
cv::absdiff(frame1, frame2, frameDiff);

实现代码


//计算帧差,并将最终的结果进行返回
Mat DifFrame(Mat PreFrame,Mat CurFrame,Mat NextFrame){

    //计算帧差
    Mat FrameDiffPre , FrameDiffNext;
    absdiff(PreFrame,CurFrame,FrameDiffPre);
    absdiff(CurFrame,NextFrame,FrameDiffNext);

    // 分别进行二值化,设定二值化的阈值
    Mat BinImgPre , BinImgNext;
    threshold(FrameDiffPre,BinImgPre,128,255,cv::THRESH_BINARY);
    threshold(FrameDiffNext,BinImgPre,128,255,cv::THRESH_BINARY);

    // 将图片进行与运算,然后将结果进行输出
    Mat ResFrame;
    bitwise_and(FrameDiffPre,FrameDiffNext,ResFrame);

    //返回最终处理过后的帧
    return ResFrame;

}

K近邻实现

基本介绍

  • 思路 : 将样本在特征空间中,根据一定的分类方法,归类于与该样本最相似的K个样本中大多数的那一类。需要一部分已经标注过的样本,然后将未标注过的样本进行分类。
  • 特点

实现过程

参考

  • Opencv 图像处理之膨胀与腐蚀 【https://zhuanlan.zhihu.com/p/110330329】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391481.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zencart/opencart/wordpress外贸独立站最少需要多少钱

以程序员的职位进入跨境电商行业已经有10年了&#xff0c;接触过不少大大小小的老板客户&#xff0c;我遇到最多的问题就是搭建一个站要多少钱&#xff1f;实话说这问题问的有些粗糙。如果我遇到不负责的公司他可能会直接报价1W&#xff0c;2W或更多&#xff0c;也有可能遇到兼…

【STM32MP157应用编程】3.控制PWM

目录 PWM文件 指令操作PWM 程序操作PWM 程序说明 程序代码 3_PWM_1.c 启动交叉编译工具 编译 拷贝到开发板 测试 PWM文件 在/sys/class/pwm目录下&#xff0c;存放了PWM的文件。 pwmchip0和pwmchip4目录对应了MP157 SoC的2个PWM控制器&#xff0c;pwmchip0对应的是M…

【Python】torch.norm()用法解析

【Python】torch.norm()用法解析 文章目录【Python】torch.norm()用法解析1. 介绍1.1 p-范数1.2 Frobenius 范数1.3 核范数2. API3. 示例1. 介绍 torch.norm()是对输入的tensor求对应的范数。tensor的范数有以下三种&#xff1a; 1.1 p-范数 1.2 Frobenius 范数 即&#xff…

Linux-GCC介绍+入门级Makefile使用

前言&#xff08;1&#xff09;我们都知道&#xff0c;在Linux中编译.c文件需要使用gcc -o .c文件的指令来将C文件变成可执行文件。但是我们有没有发现&#xff0c;如果我们需要编译大一点的工程&#xff0c;后面需要加上的.c文件是不是太多了&#xff1f;感觉非常的麻烦。&…

linux篇【16】:传输层协议<后序>

目录 六.滑动窗口 &#xff08;1&#xff09;发送缓冲区结构 &#xff08;2&#xff09;滑动窗口介绍 &#xff08;3&#xff09;滑动窗口不一定只会向右移动。滑动窗口可以变大也可以变小。 &#xff08;4&#xff09;那么如果出现了丢包, 如何进行重传? 这里分两种情况…

「微报告」激光雷达前装“成色”

激光雷达正处于第一波规模上车期。 高工智能汽车研究院监测数据显示&#xff0c;2022年中国市场&#xff08;不含进出口&#xff09;乘用车前装标配搭载激光雷达12.99万台&#xff0c;配套车辆11.18万辆&#xff0c;同比分别增长1544.30%和2626.82%。此外&#xff0c;提供选装的…

华为OD机试题,用 Java 解【相对开音节】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

基于BERT-PGN模型的中文新闻文本自动摘要生成——文本摘要生成(论文研读)

基于BERT-PGN模型的中文新闻文本自动摘要生成&#xff08;2020.07.08&#xff09; 基于BERT-PGN模型的中文新闻文本自动摘要生成&#xff08;2020.07.08&#xff09;摘要&#xff1a;0 引言相关研究2 BERT-PGN模型2. 1 基于预训练模型及多维语义特征的词向量获取阶段2. 1. 1 BE…

Python3-数据结构

Python3 数据结构 本章节我们主要结合前面所学的知识点来介绍Python数据结构。 列表 Python中列表是可变的&#xff0c;这是它区别于字符串和元组的最重要的特点&#xff0c;一句话概括即&#xff1a;列表可以修改&#xff0c;而字符串和元组不能。 以下是 Python 中列表的…

3.3 GPIO输入

按键1.1 按键介绍•按键&#xff1a;常见的输入设备&#xff0c;按下导通&#xff0c;松手断开•按键抖动&#xff1a;由于按键内部使用的是机械式弹簧片来进行通断的&#xff0c;所以在按下和松手的瞬间会伴随有一连串的抖动1.2 按键的四种接法P1是最常用的接法&#xff0c;p1…

【小程序】django学习笔记1

网页能用&#xff0c;不知道小程序能不能用。应该能吧。。。。。创建django程序文件包&#xff0c;xxx处是给该文件夹起个名django-admin startproject xxx一个project是由很多个app&#xff08;小应用&#xff09;组成的在文件夹目录下创建一个app&#xff0c;xxx处给该app起个…

脑雾到来的6个症状

在阳康后的一段时间里&#xff0c;很多人发现自己脑力不似从前&#xff0c;长时间的修养也没能彻底恢复&#xff0c;以为自己有后遗症&#xff0c;十分紧张。其实&#xff0c;脑雾不是专业的医学名词&#xff0c;它是对一类症状的统称&#xff1a;健忘、注意力不集中、思维迟钝…

第17天-整合Redis缓存改造三级分类,并解决缓存击穿、穿透、雪崩、一致性问题

1.缓存 1.1.缓存使用 为了系统性能的提升&#xff0c;一般都会将部分数据放入缓存中&#xff0c;达到快速响应的目的。而数据库承担数据落盘工作。 哪些数据适合放入缓存&#xff1f; 即时性、数据一致性要求不高的访问量大且更新频率不高的数据&#xff08;读多&#xff0c…

布隆过滤器Bloom -> Redisson系列-3

接上文&#xff1a;RBucket对象桶 -&#xff1e; Redisson系列-1&#xff08;让redis操作更优雅&#xff09;_子书少卿的博客-CSDN博客 本质上布隆过滤器是一种数据结构&#xff0c;是一种比较巧妙的概率性数据结构&#xff0c;特点是可以高效的插入和查询&#xff0c;可…

浅谈一下虚拟机栈

虚拟机栈 概述 由于跨平台性的设计&#xff0c;Java的指令都是根据栈来设计的。不同平台CPU架构不同&#xff0c;所以不能设计为基于寄存器的。 优点是跨平台&#xff0c;指令集小&#xff0c;编译器容易实现&#xff0c;缺点是性能下降&#xff0c;实现同样的功能需要更多的…

SpringBoot学习笔记(二)配置文件

1、配置文件SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1b;application.propertiesapplication.yml配置文件的作用&#xff1a;修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b;YAML&#xff1a;以数…

MySQL常用函数整理

MySQL常用函数整理sql函数分类一、流程控制1、判断值为null或空字符串2、IF函数3、IFNULL函数4、CASE函数(1) 相当于switch case的作用(2) 相当于if elseif的作用5、COALESCE函数二、字符串类&#xff08;GBT答案&#xff09;1、用于select、insert等子句中2、用于where子句中其…

来吧!接受Kotlin 协程--线程池的7个灵魂拷问

前言 之前有分析过协程里的线程池的原理&#xff1a;Kotlin 协程之线程池探索之旅(与Java线程池PK)&#xff0c;当时偏重于整体原理&#xff0c;对于细节之处并没有过多的着墨&#xff0c;后来在实际的使用过程中遇到了些问题&#xff0c;也引发了一些思考&#xff0c;故记录之…

从零开始学习c语言|21、动态内存管理

一、malloc函数 1、什么是malloc函数 malloc是memery(内存)和allocate(分配)的缩写&#xff0c;顾名思义&#xff0c;malloc函数为动态分配内存的意思 2、malloc函数语句 int *p(int *)malloc(sizeof(int))malloc函数的形参为申请的内存空间大小&#xff0c;上述申请了一个i…

“巨亏成名”的魔鬼交易员,你知道几个?

谁说在期货市场上只有赚大钱才能出名&#xff1f;殊不知还有这样一群特殊的交易员靠着巨额亏损而“一战成名”&#xff0c;亏得是老东家元气大伤&#xff0c;外号“魔鬼交易员”——“不亏不成魔”&#xff01;接下来火象就给大家盘点几位代表性魔鬼交易员&#xff0c;看看他们…