OpenCV 删除轮廓的方法(一)
一种比较方便的删除轮廓的处理方式,是我刚刚学习到的一个方法,在这之前,如果我想删除一个不需要的轮廓,用的方法是将该轮廓填充为背景色,之前的博客提到过,在countours容器中,如果把轮廓填充为背景色,那么只是视觉上看不到该轮廓,但是实际上还存在在容器中。所以之前总是要填充之后从新copyto一下,然后重新找一遍轮廓,达到删除轮廓的效果。这种方式实在是low。
·
一种比较方便的删除轮廓的处理方式,是我刚刚学习到的一个方法,在这之前,如果我想删除一个不需要的轮廓,用的方法是将该轮廓填充为背景色,之前的博客提到过,在countours容器中,如果把轮廓填充为背景色,那么只是视觉上看不到该轮廓,但是实际上还存在在容器中。所以之前总是要填充之后从新copyto一下,然后重新找一遍轮廓,达到删除轮廓的效果。这种方式实在是low。
[见之前的博客http://blog.csdn.net/chaipp0607/article/details/52858661
代码如下:
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()函数删除最后面那个数据,完成删除指定轮廓的功能。
还是举个栗子:
确定炉口位置,废渣,如图
代码如下
#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;
}
效果图:蓝色框出炉口的位置
点击阅读全文
更多推荐
所有评论(0)