https://blog.csdn.net/qq_46164507/article/details/122503851
本文所使用代码或多或少参考了以往博文的同类or相似文章的代码,并非纯原创
本文仅用于记录并提供一种代码思路,供大家参考
运行环境:Ubuntu16.04 LTS + OpenCV 3.0.4 + ROS-kinetic-full
代码语言:c++
#include
#include
#include
#include
#include
#include
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Bool.h"
#include "std_msgs/Float32.h"
#include
#include "sensor_msgs/Image.h"
#include
#define M_pi 3.14159265
#define LINEAR_X 0
using namespace std;
using namespace cv;
//滤波//
// 空域高斯滤波器函数
void Gaussian(Mat input, Mat output, double sigma){
// 3sigma原则确定模板矩阵大小
int x0=int(6*sigma+1);
if(x0%2==1){
x0=(x0-1)/2;
}else{
x0=x0/2;
}
double t[2*x0+1][2*x0+1];//定义模板矩阵
//计算模板矩阵
for(int i=-x0;i<=x0;i++){
for(int j=-x0;j<=x0;j++){
t[x0+i][x0+j]=1/(2*M_pi*pow(sigma,2))*\
exp(-(pow(i,2)+pow(j,2))/(2*pow(sigma,2)));
}
}
//归一化,3sigma仍然没有归一化
double temp=0;
for(int i=-x0;i<=x0;i++){
for(int j=-x0;j<=x0;j++){
temp+=t[x0+i][x0+j];
}
}
for(int i=0;i<input.rows;i++){
for(int j=0;j<input.cols;j++){
//图形边缘采用原图灰度值
if(i<x0||i>=input.rows-x0||j<x0||j>=input.cols-x0)
{
output.at<uchar>(i,j)=input.at<uchar>(i,j);
}else{
double sum=0;
for(int x=-x0;x<=x0;x++){
for(int y=-x0;y<=x0;y++){
sum=sum+input.at<uchar>(i+x,j+y)*t[x0+x][x0+y]/temp;
}
}
output.at<uchar>(i,j)=sum;
}
}
}
}
//形态学//
// 膨胀函数
void Dilate(Mat Src, Mat Tem, Mat Dst){
int n=Dst.rows;
int x0=(n-1)/2;int y0=(n-1)/2;//模板中心位置
//计算 Dst1 反射模板
Mat Dst1(Dst.rows,Dst.cols, CV_8UC1);
for (int i=0; i<Dst.rows; i++){
for (int j=0; j<Dst.cols; j++){
Dst1.at<uchar>(i,j)=Dst.at<uchar>(2*x0-i,2*y0-j);}}
// 创建扩充矩阵N+2*M+2
Mat Src2 = Mat::zeros(Src.rows+2*x0, Src.cols+2*y0, CV_8UC1);//Src2 扩充矩阵
// imshow("kuochongjuzhen1",Src2);
for (int i=x0; i<Src.rows+x0; i++){
for (int j=y0; j<Src.cols+y0; j++){
Src2.at<uchar>(i,j)=Src.at<uchar>(i-x0,j-x0);
}
}
// 操作
for (int i=0; i<Src.rows; i++){
for (int j=0; j<Src.cols; j++){
int flag=0;
for(int x=-x0;x<=x0;x++){
for(int y=-y0;y<=y0;y++){
if(Dst1.at<uchar>(x+x0,y+y0)==255){
if(Src2.at<uchar>(i+x+x0,j+y+y0)==255){
flag=1;
}
}
}
}
if(flag==1){Tem.at<uchar>(i,j)=255;}
}
}
}
// 腐蚀函数
void Erode(Mat Src, Mat Tem, Mat Dst){
int n=Dst.rows;
int x0=(n-1)/2;int y0=(n-1)/2;//模板中心位置
// 创建扩充矩阵N+2*M+2
Mat Src2 = Mat::zeros(Src.rows+2*x0, Src.cols+2*y0, CV_8UC1);//Src2 扩充矩阵
for (int i=x0; i<Src.rows+x0; i++){
for (int j=y0; j<Src.cols+y0; j++){
Src2.at<uchar>(i,j)=Src.at<uchar>(i-x0,j-x0);
}
}
// 操作
for (int i=0; i<Src.rows; i++){
for (int j=0; j<Src.cols; j++){
int flag=1;
for(int x=-x0;x<=x0;x++){
for(int y=-y0;y<=y0;y++){
if(Dst.at<uchar>(x0+x,y0+y)==255){
if(Src2.at<uchar>(i+x+x0,j+y+y0)==255){
}else{flag=0;}
}
}
}
if(flag==1){Tem.at<uchar>(i,j)=255;}
}
}
}
int main(int argc, char **argv)
{
VideoCapture capture;
capture.open(0); // 1 为打开 zed 相机, 0 为打开笔记本摄像头
ROS_WARN("*****START");
ros::init(argc,argv,"trafficLaneTrack");//初始化 ROS 节点
ros::NodeHandle n;
// ros::Rate loop_rate(10);//定义速度发布频率
ros::Publisher pub = n.advertise<geometry_msgs::Twist>("/smoother_cmd_vel", 5);//定义速度发布器
if (!capture.isOpened())
{
printf("摄像头没有正常打开,重新插拔工控机上当摄像头\n");
return 0;
}
waitKey(1000);
Mat frame;//当前帧图片
int nFrames = 0;//图片帧数
int frameWidth = capture.get(CV_CAP_PROP_FRAME_WIDTH);//图片宽
int frameHeight = capture.get(CV_CAP_PROP_FRAME_HEIGHT);//图片高
while (ros::ok())
{
capture.read(frame);
if(frame.empty())
{
break;
}
Mat IMG = frame.clone();// 使用笔记本摄像头Mat frIn = frame(cv::Rect(0, 0, frame.cols / 2, frame.rows));//截取 zed 的左目图片
//使用本地图像文件
// Mat IMG=imread("./src/img_pkg/src/2.png");
Mat gray;//灰度图
cvtColor(IMG, gray, COLOR_BGR2GRAY);
Mat binary(gray.rows,gray.cols, CV_8UC1);//二值化图像
threshold(gray, binary, 120, 255, CV_THRESH_BINARY);//二值化
//图像反相,便于观察
for (int i=0; i<binary.rows; i++){
for (int j=0; j<binary.cols; j++){
if(binary.at<uchar>(i,j)==255){
binary.at<uchar>(i,j)=0;}
else{binary.at<uchar>(i,j)=255;}
}
}
imshow("1_ordinary image(binary)",binary);
// 空域滤波函数
Mat output = binary.clone();
double sigma=1;//定义高斯滤波方差
Gaussian(IMG,output,sigma);
imshow("2_Gaussianed image",output);//高斯处理后图像
//定义膨胀和腐蚀模板
int n=9;//模板阶数
Mat temp = 255*Mat::ones(n,n, CV_8UC1);//此处定义为实心模板
// 膨胀函数
Mat output1 = Mat::zeros(binary.rows,binary.cols, CV_8UC1);
Dilate(binary,output1,temp);
imshow("3_dilated image",output1);//膨胀后图像
imshow("4_dilated+",output1-binary);//膨胀与原图差
// 腐蚀函数
Mat output2 = Mat::zeros(binary.rows,binary.cols, CV_8UC1);
Erode(binary,output2,temp);
imshow("5_eroded image",output2);//腐蚀后图像
imshow("6_eroded-",binary-output2);//腐蚀与原图差
ros::spinOnce();
waitKey(5);
}
return 0;
}