图像卷积的时候边界像素不被卷积操作,原因在于边界像素没有完全跟kernel重叠,只有当3X3的滤波时候有一个像素的边缘没有被处理,5x5滤波的时候有两个像素边缘没有处理。
在卷积开始之前增加边缘像素,填充的像素值为0或者RGB黑色,比如3x3在四周各填充1各像素的边缘,这样就确保图像的边缘被处理,在卷积处理hi后再去掉这些边缘,openCV中默认的处理方式就是:BORDER_DEFAULT,此外还有常用
copyMakeBorder(
Mat src,//输入图像
Mat dst,//添加边缘图像
int top,//边缘长度,一般上下左右都取相同值
int bottom,
int left,
int right,
int borderType//边缘类型
Scalar value
)
void MyApi::image_edge_processing(Mat& image)
{
//每半秒中图像的边缘就会变化一次,我们也可以通过按键选择变化的类型
Mat dst;
int top = (int)(0.05 * image.rows);
int bottom = (int)(0.05 * image.rows);
int left = (int)(0.05 * image.cols);
int right = (int)(0.05 * image.cols);
RNG rng(12345);
int borderType = BORDER_DEFAULT;
int c = 0;
while (true)
{
c = waitKey(500);
//ESC
if ((char)c == 27)
{
break;
}
if ((char)c == 'r')
{
borderType = BORDER_REPLICATE;
}
else if ((char)c == 'w')
{
borderType == BORDER_WRAP;
}
else if ((char)c == 'c')
{
borderType == BORDER_CONSTANT;
}
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
copyMakeBorder(image, dst, top, bottom, left, right, borderType, color);
imshow("OUTPUT", dst);
}
}
边缘:
- 边缘是什么:是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
- 如何捕捉/提取边缘——对图像求他的一阶导数,delta = f(x)-f(x-1).delta越大说明像素在方向变化越大,边缘信号越强
- 我们可以选择利用一些算子如Sobel算子等
水平梯度在水平方向乘以2为了扩大水平方向差异,垂直方向同理。
改进版本的Sobel算子:
相关的API
cv::Sobel(inputArray src,OutputArray dst,
int depth,//输出图像深度
int dx,//x和y方向的几节导数,选择1
int dy,
int ksize,//Sobel算子kernel大小,必须是1,3,5,7
double scale=1
double delta =0
int borderType = BORDEDR_DEFAULT
)
深度一般选择CV_8U中的 CV_16S或者CV_32F
步骤:
- 高斯平滑
- 转灰度
- 求梯度,分别在x和Y方向上的
- 振幅图片(综合X和Y方向上的)
void MyApi::image_edge_extract(Mat& image)
{
Mat gray_image, dst;
GaussianBlur(image, dst, Size(5, 5), 0, 0);
cvtColor(dst, gray_image, COLOR_BGR2GRAY);
Mat xgard, ygrad;
Sobel(gray_image, xgard, CV_16S, 1, 0, 3);
Sobel(gray_image, ygrad, CV_16S, 0, 1, 3);
//convert(ScaleAbs());
//必须取绝对值不然看不见效果
convertScaleAbs(xgard, xgard);
convertScaleAbs(ygrad, ygrad);
//x方向梯度
imshow("xgrad", xgard);
//y方向梯度
imshow("ygrad", ygrad);
//xy方向梯度
Mat xygrad;
addWeighted(xgard, 0.5, ygrad, 0.5,0,xygrad);
imshow("xygrad", xygrad);
}
高斯模糊去噪声GaussianBlue()
转换为灰度图像cvtColor()
拉普拉斯二阶导数计算Laplacian()
取绝对值convertScaleAbs()
显示结果
void MyApi::image_edge_extraxt_Laplance(Mat& image)
{
Mat gray_image, edge_image, dst;
GaussianBlur(image, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray_image, COLOR_BGR2GRAY);
Laplacian(gray_image, edge_image, CV_16S, 3);
convertScaleAbs(edge_image, edge_image);
imshow("output", edge_image);
}
为了让效果更佳的明显我们选用了二值化操作:
图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果。在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。OpenCV中提供了函数cv::threshold();
加一句:
通过二值化后:
Canny1986年提出的是边缘检测算法,是一个很好的边缘检测器,很常用的图像处理方法
Canny(
InputArray src,
OutputArray edges,
double threshold1,//低阈值,常取高于之的1/2或者1/3
double threshold2,//高阈值
int aptertureSize,//Sobel算子的size,通常3x3取值为3
bool L2gradient//选择true表示L2来归一化,否则用L1来归一化
)