目录
1.问题背景
由于拍摄时产生的阴影原因,所计算出来的物体轮廓并不完整。那么有没有方法检测出物体的完整轮廓呢?
图1-1 原始图像
图1-2 原始结果图
2.解决思路
为了得到物体的准确图像,我们要解决的本质问题是如何去光差。基于冈萨雷斯的数字图像处理的形态学章节(P673),我们知道,去光差的基本思路是对原始图像进行顶帽运算。
那么什么是顶帽运算呢?《数字图像处理》一书中给出了基本公式:
意思是说,图像f-f对b的开运算即为顶帽运算,b是半径为40的圆盘结构。(注:开运算指的是先腐蚀后膨胀)
图 2-1 冈萨雷斯给出的顶帽运算实例
那么结合HSV图像阈和OTSU算法就能分割出物体的准确轮廓。
基本思路:RGB-->HSV-->对H阈进行去光差处理-->基于OTSU算法进行阈值分割-->轮廓分析
3.代码实现
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//去光差
void moveLightdiff(Mat &src, int radius = 40)
{
//1.构造开始运算的算子mask
Mat mask = Mat::zeros(radius * 2, radius * 2, CV_8U);
circle(mask,Point(radius,radius),radius,Scalar(255),-1);
//2.对src进行开运算
Mat src_clone = src.clone();
erode(src_clone,src_clone,mask);
dilate(src_clone, src_clone, mask);
//3.顶帽运算
src = src - src_clone;
}
//寻找最大轮廓
vector<Point> FindBigestContour(Mat &src) {
int imax = 0;
int imaxcontour = -1;
std::vector<std::vector<Point> >contours;
findContours(src, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i<contours.size(); i++) {
int itmp = contourArea(contours[i]);
if (imaxcontour < itmp) {
imax = i;
imaxcontour = itmp;
}
}
return contours[imax];
}
int main()
{
Mat src = imread("complexobject.png");
//转hsv
Mat hsv_pic = src.clone();
cvtColor(src,hsv_pic,CV_BGR2HSV);
//分割通道
vector<Mat> planes(3);
split(hsv_pic,planes);
//对H阈去光差
Mat H_pic = planes[0];
moveLightdiff(H_pic);
//OTSU阈值分割
Mat otsu_pic;
threshold(H_pic,otsu_pic,0,255,THRESH_OTSU);
//定位轮廓
vector<Point> contour= FindBigestContour(otsu_pic);
//在原图上绘制
polylines(src,contour,true,Scalar(0,0,255),3);
return 0;
}
最终结果:
图3-1 去光差之后OTSU阈值分割结果
图3-2 最终的轮廓定位结果
4.相关资料
- 禾路老师的图像处理博客:https://www.cnblogs.com/jsxyhelu/p/9758690.html
- 数字图像处理的教材《数字图像处理—冈萨雷斯》 的下载衔接:https://download.csdn.net/download/duan420684/7285457