#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;
}
计算图像的拉普拉斯变换,使用方向滤波器检测边缘
最新推荐文章于 2024-01-31 21:22:03 发布