用形态学运算变换图像

数学形态学用于分析和处理离散图像,它定义了一系列的运算,用预定义的形状元素探测图像,从而实现图像的转换。
1、形态学滤波器腐蚀和膨胀图像
结构元素定义为像素的组合,在对应的像素上定义一个原点(锚点)。结构元素可以是任意形状,如正方形,圆形等,中心点为原点。
OpenCV实现腐蚀和膨胀运算: cv::erode, cv::dilate

cv::Mat image=cv::imread("xxxx.jpg");
//腐蚀图像
cv::Mat erode;
cv::erode(image,erode,cv::Mat());
//膨胀图像
cv::Mat dilate;
cv::dilate(image,dilate,cv::Mat());

腐蚀就是把当前像素替换成所定义像素集合中的最小值;膨胀与腐蚀相反,它把当前像素替换成所定义像素集合中的最大值;
腐蚀图像相当于对其反色图像膨胀后再取反色;膨胀图像相当于对其反色图像腐蚀后再取反色。

2、用形态学滤波器开启和闭合图像
开启的定义是对图像先膨胀后腐蚀;闭合的定义是对图像先腐蚀后膨胀。用于目标检测时,闭合滤波器可把错误分裂成小碎片的物体连接起来,开启滤波器可以一处因图像噪声产生的斑点。

cv::Mat element5(5,5,CV_8U,cv::Scalar(1));
//关闭
cv::Mat closed;
cv::morphologyEx(image,closed,cv::MORPH_CLOSE,element5);
//开启
cv::opened;
cv::morphologyEx(image,opened,cv::MORPH_OPEN,element5);

3、用形态学滤波器检测边缘和脚点
形态学滤波器可以用于检测图像中的某些特征。
实现原理:把图像看做是一个拓扑地貌,不同的灰度级别代表不同的高度,因此,明亮的区域代表高山,黑暗的区域代表深谷。边缘相当于黑暗和明亮像素之间的过渡,可以把边缘比作是悬崖,腐蚀的结果是:每个像素被替换成领域内的最小值,从而降低了它的高度。结果悬崖被“腐蚀”,山谷扩大;膨胀的效果刚好相反,即悬崖扩大,山谷缩小。平底的强度始终不不变。
检测边缘的方法:通过计算膨胀后的图像与腐蚀后的图像之间的差距得到边缘 。
定义特征检测类:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
class MorphoFeatures {
  private:
	  // threshold to produce binary image
	  int threshold;
	  // structuring elements used in corner detection
	  cv::Mat_<uchar> cross;  //十字形
	  cv::Mat_<uchar> diamond;//菱形
	  cv::Mat_<uchar> square;//正方形
	  cv::Mat_<uchar> x;     //x形
	  void applyThreshold(cv::Mat& result)  {
          // Apply threshold on result
		  if (threshold>0)
			cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY_INV);
	  }
  public:
	  MorphoFeatures() : threshold(-1), 
		  cross(5, 5), diamond(5, 5), square(5, 5), x(5, 5) {
	
		  // Creating the cross-shaped structuring element
		  cross <<
			  0, 0, 1, 0, 0,
			  0, 0, 1, 0, 0,
			  1, 1, 1, 1, 1,
			  0, 0, 1, 0, 0,
			  0, 0, 1, 0, 0;
		  
		  // Creating the diamond-shaped structuring element
		  diamond <<
			  0, 0, 1, 0, 0,
			  0, 1, 1, 1, 0,
			  1, 1, 1, 1, 1,
			  0, 1, 1, 1, 0,
			  0, 0, 1, 0, 0;
		  
		  // Creating the x-shaped structuring element
		  x <<
			  1, 0, 0, 0, 1,
			  0, 1, 0, 1, 0,
			  0, 0, 1, 0, 0,
			  0, 1, 0, 1, 0,
			  1, 0, 0, 0, 1;
		  // Creating the square-shaped structuring element
		  x <<
			  1, 1, 1, 1, 1,
			  1, 1, 1, 1, 1,
			  1, 1, 1, 1, 1,
			  1, 1, 1, 1, 1,
			  1, 1, 1, 1, 1;
	  }
	  void setThreshold(int t) {
		  threshold= t;
	  }
	  int getThreshold() const {
		  return threshold;
	  }
	  cv::Mat getEdges(const cv::Mat &image) {
		  // Get the gradient image
		  cv::Mat result;
		  cv::morphologyEx(image,result,cv::MORPH_GRADIENT,cv::Mat());
          // Apply threshold to obtain a binary image
		  applyThreshold(result);
		  return result;
	  }
	  cv::Mat getCorners(const cv::Mat &image) {
		  cv::Mat result;
		  // Dilate with a cross	
		  cv::dilate(image,result,cross);
		  // Erode with a diamond
		  cv::erode(result,result,diamond);
		  cv::Mat result2;
		  // Dilate with a X	
		  cv::dilate(image,result2,x);
		  // Erode with a square
		  cv::erode(result2,result2,square);
		  // Corners are obtained by differencing
		  // the two closed images
		  cv::absdiff(result2,result,result);
          // Apply threshold to obtain a binary image
		  applyThreshold(result);
		  return result;
	  }
	  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 each pixel	
		  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));
		  }
	  }
};

使用:

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "morphoFeatures.h"
int main()
{
	// Read input image
	cv::Mat image= cv::imread("house2.jpg",0);
	if (!image.data)
		return 0; 
	// resize for book printing
	cv::resize(image, image, cv::Size(), 0.7, 0.7);
    // Display the image
	cv::namedWindow("Image");
	cv::imshow("Image",image);
	// Create the morphological features instance
	MorphoFeatures morpho;
	morpho.setThreshold(40);
	// Get the edges
	cv::Mat edges;
	edges= morpho.getEdges(image);
    // Display the edge image
	cv::namedWindow("Edge Image");
	cv::imshow("Edge Image",edges);
	// Get the corners
    morpho.setThreshold(-1);
	cv::Mat corners;
	corners= morpho.getCorners(image);
	cv::morphologyEx(corners,corners,cv::MORPH_TOPHAT,cv::Mat());
    cv::threshold(corners, corners, 35, 255, cv::THRESH_BINARY_INV);
    // Display the corner image
	cv::namedWindow("Corner Image");
	cv::imshow("Corner Image",corners);
    // Display the corner on the image
	morpho.drawOnImage(corners,image);
	cv::namedWindow("Corners on Image");
	cv::imshow("Corners on Image",image);
      return 0}

4、使用MSER算法提取特征区域
最大稳定值区域(MSER)算法可以从图像和总提取有意义的区域。

class MSERFeatures {
  private:
	  cv::MSER mser;        // mser detector
	  double minAreaRatio;  // extra rejection parameter
  public:
	  MSERFeatures(int minArea=60, int maxArea=14400, // aceptable size range 
		           double minAreaRatio=0.5, // min value for MSER area/bounding-rect area
				   int delta=5, // delta value used for stability measure
				   double maxVariation=0.25, // max allowed area variation
				   double minDiversity=0.2)  // min size increase between child and parent
		              : mser(delta,minArea,maxArea,maxVariation,minDiversity), 
					    minAreaRatio(minAreaRatio) {}
	  // get the rotated bouding rectangles corresponding to each MSER feature
	  // if (mser area / bounding rect area) < areaRatio, the feature is rejected
	  void getBoundingRects(const cv::Mat &image, std::vector<cv::RotatedRect> &rects) {
		  // detect MSER features
          std::vector<std::vector<cv::Point> > points;
		  mser(image, points);
		  // for each detected feature
          for (std::vector<std::vector<cv::Point> >::iterator it= points.begin();
			   it!= points.end(); ++it) {
				   
			  // Extract bouding rectangles
			  cv::RotatedRect rr= cv::minAreaRect(*it);
		
			  // check area ratio
			  if (it->size() > minAreaRatio*rr.size.area())
				rects.push_back(rr);
		  }
	  }
	  // draw the rotated ellipses corresponding to each MSER feature
	  cv::Mat getImageOfEllipses(const cv::Mat &image, std::vector<cv::RotatedRect> &rects, cv::Scalar color=255) {
		  // image on which to draw
		  cv::Mat output= image.clone();
		  // get the MSER features
		  getBoundingRects(image, rects);
		  // for each detected feature
		  for (std::vector<cv::RotatedRect>::iterator it= rects.begin();
			   it!= rects.end(); ++it) {
			  cv::ellipse(output,*it,color);
		  }
		  return output;
	  }
	  double getAreaRatio() {
		  return minAreaRatio;
	  }
	  void setAreaRatio(double ratio) {
		  minAreaRatio= ratio;
	  }
};
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
#include "mserFeatures.h"
int main()
{
	// Read input image
	cv::Mat image= cv::imread("graze.jpg",0);
	if (!image.data)
		return 0; 
	// resize for book printing
	cv::resize(image, image, cv::Size(), 0.7, 0.7);
    // Display the image
	cv::namedWindow("Image");
	cv::imshow("Image",image);
	
	// basic MSER detector
	cv::MSER mser(5,     // delta value for local minima detection
		          200,   // min acceptable area 
				  1500); // max acceptable area
	// vector of point sets
    std::vector<std::vector<cv::Point> > points;
	// detect MSER features
	mser(image, points);
	std::cout << points.size() << " MSERs detected" << std::endl;
	// create white image
	cv::Mat output(image.size(),CV_8UC3);
	output= cv::Scalar(255,255,255);
	
	// random number generator
	cv::RNG rng;
	// for each detected feature
    for (std::vector<std::vector<cv::Point> >::iterator it= points.begin();
			   it!= points.end(); ++it) {
		// generate a random color
		cv::Vec3b c(rng.uniform(0,255),
			        rng.uniform(0,255),
					rng.uniform(0,255));
		std::cout << "MSER size= " << it->size() << std::endl;
		// for each point in MSER set
		for (std::vector<cv::Point>::iterator itPts= it->begin();
			        itPts!= it->end(); ++itPts) {
			//do not overwrite MSER pixels
			if (output.at<cv::Vec3b>(*itPts)[0]==255) {
				output.at<cv::Vec3b>(*itPts)= c;
			}
		}
	}
	cv::namedWindow("MSER point sets");
	cv::imshow("MSER point sets",output);
	cv::imwrite("mser.bmp", output);
	// detection using mserFeatures class
	// create MSER feature detector instance
	MSERFeatures mserF(200,  // min area 
		               1500, // max area
					   0.5); // ratio area threshold
	                         // default delta is used
	// the vector of bounding rotated rectangles
	std::vector<cv::RotatedRect> rects;
	// detect and get the image
	cv::Mat result= mserF.getImageOfEllipses(image,rects);
	// display detected MSER
	cv::namedWindow("MSER regions");
	cv::imshow("MSER regions",result);
	cv::waitKey();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值