在Opencv中实现Matlab的bwareaopen函数功能

在Matlab中,我们通常利用bwareaopen函数去除八邻域内面积小于一定值的连通域。
matlab函数bwareaopen──删除小面积对象
格式:BW2 = bwareaopen(BW,P,conn)
作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域。

Opencv里没有特定的函数实现该功能,但我们可以自己设计一个孔洞填充/小区域去除的方式来实现。
函数接口设计如下:
C++
void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int CheckMode, int NeihborMode)

其中,Src为源图像,Dst为目标图像,AreaLimit为连通域的面积,CheckMode为模式选择,其中0为去除小面积区域,1为孔洞填充。NeihborMode为邻域类型,可以为4邻域或者8邻域。
下面是实现的代码。

#include <cv.h>
#include <highgui.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>    

using namespace cv;
using namespace std;  

void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit=50, int CheckMode=1, int NeihborMode=0);  

int main()
{
    double t = (double)getTickCount();  

    char* imagePath = "E:\SVM\局部.jpg";
    char* OutPath = "E:\SVM\局部_去除孔洞.jpg";  

    Mat Src = imread(imagePath, CV_LOAD_IMAGE_GRAYSCALE);
    Mat Dst = Mat::zeros(Src.size(), CV_8UC1);  

    //二值化处理
    for(int i = 0; i < Src.rows; ++i)
    {
        uchar* iData = Src.ptr<uchar>(i);
        for(int j = 0; j < Src.cols; ++j)
        {
            if(iData[j] == 0 || iData[j]==255) continue;
            else if (iData[j] < 10)
            {
                iData[j] = 0;
                //cout<<'#';
            }
            else if (iData[j] > 10)
            {
                iData[j] = 255;
                //cout<<'!';
            }
        }
    }
    cout<<"Image Binary processed."<<endl;  

    RemoveSmallRegion(Src, Dst, 20, 1, 1);
    RemoveSmallRegion(Dst, Dst, 20, 0, 0);
    cout<<"Done!"<<endl;
    imwrite(OutPath, Dst);  

    t = ((double)getTickCount() - t)/getTickFrequency();
    cout<<"Time cost: "<<t<<" sec."<<endl;  

    return 0;
}    

//CheckMode: 0代表去除黑区域,1代表去除白区域; NeihborMode:0代表4邻域,1代表8邻域;
void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int CheckMode, int NeihborMode)
{
    int RemoveCount=0;       //记录除去的个数
    //记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查
    Mat Pointlabel = Mat::zeros( Src.size(), CV_8UC1 );  

    if(CheckMode==1)
    {
        cout<<"Mode: 去除小区域. ";
        for(int i = 0; i < Src.rows; ++i)
        {
            uchar* iData = Src.ptr<uchar>(i);
            uchar* iLabel = Pointlabel.ptr<uchar>(i);
            for(int j = 0; j < Src.cols; ++j)
            {
                if (iData[j] < 10)
                {
                    iLabel[j] = 3;
                }
            }
        }
    }
    else
    {
        cout<<"Mode: 去除孔洞. ";
        for(int i = 0; i < Src.rows; ++i)
        {
            uchar* iData = Src.ptr<uchar>(i);
            uchar* iLabel = Pointlabel.ptr<uchar>(i);
            for(int j = 0; j < Src.cols; ++j)
            {
                if (iData[j] > 10)
                {
                    iLabel[j] = 3;
                }
            }
        }
    }  

    vector<Point2i> NeihborPos;  //记录邻域点位置
    NeihborPos.push_back(Point2i(-1, 0));
    NeihborPos.push_back(Point2i(1, 0));
    NeihborPos.push_back(Point2i(0, -1));
    NeihborPos.push_back(Point2i(0, 1));
    if (NeihborMode==1)
    {
        cout<<"Neighbor mode: 8邻域."<<endl;
        NeihborPos.push_back(Point2i(-1, -1));
        NeihborPos.push_back(Point2i(-1, 1));
        NeihborPos.push_back(Point2i(1, -1));
        NeihborPos.push_back(Point2i(1, 1));
    }
    else cout<<"Neighbor mode: 4邻域."<<endl;
    int NeihborCount=4+4*NeihborMode;
    int CurrX=0, CurrY=0;
    //开始检测
    for(int i = 0; i < Src.rows; ++i)
    {
        uchar* iLabel = Pointlabel.ptr<uchar>(i);
        for(int j = 0; j < Src.cols; ++j)
        {
            if (iLabel[j] == 0)
            {
                //********开始该点处的检查**********
                vector<Point2i> GrowBuffer;                                      //堆栈,用于存储生长点
                GrowBuffer.push_back( Point2i(j, i) );
                Pointlabel.at<uchar>(i, j)=1;
                int CheckResult=0;                                               //用于判断结果(是否超出大小),0为未超出,1为超出  

                for ( int z=0; z<GrowBuffer.size(); z++ )
                {  

                    for (int q=0; q<NeihborCount; q++)                                      //检查四个邻域点
                    {
                        CurrX=GrowBuffer.at(z).x+NeihborPos.at(q).x;
                        CurrY=GrowBuffer.at(z).y+NeihborPos.at(q).y;
                        if (CurrX>=0&&CurrX<Src.cols&&CurrY>=0&&CurrY<Src.rows)  //防止越界
                        {
                            if ( Pointlabel.at<uchar>(CurrY, CurrX)==0 )
                            {
                                GrowBuffer.push_back( Point2i(CurrX, CurrY) );  //邻域点加入buffer
                                Pointlabel.at<uchar>(CurrY, CurrX)=1;           //更新邻域点的检查标签,避免重复检查
                            }
                        }
                    }  

                }
                if (GrowBuffer.size()>AreaLimit) CheckResult=2;                 //判断结果(是否超出限定的大小),1为未超出,2为超出
                else {CheckResult=1;   RemoveCount++;}
                for (int z=0; z<GrowBuffer.size(); z++)                         //更新Label记录
                {
                    CurrX=GrowBuffer.at(z).x;
                    CurrY=GrowBuffer.at(z).y;
                    Pointlabel.at<uchar>(CurrY, CurrX) += CheckResult;
                }
                //********结束该点处的检查**********  

            }
        }
    }    

    CheckMode=255*(1-CheckMode);
    //开始反转面积过小的区域
    for(int i = 0; i < Src.rows; ++i)
    {
        uchar* iData = Src.ptr<uchar>(i);
        uchar* iDstData = Dst.ptr<uchar>(i);
        uchar* iLabel = Pointlabel.ptr<uchar>(i);
        for(int j = 0; j < Src.cols; ++j)
        {
            if (iLabel[j] == 2)
            {
                iDstData[j] = CheckMode;
            }
            else if(iLabel[j] == 3)
            {
                iDstData[j] = iData[j];
            }
        }
    }   

    cout<<RemoveCount<<" objects removed."<<endl;
}  

原文:大专栏  在Opencv中实现Matlab的bwareaopen函数功能

原文地址:https://www.cnblogs.com/dajunjun/p/11651546.html

时间: 2024-10-10 17:21:50

在Opencv中实现Matlab的bwareaopen函数功能的相关文章

关于opencv中的imread()函数声明

在我们刚开始编写opencv程序的时候,会用到imread()函数,然后里面会有参数CV_LOAD_IMAGE_UNCHANGED 那么这个代表什么意思呢? imread()函数的声明如下: 1 CV_EXPORTS_W Mat imread( const string& filename, int flags=1 ); 它的参数: filename —— 文件的位置.如果只提供文件名,那么文件应该和C++文件在同一目录,否则必须提供图片的全路径. flags —— 有5个可能的输入. CV_L

OpenCV中响应鼠标信息cvSetMouseCallback函数的使用

转自:http://blog.csdn.net/haihong84/article/details/6599838 程序代碼如下: #include <cv.h> #include <highgui.h> #include <stdio.h void onMouse(int event,int x,int y,int flags,void* param ); int main(int argc, char** argv) { CvCapture *capture; IplIm

【源码阅读】opencv中opencl版本的dft函数的实现细节

1.函数声明 opencv-3.4.3\modules\core\include\opencv2\core.hpp:2157 CV_EXPORTS_W void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0); 2.函数实现 opencv-3.4.3\modules\core\src\dxt.cpp:3315 void cv::dft( InputArray _src0, OutputArray _

OpenCV中感兴趣区域的选取与检测(一)

1.感兴趣区域的选取 感兴趣区域(Region of Interest, ROI)的选取,一般有两种情形:1)已知ROI在图像中的位置:2)ROI在图像中的位置未知. 1)第一种情形 很简单,根据ROI的坐标直接从原图抠出,不过前提是要知道其坐标,直接上例子吧. int getROI(Mat image, Rect rect) { Mat img=image.clone(); Mat roi; int cols=img.cols, rows=img.rows; //ROI越界,返回 if(col

Matlab中psf2otf()函数在opencv中的实现

在Matlab中有个psf2otf()函数,可以将小尺寸的点扩散函数,扩大尺寸,并作二维傅里叶变换,opencv中没有这个函数,所以编了这么个函数: /*****************************Mat psf2otf(const Mat&psf, Size outSize=Size(3,3))参数说明:psf--输入的点扩散函数:outSize--是输出otf的尺寸: 在本程序中,还调用了circShift()函数,该函数具体参见:http://www.cnblogs.com/p

使用C++将OpenCV中Mat的数据写入二进制文件,用Matlab读出

在使用OpenCV开发程序时,如果想查看矩阵数据,比较费劲,而matlab查看数据很方便,有一种方法,是matlab和c++混合编程,可以用matlab访问c++的内存,可惜我不会这种方式,所以我就把数据写到文件里,用matlab读出来,然后用matlab各种高级功能查看数据的值. 1.将Mat的数据写入指定文件 为了方便拿来主义者,我直接把这个函数贴出来,你只要把代码拷贝到自己的代码里,就可以直接用了.如果有问题,赶紧评论,我会尽快看看问题出在哪里. #include <iostream>

5. openCV中常用函数学习

一.前言 经过两个星期的努力,一边学习,一边写代码,初步完成的毕业论文系统的界面和一些基本功能,主要包括:1 数据的读写和显示,及相关的基本操作(放大.缩小和移动):2 样本数据的选择:3 数据归一化处理:4 绘制光谱曲线:5 获取波段信息.接下来的工作主要是完成遥感影像分类的相关算法.这部分主要是数学计算,尤其是矩阵的相关运算和操作.为此,系统的学习和了解了openCV库中常用的矩阵操作函数,记录下来,方便以后查阅. 二.openCV函数 1 reshape 1 C++: Mat Mat::r

根据MATLAB的histeq函数改写的运行在OpenCV下的直方图规定化C源码!

据说,图像的直方图规定化比直方图均衡化用得更多,但是很奇怪的是OpenCV居然没有图像直方图规定化的源码!所以,我就有必要在OpenCV下写一个图像直方图规定化处理的函数,以方便将来使用. 我在网上找了几个直方图均稀化的源码,并基于OpenCV来改写这些源码,效果都不如MATLAB的histeq函数,这其中改写的艰辛与繁琐就不细说了.最后,没办法,只好学习MATALB的histeq函数源码,并对其进行基于OpenCV的改写. 虽然我最终改写成功了,但是对算法还是不太理解,只能按照MATLAB的帮

openCV中的findHomography函数分析以及RANSAC算法的详解

本文将openCV中的RANSAC代码全部挑选出来,进行分析和讲解,以便大家更好的理解RANSAC算法.代码我都试过,可以直接运行. 在计算机视觉和图像处理等很多领域,都需要用到RANSAC算法.openCV中也有封装好的RANSAC算法,以便于人们使用.关于RANSAC算法的一些应用,可以看我的另一篇博客: 利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较) 但是前几天师弟在使用op