使用形态滤波器侵蚀和膨胀图像
1、函数cv::erode()
默认使用3*3矩阵处理二值图像,其作用是用核心矩阵处理图像,替换矩阵所覆盖区域的像素值为这个区域的最小值,也即图像处理后白色可能会减少。
2、函数cv::dilate()
作用和cv::erode()相反
3、自定义核心矩阵
cv::Mat element(7,7,CV_8U,cv::Scalar(1));
cv::erode(image,eroded,element);
4、同一核心矩阵多次操作
cv::erode(image,eroded,cv::Mat(),cv::Point(-1,-1),3);
使用形态滤波器Opening和Closeing图像
1、关闭操作
cv::Mat element1(5 , 5 , CV_8U , cv::Scalar(1)) ;
cv::Mat closed ;
//cv::Mat closed1 ;
cv::morphologyEx(image , closed , cv::MORPH_CLOSE , element1) ;
//cv::dilate(image , closed1 , element1) ;//这两步等价于以上一步
//cv::erode(closed1 , closed1 , element1) ;
2、打开操作
类似关闭操作
注意:opened和closed可以依次使用获得不同的效果比如先使用closed在使用opened可以获得图像中的主要Object。
参考: 《opencv cookbook》P120
使用形态滤波器检测图像中的边界和角:
cv::Mat getEdges(const cv::Mat &image)
{
cv::Mat result ;
cv::morphologyEx(image , result , cv::MORPH_GRADIENT , cv::Mat()) ;
applyThreshold(result) ;
return result ;
}
cv::Mat getCorners(const cv::Mat &image)
{
cv::Mat result ;
cv::dilate(image , result , cross) ;//相当于Closing
cv::erode(result , result , diamond) ;
cv::Mat result2 ;
cv::dilate(image , result2 , x) ;
cv::erode(result2 , result2 , square) ;
cv::absdiff(result2 , result , result) ;
applyThreshold(result) ;
return result ;
}
cv::morphologyEx(corners,corners,cv::MORPH_TOPHAT,cv::Mat());
cv::threshold(corners, corners, 40, 255, cv::THRESH_BINARY_INV);
标记出角:
void drawOnImage(const cv::Mat &binary , cv::Mat & image)
{
cv::Mat_<uchar>::const_iterator it = binary.begin<uchar>() ;
cv::Mat_<uchar>::const_iterator itend = binary.end<uchar>() ;
for(int i = 0 ; it != itend ; ++it , ++i)
{
if(!*it)
{
cv::circle(image ,
cv::Point(i % image.step , i / image.step) ,
5 , cv::Scalar(255 , 0 , 0)) ;
}
}
}
图像分割分水岭法程序:
思路参考:《OpenCV中分割图像的分水岭法》
头文件:
#pragma once
#include "highgui.h"
#include <imgproc\imgproc.hpp>
class WatershedSegmenter
{
private:
cv::Mat markers ;
public:
void setMarkers(const cv::Mat & markerImage)
{
//把标记markerImage的值变成有符号的32位数存在三种值128 , 255 ,0,其中
//128 , 255分别代表一种区域,0为未知区域也即需要把0分给以上两种
markerImage.convertTo(markers , CV_32S) ;
}
cv::Mat process(const cv::Mat & image)
{
cv::watershed(image , markers) ;
return markers ;
}
cv::Mat getSegmentation()
{
cv::Mat tmp ;
markers.convertTo(tmp , CV_8U) ;
return tmp ;
}
cv::Mat getWatersheds()
{
cv::Mat tmp ;
//只得到两种值0 , 255(黑白),-1(分水岭)置为0,其他为255
markers.convertTo(tmp , CV_8U , 255 , 255) ;
return tmp ;
}
};
源文件:
/*
*
*Function:使用分水岭法分割图像
*
**/
#pragma once
#include "highgui.h"
#include "imgproc\imgproc.hpp"
#include "WatershedSegmenter.h"
#include <stdio.h>
int main()
{
cv::Mat binary = cv::imread("D:/Development/OpenCV/images/binary.bmp" , 0) ;
cv::imshow("original" , binary) ;
cv::Mat fg ;
cv::erode(binary , fg , cv::Mat() , cv::Point(-1 , -1) , 6) ;
cv::imshow("fg" , fg) ;
cv::Mat bg ;
cv::dilate(binary , bg , cv::Mat() , cv::Point(-1 , -1) , 6) ;
cv::imshow("bg_1" , bg) ;
cv::threshold(bg , bg , 1 , 128 , cv::THRESH_BINARY_INV) ;
cv::imshow("bg_2" , bg) ;
cv::Mat markers(binary.size() , CV_8U , cv::Scalar(0)) ;
markers = fg + bg ;
cv::imshow("markers" , markers) ;
cv::imwrite("D:/Development/OpenCV/images/markers.bmp" , markers) ;
cv::Mat image = cv::imread("D:/Development/OpenCV/images/group.jpg") ;
WatershedSegmenter segmenter ;
segmenter.setMarkers(markers) ;
segmenter.process(image) ;
cv::imshow("Segmenters" , segmenter.getSegmentation()) ;
cv::imwrite("D:/Development/OpenCV/images/segmenters.bmp" ,segmenter.getSegmentation() );
cv::imshow("Watersheds" , segmenter.getWatersheds()) ;
cv::imwrite("D:/Development/OpenCV/images/watersheds.bmp" ,segmenter.getWatersheds() );
cv::waitKey(0) ;
return 0 ;
}