一起学opencv (十) sobel and laplacian

#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



//这种边缘检测与canny变换类似,效果不如canny变换
#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("bfg.jpg", 0);
	if (!image.data)
		return 0;

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

	// Compute Sobel X derivative 默认图核为3X3 高通滤波 ,方向滤波,X水平方向表示为 1,0
	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标准型
	sobel = abs(sobelX) + abs(sobelY);

	double sobmin, sobmax;
	cv::minMaxLoc(sobel, &sobmin, &sobmax);//获得最大最小值double形
	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);//将图片CV_16S转化为CV_8U格式,且设置颜色范围,线性变换

	// 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);//根据图像偏白设置大的限定值225能够保证一个具体的边缘线条,设置低的190可能导致边缘缺失

	// 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(20);
	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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值