前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenCV 删除轮廓的方法(一)

OpenCV 删除轮廓的方法(一)

作者头像
chaibubble
发布2022-05-07 09:01:10
3690
发布2022-05-07 09:01:10
举报
文章被收录于专栏:深度学习与计算机视觉

一种比较方便的删除轮廓的处理方式,是我刚刚学习到的一个方法,在这之前,如果我想删除一个不需要的轮廓,用的方法是将该轮廓填充为背景色,之前的博客提到过,在countours容器中,如果把轮廓填充为背景色,那么只是视觉上看不到该轮廓,但是实际上还存在在容器中。所以之前总是要填充之后从新copyto一下,然后重新找一遍轮廓,达到删除轮廓的效果。这种方式实在是low。 [见之前的博客http://blog.csdn.net/chaipp0607/article/details/52858661 代码如下:

代码语言:javascript
复制
swap(contours_all[j], contours_all[contours_all.size() - 1]);  
contours_all.pop_back(); 

swap用于数据交换,将找到的轮廓放在容器的最后面,和j交换的轮廓是就是原来最后面那个,因为contours_all.size()是轮廓的总个数,轮廓个数标号从0开始,所以contours_all.size()-1就是最后面那个轮廓,将两者交互之后,用pop_back()函数删除最后面那个数据,完成删除指定轮廓的功能。

还是举个栗子:

确定炉口位置,废渣,如图

这里写图片描述
这里写图片描述

代码如下

代码语言:javascript
复制
#include<windows.h>
#include<ctime>
#include <iostream>   
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <opencv2/opencv.hpp>  
#include <opencv2/legacy/compat.hpp> 
#include <opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/nonfree.hpp"  
#include "opencv2/features2d/features2d.hpp"  

using namespace std;
using namespace cv; 

int  otsu(cv::Mat srcImage);
int main( )
{	
	double scale=0.2; 
    Mat g_SrcImage=imread("2.jpg");
	Size dsize = Size(g_SrcImage.cols*scale,g_SrcImage.rows*scale);
	Mat g_DsizeImage = Mat(dsize,CV_32S);
	resize(g_SrcImage, g_DsizeImage,dsize);
	
   //二值化确定炉口
	Mat g_PositionImage;
	Mat g_ThresholdImage;
	Mat g_HistImage;
	Mat g_ContrastAndBrightImage;
	Mat g_FindOvenImage_all;
	Mat g_FindOvenImage_outside;
	cvtColor(g_DsizeImage,g_HistImage,CV_BGR2GRAY);
 
	g_ContrastAndBrightImage= Mat::zeros( g_HistImage.size(), g_HistImage.type() ); 
	for(int y = 0; y < g_HistImage.rows; y++ )  
	{  
		for(int x = 0; x <g_HistImage.cols; x++ )  
		{  
			g_ContrastAndBrightImage.at<uchar>(y,x)= saturate_cast<uchar>( 2*(g_HistImage.at<uchar>(y,x) ));  	
		}  
	} 

	int  ostuThreshold = otsu(g_ContrastAndBrightImage);
	printf("阈值%d\n",ostuThreshold);
	threshold(g_ContrastAndBrightImage,g_ThresholdImage, ostuThreshold, 255,  THRESH_BINARY_INV);
	g_ThresholdImage.copyTo(g_FindOvenImage_all);
	g_ThresholdImage.copyTo(g_FindOvenImage_outside);
	g_DsizeImage.copyTo(g_PositionImage);

	vector<vector<Point> > contours_outside;
	vector<Vec4i> hierarchy_outside;
	findContours(g_FindOvenImage_outside,contours_outside,hierarchy_outside,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);  //输入必须是二值	

	vector<vector<Point> > contours_all;
	vector<Vec4i> hierarchy_all;
	findContours(g_FindOvenImage_all,contours_all,hierarchy_all,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  //输入必须是二值	
	 //if (contours_all.size() == contours_outside.size()) return -1;
	//
	 for (int i = 0; i < contours_outside.size(); i++)  
	 {  
		 int conloursize = contours_outside[i].size();  
		 for (int j = 0; j < contours_all.size(); j++)  
		 {  
			 int tem_size = contours_all[j].size();  
			 if (conloursize == tem_size)  
			 {  
				 swap(contours_all[j], contours_all[contours_all.size() - 1]);  
				 contours_all.pop_back();  
				 break;  
			 }  
		 }  
	 }  
	 //contours_all中只剩下内轮廓  
	 //查找最大轮廓  
	 double maxarea = 0;  
	 int maxAreaIdx = 0;  
	 for (int index = contours_all.size() - 1; index >= 0; index--)  
	 {  
		 double tmparea = fabs(contourArea(contours_all[index]));  
		 if (tmparea>maxarea)  
		 {  
			 maxarea = tmparea;  
			 maxAreaIdx = index;//记录最大轮廓的索引号  
		 }  
	 }  
	    drawContours(g_PositionImage, contours_all,maxAreaIdx, Scalar(150), 1);
   imshow("缩小图",g_DsizeImage);
   imshow("灰度化",g_HistImage);
   imshow("对比度亮度增强",g_ContrastAndBrightImage);
   imshow("二值化",g_ThresholdImage);
   imshow("找外轮廓",g_FindOvenImage_outside);
   imshow("找全部轮廓",g_FindOvenImage_all);
   imshow("找炉口",g_PositionImage);
   imwrite("C:\\Users\\Administrator\\Desktop\\save\\7.jpg",g_PositionImage);
      imwrite("C:\\Users\\Administrator\\Desktop\\save\\8.jpg",g_ThresholdImage);
	  imwrite("C:\\Users\\Administrator\\Desktop\\save\\9.jpg",g_FindOvenImage_outside);
	  imwrite("C:\\Users\\Administrator\\Desktop\\save\\10.jpg",g_FindOvenImage_all);
	waitKey();
	getchar();
	return 0;
}
int otsu(cv::Mat srcImage)
{
	int nCols = srcImage.cols; //列
	int nRows = srcImage.rows; //行
	int threshold = 0;
	// 初始化统计参数
	int nSumPix[256];
	float nProDis[256];
	for (int i = 0; i < 256; i++)
	{
		nSumPix[i] = 0;
		nProDis[i] = 0;
	}
	//统计灰度级中每个像素在整幅图像中的个数 
	for (int i = 0; i <nRows ; i++)
	{
		for (int j = 0; j <nCols ; j++)
		{
			nSumPix[(int)srcImage.at<uchar>(i, j)]++;
		}
	}
	 //计算每个灰度级占图像中的概率分布
	for (int i = 0; i < 256; i++)
	{
		nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
	}

	// 遍历灰度级[0,255],计算出最大类间方差下的阈值  
	float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
	double delta_max = 0.0;
	for (int i = 0; i < 256; i++)
	{
		// 初始化相关参数
		w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
		for (int j = 0; j < 256; j++)
		{
			//背景部分 
			if (j <= i)
			{
				// 当前i为分割阈值,第一类总的概率  
				w0 += nProDis[j];
				u0_temp += j * nProDis[j];
			}
			//前景部分   
			else
			{
				// 当前i为分割阈值,第一类总的概率
				w1 += nProDis[j];
				u1_temp += j * nProDis[j];
			}
		}
		// 分别计算各类的平均灰度 
		u0 = u0_temp / w0;
		u1 = u1_temp / w1;
		delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));
		// 依次找到最大类间方差下的阈值    
		if (delta_temp > delta_max)
		{
			delta_max = delta_temp;
			threshold = i;
		}
	}
	return threshold;
}

效果图:蓝色框出炉口的位置

这里写图片描述
这里写图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档