尋找複雜背景下的物體輪廓 (從禾路的部落格園整理學習)
目錄
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