天天看點

計算圖像的拉普拉斯變換,使用方向濾波器檢測邊緣

#if !defined LAPLACEZC
#define LAPLACEZC

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class LaplacianZC {

  private:

	  // original image
	  cv::Mat img;

	  // 32-bit float image containing the Laplacian
	  cv::Mat laplace;
	  // Aperture size of the laplacian kernel
	  int aperture;

  public:

	  LaplacianZC() : aperture(3) {}

	  // Set the aperture size of the kernel
	  void setAperture(int a) {

		  aperture= a;
	  }

	  // Get the aperture size of the kernel
	  int getAperture() const {

		  return aperture;
	  }

	  // Compute the floating point Laplacian
	  cv::Mat computeLaplacian(const cv::Mat& image) {


		  // Compute Laplacian
		  cv::Laplacian(image,laplace,CV_32F,aperture);

		  // Keep local copy of the image
		  // (used for zero-crossings)
		  img= image.clone();

		  return laplace;
	  }

	  // Get the Laplacian result in 8-bit image 
	  // zero corresponds to gray level 128
	  // if no scale is provided, then the max value will be
	  // scaled to intensity 255
	  // You must call computeLaplacian before calling this method
	  cv::Mat getLaplacianImage(double scale=-1.0) {

		  if (scale<0) {
	
			  double lapmin, lapmax;
			  cv::minMaxLoc(laplace,&lapmin,&lapmax);

			  scale= 127/ std::max(-lapmin,lapmax);
		  }

		  cv::Mat laplaceImage;
		  laplace.convertTo(laplaceImage,CV_8U,scale,128);

		  return laplaceImage;
	  }

	  // Get a binary image of the zero-crossings
	  // if the product of the two adjascent pixels is
	  // less than threshold then this zero-crossing will be ignored
	  cv::Mat getZeroCrossings(float threshold=1.0) {

		  // Create the iterators
		  cv::Mat_<float>::const_iterator it= laplace.begin<float>()+laplace.step1();
		  cv::Mat_<float>::const_iterator itend= laplace.end<float>();
		  cv::Mat_<float>::const_iterator itup= laplace.begin<float>();

		  // Binary image initialize to white
		  cv::Mat binary(laplace.size(),CV_8U,cv::Scalar(255));
		  cv::Mat_<uchar>::iterator itout= binary.begin<uchar>()+binary.step1();

		  // negate the input threshold value
		  threshold *= -1.0;

		  for ( ; it!= itend; ++it, ++itup, ++itout) {

			  // if the product of two adjascent pixel is negative
			  // then there is a sign change
			  if (*it * *(it-1) < threshold)
				  *itout= 0; // horizontal zero-crossing
			  else if (*it * *itup < threshold)
				  *itout= 0; // vertical zero-crossing
		  }

		  return binary;
	  }

	  // Get a binary image of the zero-crossings
	  // if the product of the two adjacent pixels is
	  // less than threshold then this zero-crossing will be ignored
	  cv::Mat getZeroCrossingsWithSobel(float threshold) {

		  cv::Mat sx;
		  cv::Sobel(img,sx,CV_32F,1,0,1);
		  cv::Mat sy;
		  cv::Sobel(img,sy,CV_32F,0,1,1);

		  // Create the iterators
		  cv::Mat_<float>::const_iterator it= laplace.begin<float>()+laplace.step1();
		  cv::Mat_<float>::const_iterator itend= laplace.end<float>();
		  cv::Mat_<float>::const_iterator itup= laplace.begin<float>();
		  cv::Mat_<float>::const_iterator itx= sx.begin<float>()+sx.step1();
		  cv::Mat_<float>::const_iterator ity= sy.begin<float>()+sy.step1();

		  // Binary image initialize to white
		  cv::Mat binary(laplace.size(),CV_8U,cv::Scalar(255));
		  cv::Mat_<uchar>::iterator itout= binary.begin<uchar>()+binary.step1();

		  for ( ; it!= itend; ++it, ++itup, ++itout, ++itx, ++ity) {

			  // if the product of two adjacent pixel is negative
			  // then there is a sign change
			  if (*it * *(it-1) < 0.0 && fabs(*ity) > threshold)
				  *itout= 0; // horizontal zero-crossing
			  else if (*it * *itup < 0.0 && fabs(*ity) > threshold)
				  *itout= 0; // vertical zero-crossing
		  }

		  return binary;
	  }

};


#endif
#include <iostream>
#include <iomanip>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "laplacianZC.h"

int main()
{
	// Read input image
	cv::Mat image= cv::imread("d:/test/opencv/boldt.jpg",0);
	if (!image.data)
		return 0; 

    // Display the image
	cv::namedWindow("Original Image");
	cv::imshow("Original Image",image);

	// Compute Sobel X derivative
	cv::Mat sobelX;
	cv::Sobel(image,sobelX,CV_8U,1,0,3,0.4,128);

    // Display the image
	cv::namedWindow("Sobel X Image");
	cv::imshow("Sobel X Image",sobelX);

	// Compute Sobel Y derivative
	cv::Mat sobelY;
	cv::Sobel(image,sobelY,CV_8U,0,1,3,0.4,128);

    // Display the image
	cv::namedWindow("Sobel Y Image");
	cv::imshow("Sobel Y Image",sobelY);

	// Compute norm of Sobel
	cv::Sobel(image,sobelX,CV_16S,1,0);
	cv::Sobel(image,sobelY,CV_16S,0,1);
	cv::Mat sobel;
	//compute the L1 norm
	sobel= abs(sobelX)+abs(sobelY);

	double sobmin, sobmax;
	cv::minMaxLoc(sobel,&sobmin,&sobmax);
	std::cout << "sobel value range: " << sobmin << "  " << sobmax << std::endl;

	// Print window pixel values
	for (int i=0; i<12; i++) {
		for (int j=0; j<12; j++)
			std::cout << std::setw(5) << static_cast<int>(sobel.at<short>(i+135,j+362)) << " ";
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << std::endl;
	std::cout << std::endl;

	// Conversion to 8-bit image
	// sobelImage = -alpha*sobel + 255
	cv::Mat sobelImage;
	sobel.convertTo(sobelImage,CV_8U,-255./sobmax,255);

    // Display the image
	cv::namedWindow("Sobel Image");
	cv::imshow("Sobel Image",sobelImage);

	// Apply threshold to Sobel norm (low threshold value)
	cv::Mat sobelThresholded;
	cv::threshold(sobelImage, sobelThresholded, 225, 255, cv::THRESH_BINARY);

    // Display the image
	cv::namedWindow("Binary Sobel Image (low)");
	cv::imshow("Binary Sobel Image (low)",sobelThresholded);

	// Apply threshold to Sobel norm (high threshold value)
	cv::threshold(sobelImage, sobelThresholded, 190, 255, cv::THRESH_BINARY);

    // Display the image
	cv::namedWindow("Binary Sobel Image (high)");
	cv::imshow("Binary Sobel Image (high)",sobelThresholded);

	// Compute Laplacian 3x3
	cv::Mat laplace;
	cv::Laplacian(image,laplace,CV_8U,1,1,128);

    // Display the image
	cv::namedWindow("Laplacian Image");
	cv::imshow("Laplacian Image",laplace);

	// Print window pixel values
	for (int i=0; i<12; i++) {
		for (int j=0; j<12; j++)
			std::cout << std::setw(5) << static_cast<int>(laplace.at<uchar>(i+135,j+362))-128 << " ";
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << std::endl;
	std::cout << std::endl;

	// Compute Laplacian 7x7
	cv::Laplacian(image,laplace,CV_8U,7,0.01,128);

    // Display the image 
	cv::namedWindow("Laplacian Image");
	cv::imshow("Laplacian Image",laplace);

	// Print window pixel values
	for (int i=0; i<12; i++) {
		for (int j=0; j<12; j++)
			std::cout << std::setw(5) << static_cast<int>(laplace.at<uchar>(i+135,j+362))-128 << " ";
		std::cout << std::endl;
	}

    // Extract small window
	cv::Mat window(image,cv::Rect(362,135,12,12));
	cv::namedWindow("Image window");
	cv::imshow("Image window",window);
	cv::imwrite("window.bmp",window);

	// Compute Laplacian using LaplacianZC class
	LaplacianZC laplacian;
	laplacian.setAperture(7);
	cv::Mat flap= laplacian.computeLaplacian(image);
	double lapmin, lapmax;
	cv::minMaxLoc(flap,&lapmin,&lapmax);
	std::cout << "Laplacian value range=[" << lapmin << "," << lapmax << "]\n";
	laplace= laplacian.getLaplacianImage();
	cv::namedWindow("Laplacian Image (7x7)");
	cv::imshow("Laplacian Image (7x7)",laplace);

	// Print Laplacian values
	std::cout << std::endl;
	for (int i=0; i<12; i++) {
		for (int j=0; j<12; j++)
			std::cout << std::setw(5) << static_cast<int>(flap.at<float>(i+135,j+362)/100) << " ";
		std::cout << std::endl;
	}
	std::cout << std::endl;

	// Compute and display the zero-crossing points
	cv::Mat zeros;
	zeros= laplacian.getZeroCrossings(lapmax);
	cv::namedWindow("Zero-crossings");
	cv::imshow("Zero-crossings",zeros);

	// Compute and display the zero-crossing points (Sobel version)
	zeros= laplacian.getZeroCrossings();
	zeros= laplacian.getZeroCrossingsWithSobel(50);
	cv::namedWindow("Zero-crossings (2)");
	cv::imshow("Zero-crossings (2)",zeros);

	// Print window pixel values
	for (int i=0; i<12; i++) {
		for (int j=0; j<12; j++)
			std::cout << std::setw(2) << static_cast<int>(zeros.at<uchar>(i+135,j+362)) << " ";
		std::cout << std::endl;
	}

    // Display the image with window
	cv::rectangle(image,cv::Point(362,135),cv::Point(374,147),cv::Scalar(255,255,255));
	cv::namedWindow("Original Image with window");
	cv::imshow("Original Image with window",image);

	cv::waitKey();
	return 0;
}