lena_gray_512
高斯滤波
高斯滤波
我之前写过高斯滤波,现在只写代码
cv::Mat Gauss(const cv::Mat& img, double sigma)
{ // 高斯模糊
int rows = img.rows, cols = img.cols;
cv::Mat temp(rows, cols, CV_8U, cv::Scalar(0));
int n = ceil(6 * sigma);
if (n % 2 == 0)
n++;
double** gauss = new double*[n]; //高斯模板
double sum = 0;
for (int i = 0; i < n; i++)
gauss[i] = new double[n];
for (int i = 0; i < n; i++)
{
int x = i - n / 2;
for (int j = 0; j < n; j++)
{
int y = j - n / 2;
gauss[i][j] = exp(-(pow(x, 2) + pow(y, 2)) / (2 * pow(sigma, 2)));
sum += gauss[i][j];
}
}
for (int i = 0; i < n; i++) // 归一化
for (int j = 0; j < n; j++)
gauss[i][j] /= sum;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
{
for (int m = 0; m < n; m++)
for (int k = 0; k < n; k++)
if (i - n / 2 + m >= 0 && i - n / 2 + m < rows && j - n / 2 + k >= 0 && j - n / 2 + k < cols)
temp.ptr(i)[j] += gauss[m][k] * img.ptr(i - n / 2 + m)[j - n / 2 + k];
else
temp.ptr(i)[j] += gauss[m][k] * img.ptr(i)[j];
}
return temp;
}
return temp;
}
高斯滤波后的lena图
求梯度
Sobel算子
将方向的值统一到上
cv::Mat Sobel(const cv::Mat& img, int** theta)
{ //同时计算角度
const int rows = img.rows;
const int cols = img.cols;
cv::Mat temp(rows, cols, CV_8U, cv::Scalar(0));
int M[rows][cols];
int gx, gy;
int min = 1000, max = 0;
for (int i = 1; i < rows - 1; i++)
for (int j = 1; j < cols - 1; j++)
{
gx = img.ptr(i + 1)[j - 1] + 2 * img.ptr(i + 1)[j] + img.ptr(i + 1)[j + 1] - img.ptr(i - 1)[j - 1] - 2 * img.ptr(i - 1)[j] - img.ptr(i - 1)[j + 1];
gy = img.ptr(i + 1)[j + 1] + 2 * img.ptr(i)[j + 1] + img.ptr(i - 1)[j + 1] - img.ptr(i - 1)[j - 1] - 2 * img.ptr(i)[j - 1] - img.ptr(i + 1)[j - 1];
M[i][j] = abs(gx) + abs(gy);
if (temp.ptr(i)[j] > max)
max = M[i][j];
if (temp.ptr(i)[j] < min)
min = M[i][j];
if (gx < 0)
{
gx = -gx;
gy = -gy;
}
gy = gy << 16;
int tanpi_8gx = gx * 27146; // 27146 是tan(pi/8)*(1<<16),使用整形可以加快运算
int tan3pi_8gx = gx * 158218; // 158218 是tan(3pi/8)*(1<<16)
if (abs(gy) > tan3pi_8gx)
theta[i][j] = 0;
else if (gy > tanpi_8gx)
theta[i][j] = 1;
else if (gy > -tanpi_8gx)
theta[i][j] = 2;
else
theta[i][j] = 3;
}
if (max != min)
for (int i = 1; i < rows - 1; i++)
for (int j = 1; j < cols - 1; j++)
M[i][j] = 255 * (M[i][j] - min) / (max - min);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
temp.ptr(i)[j] = M[i][j];
return temp;
}
非极大值抑制
如果梯度赋值在它的方向上不是最大值,将其设0
int direc_base[4][2] = {{0, 1}, {1, 1}, {1, 0}, {0, -1}};
for (int i = 1; i < rows - 1; i++) //非极大值抑制
for (int j = 1; j < cols - 1; j++)
{
if (M.ptr(i)[j] < M.ptr(i + direc_base[alpha[i][j]][0])[j + direc_base[alpha[i][j]][1]] || M.ptr(i)[j] < M.ptr(i - direc_base[alpha[i][j]][0])[j - direc_base[alpha[i][j]][1]])
M.ptr(i)[j] = 0;
}
双阈值处理
输入高阈值与低阈值
将非极大值抑制的图像分为两个边缘图像MH,ML
全部代码
cv::Mat Gauss(const cv::Mat& img, double sigma)
{ // 高斯模糊
int rows = img.rows, cols = img.cols;
cv::Mat temp(rows, cols, CV_8U, cv::Scalar(0));
int n = ceil(6 * sigma);
if (n % 2 == 0)
n++;
double** gauss = new double*[n]; //高斯模板
double sum = 0;
for (int i = 0; i < n; i++)
gauss[i] = new double[n];
for (int i = 0; i < n; i++)
{
int x = i - n / 2;
for (int j = 0; j < n; j++)
{
int y = j - n / 2;
gauss[i][j] = exp(-(pow(x, 2) + pow(y, 2)) / (2 * pow(sigma, 2)));
sum += gauss[i][j];
}
}
for (int i = 0; i < n; i++) // 归一化
for (int j = 0; j < n; j++)
gauss[i][j] /= sum;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
{
for (int m = 0; m < n; m++)
for (int k = 0; k < n; k++)
if (i - n / 2 + m >= 0 && i - n / 2 + m < rows && j - n / 2 + k >= 0 && j - n / 2 + k < cols)
temp.ptr(i)[j] += gauss[m][k] * img.ptr(i - n / 2 + m)[j - n / 2 + k];
else
temp.ptr(i)[j] += gauss[m][k] * img.ptr(i)[j];
}
return temp;
}
cv::Mat Sobel(const cv::Mat& img, int** theta)
{ //同时计算角度
const int rows = img.rows;
const int cols = img.cols;
cv::Mat temp(rows, cols, CV_8U, cv::Scalar(0));
int M[rows][cols];
int gx, gy;
int min = 1000, max = 0;
for (int i = 1; i < rows - 1; i++)
for (int j = 1; j < cols - 1; j++)
{
gx = img.ptr(i + 1)[j - 1] + 2 * img.ptr(i + 1)[j] + img.ptr(i + 1)[j + 1] - img.ptr(i - 1)[j - 1] - 2 * img.ptr(i - 1)[j] - img.ptr(i - 1)[j + 1];
gy = img.ptr(i + 1)[j + 1] + 2 * img.ptr(i)[j + 1] + img.ptr(i - 1)[j + 1] - img.ptr(i - 1)[j - 1] - 2 * img.ptr(i)[j - 1] - img.ptr(i + 1)[j - 1];
M[i][j] = abs(gx) + abs(gy);
if (temp.ptr(i)[j] > max)
max = M[i][j];
if (temp.ptr(i)[j] < min)
min = M[i][j];
if (gx < 0)
{
gx = -gx;
gy = -gy;
}
gy = gy << 16;
int tanpi_8gx = gx * 27146; // 27146 是tan(pi/8)*(1<<16),使用整形可以加快运算
int tan3pi_8gx = gx * 158218; // 158218 是tan(3pi/8)*(1<<16)
if (abs(gy) > tan3pi_8gx)
theta[i][j] = 0;
else if (gy > tanpi_8gx)
theta[i][j] = 1;
else if (gy > -tanpi_8gx)
theta[i][j] = 2;
else
theta[i][j] = 3;
}
if (max != min)
for (int i = 1; i < rows - 1; i++)
for (int j = 1; j < cols - 1; j++)
M[i][j] = 255 * (M[i][j] - min) / (max - min);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
temp.ptr(i)[j] = M[i][j];
return temp;
}
cv::Mat Canny(const cv::Mat& img)
{ // Canny边缘检测
int rows = img.rows, cols = img.cols;
int direc_base[4][2] = {{0, 1}, {1, 1}, {1, 0}, {0, -1}};
cv::Mat temp(rows, cols, CV_8U, cv::Scalar(0));
cv::Mat M(rows, cols, CV_8U, cv::Scalar(0));
cv::Mat ML(rows, cols, CV_8U, cv::Scalar(0));
cv::Mat MH(rows, cols, CV_8U, cv::Scalar(0));
int** alpha = new int*[rows];
for (int i = 0; i < rows; i++)
alpha[i] = new int[cols];
std::cout << "Canny 边缘检测" << std::endl;
std::cout << "输入高斯模板的sigma" << std::endl;
double sigma;
std::cin >> sigma;
M = Gauss(img, sigma); // 高斯滤波
cv::imwrite("gauss.png", M);
std::cout << "求梯度" << std::endl;
M = Sobel(M, alpha);
cv::imwrite("weifen.png", M);
for (int i = 1; i < rows - 1; i++) //极大值抑制
for (int j = 1; j < cols - 1; j++)
{
if (M.ptr(i)[j] < M.ptr(i + direc_base[alpha[i][j]][0])[j + direc_base[alpha[i][j]][1]] || M.ptr(i)[j] < M.ptr(i - direc_base[alpha[i][j]][0])[j - direc_base[alpha[i][j]][1]])
M.ptr(i)[j] = 0;
}
for (int i = 0; i < rows; i++)
delete[] alpha[i];
delete[] alpha;
cv::imwrite("yizhi.png", M);
// 阈值处理
int tl = 0, th = 0;
std::cout << "输入tl,th" << std::endl;
std::cin >> tl >> th;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
{
if (M.ptr(i)[j] > th)
MH.ptr(i)[j] = 255;
else if (M.ptr(i)[j] > tl)
ML.ptr(i)[j] = 255;
}
cv::imwrite("MH.png", MH);
cv::imwrite("ML.png", ML);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
{
if (MH.ptr(i)[j] != 0)
{ //检测弱边缘是否连通
MH.ptr(i)[j] = 0;
temp.ptr(i)[j] = 255;
bool flg = true;
int* point = new int[2];
point[0] = i;
point[1] = j;
std::stack S;
S.push(point);
while (flg || !S.empty())
{
flg = false;
point = S.top();
part1:
for (int m = -1; m <= 1; m++)
for (int k = -1; k <= 1; k++)
{
if (point[0] + m >= 0 && point[0] + m < rows && point[1] + k >= 0 && point[1] + k < cols && ML.ptr(point[0] + m)[point[1] + k] != 0)
{
temp.ptr(point[0] + m)[point[1] + k] = ML.ptr(point[0] + m)[point[1] + k];
ML.ptr(point[0] + m)[point[1] + k] = 0;
point = new int[2];
point[0] = S.top()[0] + m;
point[1] = S.top()[1] + k;
S.push(point);
flg = true;
goto part1;
}
}
if (!flg && !S.empty())
{
S.pop();
delete[] point;
}
}
}
}
cv::imwrite("canny.png", temp);
// ********************
return temp;
}
PS:
与opencv自带的Canny相比还有很大的差距,但是不知到如何改进, 希望高手指教