opencv分水嶺演算法分割硬幣
網上有Python寫的,但是沒有C++寫的,所以自己搞了個,東拼西湊的結果,畢竟我也不是大神,湊活著看吧。傾情奉獻,歡迎指教
#include <opencv2/opencv.hpp>
#include <stack>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stdio.h>
using namespace std;
using namespace cv;
void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg) //連通域標記,分水嶺演算法會用到,網上找的程式
{
// connected component analysis (4-component)
// use seed filling algorithm
// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0
if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}
_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;
int label = 1 ; // start by 2
int rows = _binImg.rows - 1 ;
int cols = _binImg.cols - 1 ;
for (int i = 1; i < rows-1; i++)
{
int* data= _lableImg.ptr<int>(i) ;
for (int j = 1; j < cols-1; j++)
{
if (data[j] == 1)
{
std::stack<std::pair<int,int> > neighborPixels ;
neighborPixels.push(std::pair<int,int>(i,j)) ; // pixel position: <i,j>
++label ; // begin with a new label
while (!neighborPixels.empty())
{
// get the top pixel on the stack and label it with the same label
std::pair<int,int> curPixel = neighborPixels.top() ;
int curX = curPixel.first ;
int curY = curPixel.second ;
_lableImg.at<int>(curX, curY) = label ;
// pop the top pixel
neighborPixels.pop() ;
if (curY != 1 && _lableImg.at<int>(curX, curY-1) == 1) //左值
neighborPixels.push(std::pair<int,int>(curX, curY-1)) ;
if ( curY != rows && _lableImg.at<int>(curX, curY+1) == 1)// 右值
neighborPixels.push(std::pair<int,int>(curX, curY+1)) ;
if (curX != 0 && _lableImg.at<int>(curX-1, curY) == 1)// 上值
neighborPixels.push(std::pair<int,int>(curX-1, curY)) ;
if (curX != cols && _lableImg.at<int>(curX+1, curY) == 1)//下值
neighborPixels.push(std::pair<int,int>(curX+1, curY)) ;
}
}
}
}
}
int main(int argc,char *argv[])
{
Mat image=imread("......圖片的地址.........",1);
Mat imageGray;
cvtColor(image,imageGray,CV_BGR2GRAY);
GaussianBlur(imageGray,imageGray,Size(5,5),2); //濾波
threshold(imageGray,imageGray,200,255,CV_THRESH_OTSU|CV_THRESH_BINARY_INV);
imshow("binary",imageGray);
Mat imageThin(imageGray.size(),CV_32FC1); //定義儲存距離變換結果的Mat矩陣
distanceTransform(imageGray,imageThin,CV_DIST_L2,3); //距離變換
Mat distShow;
imageThin.convertTo(distShow,CV_8UC1);
normalize(distShow,distShow,0,255,CV_MINMAX); //為了顯示清晰,做了0~255歸一化
imshow("Source Image",image);
imshow("Thin Image",distShow);
Mat fg,bg,mark0;
Mat element = getStructuringElement(MORPH_RECT, Size(25, 25));
erode(distShow,fg, element);
threshold(fg,fg,200,255,CV_THRESH_OTSU|CV_THRESH_BINARY);
imshow("front Image",fg);
Mat element2 = getStructuringElement(MORPH_RECT, Size(5, 5));
dilate(distShow,bg,element2);
threshold(bg,bg,20,125,CV_THRESH_BINARY_INV);
imshow("bg",bg);
mark0=bg+fg;
imshow("mark0",mark0);
cv::Mat labelImg ;
cv::threshold(mark0, mark0, 130, 1, CV_THRESH_BINARY) ;
icvprCcaBySeedFill(mark0, labelImg) ;
// show result
cv::Mat grayImg ;
labelImg *= 10 ;
labelImg.convertTo(grayImg, CV_8UC1) ;
grayImg=grayImg+bg;
cv::imshow("marker", grayImg) ;
cvtColor(imageGray,imageGray,CV_GRAY2BGR);
Mat marker;
grayImg.convertTo(marker,CV_32SC1);
watershed(imageGray,marker);
Mat afterWatershed;
convertScaleAbs(marker,afterWatershed);
imshow("After Watershed",afterWatershed);
waitKey();
return 0;
}